mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'main' into no-objectAllocator
This commit is contained in:
@@ -17,10 +17,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
- name: Configure Git, Run Tests, Update Baselines, Apply Fixes
|
||||
run: |
|
||||
|
||||
+12
-12
@@ -48,7 +48,7 @@ jobs:
|
||||
name: Test Node ${{ matrix.node-version }} on ${{ matrix.os }}${{ (!matrix.bundle && ' with --no-bundle') || '' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- name: Use node version ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
@@ -86,14 +86,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
check-latest: true
|
||||
- run: npm ci
|
||||
|
||||
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||
with:
|
||||
path: ~/.cache/dprint
|
||||
key: ${{ runner.os }}-dprint-${{ hashFiles('package-lock.json', '.dprint.jsonc') }}
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
@@ -179,11 +179,11 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
path: pr
|
||||
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
path: base
|
||||
ref: ${{ github.base_ref }}
|
||||
@@ -221,7 +221,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
@@ -238,7 +238,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
@@ -258,7 +258,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: '*'
|
||||
|
||||
@@ -42,11 +42,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
|
||||
uses: github/codeql-action/init@4355270be187e1b672a7a1c7c7bae5afdc1ab94a # v3.24.10
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-configuration.yml
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below).
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
|
||||
uses: github/codeql-action/autobuild@4355270be187e1b672a7a1c7c7bae5afdc1ab94a # v3.24.10
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -70,4 +70,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
|
||||
uses: github/codeql-action/analyze@4355270be187e1b672a7a1c7c7bae5afdc1ab94a # v3.24.10
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
|
||||
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
|
||||
|
||||
@@ -20,8 +20,10 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
@@ -40,9 +42,10 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
# Use NODE_AUTH_TOKEN environment variable to authenticate to this registry.
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: |
|
||||
|
||||
@@ -27,11 +27,13 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
ref: ${{ inputs.branch_name }}
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
|
||||
@@ -50,12 +50,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
|
||||
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
|
||||
@@ -21,8 +21,10 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
@@ -40,9 +42,10 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
# Use NODE_AUTH_TOKEN environment variable to authenticate to this registry.
|
||||
registry-url: https://registry.npmjs.org/
|
||||
- run: |
|
||||
|
||||
@@ -19,8 +19,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -55,6 +55,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6
|
||||
uses: github/codeql-action/upload-sarif@4355270be187e1b672a7a1c7c7bae5afdc1ab94a # v3.24.10
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -49,11 +49,13 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
ref: ${{ inputs.branch_name }}
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: |
|
||||
npm --version
|
||||
# corepack enable npm
|
||||
|
||||
@@ -43,7 +43,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
ref: ${{ inputs.branch_name }}
|
||||
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Get repo name
|
||||
run: R=${GITHUB_REPOSITORY%?wiki}; echo "BASENAME=${R##*/}" >> $GITHUB_ENV
|
||||
- name: Checkout ${{ env.BASENAME }}-wiki
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
repository: '${{ GITHUB.repository_owner }}/${{ env.BASENAME }}-wiki'
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
|
||||
@@ -49,13 +49,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- if: ${{ github.event.inputs.bisect }}
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
|
||||
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
|
||||
- if: ${{ !github.event.inputs.bisect }}
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: microsoft/TypeScript-Twoslash-Repro-Action@8680b5b290d48a7badbc7ba65971d526c61b86b8 # master
|
||||
with:
|
||||
github-token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
if: github.repository == 'microsoft/TypeScript'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
||||
with:
|
||||
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
|
||||
Generated
+277
-213
@@ -813,16 +813,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz",
|
||||
"integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
|
||||
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.0.0",
|
||||
"@octokit/request": "^8.0.2",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
"@octokit/request": "^8.3.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
@@ -831,12 +831,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz",
|
||||
"integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz",
|
||||
"integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -844,13 +844,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz",
|
||||
"integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==",
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz",
|
||||
"integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/request": "^8.0.1",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/request": "^8.3.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -858,9 +858,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"version": "22.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.1.0.tgz",
|
||||
"integrity": "sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
@@ -878,6 +878,21 @@
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-request-log": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.1.tgz",
|
||||
@@ -905,15 +920,30 @@
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz",
|
||||
"integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==",
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^9.0.0",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz",
|
||||
"integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^9.0.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -921,12 +951,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz",
|
||||
"integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz",
|
||||
"integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
@@ -950,12 +980,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"version": "13.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.4.1.tgz",
|
||||
"integrity": "sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
"@octokit/openapi-types": "^22.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
@@ -1023,9 +1053,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.12.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
|
||||
"integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
|
||||
"version": "20.12.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
||||
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
@@ -1053,22 +1083,22 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz",
|
||||
"integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
|
||||
"integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/type-utils": "7.5.0",
|
||||
"@typescript-eslint/utils": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/type-utils": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1088,15 +1118,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz",
|
||||
"integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
|
||||
"integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1116,13 +1146,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz",
|
||||
"integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
|
||||
"integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0"
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1133,15 +1163,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz",
|
||||
"integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
|
||||
"integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"@typescript-eslint/utils": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1160,9 +1190,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz",
|
||||
"integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
|
||||
"integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1173,19 +1203,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz",
|
||||
"integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
|
||||
"integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "9.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1201,18 +1231,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz",
|
||||
"integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
|
||||
"integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"semver": "^7.5.4"
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -1226,13 +1256,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz",
|
||||
"integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
|
||||
"integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
@@ -3026,9 +3056,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -3483,12 +3513,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz",
|
||||
"integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==",
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
|
||||
"integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"playwright-core": "1.43.0"
|
||||
"playwright-core": "1.43.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -3501,9 +3531,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
|
||||
"integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==",
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
|
||||
"integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
@@ -3575,9 +3605,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz",
|
||||
"integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==",
|
||||
"version": "6.12.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
|
||||
"integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.6"
|
||||
@@ -4180,9 +4210,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
|
||||
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -4919,45 +4949,45 @@
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz",
|
||||
"integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
|
||||
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.0.0",
|
||||
"@octokit/request": "^8.0.2",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
"@octokit/request": "^8.3.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz",
|
||||
"integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz",
|
||||
"integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz",
|
||||
"integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==",
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz",
|
||||
"integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/request": "^8.0.1",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/request": "^8.3.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"version": "22.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.1.0.tgz",
|
||||
"integrity": "sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
@@ -4967,6 +4997,23 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-request-log": {
|
||||
@@ -4983,27 +5030,44 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz",
|
||||
"integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==",
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz",
|
||||
"integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^9.0.0",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/endpoint": "^9.0.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz",
|
||||
"integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz",
|
||||
"integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/types": "^12.0.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
@@ -5021,12 +5085,12 @@
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"version": "13.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.4.1.tgz",
|
||||
"integrity": "sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
"@octokit/openapi-types": "^22.1.0"
|
||||
}
|
||||
},
|
||||
"@pkgjs/parseargs": {
|
||||
@@ -5088,9 +5152,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.12.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
|
||||
"integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
|
||||
"version": "20.12.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
|
||||
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"undici-types": "~5.26.4"
|
||||
@@ -5118,104 +5182,104 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz",
|
||||
"integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
|
||||
"integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/type-utils": "7.5.0",
|
||||
"@typescript-eslint/utils": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/type-utils": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz",
|
||||
"integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
|
||||
"integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz",
|
||||
"integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
|
||||
"integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0"
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz",
|
||||
"integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
|
||||
"integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"@typescript-eslint/utils": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"@typescript-eslint/utils": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"ts-api-utils": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz",
|
||||
"integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
|
||||
"integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz",
|
||||
"integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
|
||||
"integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/visitor-keys": "7.5.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/visitor-keys": "7.7.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "9.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz",
|
||||
"integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
|
||||
"integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "7.5.0",
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"@typescript-eslint/typescript-estree": "7.5.0",
|
||||
"semver": "^7.5.4"
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.7.0",
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"@typescript-eslint/typescript-estree": "7.7.0",
|
||||
"semver": "^7.6.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz",
|
||||
"integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
|
||||
"integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.5.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
"@typescript-eslint/types": "7.7.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
}
|
||||
},
|
||||
"@ungap/structured-clone": {
|
||||
@@ -6524,9 +6588,9 @@
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -6843,13 +6907,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"playwright": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz",
|
||||
"integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==",
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
|
||||
"integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "2.3.2",
|
||||
"playwright-core": "1.43.0"
|
||||
"playwright-core": "1.43.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"fsevents": {
|
||||
@@ -6862,9 +6926,9 @@
|
||||
}
|
||||
},
|
||||
"playwright-core": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
|
||||
"integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==",
|
||||
"version": "1.43.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
|
||||
"integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
|
||||
"dev": true
|
||||
},
|
||||
"plur": {
|
||||
@@ -6898,9 +6962,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz",
|
||||
"integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==",
|
||||
"version": "6.12.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
|
||||
"integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"side-channel": "^1.0.6"
|
||||
@@ -7322,9 +7386,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
|
||||
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true
|
||||
},
|
||||
"typical": {
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = createRule({
|
||||
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.`,
|
||||
internalCommentOnUnexported: `@internal should not appear on an unexported declaration.`,
|
||||
},
|
||||
schema: [],
|
||||
type: "problem",
|
||||
@@ -23,6 +24,31 @@ module.exports = createRule({
|
||||
const atInternal = "@internal";
|
||||
const jsdocStart = "/**";
|
||||
|
||||
/** @type {Map<import("@typescript-eslint/utils").TSESTree.Node, boolean>} */
|
||||
const isExportedCache = new Map();
|
||||
|
||||
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
|
||||
function isExported(node) {
|
||||
const exported = isExportedCache.get(node);
|
||||
if (exported !== undefined) {
|
||||
return exported;
|
||||
}
|
||||
|
||||
/** @type {import("@typescript-eslint/utils").TSESTree.Node | undefined} */
|
||||
let current = node;
|
||||
while (current) {
|
||||
// https://github.com/typescript-eslint/typescript-eslint/blob/e44a1a280f08f9fd0d29f74e5c3e73b7b64a9606/packages/eslint-plugin/src/util/collectUnusedVariables.ts#L440
|
||||
if (current.type.startsWith("Export")) {
|
||||
isExportedCache.set(node, true);
|
||||
return true;
|
||||
}
|
||||
isExportedCache.set(current, false);
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @type {(text: string) => boolean} */
|
||||
function isJSDocText(text) {
|
||||
return text.startsWith(jsdocStart);
|
||||
@@ -81,12 +107,15 @@ module.exports = createRule({
|
||||
if (!isJSDoc) {
|
||||
context.report({ messageId: "internalCommentInNonJSDocError", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
else if (i !== last) {
|
||||
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) });
|
||||
}
|
||||
else if (!isExported(node)) {
|
||||
context.report({ messageId: "internalCommentOnUnexported", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
else if (i !== last) {
|
||||
context.report({ messageId: "internalCommentNotLastError", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export * from "../transformers/generators";
|
||||
export * from "../transformers/module/module";
|
||||
export * from "../transformers/module/system";
|
||||
export * from "../transformers/module/esnextAnd2015";
|
||||
export * from "../transformers/module/node";
|
||||
export * from "../transformers/module/impliedNodeFormatDependent";
|
||||
export * from "../transformers/declarations/diagnostics";
|
||||
export * from "../transformers/declarations";
|
||||
export * from "../transformer";
|
||||
|
||||
+465
-857
File diff suppressed because it is too large
Load Diff
@@ -53,6 +53,7 @@ import {
|
||||
getFileMatcherPatterns,
|
||||
getLocaleSpecificMessage,
|
||||
getNormalizedAbsolutePath,
|
||||
getOwnKeys,
|
||||
getRegexFromPattern,
|
||||
getRegularExpressionForWildcard,
|
||||
getRegularExpressionsForWildcards,
|
||||
@@ -313,6 +314,7 @@ export const optionsForWatch: CommandLineOption[] = [
|
||||
isFilePath: true,
|
||||
extraValidation: specToDiagnostic,
|
||||
},
|
||||
allowConfigDirTemplateSubstitution: true,
|
||||
category: Diagnostics.Watch_and_Build_Modes,
|
||||
description: Diagnostics.Remove_a_list_of_directories_from_the_watch_process,
|
||||
},
|
||||
@@ -325,6 +327,7 @@ export const optionsForWatch: CommandLineOption[] = [
|
||||
isFilePath: true,
|
||||
extraValidation: specToDiagnostic,
|
||||
},
|
||||
allowConfigDirTemplateSubstitution: true,
|
||||
category: Diagnostics.Watch_and_Build_Modes,
|
||||
description: Diagnostics.Remove_a_list_of_files_from_the_watch_mode_s_processing,
|
||||
},
|
||||
@@ -534,6 +537,7 @@ export const targetOptionDeclaration: CommandLineOptionOfCustomType = {
|
||||
es2020: ScriptTarget.ES2020,
|
||||
es2021: ScriptTarget.ES2021,
|
||||
es2022: ScriptTarget.ES2022,
|
||||
es2023: ScriptTarget.ES2023,
|
||||
esnext: ScriptTarget.ESNext,
|
||||
})),
|
||||
affectsSourceFile: true,
|
||||
@@ -1033,6 +1037,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
|
||||
name: "paths",
|
||||
type: "object",
|
||||
affectsModuleResolution: true,
|
||||
allowConfigDirTemplateSubstitution: true,
|
||||
isTSConfigOnly: true,
|
||||
category: Diagnostics.Modules,
|
||||
description: Diagnostics.Specify_a_set_of_entries_that_re_map_imports_to_additional_lookup_locations,
|
||||
@@ -1050,6 +1055,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
|
||||
isFilePath: true,
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
allowConfigDirTemplateSubstitution: true,
|
||||
category: Diagnostics.Modules,
|
||||
description: Diagnostics.Allow_multiple_folders_to_be_treated_as_one_when_resolving_modules,
|
||||
transpileOptionValue: undefined,
|
||||
@@ -1064,6 +1070,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
|
||||
isFilePath: true,
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
allowConfigDirTemplateSubstitution: true,
|
||||
category: Diagnostics.Modules,
|
||||
description: Diagnostics.Specify_multiple_folders_that_act_like_Slashnode_modules_Slash_types,
|
||||
},
|
||||
@@ -1599,6 +1606,15 @@ export const optionsAffectingProgramStructure: readonly CommandLineOption[] = op
|
||||
/** @internal */
|
||||
export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => hasProperty(option, "transpileOptionValue"));
|
||||
|
||||
/** @internal */
|
||||
export const configDirTemplateSubstitutionOptions: readonly CommandLineOption[] = optionDeclarations.filter(
|
||||
option => option.allowConfigDirTemplateSubstitution || (!option.isCommandLineOnly && option.isFilePath),
|
||||
);
|
||||
/** @internal */
|
||||
export const configDirTemplateSubstitutionWatchOptions: readonly CommandLineOption[] = optionsForWatch.filter(
|
||||
option => option.allowConfigDirTemplateSubstitution || (!option.isCommandLineOnly && option.isFilePath),
|
||||
);
|
||||
|
||||
// Build related options
|
||||
/** @internal */
|
||||
export const optionsForBuild: CommandLineOption[] = [
|
||||
@@ -2627,6 +2643,9 @@ function serializeOptionBaseObject(
|
||||
if (pathOptions && optionDefinition.isFilePath) {
|
||||
result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!));
|
||||
}
|
||||
else if (pathOptions && optionDefinition.type === "list" && optionDefinition.element.isFilePath) {
|
||||
result.set(name, (value as string[]).map(v => getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(v, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!)));
|
||||
}
|
||||
else {
|
||||
result.set(name, value);
|
||||
}
|
||||
@@ -2889,17 +2908,23 @@ function parseJsonConfigFileContentWorker(
|
||||
|
||||
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 options = handleOptionConfigDirTemplateSubstitution(
|
||||
extend(existingOptions, parsedConfig.options || {}),
|
||||
configDirTemplateSubstitutionOptions,
|
||||
basePath,
|
||||
) as CompilerOptions;
|
||||
const watchOptions = handleWatchOptionsConfigDirTemplateSubstitution(
|
||||
existingWatchOptions && parsedConfig.watchOptions ?
|
||||
extend(existingWatchOptions, parsedConfig.watchOptions) :
|
||||
parsedConfig.watchOptions || existingWatchOptions,
|
||||
basePath,
|
||||
);
|
||||
options.configFilePath = configFileName && normalizeSlashes(configFileName);
|
||||
const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath);
|
||||
const configFileSpecs = getConfigFileSpecs();
|
||||
if (sourceFile) sourceFile.configFileSpecs = configFileSpecs;
|
||||
setConfigFileInOptions(options, sourceFile);
|
||||
|
||||
const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath);
|
||||
return {
|
||||
options,
|
||||
watchOptions,
|
||||
@@ -2954,6 +2979,7 @@ function parseJsonConfigFileContentWorker(
|
||||
includeSpecs = [defaultIncludeSpec];
|
||||
isDefaultIncludeSpec = true;
|
||||
}
|
||||
let validatedIncludeSpecsBeforeSubstitution: readonly string[] | undefined, validatedExcludeSpecsBeforeSubstitution: readonly string[] | undefined;
|
||||
let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined;
|
||||
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
@@ -2961,20 +2987,37 @@ function parseJsonConfigFileContentWorker(
|
||||
// file system.
|
||||
|
||||
if (includeSpecs) {
|
||||
validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include");
|
||||
validatedIncludeSpecsBeforeSubstitution = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include");
|
||||
validatedIncludeSpecs = getSubstitutedStringArrayWithConfigDirTemplate(
|
||||
validatedIncludeSpecsBeforeSubstitution,
|
||||
basePathForFileNames,
|
||||
) || validatedIncludeSpecsBeforeSubstitution;
|
||||
}
|
||||
|
||||
if (excludeSpecs) {
|
||||
validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude");
|
||||
validatedExcludeSpecsBeforeSubstitution = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude");
|
||||
validatedExcludeSpecs = getSubstitutedStringArrayWithConfigDirTemplate(
|
||||
validatedExcludeSpecsBeforeSubstitution,
|
||||
basePathForFileNames,
|
||||
) || validatedExcludeSpecsBeforeSubstitution;
|
||||
}
|
||||
|
||||
const validatedFilesSpecBeforeSubstitution = filter(filesSpecs, isString);
|
||||
const validatedFilesSpec = getSubstitutedStringArrayWithConfigDirTemplate(
|
||||
validatedFilesSpecBeforeSubstitution,
|
||||
basePathForFileNames,
|
||||
) || validatedFilesSpecBeforeSubstitution;
|
||||
|
||||
return {
|
||||
filesSpecs,
|
||||
includeSpecs,
|
||||
excludeSpecs,
|
||||
validatedFilesSpec: filter(filesSpecs, isString),
|
||||
validatedFilesSpec,
|
||||
validatedIncludeSpecs,
|
||||
validatedExcludeSpecs,
|
||||
validatedFilesSpecBeforeSubstitution,
|
||||
validatedIncludeSpecsBeforeSubstitution,
|
||||
validatedExcludeSpecsBeforeSubstitution,
|
||||
pathPatterns: undefined, // Initialized on first use
|
||||
isDefaultIncludeSpec,
|
||||
};
|
||||
@@ -3042,6 +3085,84 @@ function parseJsonConfigFileContentWorker(
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function handleWatchOptionsConfigDirTemplateSubstitution(
|
||||
watchOptions: WatchOptions | undefined,
|
||||
basePath: string,
|
||||
) {
|
||||
return handleOptionConfigDirTemplateSubstitution(watchOptions, configDirTemplateSubstitutionWatchOptions, basePath) as WatchOptions | undefined;
|
||||
}
|
||||
|
||||
function handleOptionConfigDirTemplateSubstitution(
|
||||
options: OptionsBase | undefined,
|
||||
optionDeclarations: readonly CommandLineOption[],
|
||||
basePath: string,
|
||||
) {
|
||||
if (!options) return options;
|
||||
let result: OptionsBase | undefined;
|
||||
for (const option of optionDeclarations) {
|
||||
if (options[option.name] !== undefined) {
|
||||
const value = options[option.name];
|
||||
switch (option.type) {
|
||||
case "string":
|
||||
Debug.assert(option.isFilePath);
|
||||
if (startsWithConfigDirTemplate(value)) {
|
||||
setOptionValue(option, getSubstitutedPathWithConfigDirTemplate(value, basePath));
|
||||
}
|
||||
break;
|
||||
case "list":
|
||||
Debug.assert(option.element.isFilePath);
|
||||
const listResult = getSubstitutedStringArrayWithConfigDirTemplate(value as string[], basePath);
|
||||
if (listResult) setOptionValue(option, listResult);
|
||||
break;
|
||||
case "object":
|
||||
Debug.assert(option.name === "paths");
|
||||
const objectResult = getSubstitutedMapLikeOfStringArrayWithConfigDirTemplate(value as MapLike<string[]>, basePath);
|
||||
if (objectResult) setOptionValue(option, objectResult);
|
||||
break;
|
||||
default:
|
||||
Debug.fail("option type not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result || options;
|
||||
|
||||
function setOptionValue(option: CommandLineOption, value: CompilerOptionsValue) {
|
||||
(result ??= assign({}, options))[option.name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
const configDirTemplate = `\${configDir}`;
|
||||
function startsWithConfigDirTemplate(value: any): value is string {
|
||||
return isString(value) && startsWith(value, configDirTemplate, /*ignoreCase*/ true);
|
||||
}
|
||||
|
||||
function getSubstitutedPathWithConfigDirTemplate(value: string, basePath: string) {
|
||||
return getNormalizedAbsolutePath(value.replace(configDirTemplate, "./"), basePath);
|
||||
}
|
||||
|
||||
function getSubstitutedStringArrayWithConfigDirTemplate(list: readonly string[] | undefined, basePath: string) {
|
||||
if (!list) return list;
|
||||
let result: string[] | undefined;
|
||||
list.forEach((element, index) => {
|
||||
if (!startsWithConfigDirTemplate(element)) return;
|
||||
(result ??= list.slice())[index] = getSubstitutedPathWithConfigDirTemplate(element, basePath);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getSubstitutedMapLikeOfStringArrayWithConfigDirTemplate(mapLike: MapLike<string[]>, basePath: string) {
|
||||
let result: MapLike<string[]> | undefined;
|
||||
const ownKeys = getOwnKeys(mapLike);
|
||||
ownKeys.forEach(key => {
|
||||
if (!isArray(mapLike[key])) return;
|
||||
const subStitution = getSubstitutedStringArrayWithConfigDirTemplate(mapLike[key], basePath);
|
||||
if (!subStitution) return;
|
||||
(result ??= assign({}, mapLike))[key] = subStitution;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -3143,9 +3264,10 @@ function parseConfig(
|
||||
else {
|
||||
ownConfig.extendedConfigPath.forEach(extendedConfigPath => applyExtendedConfig(result, extendedConfigPath));
|
||||
}
|
||||
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 (result.include) ownConfig.raw.include = result.include;
|
||||
if (result.exclude) ownConfig.raw.exclude = result.exclude;
|
||||
if (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());
|
||||
|
||||
@@ -3162,12 +3284,15 @@ function parseConfig(
|
||||
const extendsRaw = extendedConfig.raw;
|
||||
let relativeDifference: string | undefined;
|
||||
const setPropertyInResultIfNotUndefined = (propertyName: "include" | "exclude" | "files") => {
|
||||
if (ownConfig.raw[propertyName]) return; // No need to calculate if already set in own config
|
||||
if (extendsRaw[propertyName]) {
|
||||
result[propertyName] = map(extendsRaw[propertyName], (path: string) =>
|
||||
isRootedDiskPath(path) ? path : combinePaths(
|
||||
relativeDifference ||= convertToRelativePath(getDirectoryPath(extendedConfigPath), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)),
|
||||
path,
|
||||
));
|
||||
startsWithConfigDirTemplate(path) || isRootedDiskPath(path) ?
|
||||
path :
|
||||
combinePaths(
|
||||
relativeDifference ||= convertToRelativePath(getDirectoryPath(extendedConfigPath), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)),
|
||||
path,
|
||||
));
|
||||
}
|
||||
};
|
||||
setPropertyInResultIfNotUndefined("include");
|
||||
@@ -3526,7 +3651,8 @@ export function convertJsonOption(
|
||||
|
||||
function normalizeNonListOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue {
|
||||
if (option.isFilePath) {
|
||||
value = getNormalizedAbsolutePath(value, basePath);
|
||||
value = normalizeSlashes(value);
|
||||
value = !startsWithConfigDirTemplate(value) ? getNormalizedAbsolutePath(value, basePath) : value;
|
||||
if (value === "") {
|
||||
value = ".";
|
||||
}
|
||||
|
||||
@@ -967,6 +967,10 @@
|
||||
"category": "Error",
|
||||
"code": 1292
|
||||
},
|
||||
"ESM syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'.": {
|
||||
"category": "Error",
|
||||
"code": 1293
|
||||
},
|
||||
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -130,6 +130,7 @@ import {
|
||||
getEmitFlags,
|
||||
getEmitHelpers,
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getExternalModuleName,
|
||||
getIdentifierTypeArguments,
|
||||
@@ -800,6 +801,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
|
||||
newLine: compilerOptions.newLine,
|
||||
noEmitHelpers: compilerOptions.noEmitHelpers,
|
||||
module: getEmitModuleKind(compilerOptions),
|
||||
moduleResolution: getEmitModuleResolutionKind(compilerOptions),
|
||||
target: getEmitScriptTarget(compilerOptions),
|
||||
sourceMap: compilerOptions.sourceMap,
|
||||
inlineSourceMap: compilerOptions.inlineSourceMap,
|
||||
@@ -867,6 +869,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
|
||||
newLine: compilerOptions.newLine,
|
||||
noEmitHelpers: true,
|
||||
module: compilerOptions.module,
|
||||
moduleResolution: compilerOptions.moduleResolution,
|
||||
target: compilerOptions.target,
|
||||
sourceMap: !forceDtsEmit && compilerOptions.declarationMap,
|
||||
inlineSourceMap: compilerOptions.inlineSourceMap,
|
||||
|
||||
@@ -53,10 +53,12 @@ import {
|
||||
getAllAccessorDeclarations,
|
||||
getEmitFlags,
|
||||
getEmitHelpers,
|
||||
getEmitModuleFormatOfFileWorker,
|
||||
getEmitModuleKind,
|
||||
getESModuleInterop,
|
||||
getExternalModuleName,
|
||||
getExternalModuleNameFromPath,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getJSDocType,
|
||||
getJSDocTypeTag,
|
||||
getModifiers,
|
||||
@@ -712,7 +714,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
|
||||
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) || getImpliedNodeFormatForEmitWorker(sourceFile, compilerOptions) === ModuleKind.ESNext) {
|
||||
// use named imports
|
||||
const helpers = getEmitHelpers(sourceFile);
|
||||
if (helpers) {
|
||||
@@ -769,10 +771,8 @@ export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactor
|
||||
return externalHelpersModuleName;
|
||||
}
|
||||
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
let create = (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault))
|
||||
&& moduleKind !== ModuleKind.System
|
||||
&& (moduleKind < ModuleKind.ES2015 || node.impliedNodeFormat === ModuleKind.CommonJS);
|
||||
&& getEmitModuleFormatOfFileWorker(node, compilerOptions) < ModuleKind.System;
|
||||
if (!create) {
|
||||
const helpers = getEmitHelpers(node);
|
||||
if (helpers) {
|
||||
|
||||
@@ -2703,7 +2703,7 @@ function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleRes
|
||||
const target = (lookupTable as { [idx: string]: unknown; })[moduleName];
|
||||
return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false, moduleName);
|
||||
}
|
||||
const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => k.includes("*") || endsWith(k, "/")), comparePatternKeys);
|
||||
const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => hasOneAsterisk(k) || endsWith(k, "/")), comparePatternKeys);
|
||||
for (const potentialTarget of expandingKeys) {
|
||||
if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) {
|
||||
const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget];
|
||||
@@ -2731,6 +2731,11 @@ function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleRes
|
||||
}
|
||||
}
|
||||
|
||||
function hasOneAsterisk(patternKey: string): boolean {
|
||||
const firstStar = patternKey.indexOf("*");
|
||||
return firstStar !== -1 && firstStar === patternKey.lastIndexOf("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the self-recursive function specialized to retrieving the targeted import/export element for the given resolution configuration
|
||||
*/
|
||||
|
||||
@@ -32,12 +32,13 @@ import {
|
||||
flatten,
|
||||
forEach,
|
||||
forEachAncestorDirectory,
|
||||
FutureSourceFile,
|
||||
getBaseFileName,
|
||||
GetCanonicalFileName,
|
||||
getConditions,
|
||||
getDefaultResolutionModeForFileWorker,
|
||||
getDirectoryPath,
|
||||
getEmitModuleResolutionKind,
|
||||
getModeForResolutionAtIndex,
|
||||
getModuleNameStringLiteralAt,
|
||||
getModuleSpecifierEndingPreference,
|
||||
getNodeModulePathParts,
|
||||
@@ -65,6 +66,7 @@ import {
|
||||
isDeclarationFileName,
|
||||
isExternalModuleAugmentation,
|
||||
isExternalModuleNameRelative,
|
||||
isFullSourceFile,
|
||||
isMissingPackageJsonInfo,
|
||||
isModuleBlock,
|
||||
isModuleDeclaration,
|
||||
@@ -134,14 +136,15 @@ export interface ModuleSpecifierPreferences {
|
||||
/**
|
||||
* @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?: ResolutionMode): ModuleSpecifierEnding[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getModuleSpecifierPreferences(
|
||||
{ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences,
|
||||
host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">,
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat">,
|
||||
oldImportSpecifier?: string,
|
||||
): ModuleSpecifierPreferences {
|
||||
const filePreferredEnding = getPreferredEnding();
|
||||
@@ -154,8 +157,10 @@ export function getModuleSpecifierPreferences(
|
||||
importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative :
|
||||
RelativePreference.Shortest,
|
||||
getAllowedEndingsInPreferredOrder: syntaxImpliedNodeFormat => {
|
||||
const preferredEnding = syntaxImpliedNodeFormat !== importingSourceFile.impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
|
||||
if ((syntaxImpliedNodeFormat ?? importingSourceFile.impliedNodeFormat) === ModuleKind.ESNext) {
|
||||
const impliedNodeFormat = getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions);
|
||||
const preferredEnding = syntaxImpliedNodeFormat !== impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
|
||||
const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
|
||||
if ((syntaxImpliedNodeFormat ?? impliedNodeFormat) === ModuleKind.ESNext && ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) {
|
||||
if (shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName)) {
|
||||
return [ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension];
|
||||
}
|
||||
@@ -195,9 +200,9 @@ export function getModuleSpecifierPreferences(
|
||||
}
|
||||
return getModuleSpecifierEndingPreference(
|
||||
importModuleSpecifierEnding,
|
||||
resolutionMode ?? importingSourceFile.impliedNodeFormat,
|
||||
resolutionMode ?? getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions),
|
||||
compilerOptions,
|
||||
importingSourceFile,
|
||||
isFullSourceFile(importingSourceFile) ? importingSourceFile : undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -216,7 +221,7 @@ export function updateModuleSpecifier(
|
||||
oldImportSpecifier: string,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
): string | undefined {
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
|
||||
if (res === oldImportSpecifier) return undefined;
|
||||
return res;
|
||||
}
|
||||
@@ -230,19 +235,19 @@ export function updateModuleSpecifier(
|
||||
/** @internal */
|
||||
export function getModuleSpecifier(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
importingSourceFileName: string,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
): string {
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile), {}, options);
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile), {}, options);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getNodeModulesPackageName(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
nodeModulesFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
preferences: UserPreferences,
|
||||
@@ -255,7 +260,7 @@ export function getNodeModulesPackageName(
|
||||
|
||||
function getModuleSpecifierWorker(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
importingSourceFileName: string,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
@@ -266,13 +271,13 @@ function getModuleSpecifierWorker(
|
||||
const info = getInfo(importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(info, 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);
|
||||
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions), preferences);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetModuleSpecifiersFromCache(
|
||||
moduleSymbol: Symbol,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
userPreferences: UserPreferences,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
@@ -288,7 +293,7 @@ export function tryGetModuleSpecifiersFromCache(
|
||||
|
||||
function tryGetModuleSpecifiersFromCacheWorker(
|
||||
moduleSymbol: Symbol,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
userPreferences: UserPreferences,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
@@ -334,7 +339,7 @@ export function getModuleSpecifiersWithCacheInfo(
|
||||
moduleSymbol: Symbol,
|
||||
checker: TypeChecker,
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
userPreferences: UserPreferences,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
@@ -370,25 +375,49 @@ export function getModuleSpecifiersWithCacheInfo(
|
||||
return { moduleSpecifiers: result, computedWithoutCache };
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getLocalModuleSpecifierBetweenFileNames(
|
||||
importingFile: Pick<SourceFile, "fileName" | "impliedNodeFormat">,
|
||||
targetFileName: string,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
): string {
|
||||
const info = getInfo(importingFile.fileName, host);
|
||||
const importMode = options.overrideImportMode ?? importingFile.impliedNodeFormat;
|
||||
return getLocalModuleSpecifier(
|
||||
targetFileName,
|
||||
info,
|
||||
compilerOptions,
|
||||
host,
|
||||
importMode,
|
||||
getModuleSpecifierPreferences({}, host, compilerOptions, importingFile),
|
||||
);
|
||||
}
|
||||
|
||||
function computeModuleSpecifiers(
|
||||
modulePaths: readonly ModulePath[],
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFile: SourceFile | FutureSourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
userPreferences: UserPreferences,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
forAutoImport: boolean,
|
||||
): readonly string[] {
|
||||
const info = getInfo(importingSourceFile.fileName, host);
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, compilerOptions, importingSourceFile);
|
||||
const existingSpecifier = forEach(modulePaths, modulePath =>
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, host, compilerOptions, importingSourceFile);
|
||||
const existingSpecifier = isFullSourceFile(importingSourceFile) && 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, compilerOptions)) return undefined;
|
||||
const existingMode = host.getModeForResolutionAtIndex(importingSourceFile, reason.index);
|
||||
const targetMode = options.overrideImportMode ?? host.getDefaultResolutionModeForFile(importingSourceFile);
|
||||
if (existingMode !== targetMode && existingMode !== undefined && targetMode !== undefined) {
|
||||
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) ?
|
||||
@@ -1014,7 +1043,7 @@ function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileNam
|
||||
return processEnding(shortest, allowedEndings, compilerOptions);
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, canonicalSourceDirectory }: Info, importingSourceFile: SourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ResolutionMode): string | undefined {
|
||||
function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, canonicalSourceDirectory }: Info, importingSourceFile: SourceFile | FutureSourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ResolutionMode): string | undefined {
|
||||
if (!host.fileExists || !host.readFile) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1025,7 +1054,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
|
||||
|
||||
// Simplify the full file path to something that can be resolved by Node.
|
||||
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, options, importingSourceFile);
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, host, options, importingSourceFile);
|
||||
const allowedEndings = preferences.getAllowedEndingsInPreferredOrder();
|
||||
let moduleSpecifier = path;
|
||||
let isPackageRootPath = false;
|
||||
@@ -1085,7 +1114,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
|
||||
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
|
||||
if (isPackageJsonInfo(cachedPackageJson) || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent: Record<string, any> | undefined = cachedPackageJson?.contents.packageJsonContent || tryParseJson(host.readFile!(packageJsonPath)!);
|
||||
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
|
||||
const importMode = overrideMode || getDefaultResolutionModeForFile(importingSourceFile, host, options);
|
||||
if (getResolvePackageJsonExports(options)) {
|
||||
// The package name that we found in node_modules could be different from the package
|
||||
// name in the package.json content via url/filepath dependency specifiers. We need to
|
||||
@@ -1280,3 +1309,7 @@ function getRelativePathIfInSameVolume(path: string, directoryPath: string, getC
|
||||
function isPathRelativeToParent(path: string): boolean {
|
||||
return startsWith(path, "..");
|
||||
}
|
||||
|
||||
function getDefaultResolutionModeForFile(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">, compilerOptions: CompilerOptions) {
|
||||
return isFullSourceFile(file) ? host.getDefaultResolutionModeForFile(file) : getDefaultResolutionModeForFileWorker(file, compilerOptions);
|
||||
}
|
||||
|
||||
+147
-36
@@ -168,6 +168,7 @@ import {
|
||||
ImportClause,
|
||||
ImportDeclaration,
|
||||
ImportOrExportSpecifier,
|
||||
importSyntaxAffectsModuleResolution,
|
||||
InternalEmitFlags,
|
||||
inverseJsxOptionMap,
|
||||
isAmbientModule,
|
||||
@@ -834,9 +835,11 @@ export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageCha
|
||||
* @internal
|
||||
*/
|
||||
export interface SourceFileImportsList {
|
||||
/** @internal */ imports: SourceFile["imports"];
|
||||
/** @internal */ moduleAugmentations: SourceFile["moduleAugmentations"];
|
||||
imports: SourceFile["imports"];
|
||||
moduleAugmentations: SourceFile["moduleAugmentations"];
|
||||
impliedNodeFormat?: ResolutionMode;
|
||||
fileName: string;
|
||||
packageJsonScope?: SourceFile["packageJsonScope"];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -882,22 +885,47 @@ export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | Ex
|
||||
|
||||
/**
|
||||
* Use `program.getModeForUsageLocation`, which retrieves the correct `compilerOptions`, instead of this function whenever possible.
|
||||
* Calculates the final resolution mode for a given module reference node. This is the resolution mode explicitly provided via import
|
||||
* attributes, if present, or the syntax the usage would have if emitted to JavaScript. In `--module node16` or `nodenext`, this may
|
||||
* depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the input syntax of the reference. In other
|
||||
* `module` modes, when overriding import attributes are not provided, this function returns `undefined`, as the result would have no
|
||||
* impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for a given module reference node. This function only returns a result when module resolution
|
||||
* settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided via import attributes,
|
||||
* which cause an `import` or `require` condition to be used during resolution regardless of module resolution settings. In absence of
|
||||
* overriding attributes, and in modes that support differing resolution, the result indicates the syntax the usage would emit to JavaScript.
|
||||
* Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*
|
||||
* @param file The file the import or import-like reference is contained within
|
||||
* @param usage The module reference string
|
||||
* @param compilerOptions The compiler options for the program that owns the file. If the file belongs to a referenced project, the compiler options
|
||||
* should be the options of the referenced project, not the referencing project.
|
||||
* @returns The final resolution mode of the import
|
||||
*/
|
||||
export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike, compilerOptions: CompilerOptions) {
|
||||
export function getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike, compilerOptions: CompilerOptions) {
|
||||
return getModeForUsageLocationWorker(file, usage, compilerOptions);
|
||||
}
|
||||
|
||||
function getModeForUsageLocationWorker(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike, compilerOptions?: CompilerOptions) {
|
||||
function getModeForUsageLocationWorker(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, usage: StringLiteralLike, compilerOptions?: CompilerOptions) {
|
||||
if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) {
|
||||
const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent);
|
||||
if (isTypeOnly) {
|
||||
@@ -913,20 +941,36 @@ function getModeForUsageLocationWorker(file: { impliedNodeFormat?: ResolutionMod
|
||||
return override;
|
||||
}
|
||||
}
|
||||
if (compilerOptions && getEmitModuleKind(compilerOptions) === ModuleKind.Preserve) {
|
||||
return (usage.parent.parent && isImportEqualsDeclaration(usage.parent.parent) || isRequireCall(usage.parent, /*requireStringLiteralLikeArgument*/ false))
|
||||
? ModuleKind.CommonJS
|
||||
: ModuleKind.ESNext;
|
||||
|
||||
if (compilerOptions && importSyntaxAffectsModuleResolution(compilerOptions)) {
|
||||
return getEmitSyntaxForUsageLocationWorker(file, usage, compilerOptions);
|
||||
}
|
||||
if (file.impliedNodeFormat === undefined) return undefined;
|
||||
if (file.impliedNodeFormat !== ModuleKind.ESNext) {
|
||||
// in cjs files, import call expressions are esm format, otherwise everything is cjs
|
||||
return isImportCall(walkUpParenthesizedExpressions(usage.parent)) ? ModuleKind.ESNext : ModuleKind.CommonJS;
|
||||
}
|
||||
|
||||
function getEmitSyntaxForUsageLocationWorker(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, usage: StringLiteralLike, compilerOptions?: CompilerOptions): ResolutionMode {
|
||||
if (!compilerOptions) {
|
||||
// This should always be provided, but we try to fail somewhat
|
||||
// gracefully to allow projects like ts-node time to update.
|
||||
return undefined;
|
||||
}
|
||||
// in esm files, import=require statements are cjs format, otherwise everything is esm
|
||||
// imports are only parent'd up to their containing declaration/expression, so access farther parents with care
|
||||
const exprParentParent = walkUpParenthesizedExpressions(usage.parent)?.parent;
|
||||
return exprParentParent && isImportEqualsDeclaration(exprParentParent) ? ModuleKind.CommonJS : ModuleKind.ESNext;
|
||||
if (exprParentParent && isImportEqualsDeclaration(exprParentParent) || isRequireCall(usage.parent, /*requireStringLiteralLikeArgument*/ false)) {
|
||||
return ModuleKind.CommonJS;
|
||||
}
|
||||
if (isImportCall(walkUpParenthesizedExpressions(usage.parent))) {
|
||||
return shouldTransformImportCallWorker(file, compilerOptions) ? ModuleKind.CommonJS : ModuleKind.ESNext;
|
||||
}
|
||||
// If we're in --module preserve on an input file, we know that an import
|
||||
// is an import. But if this is a declaration file, we'd prefer to use the
|
||||
// impliedNodeFormat. Since we want things to be consistent between the two,
|
||||
// we need to issue errors when the user writes ESM syntax in a definitely-CJS
|
||||
// file, until/unless declaration emit can indicate a true ESM import. On the
|
||||
// other hand, writing CJS syntax in a definitely-ESM file is fine, since declaration
|
||||
// emit preserves the CJS syntax.
|
||||
const fileEmitMode = getEmitModuleFormatOfFileWorker(file, compilerOptions);
|
||||
return fileEmitMode === ModuleKind.CommonJS ? ModuleKind.CommonJS :
|
||||
emitModuleKindIsNonNodeESM(fileEmitMode) || fileEmitMode === ModuleKind.Preserve ? ModuleKind.ESNext :
|
||||
undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -1017,7 +1061,7 @@ function getTypeReferenceResolutionName<T extends FileReference | string>(entry:
|
||||
|
||||
const typeReferenceResolutionNameAndModeGetter: ResolutionNameAndModeGetter<FileReference | string, SourceFile | undefined> = {
|
||||
getName: getTypeReferenceResolutionName,
|
||||
getMode: (entry, file) => getModeForFileReference(entry, file?.impliedNodeFormat),
|
||||
getMode: (entry, file, compilerOptions) => getModeForFileReference(entry, file && getDefaultResolutionModeForFileWorker(file, compilerOptions)),
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
@@ -1339,16 +1383,11 @@ export function getImpliedNodeFormatForFileWorker(
|
||||
host: ModuleResolutionHost,
|
||||
options: CompilerOptions,
|
||||
) {
|
||||
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
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
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
|
||||
|
||||
function lookupFromPackageJson(): Partial<CreateSourceFileOptions> {
|
||||
const state = getTemporaryModuleResolutionState(packageJsonInfoCache, host, options);
|
||||
const packageJsonLocations: string[] = [];
|
||||
@@ -1899,6 +1938,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
isSourceFileFromExternalLibrary,
|
||||
isSourceFileDefaultLibrary,
|
||||
getModeForUsageLocation,
|
||||
getEmitSyntaxForUsageLocation,
|
||||
getModeForResolutionAtIndex,
|
||||
getSourceFileFromReference,
|
||||
getLibFileFromReference,
|
||||
@@ -1926,6 +1966,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
forEachResolvedProjectReference,
|
||||
isSourceOfProjectReferenceRedirect,
|
||||
getRedirectReferenceForResolutionFromSourceOfProject,
|
||||
getCompilerOptionsForFile,
|
||||
getDefaultResolutionModeForFile,
|
||||
getEmitModuleFormatOfFile,
|
||||
getImpliedNodeFormatForEmit,
|
||||
shouldTransformImportCall,
|
||||
emitBuildInfo,
|
||||
fileExists,
|
||||
readFile,
|
||||
@@ -2640,6 +2685,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
getSymlinkCache,
|
||||
writeFile: writeFileCallback || writeFile,
|
||||
isEmitBlocked,
|
||||
shouldTransformImportCall,
|
||||
getEmitModuleFormatOfFile,
|
||||
getDefaultResolutionModeForFile,
|
||||
getModeForResolutionAtIndex,
|
||||
readFile: f => host.readFile(f),
|
||||
fileExists: f => {
|
||||
// Use local caches
|
||||
@@ -3871,11 +3920,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
// store resolved type directive on the file
|
||||
const fileName = toFileNameLowerCase(ref.fileName);
|
||||
resolutionsInFile.set(fileName, getModeForFileReference(ref, file.impliedNodeFormat), resolvedTypeReferenceDirective);
|
||||
const mode = ref.resolutionMode || file.impliedNodeFormat;
|
||||
const mode = ref.resolutionMode || getDefaultResolutionModeForFile(file);
|
||||
processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index });
|
||||
}
|
||||
}
|
||||
|
||||
function getCompilerOptionsForFile(file: SourceFile): CompilerOptions {
|
||||
return getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
}
|
||||
|
||||
function processTypeReferenceDirective(
|
||||
typeReferenceDirective: string,
|
||||
mode: ResolutionMode,
|
||||
@@ -4033,7 +4086,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
const resolutions = resolvedModulesProcessing?.get(file.path) ||
|
||||
resolveModuleNamesReusingOldState(moduleNames, file);
|
||||
Debug.assert(resolutions.length === moduleNames.length);
|
||||
const optionsForFile = getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
const optionsForFile = getCompilerOptionsForFile(file);
|
||||
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
|
||||
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
|
||||
for (let index = 0; index < moduleNames.length; index++) {
|
||||
@@ -4604,7 +4657,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined;
|
||||
const location = locationReason && getReferencedFileLocation(program, locationReason);
|
||||
const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
|
||||
const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file);
|
||||
const optionsForFile = file && getCompilerOptionsForFile(file) || options;
|
||||
const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file, optionsForFile);
|
||||
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) :
|
||||
@@ -4934,13 +4988,70 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
|
||||
function getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode {
|
||||
const optionsForFile = getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
return getModeForUsageLocationWorker(file, usage, optionsForFile);
|
||||
return getModeForUsageLocationWorker(file, usage, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
function getEmitSyntaxForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode {
|
||||
return getEmitSyntaxForUsageLocationWorker(file, usage, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
function getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode {
|
||||
return getModeForUsageLocation(file, getModuleNameStringLiteralAt(file, index));
|
||||
}
|
||||
|
||||
function getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode {
|
||||
return getDefaultResolutionModeForFileWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode {
|
||||
return getImpliedNodeFormatForEmitWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind {
|
||||
return getEmitModuleFormatOfFileWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function shouldTransformImportCall(sourceFile: SourceFile): boolean {
|
||||
return shouldTransformImportCallWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
}
|
||||
|
||||
function shouldTransformImportCallWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): boolean {
|
||||
const moduleKind = getEmitModuleKind(options);
|
||||
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext || moduleKind === ModuleKind.Preserve) {
|
||||
return false;
|
||||
}
|
||||
return getEmitModuleFormatOfFileWorker(sourceFile, options) < ModuleKind.ES2015;
|
||||
}
|
||||
/** @internal Prefer `program.getEmitModuleFormatOfFile` when possible. */
|
||||
export function getEmitModuleFormatOfFileWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ModuleKind {
|
||||
return getImpliedNodeFormatForEmitWorker(sourceFile, options) ?? getEmitModuleKind(options);
|
||||
}
|
||||
/** @internal Prefer `program.getImpliedNodeFormatForEmit` when possible. */
|
||||
export function getImpliedNodeFormatForEmitWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ResolutionMode {
|
||||
const moduleKind = getEmitModuleKind(options);
|
||||
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
|
||||
return sourceFile.impliedNodeFormat;
|
||||
}
|
||||
if (
|
||||
sourceFile.impliedNodeFormat === ModuleKind.CommonJS
|
||||
&& (sourceFile.packageJsonScope?.contents.packageJsonContent.type === "commonjs"
|
||||
|| fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cjs, Extension.Cts]))
|
||||
) {
|
||||
return ModuleKind.CommonJS;
|
||||
}
|
||||
if (
|
||||
sourceFile.impliedNodeFormat === ModuleKind.ESNext
|
||||
&& (sourceFile.packageJsonScope?.contents.packageJsonContent.type === "module"
|
||||
|| fileExtensionIsOneOf(sourceFile.fileName, [Extension.Mjs, Extension.Mts]))
|
||||
) {
|
||||
return ModuleKind.ESNext;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/** @internal Prefer `program.getDefaultResolutionModeForFile` when possible. */
|
||||
export function getDefaultResolutionModeForFileWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ResolutionMode {
|
||||
return importSyntaxAffectsModuleResolution(options) ? getImpliedNodeFormatForEmitWorker(sourceFile, options) : undefined;
|
||||
}
|
||||
|
||||
interface HostForUseSourceOfProjectReferenceRedirect {
|
||||
|
||||
+168
-12
@@ -98,6 +98,8 @@ export interface ResolutionCache {
|
||||
resolutionsWithOnlyAffectingLocations: Set<ResolutionWithFailedLookupLocations>;
|
||||
directoryWatchesOfFailedLookups: Map<string, DirectoryWatchesOfFailedLookup>;
|
||||
fileWatchesOfAffectingLocations: Map<string, FileWatcherOfAffectingLocation>;
|
||||
packageDirWatchers: Map<Path, PackageDirWatcher>;
|
||||
dirPathToSymlinkPackageRefCount: Map<Path, number>;
|
||||
startRecordingFilesWithChangedResolutions(): void;
|
||||
finishRecordingFilesWithChangedResolutions(): Path[] | undefined;
|
||||
|
||||
@@ -236,12 +238,24 @@ export interface DirectoryWatchesOfFailedLookup {
|
||||
/** is the directory watched being non recursive */
|
||||
nonRecursive?: boolean;
|
||||
}
|
||||
/** @internal */
|
||||
export interface DirPathToWatcherOfPackageDirWatcher {
|
||||
watcher: DirectoryWatchesOfFailedLookup;
|
||||
refCount: number;
|
||||
}
|
||||
/** @internal */
|
||||
export interface PackageDirWatcher {
|
||||
dirPathToWatcher: Map<Path, DirPathToWatcherOfPackageDirWatcher>;
|
||||
isSymlink: boolean;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface DirectoryOfFailedLookupWatch {
|
||||
dir: string;
|
||||
dirPath: Path;
|
||||
nonRecursive?: boolean;
|
||||
packageDir?: string;
|
||||
packageDirPath?: Path;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -347,10 +361,16 @@ export function getDirectoryToWatchFailedLookupLocation(
|
||||
// If directory path contains node module, get the most parent node_modules directory for watching
|
||||
const nodeModulesIndex = failedLookupPathComponents.indexOf("node_modules" as Path);
|
||||
if (nodeModulesIndex !== -1 && nodeModulesIndex + 1 <= perceivedOsRootLength + 1) return undefined; // node_modules not at position where it can be watched
|
||||
const lastNodeModulesIndex = failedLookupPathComponents.lastIndexOf("node_modules" as Path);
|
||||
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),
|
||||
lastNodeModulesIndex,
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Always watch root directory non recursively
|
||||
@@ -369,6 +389,7 @@ export function getDirectoryToWatchFailedLookupLocation(
|
||||
perceivedOsRootLength,
|
||||
nodeModulesIndex,
|
||||
rootPathComponents,
|
||||
lastNodeModulesIndex,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -379,11 +400,17 @@ function getDirectoryToWatchFromFailedLookupLocationDirectory(
|
||||
perceivedOsRootLength: number,
|
||||
nodeModulesIndex: number,
|
||||
rootPathComponents: Readonly<PathPathComponents>,
|
||||
lastNodeModulesIndex: number,
|
||||
): DirectoryOfFailedLookupWatch | undefined {
|
||||
// If directory path contains node module, get the most parent node_modules directory for watching
|
||||
if (nodeModulesIndex !== -1) {
|
||||
// If the directory is node_modules use it to watch, always watch it recursively
|
||||
return getDirectoryOfFailedLookupWatch(dirComponents, dirPathComponents, nodeModulesIndex + 1);
|
||||
return getDirectoryOfFailedLookupWatch(
|
||||
dirComponents,
|
||||
dirPathComponents,
|
||||
nodeModulesIndex + 1,
|
||||
lastNodeModulesIndex,
|
||||
);
|
||||
}
|
||||
// Use some ancestor of the root directory
|
||||
let nonRecursive = true;
|
||||
@@ -395,19 +422,37 @@ function getDirectoryToWatchFromFailedLookupLocationDirectory(
|
||||
break;
|
||||
}
|
||||
}
|
||||
return getDirectoryOfFailedLookupWatch(dirComponents, dirPathComponents, length, nonRecursive);
|
||||
return getDirectoryOfFailedLookupWatch(
|
||||
dirComponents,
|
||||
dirPathComponents,
|
||||
length,
|
||||
lastNodeModulesIndex,
|
||||
nonRecursive,
|
||||
);
|
||||
}
|
||||
|
||||
function getDirectoryOfFailedLookupWatch(
|
||||
dirComponents: readonly string[],
|
||||
dirPathComponents: Readonly<PathPathComponents>,
|
||||
length: number,
|
||||
lastNodeModulesIndex: number,
|
||||
nonRecursive?: boolean,
|
||||
): DirectoryOfFailedLookupWatch {
|
||||
let packageDirLength;
|
||||
if (lastNodeModulesIndex !== -1 && lastNodeModulesIndex + 1 >= length && lastNodeModulesIndex + 2 < dirPathComponents.length) {
|
||||
if (!startsWith(dirPathComponents[lastNodeModulesIndex + 1], "@")) {
|
||||
packageDirLength = lastNodeModulesIndex + 2;
|
||||
}
|
||||
else if (lastNodeModulesIndex + 3 < dirPathComponents.length) {
|
||||
packageDirLength = lastNodeModulesIndex + 3;
|
||||
}
|
||||
}
|
||||
return {
|
||||
dir: getPathFromPathComponents(dirComponents, length),
|
||||
dirPath: getPathFromPathComponents(dirPathComponents, length),
|
||||
nonRecursive,
|
||||
packageDir: packageDirLength !== undefined ? getPathFromPathComponents(dirComponents, packageDirLength) : undefined,
|
||||
packageDirPath: packageDirLength !== undefined ? getPathFromPathComponents(dirPathComponents, packageDirLength) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -433,6 +478,7 @@ export function getDirectoryToWatchFailedLookupLocationFromTypeRoot(
|
||||
perceivedOsRootLengthForWatching(typeRootPathComponents, typeRootPathComponents.length),
|
||||
typeRootPathComponents.indexOf("node_modules" as Path),
|
||||
rootPathComponents,
|
||||
typeRootPathComponents.lastIndexOf("node_modules" as Path),
|
||||
);
|
||||
return toWatch && filterCustomPath(toWatch.dirPath) ? toWatch.dirPath : undefined;
|
||||
}
|
||||
@@ -543,7 +589,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
let isInDirectoryChecks: Set<Path> | undefined;
|
||||
let allModuleAndTypeResolutionsAreInvalidated = false;
|
||||
|
||||
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
|
||||
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!());
|
||||
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
|
||||
|
||||
// The resolvedModuleNames and resolvedTypeReferenceDirectives are the cache of resolutions per file.
|
||||
@@ -579,6 +625,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
const rootPath = resolutionHost.toPath(rootDir);
|
||||
const rootPathComponents = getPathComponents(rootPath);
|
||||
|
||||
const isSymlinkCache = new Map<Path, boolean>();
|
||||
const packageDirWatchers = new Map<Path, PackageDirWatcher>(); // Watching packageDir if symlink otherwise watching dirPath
|
||||
const dirPathToSymlinkPackageRefCount = new Map<Path, number>(); // Refcount for dirPath watches when watching symlinked packageDir
|
||||
|
||||
// TypeRoot watches for the types that get added as part of getAutomaticTypeDirectiveNames
|
||||
const typeRootsWatches = new Map<string, FileWatcher>();
|
||||
|
||||
@@ -592,6 +642,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
resolutionsWithOnlyAffectingLocations,
|
||||
directoryWatchesOfFailedLookups,
|
||||
fileWatchesOfAffectingLocations,
|
||||
packageDirWatchers,
|
||||
dirPathToSymlinkPackageRefCount,
|
||||
watchFailedLookupLocationsOfExternalModuleResolutions,
|
||||
getModuleResolutionCache: () => moduleResolutionCache,
|
||||
startRecordingFilesWithChangedResolutions,
|
||||
@@ -629,6 +681,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
function clear() {
|
||||
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
|
||||
clearMap(fileWatchesOfAffectingLocations, closeFileWatcherOf);
|
||||
isSymlinkCache.clear();
|
||||
packageDirWatchers.clear();
|
||||
dirPathToSymlinkPackageRefCount.clear();
|
||||
nonRelativeExternalModuleResolutions.clear();
|
||||
closeTypeRootsWatch();
|
||||
resolvedModuleNames.clear();
|
||||
@@ -712,6 +767,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
|
||||
nonRelativeExternalModuleResolutions.forEach(watchFailedLookupLocationOfNonRelativeModuleResolutions);
|
||||
nonRelativeExternalModuleResolutions.clear();
|
||||
isSymlinkCache.clear();
|
||||
}
|
||||
|
||||
function cleanupLibResolutionWatching(newProgram: Program | undefined) {
|
||||
@@ -759,11 +815,19 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
}
|
||||
directoryWatchesOfFailedLookups.forEach(closeDirectoryWatchesOfFailedLookup);
|
||||
fileWatchesOfAffectingLocations.forEach(closeFileWatcherOfAffectingLocation);
|
||||
packageDirWatchers.forEach(closePackageDirWatcher);
|
||||
hasChangedAutomaticTypeDirectiveNames = false;
|
||||
moduleResolutionCache.isReadonly = true;
|
||||
typeReferenceDirectiveResolutionCache.isReadonly = true;
|
||||
libraryResolutionCache.isReadonly = true;
|
||||
moduleResolutionCache.getPackageJsonInfoCache().isReadonly = true;
|
||||
isSymlinkCache.clear();
|
||||
}
|
||||
|
||||
function closePackageDirWatcher(watcher: PackageDirWatcher, packageDirPath: Path) {
|
||||
if (watcher.dirPathToWatcher.size === 0) {
|
||||
packageDirWatchers.delete(packageDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
function closeDirectoryWatchesOfFailedLookup(watcher: DirectoryWatchesOfFailedLookup, path: Path) {
|
||||
@@ -1078,13 +1142,14 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dir, dirPath, nonRecursive } = toWatch;
|
||||
const { dir, dirPath, nonRecursive, packageDir, packageDirPath } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
Debug.assert(nonRecursive);
|
||||
Debug.assert(!packageDir);
|
||||
setAtRoot = true;
|
||||
}
|
||||
else {
|
||||
setDirectoryWatcher(dir, dirPath, nonRecursive);
|
||||
setDirectoryWatcher(dir, dirPath, packageDir, packageDirPath, nonRecursive);
|
||||
}
|
||||
}
|
||||
return setAtRoot;
|
||||
@@ -1106,7 +1171,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
if (alternateResult) setAtRoot = watchFailedLookupLocation(alternateResult, setAtRoot);
|
||||
if (setAtRoot) {
|
||||
// This is always non recursive
|
||||
setDirectoryWatcher(rootDir, rootPath, /*nonRecursive*/ true);
|
||||
setDirectoryWatcher(rootDir, rootPath, /*packageDir*/ undefined, /*packageDirPath*/ undefined, /*nonRecursive*/ true);
|
||||
}
|
||||
watchAffectingLocationsOfResolution(resolution, !failedLookupLocations?.length && !alternateResult);
|
||||
}
|
||||
@@ -1197,15 +1262,87 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
}
|
||||
}
|
||||
|
||||
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
function createDirectoryWatcherForPackageDir(
|
||||
dir: string,
|
||||
dirPath: Path,
|
||||
packageDir: string,
|
||||
packageDirPath: Path,
|
||||
nonRecursive: boolean | undefined,
|
||||
) {
|
||||
Debug.assert(!nonRecursive);
|
||||
// Check if this is symlink:
|
||||
let isSymlink = isSymlinkCache.get(packageDirPath);
|
||||
let packageDirWatcher = packageDirWatchers.get(packageDirPath);
|
||||
if (isSymlink === undefined) {
|
||||
const realPath = resolutionHost.realpath!(packageDir);
|
||||
isSymlink = realPath !== packageDir && resolutionHost.toPath(realPath) !== packageDirPath;
|
||||
isSymlinkCache.set(packageDirPath, isSymlink);
|
||||
if (!packageDirWatcher) {
|
||||
packageDirWatchers.set(
|
||||
packageDirPath,
|
||||
packageDirWatcher = {
|
||||
dirPathToWatcher: new Map(),
|
||||
isSymlink,
|
||||
},
|
||||
);
|
||||
}
|
||||
else if (packageDirWatcher.isSymlink !== isSymlink) {
|
||||
// Handle the change
|
||||
packageDirWatcher.dirPathToWatcher.forEach(watcher => {
|
||||
removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath, /*syncDirWatcherRemove*/ false);
|
||||
watcher.watcher = createDirPathToWatcher();
|
||||
});
|
||||
packageDirWatcher.isSymlink = isSymlink;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assertIsDefined(packageDirWatcher);
|
||||
Debug.assert(isSymlink === packageDirWatcher.isSymlink);
|
||||
}
|
||||
const forDirPath = packageDirWatcher.dirPathToWatcher.get(dirPath);
|
||||
if (forDirPath) {
|
||||
forDirPath.refCount++;
|
||||
}
|
||||
else {
|
||||
packageDirWatcher.dirPathToWatcher.set(dirPath, {
|
||||
watcher: createDirPathToWatcher(),
|
||||
refCount: 1,
|
||||
});
|
||||
if (isSymlink) dirPathToSymlinkPackageRefCount.set(dirPath, (dirPathToSymlinkPackageRefCount.get(dirPath) ?? 0) + 1);
|
||||
}
|
||||
|
||||
function createDirPathToWatcher() {
|
||||
return isSymlink ?
|
||||
createOrAddRefToDirectoryWatchOfFailedLookups(packageDir, packageDirPath, nonRecursive) :
|
||||
createOrAddRefToDirectoryWatchOfFailedLookups(dir, dirPath, nonRecursive);
|
||||
}
|
||||
}
|
||||
|
||||
function setDirectoryWatcher(
|
||||
dir: string,
|
||||
dirPath: Path,
|
||||
packageDir: string | undefined,
|
||||
packageDirPath: Path | undefined,
|
||||
nonRecursive: boolean | undefined,
|
||||
) {
|
||||
if (!packageDirPath || !resolutionHost.realpath) {
|
||||
createOrAddRefToDirectoryWatchOfFailedLookups(dir, dirPath, nonRecursive);
|
||||
}
|
||||
else {
|
||||
createDirectoryWatcherForPackageDir(dir, dirPath, packageDir!, packageDirPath, nonRecursive);
|
||||
}
|
||||
}
|
||||
|
||||
function createOrAddRefToDirectoryWatchOfFailedLookups(dir: string, dirPath: Path, nonRecursive: boolean | undefined) {
|
||||
let dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
Debug.assert(!!nonRecursive === !!dirWatcher.nonRecursive);
|
||||
dirWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), refCount: 1, nonRecursive });
|
||||
directoryWatchesOfFailedLookups.set(dirPath, dirWatcher = { watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), refCount: 1, nonRecursive });
|
||||
}
|
||||
return dirWatcher;
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean, syncDirWatcherRemove: boolean | undefined) {
|
||||
@@ -1219,10 +1356,29 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dirPath } = toWatch;
|
||||
const { dirPath, packageDirPath } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
removeAtRoot = true;
|
||||
}
|
||||
else if (packageDirPath && resolutionHost.realpath) {
|
||||
const packageDirWatcher = packageDirWatchers.get(packageDirPath)!;
|
||||
const forDirPath = packageDirWatcher.dirPathToWatcher.get(dirPath)!;
|
||||
forDirPath.refCount--;
|
||||
if (forDirPath.refCount === 0) {
|
||||
removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath, syncDirWatcherRemove);
|
||||
packageDirWatcher.dirPathToWatcher.delete(dirPath);
|
||||
if (packageDirWatcher.isSymlink) {
|
||||
const refCount = dirPathToSymlinkPackageRefCount.get(dirPath)! - 1;
|
||||
if (refCount === 0) {
|
||||
dirPathToSymlinkPackageRefCount.delete(dirPath);
|
||||
}
|
||||
else {
|
||||
dirPathToSymlinkPackageRefCount.set(dirPath, refCount);
|
||||
}
|
||||
}
|
||||
if (syncDirWatcherRemove) closePackageDirWatcher(packageDirWatcher, packageDirPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
removeDirectoryWatcher(dirPath, syncDirWatcherRemove);
|
||||
}
|
||||
@@ -1506,7 +1662,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
rootPath,
|
||||
rootPathComponents,
|
||||
getCurrentDirectory,
|
||||
dirPath => directoryWatchesOfFailedLookups.has(dirPath),
|
||||
dirPath => directoryWatchesOfFailedLookups.has(dirPath) || dirPathToSymlinkPackageRefCount.has(dirPath),
|
||||
);
|
||||
if (dirPath) {
|
||||
scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath);
|
||||
|
||||
+8
-14
@@ -1768,18 +1768,6 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
|
||||
|
||||
const ch = codePointAt(text, pos);
|
||||
if (pos === 0) {
|
||||
// If a file isn't valid text at all, it will usually be apparent
|
||||
// in the first few characters because UTF-8 decode will fail and produce U+FFFD.
|
||||
// If that happens, just issue one error and refuse to try to scan further;
|
||||
// this is likely a binary file that cannot be parsed.
|
||||
//
|
||||
// It's safe to slice the text; U+FFFD can only be produced by an invalid decode,
|
||||
// so even if we cut a surrogate pair in half, they wouldn't be U+FFFD.
|
||||
if (text.slice(0, 256).includes("\uFFFD")) {
|
||||
error(Diagnostics.File_appears_to_be_binary);
|
||||
pos = end;
|
||||
return token = SyntaxKind.NonTextFileMarkerTrivia;
|
||||
}
|
||||
// Special handling for shebang
|
||||
if (ch === CharacterCodes.hash && isShebangTrivia(text, pos)) {
|
||||
pos = scanShebangTrivia(text, pos);
|
||||
@@ -2242,6 +2230,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
|
||||
error(Diagnostics.Invalid_character, pos++, charSize(ch));
|
||||
}
|
||||
return token = SyntaxKind.PrivateIdentifier;
|
||||
case CharacterCodes.replacementCharacter:
|
||||
error(Diagnostics.File_appears_to_be_binary, 0, 0);
|
||||
pos = end;
|
||||
return token = SyntaxKind.NonTextFileMarkerTrivia;
|
||||
default:
|
||||
const identifierKind = scanIdentifier(ch, languageVersion);
|
||||
if (identifierKind) {
|
||||
@@ -2656,6 +2648,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
|
||||
return token = SyntaxKind.OpenBracketToken;
|
||||
case CharacterCodes.closeBracket:
|
||||
return token = SyntaxKind.CloseBracketToken;
|
||||
case CharacterCodes.openParen:
|
||||
return token = SyntaxKind.OpenParenToken;
|
||||
case CharacterCodes.closeParen:
|
||||
return token = SyntaxKind.CloseParenToken;
|
||||
case CharacterCodes.lessThan:
|
||||
return token = SyntaxKind.LessThanToken;
|
||||
case CharacterCodes.greaterThan:
|
||||
@@ -2809,13 +2805,11 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function codePointAt(s: string, i: number): number {
|
||||
// TODO(jakebailey): this is wrong and should have ?? 0; but all users are okay with it
|
||||
return s.codePointAt(i)!;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function charSize(ch: number) {
|
||||
if (ch >= 0x10000) {
|
||||
return 2;
|
||||
|
||||
+70
-23
@@ -18,6 +18,7 @@ import {
|
||||
getDirectoryPath,
|
||||
getFallbackOptions,
|
||||
getNormalizedAbsolutePath,
|
||||
getRelativePathFromDirectory,
|
||||
getRelativePathToDirectoryOrUrl,
|
||||
getRootLength,
|
||||
getStringComparer,
|
||||
@@ -607,15 +608,17 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
watcher: FileWatcher;
|
||||
childWatches: ChildWatches;
|
||||
refCount: number;
|
||||
targetWatcher: ChildDirectoryWatcher | undefined;
|
||||
links: Set<string> | undefined;
|
||||
}
|
||||
|
||||
const cache = new Map<string, HostDirectoryWatcher>();
|
||||
const cache = new Map<Path, HostDirectoryWatcher>();
|
||||
const callbackCache = createMultiMap<Path, { dirName: string; callback: DirectoryWatcherCallback; }>();
|
||||
const cacheToUpdateChildWatches = new Map<Path, { dirName: string; options: WatchOptions | undefined; fileNames: string[]; }>();
|
||||
let timerToUpdateChildWatches: any;
|
||||
|
||||
const filePathComparer = getStringComparer(!useCaseSensitiveFileNames);
|
||||
const toCanonicalFilePath = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
const toCanonicalFilePath = createGetCanonicalFileName(useCaseSensitiveFileNames) as (fileName: string) => Path;
|
||||
|
||||
return (dirName, callback, recursive, options) =>
|
||||
recursive ?
|
||||
@@ -625,8 +628,13 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
/**
|
||||
* Create the directory watcher for the dirPath.
|
||||
*/
|
||||
function createDirectoryWatcher(dirName: string, options: WatchOptions | undefined, callback?: DirectoryWatcherCallback): ChildDirectoryWatcher {
|
||||
const dirPath = toCanonicalFilePath(dirName) as Path;
|
||||
function createDirectoryWatcher(
|
||||
dirName: string,
|
||||
options: WatchOptions | undefined,
|
||||
callback?: DirectoryWatcherCallback,
|
||||
link?: string,
|
||||
): ChildDirectoryWatcher {
|
||||
const dirPath = toCanonicalFilePath(dirName);
|
||||
let directoryWatcher = cache.get(dirPath);
|
||||
if (directoryWatcher) {
|
||||
directoryWatcher.refCount++;
|
||||
@@ -640,7 +648,7 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
|
||||
if (options?.synchronousWatchDirectory) {
|
||||
// Call the actual callback
|
||||
invokeCallbacks(dirPath, fileName);
|
||||
if (!cache.get(dirPath)?.targetWatcher) invokeCallbacks(dirName, dirPath, fileName);
|
||||
|
||||
// Iterate through existing children and update the watches if needed
|
||||
updateChildWatches(dirName, dirPath, options);
|
||||
@@ -654,11 +662,15 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
),
|
||||
refCount: 1,
|
||||
childWatches: emptyArray,
|
||||
targetWatcher: undefined,
|
||||
links: undefined,
|
||||
};
|
||||
cache.set(dirPath, directoryWatcher);
|
||||
updateChildWatches(dirName, dirPath, options);
|
||||
}
|
||||
|
||||
if (link) (directoryWatcher.links ??= new Set()).add(link);
|
||||
|
||||
const callbackToAdd = callback && { dirName, callback };
|
||||
if (callbackToAdd) {
|
||||
callbackCache.add(dirPath, callbackToAdd);
|
||||
@@ -669,21 +681,24 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
close: () => {
|
||||
const directoryWatcher = Debug.checkDefined(cache.get(dirPath));
|
||||
if (callbackToAdd) callbackCache.remove(dirPath, callbackToAdd);
|
||||
if (link) directoryWatcher.links?.delete(link);
|
||||
directoryWatcher.refCount--;
|
||||
|
||||
if (directoryWatcher.refCount) return;
|
||||
|
||||
cache.delete(dirPath);
|
||||
directoryWatcher.links = undefined;
|
||||
closeFileWatcherOf(directoryWatcher);
|
||||
closeTargetWatcher(directoryWatcher);
|
||||
directoryWatcher.childWatches.forEach(closeFileWatcher);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type InvokeMap = Map<Path, string[] | true>;
|
||||
function invokeCallbacks(dirPath: Path, fileName: string): void;
|
||||
function invokeCallbacks(dirPath: Path, invokeMap: InvokeMap, fileNames: string[] | undefined): void;
|
||||
function invokeCallbacks(dirPath: Path, fileNameOrInvokeMap: string | InvokeMap, fileNames?: string[]) {
|
||||
function invokeCallbacks(dirName: string, dirPath: Path, fileName: string): void;
|
||||
function invokeCallbacks(dirName: string, dirPath: Path, invokeMap: InvokeMap, fileNames: string[] | undefined): void;
|
||||
function invokeCallbacks(dirName: string, dirPath: Path, fileNameOrInvokeMap: string | InvokeMap, fileNames?: string[]) {
|
||||
let fileName: string | undefined;
|
||||
let invokeMap: InvokeMap | undefined;
|
||||
if (isString(fileNameOrInvokeMap)) {
|
||||
@@ -715,6 +730,15 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
}
|
||||
}
|
||||
});
|
||||
cache.get(dirPath)?.links?.forEach(link => {
|
||||
const toPathInLink = (fileName: string) => combinePaths(link, getRelativePathFromDirectory(dirName, fileName, toCanonicalFilePath));
|
||||
if (invokeMap) {
|
||||
invokeCallbacks(link, toCanonicalFilePath(link), invokeMap, fileNames?.map(toPathInLink));
|
||||
}
|
||||
else {
|
||||
invokeCallbacks(link, toCanonicalFilePath(link), toPathInLink(fileName!));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function nonSyncUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) {
|
||||
@@ -727,7 +751,8 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
}
|
||||
|
||||
// Call the actual callbacks and remove child watches
|
||||
invokeCallbacks(dirPath, fileName);
|
||||
invokeCallbacks(dirName, dirPath, fileName);
|
||||
closeTargetWatcher(parentWatcher);
|
||||
removeChildWatches(parentWatcher);
|
||||
}
|
||||
|
||||
@@ -760,7 +785,7 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
// Because the child refresh is fresh, we would need to invalidate whole root directory being watched
|
||||
// to ensure that all the changes are reflected at this time
|
||||
const hasChanges = updateChildWatches(dirName, dirPath, options);
|
||||
invokeCallbacks(dirPath, invokeMap, hasChanges ? undefined : fileNames);
|
||||
if (!cache.get(dirPath)?.targetWatcher) invokeCallbacks(dirName, dirPath, invokeMap, hasChanges ? undefined : fileNames);
|
||||
}
|
||||
|
||||
sysLog(`sysLog:: invokingWatchers:: Elapsed:: ${timestamp() - start}ms:: ${cacheToUpdateChildWatches.size}`);
|
||||
@@ -792,24 +817,46 @@ function createDirectoryWatcherSupportingRecursive({
|
||||
}
|
||||
}
|
||||
|
||||
function closeTargetWatcher(watcher: HostDirectoryWatcher | undefined) {
|
||||
if (watcher?.targetWatcher) {
|
||||
watcher.targetWatcher.close();
|
||||
watcher.targetWatcher = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function updateChildWatches(parentDir: string, parentDirPath: Path, options: WatchOptions | undefined) {
|
||||
// Iterate through existing children and update the watches if needed
|
||||
const parentWatcher = cache.get(parentDirPath);
|
||||
if (!parentWatcher) return false;
|
||||
const target = normalizePath(realpath(parentDir));
|
||||
let hasChanges;
|
||||
let newChildWatches: ChildDirectoryWatcher[] | undefined;
|
||||
const hasChanges = enumerateInsertsAndDeletes<string, ChildDirectoryWatcher>(
|
||||
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,
|
||||
);
|
||||
if (filePathComparer(target, parentDir) === Comparison.EqualTo) {
|
||||
// if (parentWatcher.target) closeFileWatcher
|
||||
hasChanges = enumerateInsertsAndDeletes<string, ChildDirectoryWatcher>(
|
||||
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,
|
||||
);
|
||||
}
|
||||
else if (parentWatcher.targetWatcher && filePathComparer(target, parentWatcher.targetWatcher.dirName) === Comparison.EqualTo) {
|
||||
hasChanges = false;
|
||||
Debug.assert(parentWatcher.childWatches === emptyArray);
|
||||
}
|
||||
else {
|
||||
closeTargetWatcher(parentWatcher);
|
||||
parentWatcher.targetWatcher = createDirectoryWatcher(target, options, /*callback*/ undefined, parentDir);
|
||||
parentWatcher.childWatches.forEach(closeFileWatcher);
|
||||
hasChanges = true;
|
||||
}
|
||||
parentWatcher.childWatches = newChildWatches || emptyArray;
|
||||
return hasChanges;
|
||||
|
||||
|
||||
@@ -65,10 +65,10 @@ import {
|
||||
transformESDecorators,
|
||||
transformESNext,
|
||||
transformGenerators,
|
||||
transformImpliedNodeFormatDependentModule,
|
||||
transformJsx,
|
||||
transformLegacyDecorators,
|
||||
transformModule,
|
||||
transformNodeModule,
|
||||
transformSystemModule,
|
||||
transformTypeScript,
|
||||
VariableDeclaration,
|
||||
@@ -77,17 +77,23 @@ import * as performance from "./_namespaces/ts.performance";
|
||||
|
||||
function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile | Bundle> {
|
||||
switch (moduleKind) {
|
||||
case ModuleKind.Preserve:
|
||||
// `transformECMAScriptModule` contains logic for preserving
|
||||
// CJS input syntax in `--module preserve`
|
||||
return transformECMAScriptModule;
|
||||
case ModuleKind.ESNext:
|
||||
case ModuleKind.ES2022:
|
||||
case ModuleKind.ES2020:
|
||||
case ModuleKind.ES2015:
|
||||
case ModuleKind.Preserve:
|
||||
return transformECMAScriptModule;
|
||||
case ModuleKind.System:
|
||||
return transformSystemModule;
|
||||
case ModuleKind.Node16:
|
||||
case ModuleKind.NodeNext:
|
||||
return transformNodeModule;
|
||||
case ModuleKind.CommonJS:
|
||||
// Wraps `transformModule` and `transformECMAScriptModule` and
|
||||
// selects between them based on the `impliedNodeFormat` of the
|
||||
// source file.
|
||||
return transformImpliedNodeFormatDependentModule;
|
||||
case ModuleKind.System:
|
||||
return transformSystemModule;
|
||||
default:
|
||||
return transformModule;
|
||||
}
|
||||
|
||||
@@ -638,7 +638,7 @@ export function transformDeclarations(context: TransformationContext) {
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
typeNode = resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldAddImplicitUndefined);
|
||||
typeNode = resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
|
||||
+5
-4
@@ -14,7 +14,7 @@ import {
|
||||
} from "../../_namespaces/ts";
|
||||
|
||||
/** @internal */
|
||||
export function transformNodeModule(context: TransformationContext) {
|
||||
export function transformImpliedNodeFormatDependentModule(context: TransformationContext) {
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
|
||||
@@ -30,6 +30,7 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
|
||||
const cjsOnSubstituteNode = context.onSubstituteNode;
|
||||
const cjsOnEmitNode = context.onEmitNode;
|
||||
const getEmitModuleFormatOfFile = (file: SourceFile) => context.getEmitHost().getEmitModuleFormatOfFile(file);
|
||||
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
@@ -51,7 +52,7 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
if (!currentSourceFile) {
|
||||
return previousOnSubstituteNode(hint, node);
|
||||
}
|
||||
if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) {
|
||||
if (getEmitModuleFormatOfFile(currentSourceFile) >= ModuleKind.ES2015) {
|
||||
return esmOnSubstituteNode(hint, node);
|
||||
}
|
||||
return cjsOnSubstituteNode(hint, node);
|
||||
@@ -65,14 +66,14 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
if (!currentSourceFile) {
|
||||
return previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) {
|
||||
if (getEmitModuleFormatOfFile(currentSourceFile) >= ModuleKind.ES2015) {
|
||||
return esmOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
return cjsOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
|
||||
function getModuleTransformForFile(file: SourceFile): typeof esmTransform {
|
||||
return file.impliedNodeFormat === ModuleKind.ESNext ? esmTransform : cjsTransform;
|
||||
return getEmitModuleFormatOfFile(file) >= ModuleKind.ES2015 ? esmTransform : cjsTransform;
|
||||
}
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
getOriginalNodeId,
|
||||
getStrictOptionValue,
|
||||
getTextOfIdentifierOrLiteral,
|
||||
hasJSFileExtension,
|
||||
hasJsonModuleEmitEnabled,
|
||||
hasSyntacticModifier,
|
||||
Identifier,
|
||||
@@ -243,6 +244,9 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
}
|
||||
|
||||
function shouldEmitUnderscoreUnderscoreESModule() {
|
||||
if (hasJSFileExtension(currentSourceFile.fileName) && currentSourceFile.commonJsModuleIndicator && (!currentSourceFile.externalModuleIndicator || currentSourceFile.externalModuleIndicator === true)) {
|
||||
return false;
|
||||
}
|
||||
if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) {
|
||||
return true;
|
||||
}
|
||||
@@ -785,7 +789,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
return visitPartiallyEmittedExpression(node as PartiallyEmittedExpression, valueIsDiscarded);
|
||||
case SyntaxKind.CallExpression:
|
||||
if (isImportCall(node) && currentSourceFile.impliedNodeFormat === undefined) {
|
||||
if (isImportCall(node) && host.shouldTransformImportCall(currentSourceFile)) {
|
||||
return visitImportCallExpression(node);
|
||||
}
|
||||
break;
|
||||
|
||||
+105
-12
@@ -763,6 +763,8 @@ export type JSDocSyntaxKind =
|
||||
| SyntaxKind.GreaterThanToken
|
||||
| SyntaxKind.OpenBracketToken
|
||||
| SyntaxKind.CloseBracketToken
|
||||
| SyntaxKind.OpenParenToken
|
||||
| SyntaxKind.CloseParenToken
|
||||
| SyntaxKind.EqualsToken
|
||||
| SyntaxKind.CommaToken
|
||||
| SyntaxKind.DotToken
|
||||
@@ -4242,6 +4244,18 @@ export interface SourceFileLike {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface FutureSourceFile {
|
||||
readonly path: Path;
|
||||
readonly fileName: string;
|
||||
readonly impliedNodeFormat?: ResolutionMode;
|
||||
readonly packageJsonScope?: PackageJsonInfo;
|
||||
readonly externalModuleIndicator?: true | undefined;
|
||||
readonly commonJsModuleIndicator?: true | undefined;
|
||||
readonly statements: readonly never[];
|
||||
readonly imports: readonly never[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface RedirectInfo {
|
||||
/** Source file this redirects to. */
|
||||
@@ -4769,21 +4783,79 @@ export interface Program extends ScriptReferenceHost {
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
isSourceFileDefaultLibrary(file: SourceFile): boolean;
|
||||
/**
|
||||
* Calculates the final resolution mode for a given module reference node. This is the resolution mode explicitly provided via import
|
||||
* attributes, if present, or the syntax the usage would have if emitted to JavaScript. In `--module node16` or `nodenext`, this may
|
||||
* depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the input syntax of the reference. In other
|
||||
* `module` modes, when overriding import attributes are not provided, this function returns `undefined`, as the result would have no
|
||||
* impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for a given module reference node. This function only returns a result when module resolution
|
||||
* settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided via import attributes,
|
||||
* which cause an `import` or `require` condition to be used during resolution regardless of module resolution settings. In absence of
|
||||
* overriding attributes, and in modes that support differing resolution, the result indicates the syntax the usage would emit to JavaScript.
|
||||
* Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*/
|
||||
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
/**
|
||||
* Calculates the final resolution mode for an import at some index within a file's `imports` list. This is the resolution mode
|
||||
* explicitly provided via import attributes, if present, or the syntax the usage would have if emitted to JavaScript. In
|
||||
* `--module node16` or `nodenext`, this may depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the
|
||||
* input syntax of the reference. In other `module` modes, when overriding import attributes are not provided, this function returns
|
||||
* `undefined`, as the result would have no impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for an import at some index within a file's `imports` list. This function only returns a result
|
||||
* when module resolution settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided
|
||||
* via import attributes, which cause an `import` or `require` condition to be used during resolution regardless of module resolution
|
||||
* settings. In absence of overriding attributes, and in modes that support differing resolution, the result indicates the syntax the
|
||||
* usage would emit to JavaScript. Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*/
|
||||
getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
/**
|
||||
* @internal
|
||||
* The resolution mode to use for module resolution or module specifier resolution
|
||||
* outside the context of an existing module reference, where
|
||||
* `program.getModeForUsageLocation` should be used instead.
|
||||
*/
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
/** @internal */ getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode;
|
||||
/** @internal */ getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
/** @internal */ shouldTransformImportCall(sourceFile: SourceFile): boolean;
|
||||
|
||||
// For testing purposes only.
|
||||
// This is set on created program to let us know how the program was created using old program
|
||||
@@ -4838,6 +4910,7 @@ export interface Program extends ScriptReferenceHost {
|
||||
/** @internal */ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
|
||||
/** @internal */ getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
|
||||
/** @internal */ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
/** @internal */ getCompilerOptionsForFile(file: SourceFile): CompilerOptions;
|
||||
/** @internal */ getBuildInfo?(): BuildInfo;
|
||||
/** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
/**
|
||||
@@ -4953,8 +5026,12 @@ export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
getProjectReferenceRedirect(fileName: string): string | undefined;
|
||||
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
getEmitSyntaxForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
|
||||
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode;
|
||||
getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
|
||||
getResolvedModule(f: SourceFile, moduleName: string, mode: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
|
||||
@@ -5609,6 +5686,9 @@ export interface RequireVariableDeclarationList extends VariableDeclarationList
|
||||
readonly declarations: NodeArray<VariableDeclarationInitializedTo<RequireOrImportCall>>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type CanHaveModuleSpecifier = AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode;
|
||||
|
||||
/** @internal */
|
||||
export type LateVisibilityPaintedStatement =
|
||||
| AnyImportOrJsDocImport
|
||||
@@ -5714,7 +5794,7 @@ export interface EmitResolver {
|
||||
requiresAddingImplicitUndefined(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;
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): 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;
|
||||
@@ -7498,6 +7578,7 @@ export const enum ScriptTarget {
|
||||
ES2020 = 7,
|
||||
ES2021 = 8,
|
||||
ES2022 = 9,
|
||||
ES2023 = 10,
|
||||
ESNext = 99,
|
||||
JSON = 100,
|
||||
Latest = ESNext,
|
||||
@@ -7540,6 +7621,9 @@ export interface ConfigFileSpecs {
|
||||
validatedFilesSpec: readonly string[] | undefined;
|
||||
validatedIncludeSpecs: readonly string[] | undefined;
|
||||
validatedExcludeSpecs: readonly string[] | undefined;
|
||||
validatedFilesSpecBeforeSubstitution: readonly string[] | undefined;
|
||||
validatedIncludeSpecsBeforeSubstitution: readonly string[] | undefined;
|
||||
validatedExcludeSpecsBeforeSubstitution: readonly string[] | undefined;
|
||||
pathPatterns: readonly (string | Pattern)[] | undefined;
|
||||
isDefaultIncludeSpec: boolean;
|
||||
}
|
||||
@@ -7586,7 +7670,8 @@ export interface CommandLineOptionBase {
|
||||
affectsBuildInfo?: true; // true if this options should be emitted in buildInfo
|
||||
transpileOptionValue?: boolean | undefined; // If set this means that the option should be set to this value when transpiling
|
||||
extraValidation?: (value: CompilerOptionsValue) => [DiagnosticMessage, ...string[]] | undefined; // Additional validation to be performed for the value to be valid
|
||||
disallowNullOrUndefined?: true; // If set option does not allow setting null
|
||||
disallowNullOrUndefined?: true; // If set option does not allow setting null
|
||||
allowConfigDirTemplateSubstitution?: true; // If set option allows substitution of `${configDir}` in the value
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -7677,6 +7762,9 @@ export const enum CharacterCodes {
|
||||
mathematicalSpace = 0x205F,
|
||||
ogham = 0x1680,
|
||||
|
||||
// Unicode replacement character produced when a byte sequence is invalid
|
||||
replacementCharacter = 0xFFFD,
|
||||
|
||||
_ = 0x5F,
|
||||
$ = 0x24,
|
||||
|
||||
@@ -8392,6 +8480,8 @@ export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolution
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
|
||||
isEmitBlocked(emitFileName: string): boolean;
|
||||
shouldTransformImportCall(sourceFile: SourceFile): boolean;
|
||||
getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
|
||||
writeFile: WriteFileCallback;
|
||||
getBuildInfo(): BuildInfo | undefined;
|
||||
@@ -9632,6 +9722,7 @@ export interface PrinterOptions {
|
||||
omitTrailingSemicolon?: boolean;
|
||||
noEmitHelpers?: boolean;
|
||||
/** @internal */ module?: CompilerOptions["module"];
|
||||
/** @internal */ moduleResolution?: CompilerOptions["moduleResolution"];
|
||||
/** @internal */ target?: CompilerOptions["target"];
|
||||
/** @internal */ sourceMap?: boolean;
|
||||
/** @internal */ inlineSourceMap?: boolean;
|
||||
@@ -9766,6 +9857,8 @@ export interface ModuleSpecifierResolutionHost {
|
||||
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
|
||||
getCommonSourceDirectory(): string;
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
+650
-12
@@ -5,12 +5,12 @@ import {
|
||||
addRange,
|
||||
affectsDeclarationPathOptionDeclarations,
|
||||
affectsEmitOptionDeclarations,
|
||||
AliasDeclarationNode,
|
||||
AllAccessorDeclarations,
|
||||
AmbientModuleDeclaration,
|
||||
AmpersandAmpersandEqualsToken,
|
||||
AnyImportOrBareOrAccessedRequire,
|
||||
AnyImportOrReExport,
|
||||
AnyImportOrRequireStatement,
|
||||
AnyImportSyntax,
|
||||
AnyValidImportOrReExport,
|
||||
append,
|
||||
@@ -38,7 +38,9 @@ import {
|
||||
CallLikeExpression,
|
||||
CallSignatureDeclaration,
|
||||
canHaveDecorators,
|
||||
canHaveLocals,
|
||||
canHaveModifiers,
|
||||
type CanHaveModuleSpecifier,
|
||||
CaseBlock,
|
||||
CaseClause,
|
||||
CaseOrDefaultClause,
|
||||
@@ -165,6 +167,7 @@ import {
|
||||
getCommonSourceDirectory,
|
||||
getContainerFlags,
|
||||
getDirectoryPath,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getJSDocAugmentsTag,
|
||||
getJSDocDeprecatedTagNoCache,
|
||||
getJSDocImplementsTags,
|
||||
@@ -232,16 +235,19 @@ import {
|
||||
IndexInfo,
|
||||
indexOfAnyCharCode,
|
||||
IndexSignatureDeclaration,
|
||||
InferTypeNode,
|
||||
InitializedVariableDeclaration,
|
||||
insertSorted,
|
||||
InstanceofExpression,
|
||||
InterfaceDeclaration,
|
||||
InternalEmitFlags,
|
||||
InternalSymbolName,
|
||||
isAccessor,
|
||||
isAnyDirectorySeparator,
|
||||
isArray,
|
||||
isArrayLiteralExpression,
|
||||
isArrowFunction,
|
||||
isAssertionExpression,
|
||||
isAutoAccessorPropertyDeclaration,
|
||||
isBigIntLiteral,
|
||||
isBinaryExpression,
|
||||
@@ -256,6 +262,7 @@ import {
|
||||
isCommaListExpression,
|
||||
isComputedPropertyName,
|
||||
isConstructorDeclaration,
|
||||
isConstTypeReference,
|
||||
isDeclaration,
|
||||
isDecorator,
|
||||
isElementAccessExpression,
|
||||
@@ -292,6 +299,7 @@ import {
|
||||
isJSDocOverloadTag,
|
||||
isJSDocParameterTag,
|
||||
isJSDocPropertyLikeTag,
|
||||
isJSDocReturnTag,
|
||||
isJSDocSatisfiesTag,
|
||||
isJSDocSignature,
|
||||
isJSDocTag,
|
||||
@@ -313,15 +321,19 @@ import {
|
||||
isMethodOrAccessor,
|
||||
isModifierLike,
|
||||
isModuleDeclaration,
|
||||
isModuleOrEnumDeclaration,
|
||||
isNamedDeclaration,
|
||||
isNamespaceExport,
|
||||
isNamespaceExportDeclaration,
|
||||
isNamespaceImport,
|
||||
isNonNullExpression,
|
||||
isNoSubstitutionTemplateLiteral,
|
||||
isNullishCoalesce,
|
||||
isNumericLiteral,
|
||||
isObjectBindingPattern,
|
||||
isObjectLiteralExpression,
|
||||
isOmittedExpression,
|
||||
isOptionalChain,
|
||||
isParameter,
|
||||
isParameterPropertyDeclaration,
|
||||
isParenthesizedExpression,
|
||||
@@ -347,6 +359,7 @@ import {
|
||||
isTypeLiteralNode,
|
||||
isTypeNode,
|
||||
isTypeParameterDeclaration,
|
||||
isTypeQueryNode,
|
||||
isTypeReferenceNode,
|
||||
isVariableDeclaration,
|
||||
isVariableStatement,
|
||||
@@ -474,7 +487,9 @@ import {
|
||||
ResolvedModuleWithFailedLookupLocations,
|
||||
ResolvedTypeReferenceDirective,
|
||||
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
|
||||
returnFalse,
|
||||
ReturnStatement,
|
||||
returnUndefined,
|
||||
SatisfiesExpression,
|
||||
ScriptKind,
|
||||
ScriptTarget,
|
||||
@@ -1743,7 +1758,7 @@ function canUseOriginalText(node: LiteralLikeNode, flags: GetLiteralTextFlags):
|
||||
|
||||
/** @internal */
|
||||
export function getTextOfConstantValue(value: string | number) {
|
||||
return isString(value) ? '"' + escapeNonAsciiString(value) + '"' : "" + value;
|
||||
return isString(value) ? `"${escapeString(value)}"` : "" + value;
|
||||
}
|
||||
|
||||
// Make an identifier from an external module name by extracting the string after the last "/" and replacing
|
||||
@@ -1981,6 +1996,11 @@ export function isAnyImportOrBareOrAccessedRequire(node: Node): node is AnyImpor
|
||||
return isAnyImportSyntax(node) || isVariableDeclarationInitializedToBareOrAccessedRequire(node);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isAnyImportOrRequireStatement(node: Node): node is AnyImportOrRequireStatement {
|
||||
return isAnyImportSyntax(node) || isRequireVariableStatement(node);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isLateVisibilityPaintedStatement(node: Node): node is LateVisibilityPaintedStatement {
|
||||
switch (node.kind) {
|
||||
@@ -2296,6 +2316,11 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa
|
||||
return createTextSpanFromBounds(pos, errorNode.end);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isGlobalSourceFile(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node as SourceFile);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isExternalOrCommonJsModule(file: SourceFile): boolean {
|
||||
return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined;
|
||||
@@ -3457,6 +3482,11 @@ export function isInternalModuleImportEqualsDeclaration(node: Node): node is Imp
|
||||
return node.kind === SyntaxKind.ImportEqualsDeclaration && (node as ImportEqualsDeclaration).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isFullSourceFile(sourceFile: object): sourceFile is SourceFile {
|
||||
return (sourceFile as Partial<SourceFile>)?.kind === SyntaxKind.SourceFile;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isSourceFileJS(file: SourceFile): boolean {
|
||||
return isInJSFile(file);
|
||||
@@ -3984,7 +4014,26 @@ export function isFunctionSymbol(symbol: Symbol | undefined) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode | JSDocImportTag): StringLiteralLike | undefined {
|
||||
export function canHaveModuleSpecifier(node: Node | undefined): node is CanHaveModuleSpecifier {
|
||||
switch (node?.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.NamespaceExport:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ImportType:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetModuleSpecifierFromDeclaration(node: CanHaveModuleSpecifier | JSDocImportTag): StringLiteralLike | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
@@ -8441,11 +8490,13 @@ function isFileModuleFromUsingJSXTag(file: SourceFile): Node | undefined {
|
||||
* Note that this requires file.impliedNodeFormat be set already; meaning it must be set very early on
|
||||
* in SourceFile construction.
|
||||
*/
|
||||
function isFileForcedToBeModuleByFormat(file: SourceFile): true | undefined {
|
||||
function isFileForcedToBeModuleByFormat(file: SourceFile, options: CompilerOptions): 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;
|
||||
//
|
||||
// TODO: extension check never considered compilerOptions; should impliedNodeFormat?
|
||||
return (getImpliedNodeFormatForEmitWorker(file, options) === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) && !file.isDeclarationFile ? true : undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -8466,17 +8517,29 @@ export function getSetExternalModuleIndicator(options: CompilerOptions): (file:
|
||||
// If module is nodenext or node16, all esm format files are modules
|
||||
// If jsx is react-jsx or react-jsxdev then jsx tags force module-ness
|
||||
// otherwise, the presence of import or export statments (or import.meta) implies module-ness
|
||||
const checks: ((file: SourceFile) => Node | true | undefined)[] = [isFileProbablyExternalModule];
|
||||
const checks: ((file: SourceFile, options: CompilerOptions) => Node | true | undefined)[] = [isFileProbablyExternalModule];
|
||||
if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
|
||||
checks.push(isFileModuleFromUsingJSXTag);
|
||||
}
|
||||
checks.push(isFileForcedToBeModuleByFormat);
|
||||
const combined = or(...checks);
|
||||
const callback = (file: SourceFile) => void (file.externalModuleIndicator = combined(file));
|
||||
const callback = (file: SourceFile) => void (file.externalModuleIndicator = combined(file, options));
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Returns true if an `import` and a `require` of the same module specifier
|
||||
* can resolve to a different file.
|
||||
*/
|
||||
export function importSyntaxAffectsModuleResolution(options: CompilerOptions) {
|
||||
const moduleResolution = getEmitModuleResolutionKind(options);
|
||||
return ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext
|
||||
|| getResolvePackageJsonExports(options)
|
||||
|| getResolvePackageJsonImports(options);
|
||||
}
|
||||
|
||||
type CompilerOptionKeys = keyof { [K in keyof CompilerOptions as string extends K ? never : K]: any; };
|
||||
function createComputedCompilerOptions<T extends Record<string, CompilerOptionKeys[]>>(
|
||||
options: {
|
||||
@@ -9457,7 +9520,7 @@ export function usesExtensionsOnImports({ imports }: SourceFile, hasExtension: (
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getModuleSpecifierEndingPreference(preference: UserPreferences["importModuleSpecifierEnding"], resolutionMode: ResolutionMode, compilerOptions: CompilerOptions, sourceFile: SourceFile): ModuleSpecifierEnding {
|
||||
export function getModuleSpecifierEndingPreference(preference: UserPreferences["importModuleSpecifierEnding"], resolutionMode: ResolutionMode, compilerOptions: CompilerOptions, sourceFile?: SourceFile): ModuleSpecifierEnding {
|
||||
const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
|
||||
const moduleResolutionIsNodeNext = ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext;
|
||||
if (preference === "js" || resolutionMode === ModuleKind.ESNext && moduleResolutionIsNodeNext) {
|
||||
@@ -9484,22 +9547,22 @@ export function getModuleSpecifierEndingPreference(preference: UserPreferences["
|
||||
// accurately, and more importantly, literally nobody wants `Index` and its existence is a mystery.
|
||||
if (!shouldAllowImportingTsExtension(compilerOptions)) {
|
||||
// If .ts imports are not valid, we only need to see one .js import to go with that.
|
||||
return usesExtensionsOnImports(sourceFile) ? ModuleSpecifierEnding.JsExtension : ModuleSpecifierEnding.Minimal;
|
||||
return sourceFile && usesExtensionsOnImports(sourceFile) ? ModuleSpecifierEnding.JsExtension : ModuleSpecifierEnding.Minimal;
|
||||
}
|
||||
|
||||
return inferPreference();
|
||||
|
||||
function inferPreference() {
|
||||
let usesJsExtensions = false;
|
||||
const specifiers = sourceFile.imports.length ? sourceFile.imports :
|
||||
isSourceFileJS(sourceFile) ? getRequiresAtTopOfFile(sourceFile).map(r => r.arguments[0]) :
|
||||
const specifiers = sourceFile?.imports.length ? sourceFile.imports :
|
||||
sourceFile && isSourceFileJS(sourceFile) ? getRequiresAtTopOfFile(sourceFile).map(r => r.arguments[0]) :
|
||||
emptyArray;
|
||||
for (const specifier of specifiers) {
|
||||
if (pathIsRelative(specifier.text)) {
|
||||
if (
|
||||
moduleResolutionIsNodeNext &&
|
||||
resolutionMode === ModuleKind.CommonJS &&
|
||||
getModeForUsageLocation(sourceFile, specifier, compilerOptions) === ModuleKind.ESNext
|
||||
getModeForUsageLocation(sourceFile!, specifier, compilerOptions) === ModuleKind.ESNext
|
||||
) {
|
||||
// We're trying to decide a preference for a CommonJS module specifier, but looking at an ESM import.
|
||||
continue;
|
||||
@@ -10667,3 +10730,578 @@ export function createEvaluator({ evaluateElementAccessExpression, evaluateEntit
|
||||
}
|
||||
return evaluate;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isConstAssertion(location: Node) {
|
||||
return (isAssertionExpression(location) && isConstTypeReference(location.type))
|
||||
|| (isJSDocTypeTag(location) && isConstTypeReference(location.typeExpression));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration | undefined {
|
||||
const members = node.members;
|
||||
for (const member of members) {
|
||||
if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member as ConstructorDeclaration).body)) {
|
||||
return member as ConstructorDeclaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createNameResolver({
|
||||
compilerOptions,
|
||||
requireSymbol,
|
||||
argumentsSymbol,
|
||||
error,
|
||||
getSymbolOfDeclaration,
|
||||
globals,
|
||||
lookup,
|
||||
setRequiresScopeChangeCache = returnUndefined,
|
||||
getRequiresScopeChangeCache = returnUndefined,
|
||||
onPropertyWithInvalidInitializer = returnFalse,
|
||||
onFailedToResolveSymbol = returnUndefined,
|
||||
onSuccessfullyResolvedSymbol = returnUndefined,
|
||||
}: {
|
||||
compilerOptions: CompilerOptions;
|
||||
getSymbolOfDeclaration: (node: Declaration) => Symbol;
|
||||
error: (location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) => void;
|
||||
globals: SymbolTable;
|
||||
argumentsSymbol: Symbol;
|
||||
requireSymbol: Symbol;
|
||||
lookup: (symbols: SymbolTable, name: __String, meaning: SymbolFlags) => Symbol | undefined;
|
||||
setRequiresScopeChangeCache: undefined | ((node: FunctionLikeDeclaration, value: boolean) => void);
|
||||
getRequiresScopeChangeCache: undefined | ((node: FunctionLikeDeclaration) => boolean | undefined);
|
||||
onPropertyWithInvalidInitializer?: (location: Node | undefined, name: __String, declaration: PropertyDeclaration, result: Symbol | undefined) => boolean;
|
||||
onFailedToResolveSymbol?: (
|
||||
location: Node | undefined,
|
||||
name: __String | Identifier,
|
||||
meaning: SymbolFlags,
|
||||
nameNotFoundMessage: DiagnosticMessage,
|
||||
) => void;
|
||||
onSuccessfullyResolvedSymbol?: (
|
||||
location: Node | undefined,
|
||||
result: Symbol,
|
||||
meaning: SymbolFlags,
|
||||
lastLocation: Node | undefined,
|
||||
associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined,
|
||||
withinDeferredContext: boolean,
|
||||
) => void;
|
||||
}) {
|
||||
/* eslint-disable no-var */
|
||||
var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules";
|
||||
/* eslint-disable no-var */
|
||||
var emitStandardClassFields = getEmitStandardClassFields(compilerOptions);
|
||||
var emptySymbols = createSymbolTable();
|
||||
return resolveNameHelper;
|
||||
function resolveNameHelper(
|
||||
location: Node | undefined,
|
||||
nameArg: __String | Identifier,
|
||||
meaning: SymbolFlags,
|
||||
nameNotFoundMessage: DiagnosticMessage | undefined,
|
||||
isUse: boolean,
|
||||
excludeGlobals?: boolean,
|
||||
): 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 withinDeferredContext = false;
|
||||
let grandparent: Node;
|
||||
const name = isString(nameArg) ? nameArg : (nameArg as Identifier).escapedText;
|
||||
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)
|
||||
return undefined;
|
||||
}
|
||||
if (isModuleOrEnumDeclaration(location) && lastLocation && location.name === lastLocation) {
|
||||
// If lastLocation is the name of a namespace or enum, skip the parent since it will have is own locals that could
|
||||
// conflict.
|
||||
lastLocation = 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 = lookup(location.locals, name, meaning)) {
|
||||
let useResult = true;
|
||||
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.
|
||||
// - parameters are only in the scope of function body
|
||||
// This restriction does not apply to JSDoc comment types because they are parented
|
||||
// at a higher level than type parameters would normally be
|
||||
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
|
||||
// local types not visible outside the function body
|
||||
: false;
|
||||
}
|
||||
if (meaning & result.flags & SymbolFlags.Variable) {
|
||||
// expression inside parameter will lookup as normal variable scope when targeting es2015+
|
||||
if (useOuterVariableScopeInParameter(result, location, lastLocation)) {
|
||||
useResult = false;
|
||||
}
|
||||
else if (result.flags & SymbolFlags.FunctionScopedVariable) {
|
||||
// parameters are visible only inside function body, parameter list and return type
|
||||
// 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (location.kind === SyntaxKind.ConditionalType) {
|
||||
// A type parameter declared using 'infer T' in a conditional type is visible only in
|
||||
// the true branch of the conditional type.
|
||||
useResult = lastLocation === location.trueType;
|
||||
}
|
||||
|
||||
if (useResult) {
|
||||
break loop;
|
||||
}
|
||||
else {
|
||||
result = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation);
|
||||
switch (location.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
if (!isExternalOrCommonJsModule(location as SourceFile)) break;
|
||||
// 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))) {
|
||||
// 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)) {
|
||||
const localSymbol = getLocalSymbolForExportDefault(result);
|
||||
if (localSymbol && (result.flags & meaning) && localSymbol.escapedName === name) {
|
||||
break loop;
|
||||
}
|
||||
result = undefined;
|
||||
}
|
||||
|
||||
// Because of module/namespace merging, a module's exports are in scope,
|
||||
// yet we never want to treat an export specifier as putting a member in scope.
|
||||
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
|
||||
// Two things to note about this:
|
||||
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
|
||||
// on an export specifier is that it might find the export specifier itself, and try to
|
||||
// resolve it as an alias. This will cause the checker to consider the export specifier
|
||||
// a circular alias reference when it might not be.
|
||||
// 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
|
||||
// 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))
|
||||
) {
|
||||
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)) {
|
||||
result = undefined;
|
||||
}
|
||||
else {
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
error(
|
||||
originalLocation,
|
||||
Diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead,
|
||||
unescapeLeadingUnderscores(name),
|
||||
isolatedModulesLikeFlagName,
|
||||
`${unescapeLeadingUnderscores(getSymbolOfDeclaration(location as EnumDeclaration).escapedName)}.${unescapeLeadingUnderscores(name)}`,
|
||||
);
|
||||
}
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// TypeScript 1.0 spec (April 2014): 8.4.1
|
||||
// Initializer expressions for instance member variables are evaluated in the scope
|
||||
// of the class constructor body but are not permitted to reference parameters or
|
||||
// local variables of the constructor. This effectively means that entities from outer scopes
|
||||
// by the same name as a constructor parameter or local variable are inaccessible
|
||||
// in initializer expressions for instance member variables.
|
||||
if (!isStatic(location)) {
|
||||
const ctor = findConstructorDeclaration(location.parent as ClassLikeDeclaration);
|
||||
if (ctor && ctor.locals) {
|
||||
if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) {
|
||||
// Remember the property node, it will be used later to report appropriate error
|
||||
Debug.assertNode(location, isPropertyDeclaration);
|
||||
propertyWithInvalidInitializer = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
// 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 (!isTypeParameterSymbolDeclaredInContainer(result, location)) {
|
||||
// ignore type parameters not declared in this container
|
||||
result = undefined;
|
||||
break;
|
||||
}
|
||||
if (lastLocation && isStatic(lastLocation)) {
|
||||
// TypeScript 1.0 spec (April 2014): 3.4.1
|
||||
// The scope of a type parameter extends over the entire declaration with which the type
|
||||
// parameter list is associated, with the exception of static member declarations in classes.
|
||||
if (nameNotFoundMessage) {
|
||||
error(originalLocation, Diagnostics.Static_members_cannot_reference_class_type_parameters);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
break loop;
|
||||
}
|
||||
if (isClassExpression(location) && meaning & SymbolFlags.Class) {
|
||||
const className = location.name;
|
||||
if (className && name === className.escapedText) {
|
||||
result = location.symbol;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
const container = location.parent.parent;
|
||||
if (isClassLike(container) && (result = lookup(getSymbolOfDeclaration(container).members!, name, meaning & SymbolFlags.Type))) {
|
||||
if (nameNotFoundMessage) {
|
||||
error(originalLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// It is not legal to reference a class's own type parameters from a computed property name that
|
||||
// belongs to the class. For example:
|
||||
//
|
||||
// function foo<T>() { return '' }
|
||||
// class C<T> { // <-- Class's own type parameter T
|
||||
// [foo<T>()]() { } // <-- Reference to T from class's own computed property
|
||||
// }
|
||||
//
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
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 (nameNotFoundMessage) {
|
||||
error(originalLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ArrowFunction:
|
||||
// when targeting ES6 or higher there is no 'arguments' in an arrow function
|
||||
// for lower compile targets the resolved symbol is used to emit an error
|
||||
if (getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (meaning & SymbolFlags.Variable && name === "arguments") {
|
||||
result = argumentsSymbol;
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.FunctionExpression:
|
||||
if (meaning & SymbolFlags.Variable && name === "arguments") {
|
||||
result = argumentsSymbol;
|
||||
break loop;
|
||||
}
|
||||
|
||||
if (meaning & SymbolFlags.Function) {
|
||||
const functionName = (location as FunctionExpression).name;
|
||||
if (functionName && name === functionName.escapedText) {
|
||||
result = (location as FunctionExpression).symbol;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.Decorator:
|
||||
// Decorators are resolved at the class declaration. Resolving at the parameter
|
||||
// or member would result in looking up locals in the method.
|
||||
//
|
||||
// function y() {}
|
||||
// class C {
|
||||
// method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
|
||||
// }
|
||||
//
|
||||
if (location.parent && location.parent.kind === SyntaxKind.Parameter) {
|
||||
location = location.parent;
|
||||
}
|
||||
//
|
||||
// function y() {}
|
||||
// class C {
|
||||
// @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method.
|
||||
// }
|
||||
//
|
||||
|
||||
// class Decorators are resolved outside of the class to avoid referencing type parameters of that class.
|
||||
//
|
||||
// type T = number;
|
||||
// declare function y(x: T): any;
|
||||
// @param(1 as T) // <-- T should resolve to the type alias outside of class C
|
||||
// class C<T> {}
|
||||
if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) {
|
||||
location = location.parent;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
case SyntaxKind.JSDocEnumTag:
|
||||
case SyntaxKind.JSDocImportTag:
|
||||
// js type aliases do not resolve names from their host, so skip past it
|
||||
const root = getJSDocRoot(location);
|
||||
if (root) {
|
||||
location = root.parent;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.Parameter:
|
||||
if (
|
||||
lastLocation && (
|
||||
lastLocation === (location as ParameterDeclaration).initializer ||
|
||||
lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation)
|
||||
)
|
||||
) {
|
||||
if (!associatedDeclarationForContainingInitializerOrBindingName) {
|
||||
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) {
|
||||
associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.InferType:
|
||||
if (meaning & SymbolFlags.TypeParameter) {
|
||||
const parameterName = (location as InferTypeNode).typeParameter.name;
|
||||
if (parameterName && name === parameterName.escapedText) {
|
||||
result = (location as InferTypeNode).typeParameter.symbol;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
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
|
||||
) {
|
||||
location = location.parent.parent.parent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isSelfReferenceLocation(location)) {
|
||||
lastSelfReferenceLocation = location;
|
||||
}
|
||||
lastLocation = location;
|
||||
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`.
|
||||
// If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself.
|
||||
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
|
||||
if (isUse && result && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) {
|
||||
result.isReferenced! |= meaning;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
if (lastLocation) {
|
||||
Debug.assertNode(lastLocation, isSourceFile);
|
||||
if (lastLocation.commonJsModuleIndicator && name === "exports" && meaning & lastLocation.symbol.flags) {
|
||||
return lastLocation.symbol;
|
||||
}
|
||||
}
|
||||
|
||||
if (!excludeGlobals) {
|
||||
result = lookup(globals, name, meaning);
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
if (originalLocation && isInJSFile(originalLocation) && originalLocation.parent) {
|
||||
if (isRequireCall(originalLocation.parent, /*requireStringLiteralLikeArgument*/ false)) {
|
||||
return requireSymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nameNotFoundMessage) {
|
||||
if (propertyWithInvalidInitializer && onPropertyWithInvalidInitializer(originalLocation, name, propertyWithInvalidInitializer, result)) {
|
||||
return undefined;
|
||||
}
|
||||
if (!result) {
|
||||
onFailedToResolveSymbol(originalLocation, nameArg, meaning, nameNotFoundMessage);
|
||||
}
|
||||
else {
|
||||
onSuccessfullyResolvedSymbol(originalLocation, result, meaning, lastLocation, associatedDeclarationForContainingInitializerOrBindingName, withinDeferredContext);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) {
|
||||
const target = getEmitScriptTarget(compilerOptions);
|
||||
const functionLocation = location as FunctionLikeDeclaration;
|
||||
if (
|
||||
isParameter(lastLocation)
|
||||
&& functionLocation.body
|
||||
&& result.valueDeclaration
|
||||
&& result.valueDeclaration.pos >= functionLocation.body.pos
|
||||
&& 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
|
||||
// - nullish coalesce pre-es2020
|
||||
// - spread assignment in binding pattern pre-es2017
|
||||
if (target >= ScriptTarget.ES2015) {
|
||||
let declarationRequiresScopeChange = getRequiresScopeChangeCache(functionLocation);
|
||||
if (declarationRequiresScopeChange === undefined) {
|
||||
declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false;
|
||||
setRequiresScopeChangeCache(functionLocation, declarationRequiresScopeChange);
|
||||
}
|
||||
return !declarationRequiresScopeChange;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
function requiresScopeChange(node: ParameterDeclaration): boolean {
|
||||
return requiresScopeChangeWorker(node.name)
|
||||
|| !!node.initializer && requiresScopeChangeWorker(node.initializer);
|
||||
}
|
||||
|
||||
function requiresScopeChangeWorker(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Constructor:
|
||||
// do not descend into these
|
||||
return false;
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name);
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// static properties in classes introduce temporary variables
|
||||
if (hasStaticModifier(node)) {
|
||||
return !emitStandardClassFields;
|
||||
}
|
||||
return requiresScopeChangeWorker((node as PropertyDeclaration).name);
|
||||
default:
|
||||
// null coalesce and optional chain pre-es2020 produce temporary variables
|
||||
if (isNullishCoalesce(node) || isOptionalChain(node)) {
|
||||
return target < ScriptTarget.ES2020;
|
||||
}
|
||||
if (isBindingElement(node) && node.dotDotDotToken && isObjectBindingPattern(node.parent)) {
|
||||
return target < ScriptTarget.ES2017;
|
||||
}
|
||||
if (isTypeNode(node)) return false;
|
||||
return forEachChild(node, requiresScopeChangeWorker) || false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
) && (!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)) {
|
||||
return true;
|
||||
}
|
||||
return !getImmediatelyInvokedFunctionExpression(location);
|
||||
}
|
||||
|
||||
type SelfReferenceLocation =
|
||||
| FunctionDeclaration
|
||||
| ClassDeclaration
|
||||
| InterfaceDeclaration
|
||||
| EnumDeclaration
|
||||
| TypeAliasDeclaration
|
||||
| ModuleDeclaration;
|
||||
|
||||
function isSelfReferenceLocation(node: Node): node is SelfReferenceLocation {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration: // For `namespace N { N; }`
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
|
||||
if (symbol.declarations) {
|
||||
for (const decl of symbol.declarations) {
|
||||
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 false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +311,8 @@ export function getDefaultLibFileName(options: CompilerOptions): string {
|
||||
switch (getEmitScriptTarget(options)) {
|
||||
case ScriptTarget.ESNext:
|
||||
return "lib.esnext.full.d.ts";
|
||||
case ScriptTarget.ES2023:
|
||||
return "lib.es2023.full.d.ts";
|
||||
case ScriptTarget.ES2022:
|
||||
return "lib.es2022.full.d.ts";
|
||||
case ScriptTarget.ES2021:
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
FileWatcher,
|
||||
filter,
|
||||
find,
|
||||
findIndex,
|
||||
flattenDiagnosticMessageText,
|
||||
forEach,
|
||||
forEachEntry,
|
||||
@@ -56,6 +57,7 @@ import {
|
||||
getDefaultLibFileName,
|
||||
getDirectoryPath,
|
||||
getEmitScriptTarget,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getLineAndCharacterOfPosition,
|
||||
getNewLineCharacter,
|
||||
getNormalizedAbsolutePath,
|
||||
@@ -352,13 +354,14 @@ export function explainFiles(program: Program, write: (s: string) => void) {
|
||||
for (const file of program.getSourceFiles()) {
|
||||
write(`${toFileName(file, relativeFileName)}`);
|
||||
reasons.get(file.path)?.forEach(reason => write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`));
|
||||
explainIfFileIsRedirectAndImpliedFormat(file, relativeFileName)?.forEach(d => write(` ${d.messageText}`));
|
||||
explainIfFileIsRedirectAndImpliedFormat(file, program.getCompilerOptionsForFile(file), relativeFileName)?.forEach(d => write(` ${d.messageText}`));
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function explainIfFileIsRedirectAndImpliedFormat(
|
||||
file: SourceFile,
|
||||
options: CompilerOptions,
|
||||
fileNameConvertor?: (fileName: string) => string,
|
||||
): DiagnosticMessageChain[] | undefined {
|
||||
let result: DiagnosticMessageChain[] | undefined;
|
||||
@@ -377,7 +380,7 @@ export function explainIfFileIsRedirectAndImpliedFormat(
|
||||
));
|
||||
}
|
||||
if (isExternalOrCommonJsModule(file)) {
|
||||
switch (file.impliedNodeFormat) {
|
||||
switch (getImpliedNodeFormatForEmitWorker(file, options)) {
|
||||
case ModuleKind.ESNext:
|
||||
if (file.packageJsonScope) {
|
||||
(result ??= []).push(chainDiagnosticMessages(
|
||||
@@ -416,7 +419,8 @@ 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);
|
||||
const index = findIndex(configFile.configFileSpecs.validatedFilesSpec, fileSpec => program.getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath);
|
||||
return index !== -1 ? configFile.configFileSpecs.validatedFilesSpecBeforeSubstitution![index] : undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -430,11 +434,12 @@ export function getMatchedIncludeSpec(program: Program, fileName: string) {
|
||||
const isJsonFile = fileExtensionIs(fileName, Extension.Json);
|
||||
const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory()));
|
||||
const useCaseSensitiveFileNames = program.useCaseSensitiveFileNames();
|
||||
return find(configFile?.configFileSpecs?.validatedIncludeSpecs, includeSpec => {
|
||||
const index = findIndex(configFile?.configFileSpecs?.validatedIncludeSpecs, includeSpec => {
|
||||
if (isJsonFile && !endsWith(includeSpec, Extension.Json)) return false;
|
||||
const pattern = getPatternFromSpec(includeSpec, basePath, "files");
|
||||
return !!pattern && getRegexFromPattern(`(${pattern})$`, useCaseSensitiveFileNames).test(fileName);
|
||||
});
|
||||
return index !== -1 ? configFile.configFileSpecs.validatedIncludeSpecsBeforeSubstitution![index] : undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
+35
-15
@@ -786,21 +786,27 @@ export namespace Compiler {
|
||||
const postPerformanceValues = getPerformanceBaselineValues();
|
||||
|
||||
if (!isSymbolBaseline) {
|
||||
const perfStats: [name: string, reportThreshold: number, rounding: number, beforeValue: number, afterValue: number][] = [];
|
||||
perfStats.push(["Strict subtype cache", 1000, 100, prePerformanceValues.strictSubtype, postPerformanceValues.strictSubtype]);
|
||||
perfStats.push(["Subtype cache", 1000, 100, prePerformanceValues.subtype, postPerformanceValues.subtype]);
|
||||
perfStats.push(["Identity cache", 1000, 100, prePerformanceValues.identity, postPerformanceValues.identity]);
|
||||
perfStats.push(["Assignability cache", 1000, 100, prePerformanceValues.assignability, postPerformanceValues.assignability]);
|
||||
perfStats.push(["Type Count", 1000, 100, prePerformanceValues.typeCount, postPerformanceValues.typeCount]);
|
||||
perfStats.push(["Instantiation count", 1500, 500, prePerformanceValues.instantiation, postPerformanceValues.instantiation]);
|
||||
perfStats.push(["Symbol count", 45000, 500, prePerformanceValues.symbol, postPerformanceValues.symbol]);
|
||||
const perfStats: [name: string, reportThreshold: number, beforeValue: number, afterValue: number][] = [];
|
||||
perfStats.push(["Strict subtype cache", 1000, prePerformanceValues.strictSubtype, postPerformanceValues.strictSubtype]);
|
||||
perfStats.push(["Subtype cache", 1000, prePerformanceValues.subtype, postPerformanceValues.subtype]);
|
||||
perfStats.push(["Identity cache", 1000, prePerformanceValues.identity, postPerformanceValues.identity]);
|
||||
perfStats.push(["Assignability cache", 1000, prePerformanceValues.assignability, postPerformanceValues.assignability]);
|
||||
perfStats.push(["Type Count", 1000, prePerformanceValues.typeCount, postPerformanceValues.typeCount]);
|
||||
perfStats.push(["Instantiation count", 1500, prePerformanceValues.instantiation, postPerformanceValues.instantiation]);
|
||||
perfStats.push(["Symbol count", 45000, prePerformanceValues.symbol, postPerformanceValues.symbol]);
|
||||
|
||||
if (perfStats.some(([, threshold, , , postValue]) => postValue >= threshold)) {
|
||||
if (perfStats.some(([, threshold, , postValue]) => postValue >= threshold)) {
|
||||
perfLines.push(`=== Performance Stats ===`);
|
||||
for (const [name, _, rounding, preValue, postValue] of perfStats) {
|
||||
const preDisplay = valueToString(preValue, rounding);
|
||||
if (preDisplay !== "0") {
|
||||
perfLines.push(`${name}: ${preDisplay} / ${valueToString(postValue, rounding)} (nearest ${rounding})`);
|
||||
for (const [name, threshold, preValue, postValue] of perfStats) {
|
||||
if (postValue >= threshold) {
|
||||
const preString = valueToString(preValue);
|
||||
const postString = valueToString(postValue);
|
||||
if (preString === postString) {
|
||||
perfLines.push(`${name}: ${preString}`);
|
||||
}
|
||||
else {
|
||||
perfLines.push(`${name}: ${preString} -> ${postString}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
perfLines.push("");
|
||||
@@ -809,10 +815,24 @@ export namespace Compiler {
|
||||
}
|
||||
|
||||
return result ? (`//// [${header}] ////\r\n\r\n${perfLines.join("\n")}${result}`) : null; // eslint-disable-line no-null/no-null
|
||||
|
||||
function valueToString(value: number) {
|
||||
return roundToHumanLogarithm(value).toLocaleString("en-US");
|
||||
}
|
||||
}
|
||||
|
||||
function valueToString(value: number, rounding: number) {
|
||||
return (Math.round(value / rounding) * rounding).toLocaleString("en-US");
|
||||
/**
|
||||
* Rounds to a number like 10, 25, 50, 100, 250, 500, 1000, etc
|
||||
*/
|
||||
function roundToHumanLogarithm(n: number) {
|
||||
if (n < 10) return 0;
|
||||
const powerOfTen = Math.floor(Math.log10(n));
|
||||
const basePowerOfTen = Math.pow(10, powerOfTen);
|
||||
const multipliers = [1, 2.5, 5, 10];
|
||||
const closestMultiplier = multipliers.reduce((prev, curr) => {
|
||||
return Math.abs(curr * basePowerOfTen - n) < Math.abs(prev * basePowerOfTen - n) ? curr : prev;
|
||||
});
|
||||
return closestMultiplier * basePowerOfTen;
|
||||
}
|
||||
|
||||
function getPerformanceBaselineValues() {
|
||||
|
||||
@@ -271,6 +271,8 @@ export function verifyResolutionCache(
|
||||
verifyResolutionSet(expected.resolutionsWithOnlyAffectingLocations, actual.resolutionsWithOnlyAffectingLocations, `resolutionsWithOnlyAffectingLocations`);
|
||||
verifyDirectoryWatchesOfFailedLookups(expected.directoryWatchesOfFailedLookups, actual.directoryWatchesOfFailedLookups);
|
||||
verifyFileWatchesOfAffectingLocations(expected.fileWatchesOfAffectingLocations, actual.fileWatchesOfAffectingLocations);
|
||||
verifyPackageDirWatchers(expected.packageDirWatchers, actual.packageDirWatchers);
|
||||
verifyDirPathToSymlinkPackageRefCount(expected.dirPathToSymlinkPackageRefCount, actual.dirPathToSymlinkPackageRefCount);
|
||||
|
||||
// Stop watching resolutions to verify everything gets closed.
|
||||
expected.startCachingPerDirectoryResolution();
|
||||
@@ -368,11 +370,17 @@ export function verifyResolutionCache(
|
||||
}
|
||||
|
||||
function verifyDirectoryWatchesOfFailedLookups(expected: Map<string, ts.DirectoryWatchesOfFailedLookup>, actual: Map<string, ts.DirectoryWatchesOfFailedLookup>) {
|
||||
verifyMap(expected, actual, (expected, actual, caption) => {
|
||||
ts.Debug.assert(expected?.refCount === actual?.refCount, `${projectName}:: ${caption}:: refCount`);
|
||||
ts.Debug.assert(!!expected?.refCount, `${projectName}:: ${caption}:: expected refCount to be non zero`);
|
||||
ts.Debug.assert(expected?.nonRecursive === actual?.nonRecursive, `${projectName}:: ${caption}:: nonRecursive`);
|
||||
}, "directoryWatchesOfFailedLookups");
|
||||
verifyMap(expected, actual, verifyDirectoryWatchesOfFailedLookup, "directoryWatchesOfFailedLookups");
|
||||
}
|
||||
|
||||
function verifyDirectoryWatchesOfFailedLookup(
|
||||
expected: ts.DirectoryWatchesOfFailedLookup | undefined,
|
||||
actual: ts.DirectoryWatchesOfFailedLookup | undefined,
|
||||
caption: string,
|
||||
) {
|
||||
ts.Debug.assert(expected?.refCount === actual?.refCount, `${projectName}:: ${caption}:: refCount`);
|
||||
ts.Debug.assert(!!expected?.refCount, `${projectName}:: ${caption}:: expected refCount to be non zero`);
|
||||
ts.Debug.assert(expected?.nonRecursive === actual?.nonRecursive, `${projectName}:: ${caption}:: nonRecursive`);
|
||||
}
|
||||
|
||||
function verifyFileWatchesOfAffectingLocations(
|
||||
@@ -391,6 +399,40 @@ export function verifyResolutionCache(
|
||||
ts.Debug.assert(expected?.files === actual?.files, `${projectName}:: ${caption}:: files`);
|
||||
verifySet(expected?.symlinks, actual?.symlinks, `${projectName}:: ${caption}:: symlinks`);
|
||||
}
|
||||
|
||||
function verifyPackageDirWatchers(
|
||||
expected: Map<ts.Path, ts.PackageDirWatcher>,
|
||||
actual: Map<ts.Path, ts.PackageDirWatcher>,
|
||||
) {
|
||||
verifyMap(expected, actual, verifyPackageDirWatcher, "packageDirWatchers");
|
||||
}
|
||||
|
||||
function verifyPackageDirWatcher(
|
||||
expected: ts.PackageDirWatcher | undefined,
|
||||
actual: ts.PackageDirWatcher | undefined,
|
||||
caption: string,
|
||||
) {
|
||||
ts.Debug.assert(expected?.isSymlink === actual?.isSymlink, `${projectName}:: ${caption}:: isSymlink`);
|
||||
verifyMap(expected?.dirPathToWatcher, actual?.dirPathToWatcher, verfiyDirPathToWatcherOfPackageDirWatcher, `${projectName}:: ${caption}:: dirPathToWatcher`);
|
||||
}
|
||||
|
||||
function verfiyDirPathToWatcherOfPackageDirWatcher(
|
||||
expected: ts.DirPathToWatcherOfPackageDirWatcher | undefined,
|
||||
actual: ts.DirPathToWatcherOfPackageDirWatcher | undefined,
|
||||
caption: string,
|
||||
) {
|
||||
ts.Debug.assert(expected?.refCount === actual?.refCount, `${projectName}:: ${caption}:: refCount`);
|
||||
verifyDirectoryWatchesOfFailedLookup(expected?.watcher, actual?.watcher, `${projectName}:: ${caption}:: directoryWatchesOfFailedLookup`);
|
||||
}
|
||||
|
||||
function verifyDirPathToSymlinkPackageRefCount(
|
||||
expected: Map<ts.Path, number>,
|
||||
actual: Map<ts.Path, number>,
|
||||
) {
|
||||
verifyMap(expected, actual, (expected, actual, caption) => {
|
||||
ts.Debug.assert(expected === actual, `${projectName}:: ${caption}`);
|
||||
}, "dirPathToSymlinkPackageRefCount");
|
||||
}
|
||||
}
|
||||
|
||||
function verifyMap<Key extends string, Expected, Actual>(
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import {
|
||||
AutoImportProviderProject,
|
||||
AuxiliaryProject,
|
||||
ConfiguredProject,
|
||||
isBackgroundProject,
|
||||
isConfiguredProject,
|
||||
LogLevel,
|
||||
@@ -32,6 +33,7 @@ interface ProjectData {
|
||||
isClosed: ReturnType<Project["isClosed"]>;
|
||||
isOrphan: ReturnType<Project["isOrphan"]>;
|
||||
noOpenRef: boolean;
|
||||
deferredClose: ConfiguredProject["deferredClose"];
|
||||
documentPositionMappers: SourceMapper["documentPositionMappers"];
|
||||
autoImportProviderHost: Project["autoImportProviderHost"];
|
||||
noDtsResolutionProject: Project["noDtsResolutionProject"];
|
||||
@@ -46,6 +48,7 @@ interface ScriptInfoData {
|
||||
open: ReturnType<ScriptInfo["isScriptOpen"]>;
|
||||
version: ReturnType<TextStorage["getVersion"]>;
|
||||
pendingReloadFromDisk: TextStorage["pendingReloadFromDisk"];
|
||||
deferredDelete: ScriptInfo["deferredDelete"];
|
||||
sourceMapFilePath: Exclude<ScriptInfo["sourceMapFilePath"], SourceMapFileWatcher> | SourceMapFileWatcherData | undefined;
|
||||
declarationInfoPath: ScriptInfo["declarationInfoPath"];
|
||||
sourceInfos: ScriptInfo["sourceInfos"];
|
||||
@@ -101,6 +104,8 @@ export function patchServiceForStateBaseline(service: ProjectService) {
|
||||
function baselineProjects(currentMappers: Set<DocumentPositionMapper>) {
|
||||
const autoImportProviderProjects = [] as AutoImportProviderProject[];
|
||||
const auxiliaryProjects = [] as AuxiliaryProject[];
|
||||
const orphanConfiguredProjects = service.getOrphanConfiguredProjects(/*toRetainConfiguredProjects*/ undefined);
|
||||
const noOpenRef = (project: Project) => isConfiguredProject(project) && (project.isClosed() || orphanConfiguredProjects.has(project));
|
||||
return baselineState(
|
||||
[service.externalProjects, service.configuredProjects, service.inferredProjects, autoImportProviderProjects, auxiliaryProjects],
|
||||
projects,
|
||||
@@ -115,7 +120,8 @@ export function patchServiceForStateBaseline(service: ProjectService) {
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "dirty", project.dirty, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isClosed", project.isClosed(), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isOrphan", !isBackgroundProject(project) && project.isOrphan(), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "noOpenRef", isConfiguredProject(project) && !project.hasOpenRef(), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "noOpenRef", noOpenRef(project), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "deferredClose", isConfiguredProject(project) && project.deferredClose, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printMapPropertyValue(
|
||||
PrintPropertyWhen.Changed,
|
||||
data?.documentPositionMappers,
|
||||
@@ -145,7 +151,8 @@ export function patchServiceForStateBaseline(service: ProjectService) {
|
||||
dirty: project.dirty,
|
||||
isClosed: project.isClosed(),
|
||||
isOrphan: !isBackgroundProject(project) && project.isOrphan(),
|
||||
noOpenRef: isConfiguredProject(project) && !project.hasOpenRef(),
|
||||
noOpenRef: noOpenRef(project),
|
||||
deferredClose: isConfiguredProject(project) && project.deferredClose,
|
||||
autoImportProviderHost: project.autoImportProviderHost,
|
||||
noDtsResolutionProject: project.noDtsResolutionProject,
|
||||
originalConfiguredProjects: project.originalConfiguredProjects && new Set(project.originalConfiguredProjects),
|
||||
@@ -166,6 +173,7 @@ export function patchServiceForStateBaseline(service: ProjectService) {
|
||||
infoDiff = printProperty(PrintPropertyWhen.Changed, data, "open", isOpen, infoDiff, infoPropertyLogs);
|
||||
infoDiff = printProperty(PrintPropertyWhen.Always, data, "version", info.textStorage.getVersion(), infoDiff, infoPropertyLogs);
|
||||
infoDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "pendingReloadFromDisk", info.textStorage.pendingReloadFromDisk, infoDiff, infoPropertyLogs);
|
||||
infoDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "deferredDelete", info.deferredDelete, infoDiff, infoPropertyLogs);
|
||||
infoDiff = printScriptInfoSourceMapFilePath(data, info, infoDiff, infoPropertyLogs);
|
||||
infoDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "declarationInfoPath", info.declarationInfoPath, infoDiff, infoPropertyLogs);
|
||||
infoDiff = printSetPropertyValueWorker(PrintPropertyWhen.DefinedOrChangedOrNew, data?.sourceInfos, "sourceInfos", info.sourceInfos, infoDiff, infoPropertyLogs, identity);
|
||||
@@ -200,6 +208,7 @@ export function patchServiceForStateBaseline(service: ProjectService) {
|
||||
sourceInfos: info.sourceInfos && new Set(info.sourceInfos),
|
||||
documentPositionMapper: info.documentPositionMapper,
|
||||
containingProjects: new Set(info.containingProjects),
|
||||
deferredDelete: info.deferredDelete,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,11 +44,15 @@ function* forEachASTNode(node: ts.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
function nodeIsFullySynthetic(node: ts.Node) {
|
||||
return ts.nodeIsSynthesized(node) && !ts.getParseTreeNode(node);
|
||||
}
|
||||
|
||||
const createSyntheticNodeUnderliningPrinter = memoize((): { printer: ts.Printer; writer: ts.EmitTextWriter; underliner: ts.EmitTextWriter; reset(): void; } => {
|
||||
let underlining = false;
|
||||
const printer = createPrinter({ removeComments: true }, {
|
||||
onEmitNode: (hint, node, cb) => {
|
||||
if (ts.nodeIsSynthesized(node) !== underlining) {
|
||||
if (nodeIsFullySynthetic(node) !== underlining) {
|
||||
// either node is synthetic and underlining needs to be enabled, or node is not synthetic and
|
||||
// underlining needs to be disabled
|
||||
underlining = !underlining;
|
||||
|
||||
Vendored
+6
-2
@@ -27,8 +27,12 @@ declare namespace Intl {
|
||||
source: "startRange" | "endRange" | "shared";
|
||||
}
|
||||
|
||||
type StringNumericLiteral = `${number}` | "Infinity" | "-Infinity" | "+Infinity";
|
||||
|
||||
interface NumberFormat {
|
||||
formatRange(start: number | bigint, end: number | bigint): string;
|
||||
formatRangeToParts(start: number | bigint, end: number | bigint): NumberRangeFormatPart[];
|
||||
format(value: number | bigint | StringNumericLiteral): string;
|
||||
formatToParts(value: number | bigint | StringNumericLiteral): NumberFormatPart[];
|
||||
formatRange(start: number | bigint | StringNumericLiteral, end: number | bigint | StringNumericLiteral): string;
|
||||
formatRangeToParts(start: number | bigint | StringNumericLiteral, end: number | bigint | StringNumericLiteral): NumberRangeFormatPart[];
|
||||
}
|
||||
}
|
||||
|
||||
+351
-199
File diff suppressed because it is too large
Load Diff
+51
-3
@@ -657,7 +657,12 @@ 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,
|
||||
/*deferredDeleteOk*/ false,
|
||||
);
|
||||
if (scriptInfo) {
|
||||
const existingValue = this.rootFilesMap.get(scriptInfo.path);
|
||||
if (existingValue && existingValue.info !== scriptInfo) {
|
||||
@@ -678,7 +683,12 @@ 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,
|
||||
/*deferredDeleteOk*/ false,
|
||||
);
|
||||
return (info && info.getLatestVersion())!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
@@ -1298,6 +1308,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
markAsDirty() {
|
||||
if (!this.dirty) {
|
||||
this.projectStateVersion++;
|
||||
@@ -1658,7 +1669,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
// 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,
|
||||
/*deferredDeleteOk*/ false,
|
||||
);
|
||||
scriptInfo?.attachToProject(this);
|
||||
},
|
||||
removed => this.detachScriptInfoFromProject(removed),
|
||||
@@ -2584,6 +2600,7 @@ export class AutoImportProviderProject extends Project {
|
||||
return !some(this.rootFileNames);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
override isOrphan() {
|
||||
return true;
|
||||
}
|
||||
@@ -2619,6 +2636,7 @@ export class AutoImportProviderProject extends Project {
|
||||
return !!this.rootFileNames?.length;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
override markAsDirty() {
|
||||
this.rootFileNames = undefined;
|
||||
super.markAsDirty();
|
||||
@@ -2707,6 +2725,15 @@ export class ConfiguredProject extends Project {
|
||||
/** @internal */
|
||||
private compilerHost?: CompilerHost;
|
||||
|
||||
/** @internal */
|
||||
hasConfigFileDiagnostics?: boolean;
|
||||
|
||||
/** @internal */
|
||||
skipConfigDiagEvent?: true;
|
||||
|
||||
/** @internal */
|
||||
deferredClose?: boolean;
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
configFileName: NormalizedPath,
|
||||
@@ -2767,6 +2794,7 @@ export class ConfiguredProject extends Project {
|
||||
* @returns: true if set of files in the project stays the same and false - otherwise.
|
||||
*/
|
||||
override updateGraph(): boolean {
|
||||
if (this.deferredClose) return false;
|
||||
const isInitialLoad = this.isInitialLoadPending();
|
||||
this.isInitialLoadPending = returnFalse;
|
||||
const updateLevel = this.pendingUpdateLevel;
|
||||
@@ -2790,6 +2818,9 @@ export class ConfiguredProject extends Project {
|
||||
this.compilerHost = undefined;
|
||||
this.projectService.sendProjectLoadingFinishEvent(this);
|
||||
this.projectService.sendProjectTelemetry(this);
|
||||
if (!this.skipConfigDiagEvent && !result) { // If new program, send event if diagnostics presence has changed
|
||||
this.projectService.sendConfigFileDiagEvent(this, /*triggerFile*/ undefined);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2883,6 +2914,12 @@ export class ConfiguredProject extends Project {
|
||||
super.close();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
override markAsDirty() {
|
||||
if (this.deferredClose) return;
|
||||
super.markAsDirty();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
addExternalProjectReference() {
|
||||
this.externalProjectRefCount++;
|
||||
@@ -2932,6 +2969,7 @@ export class ConfiguredProject extends Project {
|
||||
}
|
||||
|
||||
const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(this.canonicalConfigFilePath)!;
|
||||
if (this.deferredClose) return !!configFileExistenceInfo.openFilesImpactedByConfigFile?.size;
|
||||
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
|
||||
@@ -2957,6 +2995,11 @@ export class ConfiguredProject extends Project {
|
||||
) || false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
override isOrphan(): boolean {
|
||||
return !!this.deferredClose;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
hasExternalProjectRef() {
|
||||
return !!this.externalProjectRefCount;
|
||||
@@ -3014,3 +3057,8 @@ export function isExternalProject(project: Project): project is ExternalProject
|
||||
export function isBackgroundProject(project: Project): project is AutoImportProviderProject | AuxiliaryProject {
|
||||
return project.projectKind === ProjectKind.AutoImportProvider || project.projectKind === ProjectKind.Auxiliary;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isProjectDeferredClose(project: Project): project is ConfiguredProject {
|
||||
return isConfiguredProject(project) && !!project.deferredClose;
|
||||
}
|
||||
|
||||
@@ -3142,6 +3142,7 @@ export const enum ScriptTarget {
|
||||
ES2020 = "es2020",
|
||||
ES2021 = "es2021",
|
||||
ES2022 = "es2022",
|
||||
ES2023 = "es2023",
|
||||
ESNext = "esnext",
|
||||
JSON = "json",
|
||||
Latest = ESNext,
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
IScriptSnapshot,
|
||||
isString,
|
||||
LineInfo,
|
||||
missingFileModifiedTime,
|
||||
orderedRemoveItem,
|
||||
Path,
|
||||
ScriptKind,
|
||||
@@ -44,6 +45,7 @@ import {
|
||||
isConfiguredProject,
|
||||
isExternalProject,
|
||||
isInferredProject,
|
||||
isProjectDeferredClose,
|
||||
maxFileSize,
|
||||
NormalizedPath,
|
||||
Project,
|
||||
@@ -180,6 +182,14 @@ export class TextStorage {
|
||||
const reloaded = this.reload(newText);
|
||||
this.fileSize = fileSize; // NB: after reload since reload clears it
|
||||
this.ownFileText = !tempFileName || tempFileName === this.info.fileName;
|
||||
// In case we update this text before mTime gets updated to present file modified time
|
||||
// because its schedule to do that later, update the mTime so we dont re-update the text
|
||||
// Eg. with npm ci where file gets created and editor calls say get error request before
|
||||
// the timeout to update the file stamps in node_modules is run
|
||||
// Test:: watching npm install in codespaces where workspaces folder is hosted at root
|
||||
if (this.ownFileText && this.info.mTime === missingFileModifiedTime.getTime()) {
|
||||
this.info.mTime = (this.host.getModifiedTime!(this.info.fileName) || missingFileModifiedTime).getTime();
|
||||
}
|
||||
return reloaded;
|
||||
}
|
||||
|
||||
@@ -398,6 +408,9 @@ export class ScriptInfo {
|
||||
/** @internal */
|
||||
documentPositionMapper?: DocumentPositionMapper | false;
|
||||
|
||||
/** @internal */
|
||||
deferredDelete?: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly host: ServerHost,
|
||||
readonly fileName: NormalizedPath,
|
||||
@@ -567,7 +580,10 @@ export class ScriptInfo {
|
||||
case 0:
|
||||
return Errors.ThrowNoProject();
|
||||
case 1:
|
||||
return ensurePrimaryProjectKind(this.containingProjects[0]);
|
||||
return ensurePrimaryProjectKind(
|
||||
!isProjectDeferredClose(this.containingProjects[0]) ?
|
||||
this.containingProjects[0] : undefined,
|
||||
);
|
||||
default:
|
||||
// If this file belongs to multiple projects, below is the order in which default project is used
|
||||
// - for open script info, its default configured project during opening is default if info is part of it
|
||||
@@ -583,6 +599,7 @@ export class ScriptInfo {
|
||||
for (let index = 0; index < this.containingProjects.length; index++) {
|
||||
const project = this.containingProjects[index];
|
||||
if (isConfiguredProject(project)) {
|
||||
if (project.deferredClose) continue;
|
||||
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
|
||||
@@ -676,7 +693,7 @@ export class ScriptInfo {
|
||||
}
|
||||
|
||||
isOrphan() {
|
||||
return !forEach(this.containingProjects, p => !p.isOrphan());
|
||||
return this.deferredDelete || !forEach(this.containingProjects, p => !p.isOrphan());
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -591,7 +591,7 @@ export class LineNode implements LineCollection {
|
||||
if (children.length) this.updateCounts();
|
||||
}
|
||||
|
||||
isLeaf() {
|
||||
isLeaf(): this is LineLeaf {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -839,7 +839,7 @@ export class LineLeaf implements LineCollection {
|
||||
constructor(public text: string) {
|
||||
}
|
||||
|
||||
isLeaf() {
|
||||
isLeaf(): this is LineLeaf {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1575,6 +1575,7 @@ export class Session<TMessage = string> implements EventSender {
|
||||
fileNameToSearch,
|
||||
noDtsProject.currentDirectory,
|
||||
noDtsProject.directoryStructureHost,
|
||||
/*deferredDeleteOk*/ false,
|
||||
);
|
||||
if (!info) continue;
|
||||
if (!noDtsProject.containsScriptInfo(info)) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
AnyImportOrRequireStatement,
|
||||
AnyImportSyntax,
|
||||
arrayFrom,
|
||||
BindingElement,
|
||||
CancellationToken,
|
||||
cast,
|
||||
changeAnyExtension,
|
||||
@@ -15,6 +16,7 @@ import {
|
||||
compareValues,
|
||||
Comparison,
|
||||
CompilerOptions,
|
||||
createFutureSourceFile,
|
||||
createModuleSpecifierResolutionHost,
|
||||
createMultiMap,
|
||||
createPackageJsonImportFilter,
|
||||
@@ -27,50 +29,57 @@ import {
|
||||
ExportKind,
|
||||
ExportMapInfoKey,
|
||||
factory,
|
||||
findAncestor,
|
||||
first,
|
||||
firstDefined,
|
||||
flatMap,
|
||||
flatMapIterator,
|
||||
forEachExternalModuleToImportFrom,
|
||||
formatting,
|
||||
FutureSourceFile,
|
||||
FutureSymbolExportInfo,
|
||||
getAllowSyntheticDefaultImports,
|
||||
getBaseFileName,
|
||||
getDefaultExportInfoWorker,
|
||||
getDefaultLikeExportInfo,
|
||||
getDirectoryPath,
|
||||
getEmitModuleFormatOfFileWorker,
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getExportInfoMap,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getMeaningFromDeclaration,
|
||||
getMeaningFromLocation,
|
||||
getNameForExportedSymbol,
|
||||
getNodeId,
|
||||
getOutputExtension,
|
||||
getQuoteFromPreference,
|
||||
getQuotePreference,
|
||||
getSourceFileOfNode,
|
||||
getSymbolId,
|
||||
getSynthesizedDeepClone,
|
||||
getTokenAtPosition,
|
||||
getTokenPosOfNode,
|
||||
getTypeKeywordOfTypeOnlyImport,
|
||||
getUniqueSymbolId,
|
||||
hasJSFileExtension,
|
||||
hostGetCanonicalFileName,
|
||||
Identifier,
|
||||
ImportClause,
|
||||
ImportEqualsDeclaration,
|
||||
importFromModuleSpecifier,
|
||||
ImportKind,
|
||||
ImportSpecifier,
|
||||
insertImports,
|
||||
InternalSymbolName,
|
||||
isExternalModule,
|
||||
isExternalModuleReference,
|
||||
isFullSourceFile,
|
||||
isIdentifier,
|
||||
isIdentifierPart,
|
||||
isIdentifierStart,
|
||||
isImportableFile,
|
||||
isImportDeclaration,
|
||||
isImportEqualsDeclaration,
|
||||
isInJSFile,
|
||||
isIntrinsicJsxName,
|
||||
isJSDocImportTag,
|
||||
isJsxClosingElement,
|
||||
@@ -79,6 +88,7 @@ import {
|
||||
isJSXTagName,
|
||||
isNamedImports,
|
||||
isNamespaceImport,
|
||||
isRequireVariableStatement,
|
||||
isSourceFileJS,
|
||||
isStringANonContextualKeyword,
|
||||
isStringLiteral,
|
||||
@@ -101,6 +111,7 @@ import {
|
||||
MultiMap,
|
||||
Mutable,
|
||||
NamedImports,
|
||||
NamespaceImport,
|
||||
Node,
|
||||
NodeFlags,
|
||||
nodeIsMissing,
|
||||
@@ -114,6 +125,7 @@ import {
|
||||
QuotePreference,
|
||||
removeFileExtension,
|
||||
removeSuffix,
|
||||
RequireOrImportCall,
|
||||
RequireVariableStatement,
|
||||
sameMap,
|
||||
ScriptTarget,
|
||||
@@ -140,6 +152,7 @@ import {
|
||||
TypeChecker,
|
||||
TypeOnlyAliasDeclaration,
|
||||
UserPreferences,
|
||||
VariableDeclarationInitializedTo,
|
||||
} from "../_namespaces/ts";
|
||||
import {
|
||||
createCodeFixAction,
|
||||
@@ -200,6 +213,14 @@ registerCodeFix({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* The node kinds that may be the declaration of an alias symbol imported/required from an external module.
|
||||
* `ImportClause` is the declaration for a syntactic default import. `VariableDeclaration` is the declaration
|
||||
* for a non-destructured `require` call.
|
||||
* @internal
|
||||
*/
|
||||
export type ImportOrRequireAliasDeclaration = ImportEqualsDeclaration | ImportClause | ImportSpecifier | NamespaceImport | VariableDeclarationInitializedTo<RequireOrImportCall> | BindingElement;
|
||||
|
||||
/**
|
||||
* Computes multiple import additions to a file and writes them to a ChangeTracker.
|
||||
*
|
||||
@@ -208,12 +229,16 @@ registerCodeFix({
|
||||
export interface ImportAdder {
|
||||
hasFixes(): boolean;
|
||||
addImportFromDiagnostic: (diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) => void;
|
||||
addImportFromExportedSymbol: (exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean) => void;
|
||||
addImportFromExportedSymbol: (exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean, referenceImport?: ImportOrRequireAliasDeclaration) => void;
|
||||
addImportForNonExistentExport: (exportName: string, exportingFileName: string, exportKind: ExportKind, exportedMeanings: SymbolFlags, isImportUsageValidAsTypeOnly: boolean) => void;
|
||||
addImportForUnresolvedIdentifier: (context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) => void;
|
||||
addVerbatimImport: (declaration: AnyImportOrRequireStatement | ImportOrRequireAliasDeclaration) => void;
|
||||
removeExistingImport: (declaration: ImportOrRequireAliasDeclaration) => void;
|
||||
writeFixes: (changeTracker: textChanges.ChangeTracker, oldFileQuotePreference?: QuotePreference) => void;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createImportAdder(sourceFile: SourceFile, program: Program, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken?: CancellationToken): ImportAdder {
|
||||
export function createImportAdder(sourceFile: SourceFile | FutureSourceFile, program: Program, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken?: CancellationToken): ImportAdder {
|
||||
return createImportAdderWorker(sourceFile, program, /*useAutoImportProvider*/ false, preferences, host, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -223,18 +248,29 @@ interface AddToExistingState {
|
||||
readonly namedImports: Map<string, AddAsTypeOnly>;
|
||||
}
|
||||
|
||||
function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAutoImportProvider: boolean, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken: CancellationToken | undefined): ImportAdder {
|
||||
function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, 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[] = [];
|
||||
const importType: FixAddJsdocTypeImport[] = [];
|
||||
/** Keys are import clause node IDs. */
|
||||
const addToExisting = new Map<string, AddToExistingState>();
|
||||
const addToExisting = new Map<ImportClause | ObjectBindingPattern, AddToExistingState>();
|
||||
const removeExisting = new Set<ImportOrRequireAliasDeclaration>();
|
||||
const verbatimImports = new Set<AnyImportOrRequireStatement | ImportOrRequireAliasDeclaration>();
|
||||
|
||||
type NewImportsKey = `${0 | 1}|${string}`;
|
||||
/** Use `getNewImportEntry` for access */
|
||||
const newImports = new Map<NewImportsKey, Mutable<ImportsCollection & { useRequire: boolean; }>>();
|
||||
return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes };
|
||||
return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportForUnresolvedIdentifier, addImportForNonExistentExport, removeExistingImport, addVerbatimImport };
|
||||
|
||||
function addVerbatimImport(declaration: AnyImportOrRequireStatement | ImportOrRequireAliasDeclaration) {
|
||||
verbatimImports.add(declaration);
|
||||
}
|
||||
|
||||
function addImportForUnresolvedIdentifier(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) {
|
||||
const info = getFixInfosWithoutDiagnostic(context, symbolToken, useAutoImportProvider);
|
||||
if (!info || !info.length) return;
|
||||
addImport(first(info));
|
||||
}
|
||||
|
||||
function addImportFromDiagnostic(diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) {
|
||||
const info = getFixInfos(context, diagnostic.code, diagnostic.start, useAutoImportProvider);
|
||||
@@ -242,19 +278,89 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
|
||||
addImport(first(info));
|
||||
}
|
||||
|
||||
function addImportFromExportedSymbol(exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean) {
|
||||
function addImportFromExportedSymbol(exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean, referenceImport?: ImportOrRequireAliasDeclaration) {
|
||||
const moduleSymbol = Debug.checkDefined(exportedSymbol.parent);
|
||||
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 useRequire = shouldUseRequire(sourceFile, program);
|
||||
const fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences);
|
||||
let fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences);
|
||||
if (fix) {
|
||||
addImport({ fix, symbolName, errorIdentifierText: undefined });
|
||||
const localName = tryCast(referenceImport?.name, isIdentifier)?.text ?? symbolName;
|
||||
if (
|
||||
referenceImport
|
||||
&& isTypeOnlyImportDeclaration(referenceImport)
|
||||
&& (fix.kind === ImportFixKind.AddNew || fix.kind === ImportFixKind.AddToExisting)
|
||||
&& fix.addAsTypeOnly === AddAsTypeOnly.Allowed
|
||||
) {
|
||||
// Copy the type-only status from the reference import
|
||||
fix = { ...fix, addAsTypeOnly: AddAsTypeOnly.Required };
|
||||
}
|
||||
addImport({ fix, symbolName: localName ?? symbolName, errorIdentifierText: undefined });
|
||||
}
|
||||
}
|
||||
|
||||
function addImportForNonExistentExport(exportName: string, exportingFileName: string, exportKind: ExportKind, exportedMeanings: SymbolFlags, isImportUsageValidAsTypeOnly: boolean) {
|
||||
const exportingSourceFile = program.getSourceFile(exportingFileName);
|
||||
const useRequire = shouldUseRequire(sourceFile, program);
|
||||
if (exportingSourceFile && exportingSourceFile.symbol) {
|
||||
const { fixes } = getImportFixes(
|
||||
[{
|
||||
exportKind,
|
||||
isFromPackageJson: false,
|
||||
moduleFileName: exportingFileName,
|
||||
moduleSymbol: exportingSourceFile.symbol,
|
||||
targetFlags: exportedMeanings,
|
||||
}],
|
||||
/*usagePosition*/ undefined,
|
||||
isImportUsageValidAsTypeOnly,
|
||||
useRequire,
|
||||
program,
|
||||
sourceFile,
|
||||
host,
|
||||
preferences,
|
||||
);
|
||||
if (fixes.length) {
|
||||
addImport({ fix: fixes[0], symbolName: exportName, errorIdentifierText: exportName });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// File does not exist yet or has no exports, so all imports added will be "new"
|
||||
const futureExportingSourceFile = createFutureSourceFile(exportingFileName, ModuleKind.ESNext, program, host);
|
||||
const moduleSpecifier = moduleSpecifiers.getLocalModuleSpecifierBetweenFileNames(
|
||||
sourceFile,
|
||||
exportingFileName,
|
||||
compilerOptions,
|
||||
createModuleSpecifierResolutionHost(program, host),
|
||||
);
|
||||
const importKind = getImportKind(futureExportingSourceFile, exportKind, program);
|
||||
const addAsTypeOnly = getAddAsTypeOnly(
|
||||
isImportUsageValidAsTypeOnly,
|
||||
/*isForNewImportDeclaration*/ true,
|
||||
/*symbol*/ undefined,
|
||||
exportedMeanings,
|
||||
program.getTypeChecker(),
|
||||
compilerOptions,
|
||||
);
|
||||
const fix: FixAddNewImport = {
|
||||
kind: ImportFixKind.AddNew,
|
||||
moduleSpecifier,
|
||||
importKind,
|
||||
addAsTypeOnly,
|
||||
useRequire,
|
||||
};
|
||||
addImport({ fix, symbolName: exportName, errorIdentifierText: exportName });
|
||||
}
|
||||
}
|
||||
|
||||
function removeExistingImport(declaration: ImportOrRequireAliasDeclaration) {
|
||||
if (declaration.kind === SyntaxKind.ImportClause) {
|
||||
Debug.assertIsDefined(declaration.name, "ImportClause should have a name if it's being removed");
|
||||
}
|
||||
removeExisting.add(declaration);
|
||||
}
|
||||
|
||||
function addImport(info: FixInfo) {
|
||||
const { fix, symbolName } = info;
|
||||
switch (fix.kind) {
|
||||
@@ -266,10 +372,9 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
|
||||
break;
|
||||
case ImportFixKind.AddToExisting: {
|
||||
const { importClauseOrBindingPattern, importKind, addAsTypeOnly } = fix;
|
||||
const key = String(getNodeId(importClauseOrBindingPattern));
|
||||
let entry = addToExisting.get(key);
|
||||
let entry = addToExisting.get(importClauseOrBindingPattern);
|
||||
if (!entry) {
|
||||
addToExisting.set(key, entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() });
|
||||
addToExisting.set(importClauseOrBindingPattern, entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() });
|
||||
}
|
||||
if (importKind === ImportKind.Named) {
|
||||
const prevValue = entry?.namedImports.get(symbolName);
|
||||
@@ -362,7 +467,7 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
|
||||
|
||||
function writeFixes(changeTracker: textChanges.ChangeTracker, oldFileQuotePreference?: QuotePreference) {
|
||||
let quotePreference: QuotePreference;
|
||||
if (sourceFile.imports.length === 0 && oldFileQuotePreference !== undefined) {
|
||||
if (isFullSourceFile(sourceFile) && sourceFile.imports.length === 0 && oldFileQuotePreference !== undefined) {
|
||||
// If the target file has no imports, we must use the same quote preference as the file we are importing from.
|
||||
quotePreference = oldFileQuotePreference;
|
||||
}
|
||||
@@ -370,18 +475,102 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
|
||||
quotePreference = getQuotePreference(sourceFile, preferences);
|
||||
}
|
||||
for (const fix of addToNamespace) {
|
||||
addNamespaceQualifier(changeTracker, sourceFile, fix);
|
||||
// Any modifications to existing syntax imply SourceFile already exists
|
||||
addNamespaceQualifier(changeTracker, sourceFile as SourceFile, fix);
|
||||
}
|
||||
for (const fix of importType) {
|
||||
addImportType(changeTracker, sourceFile, fix, quotePreference);
|
||||
// Any modifications to existing syntax imply SourceFile already exists
|
||||
addImportType(changeTracker, sourceFile as SourceFile, fix, quotePreference);
|
||||
}
|
||||
let importSpecifiersToRemoveWhileAdding: Set<ImportSpecifier | BindingElement> | undefined;
|
||||
if (removeExisting.size) {
|
||||
Debug.assert(isFullSourceFile(sourceFile), "Cannot remove imports from a future source file");
|
||||
const importDeclarationsWithRemovals = new Set(mapDefined([...removeExisting], d => findAncestor(d, isImportDeclaration)!));
|
||||
const variableDeclarationsWithRemovals = new Set(mapDefined([...removeExisting], d => findAncestor(d, isVariableDeclarationInitializedToRequire)!));
|
||||
const emptyImportDeclarations = [...importDeclarationsWithRemovals].filter(d =>
|
||||
// nothing added to the import declaration
|
||||
!addToExisting.has(d.importClause!) &&
|
||||
// no default, or default is being removed
|
||||
(!d.importClause?.name || removeExisting.has(d.importClause)) &&
|
||||
// no namespace import, or namespace import is being removed
|
||||
(!tryCast(d.importClause?.namedBindings, isNamespaceImport) || removeExisting.has(d.importClause!.namedBindings as NamespaceImport)) &&
|
||||
// no named imports, or all named imports are being removed
|
||||
(!tryCast(d.importClause?.namedBindings, isNamedImports) || every((d.importClause!.namedBindings as NamedImports).elements, e => removeExisting.has(e)))
|
||||
);
|
||||
const emptyVariableDeclarations = [...variableDeclarationsWithRemovals].filter(d =>
|
||||
// no binding elements being added to the variable declaration
|
||||
(d.name.kind !== SyntaxKind.ObjectBindingPattern || !addToExisting.has(d.name)) &&
|
||||
// no binding elements, or all binding elements are being removed
|
||||
(d.name.kind !== SyntaxKind.ObjectBindingPattern || every(d.name.elements, e => removeExisting.has(e)))
|
||||
);
|
||||
const namedBindingsToDelete = [...importDeclarationsWithRemovals].filter(d =>
|
||||
// has named bindings
|
||||
d.importClause?.namedBindings &&
|
||||
// is not being fully removed
|
||||
emptyImportDeclarations.indexOf(d) === -1 &&
|
||||
// is not gaining named imports
|
||||
!addToExisting.get(d.importClause)?.namedImports &&
|
||||
// all named imports are being removed
|
||||
(d.importClause.namedBindings.kind === SyntaxKind.NamespaceImport || every(d.importClause.namedBindings.elements, e => removeExisting.has(e)))
|
||||
);
|
||||
for (const declaration of [...emptyImportDeclarations, ...emptyVariableDeclarations]) {
|
||||
changeTracker.delete(sourceFile, declaration);
|
||||
}
|
||||
for (const declaration of namedBindingsToDelete) {
|
||||
changeTracker.replaceNode(
|
||||
sourceFile,
|
||||
declaration.importClause!,
|
||||
factory.updateImportClause(
|
||||
declaration.importClause!,
|
||||
declaration.importClause!.isTypeOnly,
|
||||
declaration.importClause!.name,
|
||||
/*namedBindings*/ undefined,
|
||||
),
|
||||
);
|
||||
}
|
||||
for (const declaration of removeExisting) {
|
||||
const importDeclaration = findAncestor(declaration, isImportDeclaration);
|
||||
if (
|
||||
importDeclaration &&
|
||||
emptyImportDeclarations.indexOf(importDeclaration) === -1 &&
|
||||
namedBindingsToDelete.indexOf(importDeclaration) === -1
|
||||
) {
|
||||
if (declaration.kind === SyntaxKind.ImportClause) {
|
||||
changeTracker.delete(sourceFile, declaration.name!);
|
||||
}
|
||||
else {
|
||||
Debug.assert(declaration.kind === SyntaxKind.ImportSpecifier, "NamespaceImport should have been handled earlier");
|
||||
if (addToExisting.get(importDeclaration.importClause!)?.namedImports) {
|
||||
// Handle combined inserts/deletes in `doAddExistingFix`
|
||||
(importSpecifiersToRemoveWhileAdding ??= new Set()).add(declaration);
|
||||
}
|
||||
else {
|
||||
changeTracker.delete(sourceFile, declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (declaration.kind === SyntaxKind.BindingElement) {
|
||||
if (addToExisting.get(declaration.parent as ObjectBindingPattern)?.namedImports) {
|
||||
// Handle combined inserts/deletes in `doAddExistingFix`
|
||||
(importSpecifiersToRemoveWhileAdding ??= new Set()).add(declaration);
|
||||
}
|
||||
else {
|
||||
changeTracker.delete(sourceFile, declaration);
|
||||
}
|
||||
}
|
||||
else if (declaration.kind === SyntaxKind.ImportEqualsDeclaration) {
|
||||
changeTracker.delete(sourceFile, declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
addToExisting.forEach(({ importClauseOrBindingPattern, defaultImport, namedImports }) => {
|
||||
doAddExistingFix(
|
||||
changeTracker,
|
||||
sourceFile,
|
||||
sourceFile as SourceFile,
|
||||
importClauseOrBindingPattern,
|
||||
defaultImport,
|
||||
arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })),
|
||||
importSpecifiersToRemoveWhileAdding,
|
||||
preferences,
|
||||
);
|
||||
});
|
||||
@@ -401,13 +590,84 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu
|
||||
);
|
||||
newDeclarations = combine(newDeclarations, declarations);
|
||||
});
|
||||
newDeclarations = combine(newDeclarations, getCombinedVerbatimImports());
|
||||
if (newDeclarations) {
|
||||
insertImports(changeTracker, sourceFile, newDeclarations, /*blankLineBetween*/ true, preferences);
|
||||
}
|
||||
}
|
||||
|
||||
function getCombinedVerbatimImports(): AnyImportOrRequireStatement[] | undefined {
|
||||
if (!verbatimImports.size) return undefined;
|
||||
const importDeclarations = new Set(mapDefined([...verbatimImports], d => findAncestor(d, isImportDeclaration)));
|
||||
const requireStatements = new Set(mapDefined([...verbatimImports], d => findAncestor(d, isRequireVariableStatement)));
|
||||
return [
|
||||
...mapDefined([...verbatimImports], d =>
|
||||
d.kind === SyntaxKind.ImportEqualsDeclaration
|
||||
? getSynthesizedDeepClone(d, /*includeTrivia*/ true)
|
||||
: undefined),
|
||||
...[...importDeclarations].map(d => {
|
||||
if (verbatimImports.has(d)) {
|
||||
return getSynthesizedDeepClone(d, /*includeTrivia*/ true);
|
||||
}
|
||||
return getSynthesizedDeepClone(
|
||||
factory.updateImportDeclaration(
|
||||
d,
|
||||
d.modifiers,
|
||||
d.importClause && factory.updateImportClause(
|
||||
d.importClause,
|
||||
d.importClause.isTypeOnly,
|
||||
verbatimImports.has(d.importClause) ? d.importClause.name : undefined,
|
||||
verbatimImports.has(d.importClause.namedBindings as NamespaceImport)
|
||||
? d.importClause.namedBindings as NamespaceImport :
|
||||
tryCast(d.importClause.namedBindings, isNamedImports)?.elements.some(e => verbatimImports.has(e))
|
||||
? factory.updateNamedImports(
|
||||
d.importClause.namedBindings as NamedImports,
|
||||
(d.importClause.namedBindings as NamedImports).elements.filter(e => verbatimImports.has(e)),
|
||||
)
|
||||
: undefined,
|
||||
),
|
||||
d.moduleSpecifier,
|
||||
d.attributes,
|
||||
),
|
||||
/*includeTrivia*/ true,
|
||||
);
|
||||
}),
|
||||
...[...requireStatements].map(s => {
|
||||
if (verbatimImports.has(s)) {
|
||||
return getSynthesizedDeepClone(s, /*includeTrivia*/ true);
|
||||
}
|
||||
return getSynthesizedDeepClone(
|
||||
factory.updateVariableStatement(
|
||||
s,
|
||||
s.modifiers,
|
||||
factory.updateVariableDeclarationList(
|
||||
s.declarationList,
|
||||
mapDefined(s.declarationList.declarations, d => {
|
||||
if (verbatimImports.has(d)) {
|
||||
return d;
|
||||
}
|
||||
return factory.updateVariableDeclaration(
|
||||
d,
|
||||
d.name.kind === SyntaxKind.ObjectBindingPattern
|
||||
? factory.updateObjectBindingPattern(
|
||||
d.name,
|
||||
d.name.elements.filter(e => verbatimImports.has(e)),
|
||||
) : d.name,
|
||||
d.exclamationToken,
|
||||
d.type,
|
||||
d.initializer,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
/*includeTrivia*/ true,
|
||||
) as RequireVariableStatement;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
function hasFixes() {
|
||||
return addToNamespace.length > 0 || importType.length > 0 || addToExisting.size > 0 || newImports.size > 0;
|
||||
return addToNamespace.length > 0 || importType.length > 0 || addToExisting.size > 0 || newImports.size > 0 || verbatimImports.size > 0 || removeExisting.size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,13 +682,13 @@ export interface ImportSpecifierResolver {
|
||||
position: number,
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
fromCacheOnly?: boolean,
|
||||
): { exportInfo?: SymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined;
|
||||
): { exportInfo?: SymbolExportInfo | FutureSymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
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());
|
||||
const importMap = createExistingImportMap(importingFile, program);
|
||||
return { getModuleSpecifierForBestExportInfo };
|
||||
|
||||
function getModuleSpecifierForBestExportInfo(
|
||||
@@ -436,7 +696,7 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program
|
||||
position: number,
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
fromCacheOnly?: boolean,
|
||||
): { exportInfo?: SymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined {
|
||||
): { exportInfo?: SymbolExportInfo | FutureSymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined {
|
||||
const { fixes, computedWithoutCacheCount } = getImportFixes(
|
||||
exportInfo,
|
||||
position,
|
||||
@@ -477,7 +737,7 @@ type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImpor
|
||||
// Properties are be undefined if fix is derived from an existing import
|
||||
interface ImportFixBase {
|
||||
readonly isReExport?: boolean;
|
||||
readonly exportInfo?: SymbolExportInfo;
|
||||
readonly exportInfo?: SymbolExportInfo | FutureSymbolExportInfo;
|
||||
readonly moduleSpecifier: string;
|
||||
}
|
||||
interface Qualification {
|
||||
@@ -491,7 +751,7 @@ interface FixAddJsdocTypeImport extends ImportFixBase {
|
||||
readonly kind: ImportFixKind.JsdocTypeImport;
|
||||
readonly usagePosition: number;
|
||||
readonly isReExport: boolean;
|
||||
readonly exportInfo: SymbolExportInfo;
|
||||
readonly exportInfo: SymbolExportInfo | FutureSymbolExportInfo;
|
||||
}
|
||||
interface FixAddToExistingImport extends ImportFixBase {
|
||||
readonly kind: ImportFixKind.AddToExisting;
|
||||
@@ -516,7 +776,7 @@ interface FixAddToExistingImportInfo {
|
||||
readonly declaration: AnyImportOrRequire;
|
||||
readonly importKind: ImportKind;
|
||||
readonly targetFlags: SymbolFlags;
|
||||
readonly symbol: Symbol;
|
||||
readonly symbol?: Symbol;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -584,7 +844,7 @@ export function getPromoteTypeOnlyCompletionAction(sourceFile: SourceFile, symbo
|
||||
));
|
||||
}
|
||||
|
||||
function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], program: Program, position: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) {
|
||||
function getImportFixForSymbol(sourceFile: SourceFile | FutureSourceFile, 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);
|
||||
}
|
||||
@@ -593,7 +853,7 @@ function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAc
|
||||
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 | FutureSourceFile, 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 => {
|
||||
@@ -624,20 +884,24 @@ function getSingleExportInfoForSymbol(symbol: Symbol, symbolName: string, module
|
||||
}
|
||||
}
|
||||
|
||||
function isFutureSymbolExportInfoArray(info: readonly SymbolExportInfo[] | readonly FutureSymbolExportInfo[]): info is readonly FutureSymbolExportInfo[] {
|
||||
return info[0].symbol === undefined;
|
||||
}
|
||||
|
||||
function getImportFixes(
|
||||
exportInfos: readonly SymbolExportInfo[],
|
||||
exportInfos: readonly SymbolExportInfo[] | readonly FutureSymbolExportInfo[],
|
||||
usagePosition: number | undefined,
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
useRequire: boolean,
|
||||
program: Program,
|
||||
sourceFile: SourceFile,
|
||||
sourceFile: SourceFile | FutureSourceFile,
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
importMap = createExistingImportMap(program.getTypeChecker(), sourceFile, program.getCompilerOptions()),
|
||||
importMap = isFullSourceFile(sourceFile) ? createExistingImportMap(sourceFile, program) : undefined,
|
||||
fromCacheOnly?: boolean,
|
||||
): { computedWithoutCacheCount: number; fixes: readonly ImportFixWithModuleSpecifier[]; } {
|
||||
const checker = program.getTypeChecker();
|
||||
const existingImports = flatMap(exportInfos, importMap.getImportsForExportInfo);
|
||||
const existingImports = importMap && !isFutureSymbolExportInfoArray(exportInfos) ? flatMap(exportInfos, importMap.getImportsForExportInfo) : emptyArray;
|
||||
const useNamespace = usagePosition !== undefined && tryUseExistingNamespaceImport(existingImports, usagePosition);
|
||||
const addToExisting = tryAddToExistingImport(existingImports, isValidTypeOnlyUseSite, checker, program.getCompilerOptions());
|
||||
if (addToExisting) {
|
||||
@@ -706,7 +970,7 @@ function getNamespaceLikeImportText(declaration: AnyImportOrRequire) {
|
||||
function getAddAsTypeOnly(
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
isForNewImportDeclaration: boolean,
|
||||
symbol: Symbol,
|
||||
symbol: Symbol | undefined,
|
||||
targetFlags: SymbolFlags,
|
||||
checker: TypeChecker,
|
||||
compilerOptions: CompilerOptions,
|
||||
@@ -716,6 +980,7 @@ function getAddAsTypeOnly(
|
||||
return AddAsTypeOnly.NotAllowed;
|
||||
}
|
||||
if (
|
||||
symbol &&
|
||||
compilerOptions.verbatimModuleSyntax &&
|
||||
(!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol))
|
||||
) {
|
||||
@@ -798,7 +1063,8 @@ function tryAddToExistingImport(existingImports: readonly FixAddToExistingImport
|
||||
}
|
||||
}
|
||||
|
||||
function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile, compilerOptions: CompilerOptions) {
|
||||
function createExistingImportMap(importingFile: SourceFile, program: Program) {
|
||||
const checker = program.getTypeChecker();
|
||||
let importMap: MultiMap<SymbolId, AnyImportOrRequire> | undefined;
|
||||
for (const moduleSpecifier of importingFile.imports) {
|
||||
const i = importFromModuleSpecifier(moduleSpecifier);
|
||||
@@ -828,15 +1094,15 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile
|
||||
&& !every(matchingDeclarations, isJSDocImportTag)
|
||||
) return emptyArray;
|
||||
|
||||
const importKind = getImportKind(importingFile, exportKind, compilerOptions);
|
||||
const importKind = getImportKind(importingFile, exportKind, program);
|
||||
return matchingDeclarations.map(declaration => ({ declaration, importKind, symbol, targetFlags }));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean {
|
||||
function shouldUseRequire(sourceFile: SourceFile | FutureSourceFile, program: Program): boolean {
|
||||
// 1. TypeScript files don't use require variable declarations
|
||||
if (!isSourceFileJS(sourceFile)) {
|
||||
if (!hasJSFileExtension(sourceFile.fileName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -852,8 +1118,9 @@ function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean {
|
||||
|
||||
// 4. In --module nodenext, assume we're not emitting JS -> JS, so use
|
||||
// whatever syntax Node expects based on the detected module kind
|
||||
if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) return true;
|
||||
if (sourceFile.impliedNodeFormat === ModuleKind.ESNext) return false;
|
||||
// TODO: consider removing `impliedNodeFormatForEmit`
|
||||
if (getImpliedNodeFormatForEmit(sourceFile, program) === ModuleKind.CommonJS) return true;
|
||||
if (getImpliedNodeFormatForEmit(sourceFile, program) === ModuleKind.ESNext) return false;
|
||||
|
||||
// 5. Match the first other JS file in the program that's unambiguously CJS or ESM
|
||||
for (const otherFile of program.getSourceFiles()) {
|
||||
@@ -872,29 +1139,29 @@ function createGetChecker(program: Program, host: LanguageServiceHost) {
|
||||
|
||||
function getNewImportFixes(
|
||||
program: Program,
|
||||
sourceFile: SourceFile,
|
||||
sourceFile: SourceFile | FutureSourceFile,
|
||||
usagePosition: number | undefined,
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
useRequire: boolean,
|
||||
exportInfo: readonly SymbolExportInfo[],
|
||||
exportInfo: readonly (SymbolExportInfo | FutureSymbolExportInfo)[],
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
fromCacheOnly?: boolean,
|
||||
): { computedWithoutCacheCount: number; fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[]; } {
|
||||
const isJs = isSourceFileJS(sourceFile);
|
||||
const isJs = hasJSFileExtension(sourceFile.fileName);
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host);
|
||||
const getChecker = createGetChecker(program, host);
|
||||
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, /*options*/ undefined, /*forAutoImport*/ true);
|
||||
? (exportInfo: SymbolExportInfo | FutureSymbolExportInfo) => ({ moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache(exportInfo.moduleSymbol, sourceFile, moduleSpecifierResolutionHost, preferences), computedWithoutCache: false })
|
||||
: (exportInfo: SymbolExportInfo | FutureSymbolExportInfo, checker: TypeChecker) => moduleSpecifiers.getModuleSpecifiersWithCacheInfo(exportInfo.moduleSymbol, checker, compilerOptions, sourceFile, moduleSpecifierResolutionHost, preferences, /*options*/ undefined, /*forAutoImport*/ true);
|
||||
|
||||
let computedWithoutCacheCount = 0;
|
||||
const fixes = flatMap(exportInfo, (exportInfo, i) => {
|
||||
const checker = getChecker(exportInfo.isFromPackageJson);
|
||||
const { computedWithoutCache, moduleSpecifiers } = getModuleSpecifiers(exportInfo.moduleSymbol, checker);
|
||||
const { computedWithoutCache, moduleSpecifiers } = getModuleSpecifiers(exportInfo, checker);
|
||||
const importedSymbolHasValueMeaning = !!(exportInfo.targetFlags & SymbolFlags.Value);
|
||||
const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, exportInfo.symbol, exportInfo.targetFlags, checker, compilerOptions);
|
||||
computedWithoutCacheCount += computedWithoutCache ? 1 : 0;
|
||||
@@ -906,7 +1173,7 @@ function getNewImportFixes(
|
||||
// `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 };
|
||||
}
|
||||
const importKind = getImportKind(sourceFile, exportInfo.exportKind, compilerOptions);
|
||||
const importKind = getImportKind(sourceFile, exportInfo.exportKind, program);
|
||||
let qualification: Qualification | undefined;
|
||||
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
|
||||
@@ -944,10 +1211,10 @@ function getNewImportFixes(
|
||||
}
|
||||
|
||||
function getFixesForAddImport(
|
||||
exportInfos: readonly SymbolExportInfo[],
|
||||
exportInfos: readonly SymbolExportInfo[] | readonly FutureSymbolExportInfo[],
|
||||
existingImports: readonly FixAddToExistingImportInfo[],
|
||||
program: Program,
|
||||
sourceFile: SourceFile,
|
||||
sourceFile: SourceFile | FutureSourceFile,
|
||||
usagePosition: number | undefined,
|
||||
isValidTypeOnlyUseSite: boolean,
|
||||
useRequire: boolean,
|
||||
@@ -1011,7 +1278,13 @@ function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecif
|
||||
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 getFixInfosWithoutDiagnostic(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly FixInfo[] | undefined {
|
||||
const info = getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider);
|
||||
const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host);
|
||||
return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host);
|
||||
}
|
||||
|
||||
function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: SourceFile | FutureSourceFile, 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) {
|
||||
@@ -1035,7 +1308,7 @@ function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile:
|
||||
function compareModuleSpecifiers(
|
||||
a: ImportFixWithModuleSpecifier,
|
||||
b: ImportFixWithModuleSpecifier,
|
||||
importingFile: SourceFile,
|
||||
importingFile: SourceFile | FutureSourceFile,
|
||||
program: Program,
|
||||
allowsImportingSpecifier: (specifier: string) => boolean,
|
||||
toPath: (fileName: string) => Path,
|
||||
@@ -1044,8 +1317,8 @@ function compareModuleSpecifiers(
|
||||
return compareBooleans(allowsImportingSpecifier(b.moduleSpecifier), allowsImportingSpecifier(a.moduleSpecifier))
|
||||
|| compareNodeCoreModuleSpecifiers(a.moduleSpecifier, b.moduleSpecifier, importingFile, program)
|
||||
|| compareBooleans(
|
||||
isFixPossiblyReExportingImportingFile(a, importingFile, program.getCompilerOptions(), toPath),
|
||||
isFixPossiblyReExportingImportingFile(b, importingFile, program.getCompilerOptions(), toPath),
|
||||
isFixPossiblyReExportingImportingFile(a, importingFile.path, toPath),
|
||||
isFixPossiblyReExportingImportingFile(b, importingFile.path, toPath),
|
||||
)
|
||||
|| compareNumberOfDirectorySeparators(a.moduleSpecifier, b.moduleSpecifier);
|
||||
}
|
||||
@@ -1056,14 +1329,14 @@ function compareModuleSpecifiers(
|
||||
// E.g., do not `import { Foo } from ".."` when you could `import { Foo } from "../Foo"`.
|
||||
// This can produce false positives or negatives if re-exports cross into sibling directories
|
||||
// (e.g. `export * from "../whatever"`) or are not named "index".
|
||||
function isFixPossiblyReExportingImportingFile(fix: ImportFixWithModuleSpecifier, importingFile: SourceFile, compilerOptions: CompilerOptions, toPath: (fileName: string) => Path): boolean {
|
||||
function isFixPossiblyReExportingImportingFile(fix: ImportFixWithModuleSpecifier, importingFilePath: Path, toPath: (fileName: string) => Path): boolean {
|
||||
if (
|
||||
fix.isReExport &&
|
||||
fix.exportInfo?.moduleFileName &&
|
||||
isIndexFileName(fix.exportInfo.moduleFileName)
|
||||
) {
|
||||
const reExportDir = toPath(getDirectoryPath(fix.exportInfo.moduleFileName));
|
||||
return startsWith(importingFile.path, reExportDir);
|
||||
return startsWith(importingFilePath, reExportDir);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1072,7 +1345,7 @@ 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 {
|
||||
function compareNodeCoreModuleSpecifiers(a: string, b: string, importingFile: SourceFile | FutureSourceFile, 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;
|
||||
@@ -1117,8 +1390,8 @@ 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 | FutureSourceFile, exportKind: ExportKind, program: Program, forceImportKeyword?: boolean): ImportKind {
|
||||
if (program.getCompilerOptions().verbatimModuleSyntax && getEmitModuleFormatOfFile(importingFile, program) === 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;
|
||||
}
|
||||
@@ -1128,28 +1401,28 @@ export function getImportKind(importingFile: SourceFile, exportKind: ExportKind,
|
||||
case ExportKind.Default:
|
||||
return ImportKind.Default;
|
||||
case ExportKind.ExportEquals:
|
||||
return getExportEqualsImportKind(importingFile, compilerOptions, !!forceImportKeyword);
|
||||
return getExportEqualsImportKind(importingFile, program.getCompilerOptions(), !!forceImportKeyword);
|
||||
case ExportKind.UMD:
|
||||
return getUmdImportKind(importingFile, compilerOptions, !!forceImportKeyword);
|
||||
return getUmdImportKind(importingFile, program, !!forceImportKeyword);
|
||||
default:
|
||||
return Debug.assertNever(exportKind);
|
||||
}
|
||||
}
|
||||
|
||||
function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind {
|
||||
function getUmdImportKind(importingFile: SourceFile | FutureSourceFile, program: Program, forceImportKeyword: boolean): ImportKind {
|
||||
// Import a synthetic `default` if enabled.
|
||||
if (getAllowSyntheticDefaultImports(compilerOptions)) {
|
||||
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
|
||||
return ImportKind.Default;
|
||||
}
|
||||
|
||||
// When a synthetic `default` is unavailable, use `import..require` if the module kind supports it.
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const moduleKind = getEmitModuleKind(program.getCompilerOptions());
|
||||
switch (moduleKind) {
|
||||
case ModuleKind.AMD:
|
||||
case ModuleKind.CommonJS:
|
||||
case ModuleKind.UMD:
|
||||
if (isInJSFile(importingFile)) {
|
||||
return isExternalModule(importingFile) || forceImportKeyword ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
if (hasJSFileExtension(importingFile.fileName)) {
|
||||
return importingFile.externalModuleIndicator || forceImportKeyword ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
}
|
||||
return ImportKind.CommonJS;
|
||||
case ModuleKind.System:
|
||||
@@ -1163,7 +1436,7 @@ function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOp
|
||||
return ImportKind.Namespace;
|
||||
case ModuleKind.Node16:
|
||||
case ModuleKind.NodeNext:
|
||||
return importingFile.impliedNodeFormat === ModuleKind.ESNext ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
return getImpliedNodeFormatForEmit(importingFile, program) === ModuleKind.ESNext ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
default:
|
||||
return Debug.assertNever(moduleKind, `Unexpected moduleKind ${moduleKind}`);
|
||||
}
|
||||
@@ -1265,9 +1538,9 @@ function getExportInfos(
|
||||
return originalSymbolToExportInfos;
|
||||
}
|
||||
|
||||
function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind {
|
||||
function getExportEqualsImportKind(importingFile: SourceFile | FutureSourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind {
|
||||
const allowSyntheticDefaults = getAllowSyntheticDefaultImports(compilerOptions);
|
||||
const isJS = isInJSFile(importingFile);
|
||||
const isJS = hasJSFileExtension(importingFile.fileName);
|
||||
// 1. 'import =' will not work in es2015+ TS files, so the decision is between a default
|
||||
// and a namespace import, based on allowSyntheticDefaultImports/esModuleInterop.
|
||||
if (!isJS && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015) {
|
||||
@@ -1276,14 +1549,14 @@ function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: C
|
||||
// 2. 'import =' will not work in JavaScript, so the decision is between a default import,
|
||||
// a namespace import, and const/require.
|
||||
if (isJS) {
|
||||
return isExternalModule(importingFile) || forceImportKeyword
|
||||
return importingFile.externalModuleIndicator || forceImportKeyword
|
||||
? allowSyntheticDefaults ? ImportKind.Default : ImportKind.Namespace
|
||||
: ImportKind.CommonJS;
|
||||
}
|
||||
// 3. At this point the most correct choice is probably 'import =', but people
|
||||
// really hate that, so look to see if the importing file has any precedent
|
||||
// on how to handle it.
|
||||
for (const statement of importingFile.statements) {
|
||||
for (const statement of importingFile.statements ?? emptyArray) {
|
||||
// `import foo` parses as an ImportEqualsDeclaration even though it could be an ImportDeclaration
|
||||
if (isImportEqualsDeclaration(statement) && !nodeIsMissing(statement.moduleReference)) {
|
||||
return ImportKind.CommonJS;
|
||||
@@ -1334,6 +1607,7 @@ function codeActionForFixWorker(
|
||||
importClauseOrBindingPattern,
|
||||
importKind === ImportKind.Default ? { name: symbolName, addAsTypeOnly } : undefined,
|
||||
importKind === ImportKind.Named ? [{ name: symbolName, addAsTypeOnly }] : emptyArray,
|
||||
/*removeExistingImportSpecifiers*/ undefined,
|
||||
preferences,
|
||||
);
|
||||
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier);
|
||||
@@ -1474,9 +1748,25 @@ function doAddExistingFix(
|
||||
clause: ImportClause | ObjectBindingPattern,
|
||||
defaultImport: Import | undefined,
|
||||
namedImports: readonly Import[],
|
||||
removeExistingImportSpecifiers: Set<ImportSpecifier | BindingElement> | undefined,
|
||||
preferences: UserPreferences,
|
||||
): void {
|
||||
if (clause.kind === SyntaxKind.ObjectBindingPattern) {
|
||||
if (removeExistingImportSpecifiers && clause.elements.some(e => removeExistingImportSpecifiers.has(e))) {
|
||||
// If we're both adding and removing elements, just replace and reprint the whole
|
||||
// node. The change tracker doesn't understand all the operations and can insert or
|
||||
// leave behind stray commas.
|
||||
changes.replaceNode(
|
||||
sourceFile,
|
||||
clause,
|
||||
factory.createObjectBindingPattern([
|
||||
...clause.elements.filter(e => !removeExistingImportSpecifiers.has(e)),
|
||||
...defaultImport ? [factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ "default", defaultImport.name)] : emptyArray,
|
||||
...namedImports.map(i => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i.name)),
|
||||
]),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (defaultImport) {
|
||||
addElementToBindingPattern(clause, defaultImport.name, "default");
|
||||
}
|
||||
@@ -1508,6 +1798,19 @@ function doAddExistingFix(
|
||||
specifierComparer,
|
||||
);
|
||||
|
||||
if (removeExistingImportSpecifiers) {
|
||||
// If we're both adding and removing specifiers, just replace and reprint the whole
|
||||
// node. The change tracker doesn't understand all the operations and can insert or
|
||||
// leave behind stray commas.
|
||||
changes.replaceNode(
|
||||
sourceFile,
|
||||
clause.namedBindings!,
|
||||
factory.updateNamedImports(
|
||||
clause.namedBindings as NamedImports,
|
||||
stableSort([...existingSpecifiers!.filter(s => !removeExistingImportSpecifiers.has(s)), ...newSpecifiers], specifierComparer),
|
||||
),
|
||||
);
|
||||
}
|
||||
// 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
|
||||
@@ -1515,7 +1818,7 @@ function doAddExistingFix(
|
||||
// to do a sorted insertion.
|
||||
|
||||
// changed to check if existing specifiers are sorted
|
||||
if (existingSpecifiers?.length && isSorted !== false) {
|
||||
else if (existingSpecifiers?.length && isSorted !== false) {
|
||||
// if we're promoting the clause from type-only, we need to transform the existing imports before attempting to insert the new named imports
|
||||
const transformedExistingSpecifiers = (promoteFromTypeOnly && existingSpecifiers) ? factory.updateNamedImports(
|
||||
clause.namedBindings as NamedImports,
|
||||
@@ -1736,3 +2039,11 @@ export function moduleSpecifierToValidIdentifier(moduleSpecifier: string, target
|
||||
// Need `|| "_"` to ensure result isn't empty.
|
||||
return !isStringANonContextualKeyword(res) ? res || "_" : `_${res}`;
|
||||
}
|
||||
|
||||
function getImpliedNodeFormatForEmit(file: SourceFile | FutureSourceFile, program: Program) {
|
||||
return isFullSourceFile(file) ? program.getImpliedNodeFormatForEmit(file) : getImpliedNodeFormatForEmitWorker(file, program.getCompilerOptions());
|
||||
}
|
||||
|
||||
function getEmitModuleFormatOfFile(file: SourceFile | FutureSourceFile, program: Program) {
|
||||
return isFullSourceFile(file) ? program.getEmitModuleFormatOfFile(file) : getEmitModuleFormatOfFileWorker(file, program.getCompilerOptions());
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ import {
|
||||
forEach,
|
||||
formatting,
|
||||
FunctionLikeDeclaration,
|
||||
FutureSymbolExportInfo,
|
||||
getAllSuperTypeNodes,
|
||||
getAncestor,
|
||||
getCombinedLocalAndExportSymbolFlags,
|
||||
@@ -609,7 +610,7 @@ interface ModuleSpecifierResolutionContext {
|
||||
}
|
||||
|
||||
type ModuleSpecifierResolutionResult = "skipped" | "failed" | {
|
||||
exportInfo?: SymbolExportInfo;
|
||||
exportInfo?: SymbolExportInfo | FutureSymbolExportInfo;
|
||||
moduleSpecifier: string;
|
||||
};
|
||||
|
||||
@@ -1157,11 +1158,13 @@ function getJSDocParamAnnotation(
|
||||
? createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
})
|
||||
: createPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
});
|
||||
setEmitFlags(typeNode, EmitFlags.SingleLine);
|
||||
@@ -1455,6 +1458,7 @@ function getExhaustiveCaseSnippets(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
newLine: getNewLineKind(newLineChar),
|
||||
});
|
||||
@@ -1716,7 +1720,7 @@ 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, program, preferences));
|
||||
isSnippet = preferences.includeCompletionsWithSnippetText ? true : undefined;
|
||||
}
|
||||
}
|
||||
@@ -1942,6 +1946,7 @@ function getEntryForMemberCompletion(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: false,
|
||||
newLine: getNewLineKind(getNewLineOrDefaultFromHost(host, formatContext?.options)),
|
||||
@@ -2168,6 +2173,7 @@ function getEntryForObjectLiteralMethodCompletion(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: false,
|
||||
newLine: getNewLineKind(getNewLineOrDefaultFromHost(host, formatContext?.options)),
|
||||
@@ -2182,6 +2188,7 @@ function getEntryForObjectLiteralMethodCompletion(
|
||||
const signaturePrinter = createPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: true,
|
||||
});
|
||||
@@ -2484,14 +2491,14 @@ 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, program: Program, 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 tabStop = preferences.includeCompletionsWithSnippetText ? "$1" : "";
|
||||
const importKind = codefix.getImportKind(sourceFile, exportKind, options, /*forceImportKeyword*/ true);
|
||||
const importKind = codefix.getImportKind(sourceFile, exportKind, program, /*forceImportKeyword*/ true);
|
||||
const isImportSpecifierTypeOnly = importStatementCompletion.couldBeTypeOnlyImportSpecifier;
|
||||
const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " ";
|
||||
const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${tokenToString(SyntaxKind.TypeKeyword)} ` : "";
|
||||
@@ -4079,20 +4086,20 @@ function getCompletionData(
|
||||
// it should be identical regardless of which one is used. During the subsequent
|
||||
// `CompletionEntryDetails` request, we'll get all the ExportInfos again and pick
|
||||
// the best one based on the module specifier it produces.
|
||||
let exportInfo = info[0], moduleSpecifier;
|
||||
let exportInfo: SymbolExportInfo | FutureSymbolExportInfo = info[0], moduleSpecifier;
|
||||
if (result !== "skipped") {
|
||||
({ exportInfo = info[0], moduleSpecifier } = result);
|
||||
}
|
||||
|
||||
const isDefaultExport = exportInfo.exportKind === ExportKind.Default;
|
||||
const symbol = isDefaultExport && getLocalSymbolForExportDefault(exportInfo.symbol) || exportInfo.symbol;
|
||||
const symbol = isDefaultExport && getLocalSymbolForExportDefault(Debug.checkDefined(exportInfo.symbol)) || Debug.checkDefined(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 : Debug.checkDefined(exportInfo.symbol).name,
|
||||
fileName: exportInfo.moduleFileName,
|
||||
isDefaultExport,
|
||||
moduleSymbol: exportInfo.moduleSymbol,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
firstDefined,
|
||||
forEachAncestorDirectory,
|
||||
forEachEntry,
|
||||
FutureSourceFile,
|
||||
getBaseFileName,
|
||||
GetCanonicalFileName,
|
||||
getDirectoryPath,
|
||||
@@ -90,6 +91,12 @@ export interface SymbolExportInfo {
|
||||
isFromPackageJson: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* ExportInfo for an export that does not exist yet, so does not have a symbol.
|
||||
*/
|
||||
export type FutureSymbolExportInfo = Omit<SymbolExportInfo, "symbol"> & { readonly symbol?: undefined; };
|
||||
|
||||
interface CachedSymbolExportInfo {
|
||||
// Used to rehydrate `symbol` and `moduleSymbol` when transient
|
||||
id: number;
|
||||
@@ -477,7 +484,7 @@ 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 | FutureSourceFile, 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
|
||||
|
||||
@@ -342,7 +342,7 @@ 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 || program.getDefaultResolutionModeForFile(sourceFile))?.resolvedTypeReferenceDirective;
|
||||
const file = reference && program.getSourceFile(reference.resolvedFileName!); // TODO:GH#18217
|
||||
return file && { reference: typeReferenceDirective, fileName: file.fileName, file, unverified: false };
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ 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;
|
||||
const referenced = program.getResolvedTypeReferenceDirectives().get(ref.fileName, ref.resolutionMode || program.getDefaultResolutionModeForFile(referencingFile))?.resolvedTypeReferenceDirective;
|
||||
if (referenced !== undefined && referenced.resolvedFileName === (searchSourceFile as SourceFile).fileName) {
|
||||
refs.push({ kind: "reference", referencingFile, ref });
|
||||
}
|
||||
|
||||
@@ -329,7 +329,11 @@ class ServicesSymbolObjectInternals extends SymbolObjectInternals {
|
||||
|
||||
override getJsDocTags(symbol: SymbolObject, checker?: TypeChecker): JSDocTagInfo[] {
|
||||
const extra = ensureSymbolExtraFields(symbol);
|
||||
return extra.tags ??= getJsDocTagsOfDeclarations(symbol.declarations, checker);
|
||||
if (!extra.tags) {
|
||||
extra.tags = emptyArray; // Set temporarily to avoid an infinite loop finding inherited tags
|
||||
extra.tags = getJsDocTagsOfDeclarations(symbol.declarations, checker);
|
||||
}
|
||||
return extra.tags;
|
||||
}
|
||||
|
||||
override getContextualJsDocTags(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
|
||||
@@ -402,7 +406,7 @@ function getJsDocTagsOfDeclarations(declarations: Declaration[] | undefined, che
|
||||
if (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) {
|
||||
return symbol.getContextualJsDocTags(declaration, checker);
|
||||
}
|
||||
return symbol.declarations?.length === 1 ? symbol.getJsDocTags() : undefined;
|
||||
return symbol.declarations?.length === 1 ? symbol.getJsDocTags(checker) : undefined;
|
||||
}
|
||||
});
|
||||
if (inheritedTags) {
|
||||
|
||||
@@ -197,7 +197,7 @@ export function getStringLiteralCompletions(
|
||||
includeSymbol: boolean,
|
||||
): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
const entries = getTripleSlashReferenceCompletion(sourceFile, position, options, host);
|
||||
const entries = getTripleSlashReferenceCompletion(sourceFile, position, program, host);
|
||||
return entries && convertPathCompletions(entries);
|
||||
}
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
@@ -593,8 +593,8 @@ function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile
|
||||
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);
|
||||
? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, program, host, scriptPath, extensionOptions)
|
||||
: getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, program, host, extensionOptions);
|
||||
}
|
||||
|
||||
interface ExtensionOptions {
|
||||
@@ -614,20 +614,21 @@ 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, program: Program, host: LanguageServiceHost, scriptPath: Path, extensionOptions: ExtensionOptions) {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (compilerOptions.rootDirs) {
|
||||
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs,
|
||||
literalValue,
|
||||
scriptDirectory,
|
||||
extensionOptions,
|
||||
compilerOptions,
|
||||
program,
|
||||
host,
|
||||
scriptPath,
|
||||
);
|
||||
}
|
||||
else {
|
||||
return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values());
|
||||
return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,12 +666,13 @@ function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, sc
|
||||
);
|
||||
}
|
||||
|
||||
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, program: Program, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const basePath = compilerOptions.project || host.getCurrentDirectory();
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase);
|
||||
return deduplicate<NameAndKind>(
|
||||
flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, exclude).values())),
|
||||
flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ true, exclude).values())),
|
||||
(itemA, itemB) => itemA.name === itemB.name && itemA.kind === itemB.kind && itemA.extension === itemB.extension,
|
||||
);
|
||||
}
|
||||
@@ -686,6 +688,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
fragment: string,
|
||||
scriptDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
moduleSpecifierIsRelative: boolean,
|
||||
exclude?: string,
|
||||
@@ -725,7 +728,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
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, program, 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;
|
||||
@@ -748,7 +751,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), host.getCompilationSettings(), extensionOptions, /*isExportsWildcard*/ false);
|
||||
const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), program, extensionOptions, /*isExportsWildcard*/ false);
|
||||
result.add(nameAndKind(name, ScriptElementKind.scriptElement, extension));
|
||||
}
|
||||
}
|
||||
@@ -768,7 +771,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
return result;
|
||||
}
|
||||
|
||||
function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerOptions, extensionOptions: ExtensionOptions, isExportsWildcard: boolean): { name: string; extension: Extension | undefined; } {
|
||||
function getFilenameWithExtensionOption(name: string, program: Program, extensionOptions: ExtensionOptions, isExportsWildcard: boolean): { name: string; extension: Extension | undefined; } {
|
||||
const nonJsResult = moduleSpecifiers.tryGetRealFileNameForNonJsDeclarationFileName(name);
|
||||
if (nonJsResult) {
|
||||
return { name: nonJsResult, extension: tryGetExtensionFromPath(nonJsResult) };
|
||||
@@ -779,7 +782,8 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
|
||||
let allowedEndings = getModuleSpecifierPreferences(
|
||||
{ importModuleSpecifierEnding: extensionOptions.endingPreference },
|
||||
compilerOptions,
|
||||
program,
|
||||
program.getCompilerOptions(),
|
||||
extensionOptions.importingSourceFile,
|
||||
).getAllowedEndingsInPreferredOrder(extensionOptions.resolutionMode);
|
||||
|
||||
@@ -793,7 +797,7 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
if (fileExtensionIsOneOf(name, supportedTSImplementationExtensions)) {
|
||||
return { name, extension: tryGetExtensionFromPath(name) };
|
||||
}
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, compilerOptions);
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, program.getCompilerOptions());
|
||||
return outputExtension
|
||||
? { name: changeExtension(name, outputExtension), extension: outputExtension }
|
||||
: { name, extension: tryGetExtensionFromPath(name) };
|
||||
@@ -807,7 +811,7 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
return { name: removeFileExtension(name), extension: tryGetExtensionFromPath(name) };
|
||||
}
|
||||
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, compilerOptions);
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, program.getCompilerOptions());
|
||||
return outputExtension
|
||||
? { name: changeExtension(name, outputExtension), extension: outputExtension }
|
||||
: { name, extension: tryGetExtensionFromPath(name) };
|
||||
@@ -819,6 +823,7 @@ function addCompletionEntriesFromPaths(
|
||||
fragment: string,
|
||||
baseDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
paths: MapLike<string[]>,
|
||||
) {
|
||||
@@ -830,7 +835,7 @@ function addCompletionEntriesFromPaths(
|
||||
const lengthB = typeof patternB === "object" ? patternB.prefix.length : b.length;
|
||||
return compareValues(lengthB, lengthA);
|
||||
};
|
||||
return addCompletionEntriesFromPathsOrExports(result, /*isExports*/ false, fragment, baseDirectory, extensionOptions, host, getOwnKeys(paths), getPatternsForKey, comparePaths);
|
||||
return addCompletionEntriesFromPathsOrExports(result, /*isExports*/ false, fragment, baseDirectory, extensionOptions, program, 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) */
|
||||
@@ -840,6 +845,7 @@ function addCompletionEntriesFromPathsOrExports(
|
||||
fragment: string,
|
||||
baseDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
keys: readonly string[],
|
||||
getPatternsForKey: (key: string) => string[] | undefined,
|
||||
@@ -874,7 +880,7 @@ function addCompletionEntriesFromPathsOrExports(
|
||||
if (typeof pathPattern === "string" || matchedPath === undefined || comparePaths(key, matchedPath) !== Comparison.GreaterThan) {
|
||||
pathResults.push({
|
||||
matchedPattern: isMatch,
|
||||
results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, isExports && isMatch, host)
|
||||
results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, isExports && isMatch, program, host)
|
||||
.map(({ name, kind, extension }) => nameAndKind(name, kind, extension)),
|
||||
});
|
||||
}
|
||||
@@ -896,11 +902,12 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
fragment: string,
|
||||
scriptPath: string,
|
||||
mode: ResolutionMode,
|
||||
compilerOptions: CompilerOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
extensionOptions: ExtensionOptions,
|
||||
typeChecker: TypeChecker,
|
||||
): readonly NameAndKind[] {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const { baseUrl, paths } = compilerOptions;
|
||||
|
||||
const result = createNameAndKindSet();
|
||||
@@ -908,12 +915,12 @@ 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, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
const absolute = getPathsBasePath(compilerOptions, host)!;
|
||||
addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, host, paths);
|
||||
addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, program, host, paths);
|
||||
}
|
||||
|
||||
const fragmentDirectory = getFragmentDirectory(fragment);
|
||||
@@ -921,7 +928,7 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
result.add(nameAndKind(ambientName, ScriptElementKind.externalModuleName, /*extension*/ undefined));
|
||||
}
|
||||
|
||||
getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, fragmentDirectory, extensionOptions, result);
|
||||
getCompletionEntriesFromTypings(host, program, scriptPath, fragmentDirectory, extensionOptions, result);
|
||||
|
||||
if (moduleResolutionUsesNodeModules(moduleResolution)) {
|
||||
// If looking for a global package name, don't just include everything in `node_modules` because that includes dependencies' own dependencies.
|
||||
@@ -940,7 +947,7 @@ 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, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
};
|
||||
if (fragmentDirectory && getResolvePackageJsonExports(compilerOptions)) {
|
||||
@@ -977,6 +984,7 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
fragmentSubpath,
|
||||
packageDirectory,
|
||||
extensionOptions,
|
||||
program,
|
||||
host,
|
||||
keys,
|
||||
key => singleElementArray(getPatternFromFirstMatchingCondition(exports[key], conditions)),
|
||||
@@ -1020,6 +1028,7 @@ function getCompletionsForPathMapping(
|
||||
packageDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
isExportsWildcard: boolean,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
): readonly NameAndKind[] {
|
||||
if (!endsWith(path, "*")) {
|
||||
@@ -1031,9 +1040,9 @@ 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, isExportsWildcard, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest })));
|
||||
return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) : flatMap(patterns, pattern => getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, isExportsWildcard, program, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest })));
|
||||
}
|
||||
return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, isExportsWildcard, host));
|
||||
return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, isExportsWildcard, program, host));
|
||||
|
||||
function justPathMappingName(name: string, kind: ScriptElementKind.directory | ScriptElementKind.scriptElement): readonly NameAndKind[] {
|
||||
return startsWith(name, fragment) ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray;
|
||||
@@ -1046,6 +1055,7 @@ function getModulesForPathsPattern(
|
||||
pattern: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
isExportsWildcard: boolean,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
): readonly NameAndKind[] | undefined {
|
||||
if (!host.readDirectory) {
|
||||
@@ -1094,7 +1104,7 @@ function getModulesForPathsPattern(
|
||||
if (containsSlash(trimmedWithPattern)) {
|
||||
return directoryResult(getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1]);
|
||||
}
|
||||
const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, host.getCompilationSettings(), extensionOptions, isExportsWildcard);
|
||||
const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, program, extensionOptions, isExportsWildcard);
|
||||
return nameAndKind(name, ScriptElementKind.scriptElement, extension);
|
||||
}
|
||||
});
|
||||
@@ -1138,7 +1148,8 @@ function getAmbientModuleCompletions(fragment: string, fragmentDirectory: string
|
||||
return nonRelativeModuleNames;
|
||||
}
|
||||
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): readonly PathCompletion[] | undefined {
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, program: Program, host: LanguageServiceHost): readonly PathCompletion[] | undefined {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const token = getTokenAtPosition(sourceFile, position);
|
||||
const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos);
|
||||
const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end);
|
||||
@@ -1153,13 +1164,14 @@ 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), program, host, /*moduleSpecifierIsRelative*/ true, sourceFile.path)
|
||||
: kind === "types" ? getCompletionEntriesFromTypings(host, program, 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, program: Program, scriptPath: string, fragmentDirectory: string | undefined, extensionOptions: ExtensionOptions, result = createNameAndKindSet()): NameAndKindSet {
|
||||
const options = program.getCompilerOptions();
|
||||
// Check for typings specified in compiler options
|
||||
const seen = new Map<string, true>();
|
||||
|
||||
@@ -1194,7 +1206,7 @@ function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: Com
|
||||
const baseDirectory = combinePaths(directory, typeDirectoryName);
|
||||
const remainingFragment = tryRemoveDirectoryPrefix(fragmentDirectory, packageName, hostGetCanonicalFileName(host));
|
||||
if (remainingFragment !== undefined) {
|
||||
getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr
|
||||
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 = program.getImpliedNodeFormatForEmit(sourceFile) === ModuleKind.CommonJS || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]);
|
||||
|
||||
if (
|
||||
!isCommonJSFile &&
|
||||
|
||||
@@ -655,7 +655,7 @@ export class ChangeTracker {
|
||||
this.insertNodesAt(sourceFile, pos, insert, options);
|
||||
}
|
||||
|
||||
private insertStatementsInNewFile(fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], oldFile?: SourceFile): void {
|
||||
public insertStatementsInNewFile(fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], oldFile?: SourceFile): void {
|
||||
if (!this.newFileChanges) {
|
||||
this.newFileChanges = createMultiMap<string, NewFileInsertion>();
|
||||
}
|
||||
|
||||
+55
-13
@@ -90,13 +90,16 @@ import {
|
||||
FunctionDeclaration,
|
||||
FunctionExpression,
|
||||
FunctionLikeDeclaration,
|
||||
FutureSourceFile,
|
||||
getAssignmentDeclarationKind,
|
||||
getCombinedNodeFlagsAlwaysIncludeJSDoc,
|
||||
getDirectoryPath,
|
||||
getEmitModuleKind,
|
||||
getEmitScriptTarget,
|
||||
getExternalModuleImportEqualsDeclarationExpression,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getImpliedNodeFormatForFile,
|
||||
getImpliedNodeFormatForFileWorker,
|
||||
getIndentString,
|
||||
getJSDocEnumTag,
|
||||
getLastChild,
|
||||
@@ -106,6 +109,7 @@ import {
|
||||
getModuleInstanceState,
|
||||
getNameOfDeclaration,
|
||||
getNodeId,
|
||||
getOriginalNode,
|
||||
getPackageNameFromTypesPackageName,
|
||||
getPathComponents,
|
||||
getRootDeclaration,
|
||||
@@ -166,6 +170,7 @@ import {
|
||||
isFileLevelUniqueName,
|
||||
isForInStatement,
|
||||
isForOfStatement,
|
||||
isFullSourceFile,
|
||||
isFunctionBlock,
|
||||
isFunctionDeclaration,
|
||||
isFunctionExpression,
|
||||
@@ -278,6 +283,7 @@ import {
|
||||
ModuleDeclaration,
|
||||
ModuleInstanceState,
|
||||
ModuleKind,
|
||||
ModuleResolutionHost,
|
||||
ModuleResolutionKind,
|
||||
ModuleSpecifierResolutionHost,
|
||||
moduleSpecifiers,
|
||||
@@ -2469,6 +2475,8 @@ export function createModuleSpecifierResolutionHost(program: Program, host: Lang
|
||||
getNearestAncestorDirectoryWithPackageJson: maybeBind(host, host.getNearestAncestorDirectoryWithPackageJson),
|
||||
getFileIncludeReasons: () => program.getFileIncludeReasons(),
|
||||
getCommonSourceDirectory: () => program.getCommonSourceDirectory(),
|
||||
getDefaultResolutionModeForFile: file => program.getDefaultResolutionModeForFile(file),
|
||||
getModeForResolutionAtIndex: (file, index) => program.getModeForResolutionAtIndex(file, index),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2521,13 +2529,13 @@ export function quotePreferenceFromString(str: StringLiteral, sourceFile: Source
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getQuotePreference(sourceFile: SourceFile, preferences: UserPreferences): QuotePreference {
|
||||
export function getQuotePreference(sourceFile: SourceFile | FutureSourceFile, preferences: UserPreferences): QuotePreference {
|
||||
if (preferences.quotePreference && preferences.quotePreference !== "auto") {
|
||||
return preferences.quotePreference === "single" ? QuotePreference.Single : QuotePreference.Double;
|
||||
}
|
||||
else {
|
||||
// ignore synthetic import added when importHelpers: true
|
||||
const firstModuleSpecifier = sourceFile.imports &&
|
||||
const firstModuleSpecifier = isFullSourceFile(sourceFile) && sourceFile.imports &&
|
||||
find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral;
|
||||
return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) : QuotePreference.Double;
|
||||
}
|
||||
@@ -2615,16 +2623,28 @@ 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 | FutureSourceFile, 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 existingImportStatements = filter(sourceFile.statements, importKindPredicate);
|
||||
const { comparer, isSorted } = OrganizeImports.getOrganizeImportsStringComparerWithDetection(existingImportStatements, preferences);
|
||||
const sortedNewImports = isArray(imports) ? stableSort(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports];
|
||||
if (!existingImportStatements.length) {
|
||||
changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween);
|
||||
if (!existingImportStatements?.length) {
|
||||
if (isFullSourceFile(sourceFile)) {
|
||||
changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween);
|
||||
}
|
||||
else {
|
||||
for (const newImport of sortedNewImports) {
|
||||
// Insert one at a time to send correct original source file for accurate text reuse
|
||||
// when some imports are cloned from existing ones in other files.
|
||||
changes.insertStatementsInNewFile(sourceFile.fileName, [newImport], getOriginalNode(newImport)?.getSourceFile());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (existingImportStatements && isSorted) {
|
||||
|
||||
Debug.assert(isFullSourceFile(sourceFile));
|
||||
if (existingImportStatements && isSorted) {
|
||||
for (const newImport of sortedNewImports) {
|
||||
const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex(existingImportStatements, newImport, comparer);
|
||||
if (insertionIndex === 0) {
|
||||
@@ -3749,7 +3769,7 @@ export interface PackageJsonImportFilter {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: UserPreferences, host: LanguageServiceHost): PackageJsonImportFilter {
|
||||
export function createPackageJsonImportFilter(fromFile: SourceFile | FutureSourceFile, preferences: UserPreferences, host: LanguageServiceHost): PackageJsonImportFilter {
|
||||
const packageJsons = (
|
||||
(host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) || getPackageJsonsVisibleToFile(fromFile.fileName, host)
|
||||
).filter(p => p.parseable);
|
||||
@@ -3848,7 +3868,7 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences:
|
||||
// from Node core modules or not. We can start by seeing if the user is actually using
|
||||
// any node core modules, as opposed to simply having @types/node accidentally as a
|
||||
// dependency of a dependency.
|
||||
if (isSourceFileJS(fromFile) && JsTyping.nodeCoreModules.has(moduleSpecifier)) {
|
||||
if (isFullSourceFile(fromFile) && isSourceFileJS(fromFile) && JsTyping.nodeCoreModules.has(moduleSpecifier)) {
|
||||
if (usesNodeCoreModules === undefined) {
|
||||
usesNodeCoreModules = consumesNodeCoreModules(fromFile);
|
||||
}
|
||||
@@ -4109,7 +4129,7 @@ export function isDeprecatedDeclaration(decl: Declaration) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function shouldUseUriStyleNodeCoreModules(file: SourceFile, program: Program): boolean {
|
||||
export function shouldUseUriStyleNodeCoreModules(file: SourceFile | FutureSourceFile, program: Program): boolean {
|
||||
const decisionFromFile = firstDefined(file.imports, node => {
|
||||
if (JsTyping.nodeCoreModules.has(node.text)) {
|
||||
return startsWith(node.text, "node:");
|
||||
@@ -4233,11 +4253,13 @@ export function fileShouldUseJavaScriptRequire(file: SourceFile | string, progra
|
||||
if (!hasJSFileExtension(fileName)) {
|
||||
return false;
|
||||
}
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const compilerOptions = typeof file === "string" ? program.getCompilerOptions() : program.getCompilerOptionsForFile(file);
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const impliedNodeFormat = typeof file === "string"
|
||||
? getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions)
|
||||
: file.impliedNodeFormat;
|
||||
const sourceFileLike = typeof file === "string" ? {
|
||||
fileName: file,
|
||||
impliedNodeFormat: getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions),
|
||||
} : file;
|
||||
const impliedNodeFormat = getImpliedNodeFormatForEmitWorker(sourceFileLike, compilerOptions);
|
||||
|
||||
if (impliedNodeFormat === ModuleKind.ESNext) {
|
||||
return false;
|
||||
@@ -4281,3 +4303,23 @@ export function isBlockLike(node: Node): node is BlockLike {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createFutureSourceFile(fileName: string, syntaxModuleIndicator: ModuleKind.ESNext | ModuleKind.CommonJS | undefined, program: Program, moduleResolutionHost: ModuleResolutionHost): FutureSourceFile {
|
||||
const result = getImpliedNodeFormatForFileWorker(fileName, program.getPackageJsonInfoCache?.(), moduleResolutionHost, program.getCompilerOptions());
|
||||
let impliedNodeFormat, packageJsonScope;
|
||||
if (typeof result === "object") {
|
||||
impliedNodeFormat = result.impliedNodeFormat;
|
||||
packageJsonScope = result.packageJsonScope;
|
||||
}
|
||||
return {
|
||||
path: toPath(fileName, program.getCurrentDirectory(), program.getCanonicalFileName),
|
||||
fileName,
|
||||
externalModuleIndicator: syntaxModuleIndicator === ModuleKind.ESNext ? true : undefined,
|
||||
commonJsModuleIndicator: syntaxModuleIndicator === ModuleKind.CommonJS ? true : undefined,
|
||||
impliedNodeFormat,
|
||||
packageJsonScope,
|
||||
statements: emptyArray,
|
||||
imports: emptyArray,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ import "./unittests/tsbuild/sample";
|
||||
import "./unittests/tsbuild/transitiveReferences";
|
||||
import "./unittests/tsbuildWatch/configFileErrors";
|
||||
import "./unittests/tsbuildWatch/demo";
|
||||
import "./unittests/tsbuildWatch/extends";
|
||||
import "./unittests/tsbuildWatch/libraryResolution";
|
||||
import "./unittests/tsbuildWatch/moduleResolution";
|
||||
import "./unittests/tsbuildWatch/noEmit";
|
||||
@@ -134,6 +135,7 @@ import "./unittests/tscWatch/projectsWithReferences";
|
||||
import "./unittests/tscWatch/resolutionCache";
|
||||
import "./unittests/tscWatch/resolveJsonModuleWithIncremental";
|
||||
import "./unittests/tscWatch/sourceOfProjectReferenceRedirect";
|
||||
import "./unittests/tscWatch/symlinks";
|
||||
import "./unittests/tscWatch/watchApi";
|
||||
import "./unittests/tscWatch/watchEnvironment";
|
||||
import "./unittests/tsserver/applyChangesToOpenFiles";
|
||||
|
||||
@@ -55,34 +55,44 @@ describe("unittests:: canWatch::", () => {
|
||||
scenario: string,
|
||||
forPath: "node_modules" | "node_modules/@types" | "",
|
||||
) {
|
||||
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.`,
|
||||
(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);
|
||||
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);
|
||||
["file", "dir", "subDir"].forEach(type => {
|
||||
baselineCanWatch(
|
||||
`${scenario}In${type}`,
|
||||
() => `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, maxLength] as const;
|
||||
baselineCanWatchForRoot(paths, baseline, (rootPathCompoments, root) => {
|
||||
pushHeader(baseline, ["Location", "getDirectoryToWatchFailedLookupLocation", recursive, "Location if not symlink"], maxLengths);
|
||||
paths.forEach(path => {
|
||||
let subPath;
|
||||
switch (type) {
|
||||
case "file":
|
||||
subPath = "somefile.d.ts";
|
||||
break;
|
||||
case "dir":
|
||||
subPath = "dir/somefile.d.ts";
|
||||
break;
|
||||
case "subDir":
|
||||
subPath = "dir/subdir/somefile.d.ts";
|
||||
break;
|
||||
}
|
||||
const testPath = combinePaths(path, forPath, subPath);
|
||||
const result = ts.getDirectoryToWatchFailedLookupLocation(
|
||||
testPath,
|
||||
testPath,
|
||||
root,
|
||||
root,
|
||||
rootPathCompoments,
|
||||
ts.returnUndefined,
|
||||
);
|
||||
pushRow(baseline, [testPath, result ? result.packageDir ?? result.dir : "", result ? `${!result.nonRecursive}` : "", result?.packageDir ? result.dir : ""], maxLengths);
|
||||
});
|
||||
});
|
||||
});
|
||||
function baselineGetDirectoryToWatchFailedLookupLocation(path: ts.Path, root: ts.Path, rootPathCompoments: Readonly<ts.PathPathComponents>, maxLengths: readonly number[]) {
|
||||
const result = ts.getDirectoryToWatchFailedLookupLocation(
|
||||
path,
|
||||
path,
|
||||
root,
|
||||
root,
|
||||
rootPathCompoments,
|
||||
ts.returnUndefined,
|
||||
);
|
||||
pushRow(baseline, [path, result ? result.dir : "", result ? `${!result.nonRecursive}` : ""], maxLengths);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
baselineCanWatch(
|
||||
|
||||
@@ -253,6 +253,46 @@ function createFileSystem(ignoreCase: boolean, cwd: string, root: string) {
|
||||
},
|
||||
}),
|
||||
"dev/extendsArrayFails2.json": jsonToReadableText({ extends: [42] }),
|
||||
"dev/configs/template.json": jsonToReadableText({
|
||||
include: ["${configDir}/../supplemental.*"], // eslint-disable-line no-template-curly-in-string
|
||||
files: ["${configDir}/main.ts"], // eslint-disable-line no-template-curly-in-string,
|
||||
compilerOptions: {
|
||||
declarationDir: "${configDir}/decls", // eslint-disable-line no-template-curly-in-string
|
||||
rootDirs: ["root1", "${configDir}/root2", "root3"], // eslint-disable-line no-template-curly-in-string
|
||||
paths: {
|
||||
"something": ["${configDir}/something"], // eslint-disable-line no-template-curly-in-string
|
||||
"something/*": ["${configDir}/something/*"], // eslint-disable-line no-template-curly-in-string
|
||||
"other/*": ["./other/*"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
"dev/configs/templateandextends.json": jsonToReadableText({
|
||||
extends: "./first/templateextends.json",
|
||||
compilerOptions: {
|
||||
strict: true,
|
||||
baseUrl: "./src",
|
||||
},
|
||||
}),
|
||||
"dev/configs/first/templateextends.json": jsonToReadableText({
|
||||
extends: "../second/templateextends.json",
|
||||
include: ["${configDir}/../supplemental.*"], // eslint-disable-line no-template-curly-in-string
|
||||
compilerOptions: {
|
||||
rootDirs: ["root1", "${configDir}/root2", "root3"], // eslint-disable-line no-template-curly-in-string
|
||||
},
|
||||
}),
|
||||
"dev/configs/second/templateextends.json": jsonToReadableText({
|
||||
files: ["${configDir}/main.ts"], // eslint-disable-line no-template-curly-in-string,
|
||||
compilerOptions: {
|
||||
outDir: "./insecond",
|
||||
declarationDir: "${configDir}/decls", // eslint-disable-line no-template-curly-in-string
|
||||
paths: {
|
||||
"something": ["${configDir}/something"], // eslint-disable-line no-template-curly-in-string
|
||||
"something/*": ["${configDir}/something/*"], // eslint-disable-line no-template-curly-in-string
|
||||
"other/*": ["./other/*"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -302,6 +342,9 @@ describe("unittests:: config:: configurationExtension", () => {
|
||||
baselineParsedCommandLine("can report missing configurations", "extendsArrayFails.json");
|
||||
baselineParsedCommandLine("can error when 'extends' is not a string or Array2", "extendsArrayFails2.json");
|
||||
|
||||
baselineParsedCommandLine("handle configDir template", "configs/template.json");
|
||||
baselineParsedCommandLine("handle configDir template", "configs/templateandextends.json");
|
||||
|
||||
baselineParseConfig({
|
||||
scenario: "configurationExtension",
|
||||
subScenario: testName,
|
||||
@@ -317,7 +360,7 @@ describe("unittests:: config:: configurationExtension", () => {
|
||||
baseline.push("CompilerOptions::");
|
||||
baseline.push(jsonToReadableText(parsed.options));
|
||||
baseline.push("FileNames::");
|
||||
baseline.push(parsed.fileNames.join());
|
||||
baseline.push(...parsed.fileNames);
|
||||
},
|
||||
})),
|
||||
skipFs: true,
|
||||
|
||||
@@ -15,9 +15,9 @@ function getParsedCommandJson(
|
||||
return ts.parseJsonConfigFileContent(
|
||||
parsed.config,
|
||||
host,
|
||||
basePath ?? host.sys.getCurrentDirectory(),
|
||||
basePath ?? ts.getNormalizedAbsolutePath(ts.getDirectoryPath(configFileName), host.sys.getCurrentDirectory()),
|
||||
existingOptions,
|
||||
configFileName,
|
||||
ts.getNormalizedAbsolutePath(configFileName, host.sys.getCurrentDirectory()),
|
||||
/*resolutionStack*/ undefined,
|
||||
/*extraFileExtensions*/ undefined,
|
||||
/*extendedConfigCache*/ undefined,
|
||||
@@ -37,9 +37,9 @@ function getParsedCommandJsonSourceFile(
|
||||
return ts.parseJsonSourceFileConfigFileContent(
|
||||
parsed,
|
||||
host,
|
||||
basePath ?? host.sys.getCurrentDirectory(),
|
||||
basePath ?? ts.getNormalizedAbsolutePath(ts.getDirectoryPath(configFileName), host.sys.getCurrentDirectory()),
|
||||
existingOptions,
|
||||
configFileName,
|
||||
ts.getNormalizedAbsolutePath(configFileName, host.sys.getCurrentDirectory()),
|
||||
/*resolutionStack*/ undefined,
|
||||
/*extraFileExtensions*/ undefined,
|
||||
/*extendedConfigCache*/ undefined,
|
||||
|
||||
@@ -115,6 +115,21 @@ describe("unittests:: config:: showConfig", () => {
|
||||
],
|
||||
});
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with configDir template template", ["-p", "tsconfig.json"], {
|
||||
compilerOptions: {
|
||||
outDir: "${configDir}/outDir", // eslint-disable-line no-template-curly-in-string
|
||||
typeRoots: ["root1", "${configDir}/root2", "root3"], // eslint-disable-line no-template-curly-in-string
|
||||
paths: {
|
||||
"@myscope/*": ["${configDir}/types/*"], // eslint-disable-line no-template-curly-in-string
|
||||
"other/*": ["other/*"],
|
||||
},
|
||||
},
|
||||
include: [
|
||||
"${configDir}/src/**/*", // eslint-disable-line no-template-curly-in-string
|
||||
],
|
||||
files: ["${configDir}/main.ts"], // eslint-disable-line no-template-curly-in-string
|
||||
});
|
||||
|
||||
// Bulk validation of all option declarations
|
||||
for (const option of ts.optionDeclarations) {
|
||||
baselineOption(option, /*isCompilerOptions*/ true);
|
||||
|
||||
@@ -97,6 +97,18 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
json: {
|
||||
extends: "./base/tsconfig.json",
|
||||
},
|
||||
additionalFiles: {
|
||||
"/base/tsconfig.json": jsonToReadableText({
|
||||
watchOptions: {
|
||||
excludeFiles: ["${configDir}/temp/*.ts"], // eslint-disable-line no-template-curly-in-string
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
verifyWatchOptions("different options", () => [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
import { jsonToReadableText } from "../helpers";
|
||||
import { FsContents } from "./contents";
|
||||
import {
|
||||
createServerHost,
|
||||
createWatchedSystem,
|
||||
@@ -31,3 +32,70 @@ export function getSymlinkedExtendsSys(forTsserver?: true): TestServerHost {
|
||||
[libFile.path]: libFile.content,
|
||||
}, { currentDirectory: "/users/user/projects/myproject" });
|
||||
}
|
||||
|
||||
export function getConfigDirExtendsSys(): FsContents {
|
||||
return {
|
||||
"/home/src/projects/configs/first/tsconfig.json": jsonToReadableText({
|
||||
extends: "../second/tsconfig.json",
|
||||
include: ["${configDir}/src"], // eslint-disable-line no-template-curly-in-string
|
||||
compilerOptions: {
|
||||
typeRoots: ["root1", "${configDir}/root2", "root3"], // eslint-disable-line no-template-curly-in-string
|
||||
types: [],
|
||||
},
|
||||
}),
|
||||
"/home/src/projects/configs/second/tsconfig.json": jsonToReadableText({
|
||||
files: ["${configDir}/main.ts"], // eslint-disable-line no-template-curly-in-string,
|
||||
compilerOptions: {
|
||||
declarationDir: "${configDir}/decls", // eslint-disable-line no-template-curly-in-string
|
||||
paths: {
|
||||
"@myscope/*": ["${configDir}/types/*"], // eslint-disable-line no-template-curly-in-string
|
||||
"other/*": ["other/*"],
|
||||
},
|
||||
baseUrl: "${configDir}", // eslint-disable-line no-template-curly-in-string
|
||||
},
|
||||
watchOptions: {
|
||||
excludeFiles: ["${configDir}/main.ts"], // eslint-disable-line no-template-curly-in-string
|
||||
},
|
||||
}),
|
||||
"/home/src/projects/myproject/tsconfig.json": jsonToReadableText({
|
||||
extends: "../configs/first/tsconfig.json",
|
||||
compilerOptions: {
|
||||
declaration: true,
|
||||
outDir: "outDir",
|
||||
traceResolution: true,
|
||||
},
|
||||
}),
|
||||
|
||||
"/home/src/projects/myproject/main.ts": dedent`
|
||||
// some comment
|
||||
export const y = 10;
|
||||
import { x } from "@myscope/sometype";
|
||||
`,
|
||||
"/home/src/projects/myproject/src/secondary.ts": dedent`
|
||||
// some comment
|
||||
export const z = 10;
|
||||
import { k } from "other/sometype2";
|
||||
`,
|
||||
"/home/src/projects/myproject/types/sometype.ts": dedent`
|
||||
export const x = 10;
|
||||
`,
|
||||
"/home/src/projects/myproject/root2/other/sometype2/index.d.ts": dedent`
|
||||
export const k = 10;
|
||||
`,
|
||||
[libFile.path]: libFile.content,
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyFirstExtendedConfigOfConfigDirExtendsSys(sys: TestServerHost) {
|
||||
sys.modifyFile(
|
||||
"/home/src/projects/configs/first/tsconfig.json",
|
||||
jsonToReadableText({
|
||||
extends: "../second/tsconfig.json",
|
||||
include: ["${configDir}/src"], // eslint-disable-line no-template-curly-in-string
|
||||
compilerOptions: {
|
||||
typeRoots: ["${configDir}/root2"], // eslint-disable-line no-template-curly-in-string
|
||||
types: [],
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
import { jsonToReadableText } from "../helpers";
|
||||
import { libContent } from "./contents";
|
||||
import { solutionBuildWithBaseline } from "./solutionBuilder";
|
||||
import {
|
||||
createServerHost,
|
||||
createWatchedSystem,
|
||||
TestServerHost,
|
||||
TestServerHostOsFlavor,
|
||||
} from "./virtualFileSystemWithWatch";
|
||||
|
||||
export function getMonorepoSymlinkedSiblingPackagesSys(forTsserver: boolean, built: boolean, osFlavor?: TestServerHostOsFlavor): TestServerHost {
|
||||
const configText = jsonToReadableText({
|
||||
compilerOptions: {
|
||||
target: "es2016",
|
||||
module: "commonjs",
|
||||
rootDir: "./src",
|
||||
declaration: true,
|
||||
outDir: "./dist",
|
||||
esModuleInterop: true,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
strict: true,
|
||||
skipLibCheck: true,
|
||||
traceResolution: true,
|
||||
},
|
||||
exclude: [
|
||||
"tests/**/*",
|
||||
"dist/**/*",
|
||||
],
|
||||
});
|
||||
const sys = (!forTsserver ? createWatchedSystem : createServerHost)({
|
||||
"/home/src/projects/project/packages/package1/package.json": getPackageJson("package1"),
|
||||
"/home/src/projects/project/packages/package1/tsconfig.json": configText,
|
||||
"/home/src/projects/project/packages/package1/src/index.ts": dedent`
|
||||
export type FooType = "foo";
|
||||
export type BarType = "bar";
|
||||
`,
|
||||
"/home/src/projects/project/packages/package2/package.json": getPackageJson("package2"),
|
||||
"/home/src/projects/project/packages/package2/tsconfig.json": configText,
|
||||
"/home/src/projects/project/packages/package2/src/index.ts": dedent`
|
||||
import { FooType, BarType } from "package1"
|
||||
type MyFooType = FooType;
|
||||
type MyBarType = BarType;
|
||||
`,
|
||||
"/home/src/projects/project/node_modules/package1": { symLink: "/home/src/projects/project/packages/package1" },
|
||||
"/a/lib/lib.es2016.full.d.ts": libContent,
|
||||
}, { currentDirectory: "/home/src/projects/project", osFlavor });
|
||||
if (built) buildMonorepoSymlinkedSiblingPackage1(sys);
|
||||
return sys;
|
||||
}
|
||||
|
||||
function getPackageJson(packageName: string) {
|
||||
return jsonToReadableText({
|
||||
name: packageName,
|
||||
version: "1.0.0",
|
||||
main: "dist/index.js",
|
||||
});
|
||||
}
|
||||
|
||||
export function buildMonorepoSymlinkedSiblingPackage1(host: TestServerHost) {
|
||||
solutionBuildWithBaseline(host, ["packages/package1"]);
|
||||
}
|
||||
|
||||
export function cleanMonorepoSymlinkedSiblingPackage1(host: TestServerHost) {
|
||||
host.deleteFolder("/home/src/projects/project/packages/package1/dist", /*recursive*/ true);
|
||||
}
|
||||
@@ -35,21 +35,27 @@ export function ensureErrorFreeBuild(host: TestServerHost, rootNames: readonly s
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
solutionBuilder.build();
|
||||
sys.readFile = originalReadFile;
|
||||
sys.write = originalWrite;
|
||||
sys.writeFile = originalWriteFile;
|
||||
sys.writtenFiles = undefined;
|
||||
return sys;
|
||||
if (sys.writtenFiles === undefined) {
|
||||
const originalReadFile = sys.readFile;
|
||||
const originalWrite = sys.write;
|
||||
const originalWriteFile = sys.writeFile;
|
||||
const solutionBuilder = createSolutionBuilder(
|
||||
changeToHostTrackingWrittenFiles(
|
||||
fakes.patchHostForBuildInfoReadWrite(sys),
|
||||
),
|
||||
solutionRoots,
|
||||
originalRead,
|
||||
);
|
||||
solutionBuilder.build();
|
||||
sys.readFile = originalReadFile;
|
||||
sys.write = originalWrite;
|
||||
sys.writeFile = originalWriteFile;
|
||||
sys.writtenFiles = undefined;
|
||||
return sys;
|
||||
}
|
||||
else {
|
||||
const solutionBuilder = createSolutionBuilder(sys, solutionRoots);
|
||||
solutionBuilder.build();
|
||||
return sys;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createLoggerWithInMemoryLogs,
|
||||
LoggerWithInMemoryLogs,
|
||||
} from "../../../harness/tsserverLogger";
|
||||
import { patchHostForBuildInfoReadWrite } from "../../_namespaces/fakes";
|
||||
import * as Harness from "../../_namespaces/Harness";
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { ensureErrorFreeBuild } from "./solutionBuilder";
|
||||
@@ -126,7 +127,7 @@ export class TestSession extends ts.server.Session {
|
||||
if (typingsInstaller) typingsInstaller.session = this;
|
||||
this.serverCancellationToken = cancellationToken as TestServerCancellationToken;
|
||||
patchHostTimeouts(
|
||||
changeToHostTrackingWrittenFiles(this.host),
|
||||
changeToHostTrackingWrittenFiles(patchHostForBuildInfoReadWrite(this.host)),
|
||||
this,
|
||||
this.logger,
|
||||
);
|
||||
|
||||
@@ -1203,3 +1203,16 @@ export function changeToHostTrackingWrittenFiles(inputHost: TestServerHost) {
|
||||
};
|
||||
return host;
|
||||
}
|
||||
|
||||
export function osFlavorToString(osFlavor: TestServerHostOsFlavor) {
|
||||
switch (osFlavor) {
|
||||
case TestServerHostOsFlavor.Windows:
|
||||
return "Windows";
|
||||
case TestServerHostOsFlavor.MacOs:
|
||||
return "MacOs";
|
||||
case TestServerHostOsFlavor.Linux:
|
||||
return "Linux";
|
||||
default:
|
||||
Debug.assertNever(osFlavor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
createWatchedSystem,
|
||||
FileOrFolderOrSymLinkMap,
|
||||
osFlavorToString,
|
||||
TestServerHostOsFlavor,
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
describe("unittests:: sys:: symlinkWatching::", () => {
|
||||
@@ -148,19 +149,6 @@ describe("unittests:: sys:: symlinkWatching::", () => {
|
||||
(ts.isString(expected.event) ? actual.event === expected.event : ts.contains(expected.event, actual.event));
|
||||
}
|
||||
|
||||
function osFlavorToString(osFlavor: TestServerHostOsFlavor) {
|
||||
switch (osFlavor) {
|
||||
case TestServerHostOsFlavor.Windows:
|
||||
return "Windows";
|
||||
case TestServerHostOsFlavor.MacOs:
|
||||
return "MacOs";
|
||||
case TestServerHostOsFlavor.Linux:
|
||||
return "Linux";
|
||||
default:
|
||||
ts.Debug.assertNever(osFlavor);
|
||||
}
|
||||
}
|
||||
|
||||
interface FsEventsForWatchDirectory extends Record<string, readonly ExpectedEventAndFileName[] | undefined> {
|
||||
// The first time events are most of the time are not predictable, so just create random file for that reason
|
||||
init?: readonly ExpectedEventAndFileName[];
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { getSymlinkedExtendsSys } from "../helpers/extends";
|
||||
import {
|
||||
getConfigDirExtendsSys,
|
||||
getSymlinkedExtendsSys,
|
||||
} from "../helpers/extends";
|
||||
import { verifyTsc } from "../helpers/tsc";
|
||||
import { verifyTscWatch } from "../helpers/tscWatch";
|
||||
import { loadProjectFromFiles } from "../helpers/vfs";
|
||||
|
||||
describe("unittests:: tsbuild:: extends::", () => {
|
||||
verifyTscWatch({
|
||||
@@ -8,4 +13,11 @@ describe("unittests:: tsbuild:: extends::", () => {
|
||||
sys: getSymlinkedExtendsSys,
|
||||
commandLineArgs: ["-b", "src", "--extendedDiagnostics"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template",
|
||||
fs: () => loadProjectFromFiles(getConfigDirExtendsSys(), { cwd: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-b", "/home/src/projects/myproject", "--explainFiles", "--v"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import {
|
||||
getConfigDirExtendsSys,
|
||||
modifyFirstExtendedConfigOfConfigDirExtendsSys,
|
||||
} from "../helpers/extends";
|
||||
import { verifyTscWatch } from "../helpers/tscWatch";
|
||||
import { createWatchedSystem } from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsbuildWatch:: watchMode:: extends::", () => {
|
||||
verifyTscWatch({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template",
|
||||
sys: () => createWatchedSystem(getConfigDirExtendsSys(), { currentDirectory: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-b", "-w", "--extendedDiagnostics", "--explainFiles", "-v"],
|
||||
edits: [{
|
||||
caption: "edit extended config file",
|
||||
edit: modifyFirstExtendedConfigOfConfigDirExtendsSys,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}],
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,10 @@
|
||||
import { getSymlinkedExtendsSys } from "../helpers/extends";
|
||||
import {
|
||||
getConfigDirExtendsSys,
|
||||
getSymlinkedExtendsSys,
|
||||
} from "../helpers/extends";
|
||||
import { verifyTsc } from "../helpers/tsc";
|
||||
import { verifyTscWatch } from "../helpers/tscWatch";
|
||||
import { loadProjectFromFiles } from "../helpers/vfs";
|
||||
|
||||
describe("unittests:: tsc:: extends::", () => {
|
||||
verifyTscWatch({
|
||||
@@ -8,4 +13,25 @@ describe("unittests:: tsc:: extends::", () => {
|
||||
sys: getSymlinkedExtendsSys,
|
||||
commandLineArgs: ["-p", "src", "--extendedDiagnostics"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template",
|
||||
fs: () => loadProjectFromFiles(getConfigDirExtendsSys(), { cwd: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-p", "/home/src/projects/myproject", "--explainFiles"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template showConfig",
|
||||
fs: () => loadProjectFromFiles(getConfigDirExtendsSys(), { cwd: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-p", "/home/src/projects/myproject", "--showConfig"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template with commandline",
|
||||
fs: () => loadProjectFromFiles(getConfigDirExtendsSys(), { cwd: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-p", "/home/src/projects/myproject", "--explainFiles", "--outDir", "${configDir}/outDir"], // eslint-disable-line no-template-curly-in-string
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,6 +44,51 @@ describe("unittests:: tsc:: projectReferences::", () => {
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "default import interop uses referenced project settings",
|
||||
fs: () =>
|
||||
loadProjectFromFiles({
|
||||
"/node_modules/ambiguous-package/package.json": `{ "name": "ambiguous-package" }`,
|
||||
"/node_modules/ambiguous-package/index.d.ts": "export declare const ambiguous: number;",
|
||||
"/node_modules/esm-package/package.json": `{ "name": "esm-package", "type": "module" }`,
|
||||
"/node_modules/esm-package/index.d.ts": "export declare const esm: number;",
|
||||
"/lib/tsconfig.json": jsonToReadableText({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
declaration: true,
|
||||
rootDir: "src",
|
||||
outDir: "dist",
|
||||
module: "esnext",
|
||||
moduleResolution: "bundler",
|
||||
},
|
||||
include: ["src"],
|
||||
}),
|
||||
"/lib/src/a.ts": "export const a = 0;",
|
||||
"/lib/dist/a.d.ts": "export declare const a = 0;",
|
||||
"/app/tsconfig.json": jsonToReadableText({
|
||||
compilerOptions: {
|
||||
module: "esnext",
|
||||
moduleResolution: "bundler",
|
||||
rootDir: "src",
|
||||
outDir: "dist",
|
||||
},
|
||||
include: ["src"],
|
||||
references: [
|
||||
{ path: "../lib" },
|
||||
],
|
||||
}),
|
||||
"/app/src/local.ts": "export const local = 0;",
|
||||
"/app/src/index.ts": `
|
||||
import local from "./local"; // Error
|
||||
import esm from "esm-package"; // Error
|
||||
import referencedSource from "../../lib/src/a"; // Error
|
||||
import referencedDeclaration from "../../lib/dist/a"; // Error
|
||||
import ambiguous from "ambiguous-package"; // Ok`,
|
||||
}),
|
||||
commandLineArgs: ["--p", "app", "--pretty", "false"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "referencing ambient const enum from referenced project with preserveConstEnums",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { getSymlinkedExtendsSys } from "../helpers/extends";
|
||||
import {
|
||||
getConfigDirExtendsSys,
|
||||
getSymlinkedExtendsSys,
|
||||
modifyFirstExtendedConfigOfConfigDirExtendsSys,
|
||||
} from "../helpers/extends";
|
||||
import { verifyTscWatch } from "../helpers/tscWatch";
|
||||
import { createWatchedSystem } from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsc-watch:: extends::", () => {
|
||||
verifyTscWatch({
|
||||
@@ -8,4 +13,16 @@ describe("unittests:: tsc-watch:: extends::", () => {
|
||||
sys: getSymlinkedExtendsSys,
|
||||
commandLineArgs: ["-w", "-p", "src", "--extendedDiagnostics"],
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario: "extends",
|
||||
subScenario: "configDir template",
|
||||
sys: () => createWatchedSystem(getConfigDirExtendsSys(), { currentDirectory: "/home/src/projects/myproject" }),
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics", "--explainFiles"],
|
||||
edits: [{
|
||||
caption: "edit extended config file",
|
||||
edit: modifyFirstExtendedConfigOfConfigDirExtendsSys,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -178,19 +178,19 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
|
||||
version: system.createHash(libFile.content),
|
||||
signature: system.createHash(libFile.content),
|
||||
affectsGlobalScope: true,
|
||||
impliedFormat: undefined,
|
||||
impliedFormat: ts.ModuleKind.CommonJS,
|
||||
});
|
||||
assert.deepEqual(state.fileInfos.get(file1.path as ts.Path), {
|
||||
version: system.createHash(file1.content),
|
||||
signature: system.createHash(file1.content),
|
||||
affectsGlobalScope: undefined,
|
||||
impliedFormat: undefined,
|
||||
impliedFormat: ts.ModuleKind.CommonJS,
|
||||
});
|
||||
assert.deepEqual(state.fileInfos.get(file2.path as ts.Path), {
|
||||
version: system.createHash(fileModified.content),
|
||||
signature: system.createHash(fileModified.content),
|
||||
affectsGlobalScope: undefined,
|
||||
impliedFormat: undefined,
|
||||
impliedFormat: ts.ModuleKind.CommonJS,
|
||||
});
|
||||
|
||||
assert.deepEqual(state.compilerOptions, {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
buildMonorepoSymlinkedSiblingPackage1,
|
||||
cleanMonorepoSymlinkedSiblingPackage1,
|
||||
getMonorepoSymlinkedSiblingPackagesSys,
|
||||
} from "../helpers/monorepoSymlinkedSiblingPackages";
|
||||
import {
|
||||
noopChange,
|
||||
verifyTscWatch,
|
||||
} from "../helpers/tscWatch";
|
||||
import {
|
||||
osFlavorToString,
|
||||
TestServerHostOsFlavor,
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsc-watch:: symlinks::", () => {
|
||||
describe("monorepoSymlinkedSiblingPackages:: monorepo style sibling packages symlinked", () => {
|
||||
verify(/*built*/ false);
|
||||
verify(/*built*/ true);
|
||||
verify(/*built*/ false, TestServerHostOsFlavor.Linux);
|
||||
verify(/*built*/ true, TestServerHostOsFlavor.Linux);
|
||||
function verify(built: boolean, osFlavor?: TestServerHostOsFlavor) {
|
||||
verifyTscWatch({
|
||||
scenario: "symlinks",
|
||||
subScenario: `monorepo style sibling packages symlinked${built ? " package1 built" : ""}${osFlavor ? ` ${osFlavorToString(osFlavor)}` : ""}`,
|
||||
commandLineArgs: ["--w", "-p", "packages/package2", "--extendedDiagnostics"],
|
||||
sys: () => getMonorepoSymlinkedSiblingPackagesSys(/*forTsserver*/ false, built, osFlavor),
|
||||
edits: [
|
||||
built ? noopChange : {
|
||||
caption: "Build package1",
|
||||
edit: buildMonorepoSymlinkedSiblingPackage1,
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "Clean package1 build",
|
||||
edit: cleanMonorepoSymlinkedSiblingPackage1,
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
osFlavor === TestServerHostOsFlavor.Linux ? {
|
||||
caption: "After updating childs",
|
||||
edit: noopChange.edit,
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
} : noopChange,
|
||||
{
|
||||
caption: "Build package1",
|
||||
edit: buildMonorepoSymlinkedSiblingPackage1,
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -46,7 +46,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu
|
||||
system: sys,
|
||||
cb,
|
||||
});
|
||||
const parsedCommandResult = ts.parseJsonConfigFileContent(configFileJson, sys, config.path);
|
||||
const parsedCommandResult = ts.parseJsonConfigFileContent(configFileJson, sys, ts.getDirectoryPath(config.path));
|
||||
host.resolveModuleNames = (moduleNames, containingFile) =>
|
||||
moduleNames.map(m => {
|
||||
const result = ts.resolveModuleName(m, containingFile, parsedCommandResult.options, host);
|
||||
|
||||
@@ -188,50 +188,74 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
|
||||
|
||||
verifyRenamingFileInSubFolder("uses non recursive dynamic polling when renaming file in subfolder", Tsc_WatchDirectory.DynamicPolling);
|
||||
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: "watchDirectories/when there are symlinks to folders in recursive folders",
|
||||
commandLineArgs: ["--w"],
|
||||
sys: () => {
|
||||
const cwd = "/home/user/projects/myproject";
|
||||
const file1: File = {
|
||||
path: `${cwd}/src/file.ts`,
|
||||
content: `import * as a from "a"`,
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${cwd}/tsconfig.json`,
|
||||
content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}`,
|
||||
};
|
||||
const realA: File = {
|
||||
path: `${cwd}/node_modules/reala/index.d.ts`,
|
||||
content: `export {}`,
|
||||
};
|
||||
const realB: File = {
|
||||
path: `${cwd}/node_modules/realb/index.d.ts`,
|
||||
content: `export {}`,
|
||||
};
|
||||
const symLinkA: SymLink = {
|
||||
path: `${cwd}/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/reala`,
|
||||
};
|
||||
const symLinkB: SymLink = {
|
||||
path: `${cwd}/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/realb`,
|
||||
};
|
||||
const symLinkBInA: SymLink = {
|
||||
path: `${cwd}/node_modules/reala/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/b`,
|
||||
};
|
||||
const symLinkAInB: SymLink = {
|
||||
path: `${cwd}/node_modules/realb/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/a`,
|
||||
};
|
||||
const files = [libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
|
||||
const environmentVariables = new Map<string, string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory);
|
||||
return createWatchedSystem(files, { osFlavor: TestServerHostOsFlavor.Linux, environmentVariables, currentDirectory: cwd });
|
||||
},
|
||||
});
|
||||
function verifySymlinks(synchronousWatchDirectory: boolean) {
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchDirectories/when there are symlinks to folders in recursive folders${synchronousWatchDirectory ? " with synchronousWatchDirectory" : ""}`,
|
||||
commandLineArgs: ["--w"],
|
||||
sys: () => {
|
||||
const cwd = "/home/user/projects/myproject";
|
||||
const file1: File = {
|
||||
path: `${cwd}/src/file.ts`,
|
||||
content: `import * as a from "a"`,
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: `${cwd}/tsconfig.json`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: { extendedDiagnostics: true, traceResolution: true },
|
||||
watchOptions: synchronousWatchDirectory ? { synchronousWatchDirectory } : undefined,
|
||||
}),
|
||||
};
|
||||
const realA: File = {
|
||||
path: `${cwd}/node_modules/reala/index.d.ts`,
|
||||
content: `export {}`,
|
||||
};
|
||||
const realB: File = {
|
||||
path: `${cwd}/node_modules/realb/index.d.ts`,
|
||||
content: `export {}`,
|
||||
};
|
||||
const symLinkA: SymLink = {
|
||||
path: `${cwd}/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/reala`,
|
||||
};
|
||||
const symLinkB: SymLink = {
|
||||
path: `${cwd}/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/realb`,
|
||||
};
|
||||
const symLinkBInA: SymLink = {
|
||||
path: `${cwd}/node_modules/reala/node_modules/b`,
|
||||
symLink: `${cwd}/node_modules/b`,
|
||||
};
|
||||
const symLinkAInB: SymLink = {
|
||||
path: `${cwd}/node_modules/realb/node_modules/a`,
|
||||
symLink: `${cwd}/node_modules/a`,
|
||||
};
|
||||
const files = [libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
|
||||
const environmentVariables = new Map<string, string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", Tsc_WatchDirectory.NonRecursiveWatchDirectory);
|
||||
return createWatchedSystem(files, { osFlavor: TestServerHostOsFlavor.Linux, environmentVariables, currentDirectory: cwd });
|
||||
},
|
||||
edits: [
|
||||
{
|
||||
caption: "delete reala/index.d.ts",
|
||||
edit: sys => sys.deleteFile("/home/user/projects/myproject/node_modules/reala/index.d.ts"),
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "timeouts if any",
|
||||
edit: ts.noop,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
{
|
||||
caption: "timeouts if any",
|
||||
edit: ts.noop,
|
||||
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
verifySymlinks(/*synchronousWatchDirectory*/ true);
|
||||
verifySymlinks(/*synchronousWatchDirectory*/ false);
|
||||
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { jsonToReadableText } from "../helpers";
|
||||
import { compilerOptionsToConfigJson } from "../helpers/contents";
|
||||
import { ensureErrorFreeBuild } from "../helpers/solutionBuilder";
|
||||
import {
|
||||
commonFile1,
|
||||
@@ -23,13 +24,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("create configured project without file list", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `
|
||||
{
|
||||
"compilerOptions": {},
|
||||
"exclude": [
|
||||
"e"
|
||||
]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {},
|
||||
exclude: ["e"],
|
||||
}),
|
||||
};
|
||||
const file1: File = {
|
||||
path: "/a/b/c/f1.ts",
|
||||
@@ -53,11 +51,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("create configured project with the file list", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `
|
||||
{
|
||||
"compilerOptions": {},
|
||||
"include": ["*.ts"]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {},
|
||||
include: ["*.ts"],
|
||||
}),
|
||||
};
|
||||
const file1: File = {
|
||||
path: "/a/b/f1.ts",
|
||||
@@ -81,9 +78,7 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("add and then remove a config file in a folder with loose files", () => {
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: `{
|
||||
"files": ["commonFile1.ts"]
|
||||
}`,
|
||||
content: jsonToReadableText({ files: ["commonFile1.ts"] }),
|
||||
};
|
||||
const commonFile1: File = {
|
||||
path: `/user/username/projects/myproject/commonFile1.ts`,
|
||||
@@ -97,6 +92,7 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
const host = createServerHost([libFile, commonFile1, commonFile2]);
|
||||
|
||||
const session = new TestSession(host);
|
||||
// 1: when both files are open
|
||||
openFilesForSession([commonFile1, commonFile2], session);
|
||||
|
||||
// Add a tsconfig file
|
||||
@@ -107,9 +103,139 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks(); // Refresh inferred projects
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks(); // load configured project from disk + ensureProjectsForOpenFiles
|
||||
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
// Check status when all files are closed
|
||||
closeFilesForSession([commonFile1, commonFile2, "/random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// 2: when file is opened while config file is deleted
|
||||
closeFilesForSession(["/random/random.ts"], session);
|
||||
openFilesForSession([commonFile1], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks(); // load configured project from disk + ensureProjectsForOpenFiles
|
||||
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
// Check status when all files are closed
|
||||
closeFilesForSession([commonFile1, commonFile2, "/random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
baselineTsserverLogs("configuredProjects", "add and then remove a config file in a folder with loose files", session);
|
||||
});
|
||||
|
||||
it("add and then remove a config file when parent folder has config file", () => {
|
||||
const configFile: File = {
|
||||
path: `/user/username/projects/myproject/folder/tsconfig.json`,
|
||||
content: jsonToReadableText({ files: ["commonFile1.ts"] }),
|
||||
};
|
||||
const parentConfigFile: File = {
|
||||
path: `/user/username/projects/myproject/tsconfig.json`,
|
||||
content: jsonToReadableText({ files: ["folder/commonFile2.ts"] }),
|
||||
};
|
||||
const commonFile1: File = {
|
||||
path: `/user/username/projects/myproject/folder/commonFile1.ts`,
|
||||
content: "let x = 1",
|
||||
};
|
||||
const commonFile2: File = {
|
||||
path: `/user/username/projects/myproject/folder/commonFile2.ts`,
|
||||
content: "let y = 1",
|
||||
};
|
||||
|
||||
const host = createServerHost([libFile, commonFile1, commonFile2, configFile, parentConfigFile]);
|
||||
|
||||
const session = new TestSession(host);
|
||||
|
||||
// 1: When config file is deleted and then another file is opened
|
||||
openFilesForSession([commonFile1], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
// Check the state after files collected
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// Check status when all files are closed
|
||||
closeFilesForSession([commonFile1, commonFile2, "/random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// 2: When both files are open and config file is deleted
|
||||
closeFilesForSession(["/random/random.ts"], session);
|
||||
openFilesForSession([commonFile1, commonFile2], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks(); // load configured project from disk + ensureProjectsForOpenFiles
|
||||
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
closeFilesForSession([commonFile1, commonFile2, "/random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// 3: Check when both files are closed when config file is deleted
|
||||
closeFilesForSession(["/random/random.ts"], session);
|
||||
openFilesForSession([commonFile1], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
// State after open files are closed
|
||||
closeFilesForSession([commonFile1, commonFile2], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// 4: Check when both files are closed one by one when file is deleted
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
closeFilesForSession(["/random/random.ts"], session);
|
||||
openFilesForSession([commonFile1], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
// State after open files are closed
|
||||
closeFilesForSession([commonFile1], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
closeFilesForSession([commonFile2, "random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// 5: Check when both files are closed one by one when file is deleted order changed
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
closeFilesForSession(["/random/random.ts"], session);
|
||||
openFilesForSession([commonFile1], session);
|
||||
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
// State after open files are closed
|
||||
closeFilesForSession([commonFile2], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
closeFilesForSession([commonFile1, "random/random.ts"], session);
|
||||
openFilesForSession([{ file: "/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
baselineTsserverLogs("configuredProjects", "add and then remove a config file when parent folder has config file", session);
|
||||
});
|
||||
|
||||
it("add new files to a configured project without file list", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
@@ -128,13 +254,13 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("should ignore non-existing files specified in the config file", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {},
|
||||
"files": [
|
||||
"commonFile1.ts",
|
||||
"commonFile3.ts"
|
||||
]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {},
|
||||
files: [
|
||||
"commonFile1.ts",
|
||||
"commonFile3.ts",
|
||||
],
|
||||
}),
|
||||
};
|
||||
const host = createServerHost([commonFile1, commonFile2, configFile]);
|
||||
const session = new TestSession(host);
|
||||
@@ -164,10 +290,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("files explicitly excluded in config file", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {},
|
||||
"exclude": ["/a/c"]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {},
|
||||
exclude: ["/a/c"],
|
||||
}),
|
||||
};
|
||||
const excludedFile1: File = {
|
||||
path: "/a/c/excluedFile1.ts",
|
||||
@@ -200,12 +326,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
};
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"files": ["${file1.path}"]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: compilerOptionsToConfigJson({ moduleResolution: ts.ModuleResolutionKind.Node10 }),
|
||||
files: [file1.path],
|
||||
}),
|
||||
};
|
||||
const files = [file1, nodeModuleFile, classicModuleFile, configFile, randomFile];
|
||||
const host = createServerHost(files);
|
||||
@@ -214,12 +338,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
|
||||
host.writeFile(
|
||||
configFile.path,
|
||||
`{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "classic"
|
||||
},
|
||||
"files": ["${file1.path}"]
|
||||
}`,
|
||||
jsonToReadableText({
|
||||
compilerOptions: compilerOptionsToConfigJson({ moduleResolution: ts.ModuleResolutionKind.Classic }),
|
||||
files: [file1.path],
|
||||
}),
|
||||
);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
@@ -240,12 +362,12 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
};
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"target": "es6"
|
||||
},
|
||||
"files": [ "main.ts" ]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {
|
||||
target: "es6",
|
||||
},
|
||||
files: ["main.ts"],
|
||||
}),
|
||||
};
|
||||
const host = createServerHost([file1, file2, configFile]);
|
||||
const session = new TestSession(host);
|
||||
@@ -258,13 +380,13 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
it("should tolerate config file errors and still try to build a project", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"allowAnything": true
|
||||
},
|
||||
"someOtherProperty": {}
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {
|
||||
target: "es6",
|
||||
allowAnything: true,
|
||||
},
|
||||
someOtherProperty: {},
|
||||
}),
|
||||
};
|
||||
const host = createServerHost([commonFile1, commonFile2, libFile, configFile]);
|
||||
const session = new TestSession(host);
|
||||
@@ -283,12 +405,12 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
};
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"target": "es6"
|
||||
},
|
||||
"files": [ "main.ts", "main2.ts" ]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {
|
||||
target: "es6",
|
||||
},
|
||||
files: ["main.ts", "main2.ts"],
|
||||
}),
|
||||
};
|
||||
const host = createServerHost([file1, file2, configFile, libFile]);
|
||||
const session = new TestSession({ host, useSingleInferredProject: true });
|
||||
@@ -305,12 +427,12 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => {
|
||||
};
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
content: `{
|
||||
"compilerOptions": {
|
||||
"target": "es6"
|
||||
},
|
||||
"files": [ "main.ts" ]
|
||||
}`,
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {
|
||||
target: "es6",
|
||||
},
|
||||
files: ["main.ts"],
|
||||
}),
|
||||
};
|
||||
const host = createServerHost([file1, configFile, libFile]);
|
||||
const session = new TestSession({ host, useSingleInferredProject: true });
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { getSymlinkedExtendsSys } from "../helpers/extends";
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import {
|
||||
getConfigDirExtendsSys,
|
||||
getSymlinkedExtendsSys,
|
||||
modifyFirstExtendedConfigOfConfigDirExtendsSys,
|
||||
} from "../helpers/extends";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
openFilesForSession,
|
||||
TestSession,
|
||||
} from "../helpers/tsserver";
|
||||
import { createServerHost } from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsserver:: extends::", () => {
|
||||
it("resolves the symlink path", () => {
|
||||
@@ -12,4 +18,21 @@ describe("unittests:: tsserver:: extends::", () => {
|
||||
openFilesForSession(["/users/user/projects/myproject/src/index.ts"], session);
|
||||
baselineTsserverLogs("tsserver", "resolves the symlink path", session);
|
||||
});
|
||||
|
||||
it("configDir template", () => {
|
||||
const host = createServerHost(getConfigDirExtendsSys(), { currentDirectory: "/home/src/projects/myproject" });
|
||||
const session = new TestSession(host);
|
||||
session.executeCommandSeq<ts.server.protocol.ConfigureRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Configure,
|
||||
arguments: {
|
||||
watchOptions: {
|
||||
excludeDirectories: ["${configDir}/node_modules"], // eslint-disable-line no-template-curly-in-string
|
||||
},
|
||||
},
|
||||
});
|
||||
openFilesForSession(["/home/src/projects/myproject/src/secondary.ts"], session);
|
||||
modifyFirstExtendedConfigOfConfigDirExtendsSys(host);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
baselineTsserverLogs("tsserver", "configDir template", session);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { defer } from "../../_namespaces/Utils";
|
||||
import {
|
||||
defer,
|
||||
Deferred,
|
||||
} from "../../_namespaces/Utils";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
closeFilesForSession,
|
||||
@@ -22,9 +25,11 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
const { host, session } = setup(["plugin-a"]);
|
||||
let pluginModuleInstantiated = false;
|
||||
let pluginInvoked = false;
|
||||
host.importPlugin = async (_root: string, _moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
host.importPlugin = async (_root: string, moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
session.logger.log(`request import ${moduleName}`);
|
||||
await Promise.resolve(); // simulate at least a single turn delay
|
||||
pluginModuleInstantiated = true;
|
||||
session.logger.log(`fulfill import ${moduleName}`);
|
||||
return {
|
||||
module: (() => {
|
||||
pluginInvoked = true;
|
||||
@@ -47,6 +52,7 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
session.logger.log(`pluginModuleInstantiated:: ${pluginModuleInstantiated}`);
|
||||
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("after waitForPendingPlugins");
|
||||
|
||||
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}`);
|
||||
@@ -85,14 +91,17 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
|
||||
// wait for load to complete
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("after waitForPendingPlugins ");
|
||||
|
||||
baselineTsserverLogs("pluginsAsync", "plugins evaluation in correct order even if imports resolve out of order", session);
|
||||
});
|
||||
|
||||
it("sends projectsUpdatedInBackground event", async () => {
|
||||
const { host, session } = setup(["plugin-a"]);
|
||||
host.importPlugin = async (_root: string, _moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
host.importPlugin = async (_root: string, moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
session.logger.log(`request import ${moduleName}`);
|
||||
await Promise.resolve(); // simulate at least a single turn delay
|
||||
session.logger.log(`fulfill import ${moduleName}`);
|
||||
return {
|
||||
module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory,
|
||||
error: undefined,
|
||||
@@ -103,6 +112,7 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("after waitForPendingPlugins");
|
||||
|
||||
baselineTsserverLogs("pluginsAsync", "sends projectsUpdatedInBackground event", session);
|
||||
});
|
||||
@@ -110,10 +120,11 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
it("adds external files", async () => {
|
||||
const { host, session } = setup(["plugin-a"]);
|
||||
const pluginAShouldLoad = defer();
|
||||
host.importPlugin = async (_root: string, _moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
host.importPlugin = async (_root: string, moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
session.logger.log(`request import ${moduleName}`);
|
||||
// wait until the initial external files are requested from the project service.
|
||||
await pluginAShouldLoad.promise;
|
||||
|
||||
session.logger.log(`fulfill import ${moduleName}`);
|
||||
return {
|
||||
module: (() => ({
|
||||
create: info => info.languageService,
|
||||
@@ -145,12 +156,16 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
const { host, session } = setup(["plugin-a"]);
|
||||
const pluginALoaded = defer();
|
||||
const projectClosed = defer();
|
||||
host.importPlugin = async (_root: string, _moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
host.importPlugin = async (_root: string, moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
session.logger.log(`request import ${moduleName}`);
|
||||
// mark that the plugin has started loading
|
||||
pluginALoaded.resolve();
|
||||
|
||||
// wait until after a project close has been requested to continue
|
||||
session.logger.log(`Awaiting project close`);
|
||||
await projectClosed.promise;
|
||||
|
||||
session.logger.log(`fulfill import ${moduleName}`);
|
||||
return {
|
||||
module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory,
|
||||
error: undefined,
|
||||
@@ -165,13 +180,75 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => {
|
||||
|
||||
// close the project
|
||||
closeFilesForSession(["^memfs:/foo.ts"], session);
|
||||
openFilesForSession([{ file: "/random/foo2.ts", content: "" }], session);
|
||||
|
||||
// continue loading the plugin
|
||||
projectClosed.resolve();
|
||||
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("before waitForPendingPlugins");
|
||||
await projectService.waitForPendingPlugins(); // For closed foo.ts
|
||||
session.host.baselineHost("after waitForPendingPlugins for closed foo.ts");
|
||||
await projectService.waitForPendingPlugins(); // For random file
|
||||
session.host.baselineHost("after waitForPendingPlugins for random file");
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
it("project is deferred closed before plugins are loaded", async () => {
|
||||
const config = "/home/src/projects/project/tsconfig.json";
|
||||
const file = "/home/src/projects/project/a.ts";
|
||||
const host = createServerHost({
|
||||
[config]: `{}`,
|
||||
[file]: "export const a = 10;",
|
||||
[libFile.path]: libFile.content,
|
||||
});
|
||||
const session = new TestSession({ host, globalPlugins: ["plugin-a"] });
|
||||
const pluginALoaded = defer();
|
||||
let configFileDeleted: Deferred<void> | undefined = defer();
|
||||
host.importPlugin = async (_root: string, moduleName: string): Promise<ts.server.ModuleImportResult> => {
|
||||
session.logger.log(`request import ${moduleName}`);
|
||||
// mark that the plugin has started loading
|
||||
pluginALoaded.resolve();
|
||||
// wait until after a project close has been requested to continue
|
||||
if (configFileDeleted) {
|
||||
session.logger.log(`awaiting config file delete`);
|
||||
await configFileDeleted.promise;
|
||||
}
|
||||
session.logger.log(`fulfill import ${moduleName}`);
|
||||
return {
|
||||
module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory,
|
||||
error: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
openFilesForSession([file], session);
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
// wait for the plugin to start loading
|
||||
await pluginALoaded.promise;
|
||||
|
||||
session.host.baselineHost("before deleteFile");
|
||||
// close the project
|
||||
host.deleteFile(config);
|
||||
session.host.baselineHost("after deleteFile");
|
||||
|
||||
// continue loading the plugin
|
||||
configFileDeleted.resolve();
|
||||
session.host.baselineHost("before waitForPendingPlugins");
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("after waitForPendingPlugins");
|
||||
|
||||
configFileDeleted = undefined;
|
||||
host.writeFile(config, "{}");
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
session.host.baselineHost("before enableRequestedPlugins");
|
||||
projectService.enableRequestedPlugins();
|
||||
session.host.baselineHost("before waitForPendingPlugins");
|
||||
await projectService.waitForPendingPlugins();
|
||||
session.host.baselineHost("after waitForPendingPlugins");
|
||||
|
||||
// the project was closed before plugins were ready. no project update should have been requested
|
||||
baselineTsserverLogs("pluginsAsync", "project is deferred closed before plugins are loaded", session);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
File,
|
||||
Folder,
|
||||
libFile,
|
||||
TestServerHostOsFlavor,
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsserver:: projectErrors::", () => {
|
||||
@@ -808,3 +809,27 @@ describe("unittests:: tsserver:: projectErrors:: with npm install when", () => {
|
||||
verifyNpmInstall(/*timeoutDuringPartialInstallation*/ false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsserver:: projectErrors:: with file rename on wsl2::", () => {
|
||||
it("rename a file", () => {
|
||||
const host = createServerHost({
|
||||
"/home/username/project/src/a.ts": `export const a = 10;`,
|
||||
"/home/username/project/src/b.ts": `export const b = 10;`,
|
||||
"/home/username/project/tsconfig.json": jsonToReadableText({
|
||||
compilerOptions: {
|
||||
strictNullChecks: true,
|
||||
},
|
||||
include: ["src/**/*.ts"],
|
||||
}),
|
||||
[libFile.path]: libFile.content,
|
||||
}, { osFlavor: TestServerHostOsFlavor.Linux });
|
||||
const session = new TestSession(host);
|
||||
openFilesForSession([{ file: "/home/username/project/src/a.ts", projectRootPath: "/home/username/project" }], session);
|
||||
host.renameFile("/home/username/project/src/b.ts", "/home/username/project/src/c.ts");
|
||||
openFilesForSession([{ file: "/home/username/project/src/c.ts", content: `export const b = 10;`, projectRootPath: "/home/username/project" }], session);
|
||||
host.runQueuedTimeoutCallbacks(); // Updates the project that c.ts now exists on the disk and schedules one more update
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
closeFilesForSession(["/home/username/project/src/c.ts"], session);
|
||||
baselineTsserverLogs("projectErrors", "file rename on wsl2", session);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1073,11 +1073,12 @@ export function bar() {}`,
|
||||
}
|
||||
|
||||
function verifySolutionScenario(input: Setup) {
|
||||
const { session } = setup(input);
|
||||
const { session, host } = setup(input);
|
||||
|
||||
const info = session.getProjectService().getScriptInfoForPath(main.path as ts.Path)!;
|
||||
const defaultProject = info.getDefaultProject();
|
||||
session.logger.startGroup();
|
||||
session.logger.info(`getDefaultProject for ${main.path}: ${info.getDefaultProject().projectName}`);
|
||||
session.logger.info(`getDefaultProject for ${main.path}: ${defaultProject.projectName}`);
|
||||
session.logger.info(`findDefaultConfiguredProject for ${main.path}: ${session.getProjectService().findDefaultConfiguredProject(info)!.projectName}`);
|
||||
session.logger.endGroup();
|
||||
|
||||
@@ -1093,6 +1094,24 @@ export function bar() {}`,
|
||||
closeFilesForSession([dummyFilePath], session);
|
||||
openFilesForSession([dummyFilePath], session);
|
||||
|
||||
// Verify that tsconfig can be deleted and watched
|
||||
if (ts.server.isConfiguredProject(defaultProject)) {
|
||||
closeFilesForSession([dummyFilePath], session);
|
||||
const config = defaultProject.projectName;
|
||||
const content = host.readFile(config)!;
|
||||
host.deleteFile(config);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
host.writeFile(config, content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
host.deleteFile(config);
|
||||
openFilesForSession([dummyFilePath], session);
|
||||
|
||||
host.writeFile(config, content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
}
|
||||
|
||||
// Verify Reload projects
|
||||
session.executeCommandSeq<ts.server.protocol.ReloadProjectsRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ReloadProjects,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
TestServerHost,
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsserver:: with project references and tsbuild source map", () => {
|
||||
describe("unittests:: tsserver:: projectReferencesSourcemap:: with project references and tsbuild source map", () => {
|
||||
const dependecyLocation = `/user/username/projects/myproject/dependency`;
|
||||
const dependecyDeclsLocation = `/user/username/projects/myproject/decls`;
|
||||
const mainLocation = `/user/username/projects/myproject/main`;
|
||||
@@ -71,10 +71,10 @@ fn5();
|
||||
|
||||
const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, libFile, randomFile, randomConfig];
|
||||
|
||||
function changeDtsFile(session: TestSession) {
|
||||
function changeDtsFile(session: TestSession, content?: string) {
|
||||
session.host.writeFile(
|
||||
dtsLocation,
|
||||
session.host.readFile(dtsLocation)!.replace(
|
||||
(content ?? session.host.readFile(dtsLocation)!).replace(
|
||||
"//# sourceMappingURL=FnS.d.ts.map",
|
||||
`export declare function fn6(): void;
|
||||
//# sourceMappingURL=FnS.d.ts.map`,
|
||||
@@ -147,14 +147,18 @@ fn5();
|
||||
function createSessionWithoutProjectReferences(onHostCreate?: OnHostCreate) {
|
||||
const host = createHostWithSolutionBuild(files, [mainConfig.path]);
|
||||
// Erase project reference
|
||||
writeConfigWithoutProjectReferences(host);
|
||||
onHostCreate?.(host);
|
||||
return new TestSession(host);
|
||||
}
|
||||
|
||||
function writeConfigWithoutProjectReferences(host: TestServerHost) {
|
||||
host.writeFile(
|
||||
mainConfig.path,
|
||||
jsonToReadableText({
|
||||
compilerOptions: { composite: true, declarationMap: true },
|
||||
}),
|
||||
);
|
||||
onHostCreate?.(host);
|
||||
return new TestSession(host);
|
||||
}
|
||||
|
||||
function createSessionWithProjectReferences(onHostCreate?: OnHostCreate) {
|
||||
@@ -166,6 +170,12 @@ fn5();
|
||||
function createSessionWithDisabledProjectReferences(onHostCreate?: OnHostCreate) {
|
||||
const host = createHostWithSolutionBuild(files, [mainConfig.path]);
|
||||
// Erase project reference
|
||||
WithDisabledProjectReferences(host);
|
||||
onHostCreate?.(host);
|
||||
return new TestSession(host);
|
||||
}
|
||||
|
||||
function WithDisabledProjectReferences(host: TestServerHost) {
|
||||
host.writeFile(
|
||||
mainConfig.path,
|
||||
jsonToReadableText({
|
||||
@@ -177,8 +187,6 @@ fn5();
|
||||
references: [{ path: "../dependency" }],
|
||||
}),
|
||||
);
|
||||
onHostCreate?.(host);
|
||||
return new TestSession(host);
|
||||
}
|
||||
|
||||
function makeChangeToMainTs(session: TestSession) {
|
||||
@@ -209,12 +217,28 @@ fn5();
|
||||
});
|
||||
}
|
||||
|
||||
function setup(type: SessionType, openFiles: readonly File[], action: Action | Action[], max?: number, onHostCreate?: OnHostCreate) {
|
||||
const session = type === SessionType.NoReference ? createSessionWithoutProjectReferences(onHostCreate) :
|
||||
function verifyForAllSessionTypes<T>(worker: (type: SessionType, options: T) => void, options: T) {
|
||||
describe("when main tsconfig doesnt have project reference", () => {
|
||||
worker(SessionType.NoReference, options);
|
||||
});
|
||||
describe("when main tsconfig has project reference", () => {
|
||||
worker(SessionType.ProjectReference, options);
|
||||
});
|
||||
describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => {
|
||||
worker(SessionType.DisableSourceOfProjectReferenceRedirect, options);
|
||||
});
|
||||
}
|
||||
|
||||
function createSession(type: SessionType, onHostCreate?: OnHostCreate) {
|
||||
return type === SessionType.NoReference ? createSessionWithoutProjectReferences(onHostCreate) :
|
||||
type === SessionType.ProjectReference ? createSessionWithProjectReferences(onHostCreate) :
|
||||
type === SessionType.DisableSourceOfProjectReferenceRedirect ?
|
||||
createSessionWithDisabledProjectReferences(onHostCreate) :
|
||||
ts.Debug.assertNever(type);
|
||||
}
|
||||
|
||||
function setup(type: SessionType, openFiles: readonly File[], action: Action | Action[], max?: number, onHostCreate?: OnHostCreate) {
|
||||
const session = createSession(type, onHostCreate);
|
||||
openFilesForSession(openFiles, session);
|
||||
runActions(session, action, max);
|
||||
return session;
|
||||
@@ -275,10 +299,60 @@ fn5();
|
||||
openFiles: readonly File[];
|
||||
action: Action | Action[];
|
||||
}
|
||||
function verifyFileRenames(options: VerifyFileRenamesOptions) {
|
||||
function verifyFileChangeAndRenames(options: VerifyFileRenamesOptions) {
|
||||
function file(options: VerifyFileRenamesOptions) {
|
||||
return options.file === "dts" ? dtsLocation : dtsMapLocation;
|
||||
}
|
||||
enum ChangeAsRenameType {
|
||||
NoTimeout = "no timeout",
|
||||
TimeoutAfterDelete = "timeout after delete",
|
||||
TimeoutAfterWrite = "timeout after write",
|
||||
ActionBeforeWrite = "action before write",
|
||||
}
|
||||
function change(options: VerifyFileRenamesOptions) {
|
||||
return options.file === "dts" ? changeDtsFile : changeDtsMapFile;
|
||||
}
|
||||
function verifyChangeAsRename(withChange: boolean) {
|
||||
[
|
||||
ChangeAsRenameType.NoTimeout,
|
||||
ChangeAsRenameType.TimeoutAfterDelete,
|
||||
ChangeAsRenameType.TimeoutAfterWrite,
|
||||
ChangeAsRenameType.ActionBeforeWrite,
|
||||
].forEach(changeAsRenameType => {
|
||||
it(`with ${options.file} file, change as rename ${changeAsRenameType}`, () => {
|
||||
const session = setup(options.type, options.openFiles, options.action, 1);
|
||||
const location = file(options);
|
||||
const fileContents = session.host.readFile(location)!;
|
||||
session.host.deleteFile(location);
|
||||
switch (changeAsRenameType) {
|
||||
case ChangeAsRenameType.TimeoutAfterDelete:
|
||||
session.host.runQueuedTimeoutCallbacks();
|
||||
break;
|
||||
case ChangeAsRenameType.ActionBeforeWrite:
|
||||
runActions(session, options.action, 2);
|
||||
break;
|
||||
default:
|
||||
session.host.baselineHost(`Before write ${location}`);
|
||||
}
|
||||
if (withChange) change(options)(session, fileContents);
|
||||
else session.host.writeFile(location, fileContents);
|
||||
if (changeAsRenameType === ChangeAsRenameType.TimeoutAfterWrite) session.host.runQueuedTimeoutCallbacks();
|
||||
runActions(session, options.action, 2);
|
||||
baselineTsserverLogs("projectReferencesSourcemap", `${options.scenarioLocation}/${options.type}/dependency ${options.file} ${withChange ? "change" : "rewrite"} as rename ${changeAsRenameType}`, session);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Edit to add new fn
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type: options.type,
|
||||
scenario: `dependency ${options.file} changes`,
|
||||
openFiles: options.openFiles,
|
||||
change: change(options),
|
||||
action: options.action,
|
||||
});
|
||||
verifyChangeAsRename(/*withChange*/ true);
|
||||
verifyChangeAsRename(/*withChange*/ false);
|
||||
it(`with ${options.file} file, when file is not present`, () => {
|
||||
const session = setup(options.type, options.openFiles, options.action, undefined, host => host.deleteFile(file(options)));
|
||||
verifyScriptInfoCollectionWith(session, options.openFiles);
|
||||
@@ -314,93 +388,63 @@ fn5();
|
||||
referenceChange: (session: TestSession) => void;
|
||||
referenceChangeAction?: Action | Action[];
|
||||
}
|
||||
function verifyScenarioWorker(options: VerifyScenario, type: SessionType) {
|
||||
verifyAction({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: options.scenario,
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
// Edit
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "usage file changes",
|
||||
openFiles: options.openFiles,
|
||||
change: options.change,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
// Edit dts to add new fn
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "dependency dts changes",
|
||||
openFiles: options.openFiles,
|
||||
change: changeDtsFile,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
// Edit map file to represent added new line
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "dependency dtsMap changes",
|
||||
openFiles: options.openFiles,
|
||||
change: changeDtsMapFile,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
verifyFileRenames({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
file: "dtsMap",
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
verifyFileRenames({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
file: "dts",
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
if (type !== SessionType.ProjectReference) return;
|
||||
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "dependency source changes",
|
||||
openFiles: options.openFiles,
|
||||
change: options.referenceChange,
|
||||
action: options.action,
|
||||
actionAfterChange: options.referenceChangeAction,
|
||||
});
|
||||
|
||||
it("when projects are not built", () => {
|
||||
const host = createServerHost(files);
|
||||
const session = new TestSession(host);
|
||||
openFilesForSession(options.openFiles, session);
|
||||
runActions(session, options.action);
|
||||
verifyScriptInfoCollectionWith(session, options.openFiles);
|
||||
baselineTsserverLogs("projectReferencesSourcemap", `${options.scenarioLocation}/${type}/when projects are not built`, session);
|
||||
});
|
||||
}
|
||||
|
||||
function verifyScenario(options: VerifyScenario) {
|
||||
describe("when main tsconfig doesnt have project reference", () => {
|
||||
verifyScenarioWorker(options, SessionType.NoReference);
|
||||
});
|
||||
describe("when main tsconfig has project reference", () => {
|
||||
verifyScenarioWorker(options, SessionType.ProjectReference);
|
||||
});
|
||||
describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => {
|
||||
verifyScenarioWorker(options, SessionType.DisableSourceOfProjectReferenceRedirect);
|
||||
});
|
||||
verifyForAllSessionTypes((type, options) => {
|
||||
verifyAction({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: options.scenario,
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
// Edit
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "usage file changes",
|
||||
openFiles: options.openFiles,
|
||||
change: options.change,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
verifyFileChangeAndRenames({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
file: "dtsMap",
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
verifyFileChangeAndRenames({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
file: "dts",
|
||||
openFiles: options.openFiles,
|
||||
action: options.action,
|
||||
});
|
||||
|
||||
if (type !== SessionType.ProjectReference) return;
|
||||
|
||||
verifyScenarioWithChanges({
|
||||
scenarioLocation: options.scenarioLocation,
|
||||
type,
|
||||
scenario: "dependency source changes",
|
||||
openFiles: options.openFiles,
|
||||
change: options.referenceChange,
|
||||
action: options.action,
|
||||
actionAfterChange: options.referenceChangeAction,
|
||||
});
|
||||
|
||||
it("when projects are not built", () => {
|
||||
const host = createServerHost(files);
|
||||
const session = new TestSession(host);
|
||||
openFilesForSession(options.openFiles, session);
|
||||
runActions(session, options.action);
|
||||
verifyScriptInfoCollectionWith(session, options.openFiles);
|
||||
baselineTsserverLogs("projectReferencesSourcemap", `${options.scenarioLocation}/${type}/when projects are not built`, session);
|
||||
});
|
||||
}, options);
|
||||
}
|
||||
|
||||
describe("from project that uses dependency: goToDef", () => {
|
||||
@@ -465,5 +509,46 @@ fn5();
|
||||
}),
|
||||
referenceChangeAction: [goToDefFromMainTs, renameFromDependencyTsWithDependencyChange],
|
||||
});
|
||||
|
||||
verifyForAllSessionTypes(type => {
|
||||
it("goto Definition in usage and rename locations, deleting config file", () => {
|
||||
const session = createSession(type);
|
||||
openFilesForSession([mainTs], session);
|
||||
session.executeCommandSeq<ts.server.protocol.RenameRequest>({
|
||||
command: ts.server.protocol.CommandTypes.Rename,
|
||||
arguments: { file: mainTs.path, line: 2, offset: 17 },
|
||||
});
|
||||
|
||||
verifyMainConfigDelete(mainConfig, /*runTimeoutAfterDelete*/ true, /*openRandomAfterDelete*/ false);
|
||||
verifyMainConfigDelete(mainConfig, /*runTimeoutAfterDelete*/ true, /*openRandomAfterDelete*/ true);
|
||||
verifyMainConfigDelete(mainConfig, /*runTimeoutAfterDelete*/ false, /*openRandomAfterDelete*/ false);
|
||||
verifyMainConfigDelete(mainConfig, /*runTimeoutAfterDelete*/ false, /*openRandomAfterDelete*/ true);
|
||||
|
||||
verifyMainConfigDelete(dependencyConfig, /*runTimeoutAfterDelete*/ true, /*openRandomAfterDelete*/ false);
|
||||
verifyMainConfigDelete(dependencyConfig, /*runTimeoutAfterDelete*/ false, /*openRandomAfterDelete*/ true);
|
||||
verifyMainConfigDelete(dependencyConfig, /*runTimeoutAfterDelete*/ true, /*openRandomAfterDelete*/ true);
|
||||
verifyMainConfigDelete(dependencyConfig, /*runTimeoutAfterDelete*/ false, /*openRandomAfterDelete*/ false);
|
||||
|
||||
baselineTsserverLogs("projectReferencesSourcemap", `dependencyAndUsage/${type}/goToDef and rename locations and deleting config file`, session);
|
||||
|
||||
function verifyMainConfigDelete(
|
||||
config: File,
|
||||
runTimeoutAfterDelete: boolean,
|
||||
openRandomAfterDelete: boolean,
|
||||
) {
|
||||
const configContent = session.host.readFile(config.path)!;
|
||||
session.host.deleteFile(config.path);
|
||||
if (runTimeoutAfterDelete) session.host.runQueuedTimeoutCallbacks();
|
||||
if (openRandomAfterDelete) {
|
||||
openFilesForSession([randomFile], session);
|
||||
closeFilesForSession([randomFile], session);
|
||||
}
|
||||
session.host.writeFile(config.path, configContent);
|
||||
session.host.runQueuedTimeoutCallbacks();
|
||||
openFilesForSession([randomFile], session);
|
||||
closeFilesForSession([randomFile], session);
|
||||
}
|
||||
});
|
||||
}, /*options*/ undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import * as ts from "../../_namespaces/ts";
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
import { jsonToReadableText } from "../helpers";
|
||||
import {
|
||||
buildMonorepoSymlinkedSiblingPackage1,
|
||||
cleanMonorepoSymlinkedSiblingPackage1,
|
||||
getMonorepoSymlinkedSiblingPackagesSys,
|
||||
} from "../helpers/monorepoSymlinkedSiblingPackages";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
closeFilesForSession,
|
||||
@@ -13,11 +18,13 @@ import {
|
||||
createServerHost,
|
||||
File,
|
||||
libFile,
|
||||
osFlavorToString,
|
||||
SymLink,
|
||||
TestServerHost,
|
||||
TestServerHostOsFlavor,
|
||||
} from "../helpers/virtualFileSystemWithWatch";
|
||||
|
||||
describe("unittests:: tsserver:: symLinks", () => {
|
||||
describe("unittests:: tsserver:: symLinks::", () => {
|
||||
it("rename in common file renames all project", () => {
|
||||
const folderA = `/users/username/projects/a`;
|
||||
const aFile: File = {
|
||||
@@ -264,4 +271,42 @@ new C();`,
|
||||
openFilesForSession(["c:/temp/replay/axios-src/lib/core/settle.js"], session);
|
||||
baselineTsserverLogs("symLinks", "when not symlink but differs in casing", session);
|
||||
});
|
||||
|
||||
describe("monorepoSymlinkedSiblingPackages:: monorepo style sibling packages symlinked", () => {
|
||||
verify(/*built*/ false);
|
||||
verify(/*built*/ true);
|
||||
verify(/*built*/ false, TestServerHostOsFlavor.Linux);
|
||||
verify(/*built*/ true, TestServerHostOsFlavor.Linux);
|
||||
function verify(built: boolean, osFlavor?: TestServerHostOsFlavor) {
|
||||
it(`monorepo style sibling packages symlinked${built ? " package1 built" : ""}${osFlavor ? ` ${osFlavorToString(osFlavor)}` : ""}`, () => {
|
||||
const indexFile = "/home/src/projects/project/packages/package2/src/index.ts";
|
||||
const host = getMonorepoSymlinkedSiblingPackagesSys(/*forTsserver*/ true, built, osFlavor);
|
||||
const session = new TestSession(host);
|
||||
openFilesForSession([indexFile], session);
|
||||
verifyGetErrRequest({ session, files: [indexFile] });
|
||||
|
||||
if (!built) {
|
||||
buildMonorepoSymlinkedSiblingPackage1(host);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyGetErrRequest({ session, files: [indexFile] });
|
||||
}
|
||||
|
||||
cleanMonorepoSymlinkedSiblingPackage1(host);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyGetErrRequest({ session, files: [indexFile] });
|
||||
|
||||
buildMonorepoSymlinkedSiblingPackage1(host);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyGetErrRequest({ session, files: [indexFile] });
|
||||
|
||||
baselineTsserverLogs("symLinks", `monorepo style sibling packages symlinked${built ? " package1 built" : ""}${osFlavor ? ` ${osFlavorToString(osFlavor)}` : ""}`, session);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ class Board {
|
||||
>this.ships.every(function (val) { return val.isSunk; }) : boolean
|
||||
> : ^^^^^^^
|
||||
>this.ships.every : { <S extends Ship>(predicate: (value: Ship, index: number, array: Ship[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Ship, index: number, array: Ship[]) => unknown, thisArg?: any): boolean; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^
|
||||
>this.ships : Ship[]
|
||||
> : ^^^^^^
|
||||
>this : this
|
||||
@@ -43,9 +43,9 @@ class Board {
|
||||
>ships : Ship[]
|
||||
> : ^^^^^^
|
||||
>every : { <S extends Ship>(predicate: (value: Ship, index: number, array: Ship[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Ship, index: number, array: Ship[]) => unknown, thisArg?: any): boolean; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^
|
||||
>function (val) { return val.isSunk; } : (val: Ship) => boolean
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^^^^^^^^^^^^
|
||||
>val : Ship
|
||||
> : ^^^^
|
||||
>val.isSunk : boolean
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
=== ArrowFunction1.ts ===
|
||||
var v = (a: ) => {
|
||||
>v : (a: any) => void
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^^^^^^^^
|
||||
>(a: ) => { } : (a: any) => void
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^^^^^^^^
|
||||
>a : any
|
||||
> : ^^^
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
=== ArrowFunction4.ts ===
|
||||
var v = (a, b) => {
|
||||
>v : (a: any, b: any) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^ ^^^^^^^^^^^^^^
|
||||
>(a, b) => { } : (a: any, b: any) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^ ^^^^^^^^^^^^^^
|
||||
>a : any
|
||||
>b : any
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
=== ArrowFunctionExpression1.ts ===
|
||||
var v = (public x: string) => { };
|
||||
>v : (x: string) => void
|
||||
> : ^^^^ ^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
>(public x: string) => { } : (x: string) => void
|
||||
> : ^^^^ ^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
>x : string
|
||||
> : ^^^^^^
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ module clodule1 {
|
||||
|
||||
function f(x: T) { }
|
||||
>f : (x: T) => void
|
||||
> : ^^^^^^^^^^^^^^
|
||||
> : ^ ^^^^^^^^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
}
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ class clodule<T> {
|
||||
|
||||
static fn<U>(id: U) { }
|
||||
>fn : <U>(id: U) => void
|
||||
> : ^ ^^^^^^ ^^^^^^^^^
|
||||
> : ^ ^^ ^^ ^^^^^^^^^
|
||||
>id : U
|
||||
> : ^
|
||||
}
|
||||
@@ -27,7 +27,7 @@ module clodule {
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : <T>(x: T, y: T) => T
|
||||
> : ^ ^^^^^ ^^^^^ ^^^^^
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
>y : T
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ class clodule<T> {
|
||||
|
||||
static fn(id: string) { }
|
||||
>fn : (id: string) => void
|
||||
> : ^^^^^ ^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^
|
||||
>id : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
@@ -27,7 +27,7 @@ module clodule {
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): T {
|
||||
>fn : <T>(x: T, y: T) => T
|
||||
> : ^ ^^^^^ ^^^^^ ^^^^^
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
>y : T
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@ class clodule<T> {
|
||||
|
||||
private static sfn(id: string) { return 42; }
|
||||
>sfn : (id: string) => number
|
||||
> : ^^^^^ ^^^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^^^
|
||||
>id : string
|
||||
> : ^^^^^^
|
||||
>42 : 42
|
||||
@@ -29,7 +29,7 @@ module clodule {
|
||||
// error: duplicate identifier expected
|
||||
export function fn<T>(x: T, y: T): number {
|
||||
>fn : <T>(x: T, y: T) => number
|
||||
> : ^ ^^^^^ ^^^^^ ^^^^^
|
||||
> : ^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
>y : T
|
||||
@@ -39,11 +39,11 @@ module clodule {
|
||||
>clodule.sfn('a') : number
|
||||
> : ^^^^^^
|
||||
>clodule.sfn : (id: string) => number
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^^^
|
||||
>clodule : typeof clodule
|
||||
> : ^^^^^^^^^^^^^^
|
||||
>sfn : (id: string) => number
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^ ^^ ^^^^^^^^^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ for (var v of ['a', 'b', 'c']) {
|
||||
>console.log(v) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>v : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ for (var x of [1, 2, 3]) {
|
||||
>console.log(x) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ for (var x of [1, 2, 3]) {
|
||||
>console.log(x) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ for (var v of ['a', 'b', 'c']) {
|
||||
>console.log(v) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>v : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
@@ -54,11 +54,11 @@ for (const i of [0, 1, 2, 3, 4]) {
|
||||
>console.log(i) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>i : number
|
||||
> : ^^^^^^
|
||||
|
||||
@@ -69,11 +69,11 @@ for (const i of [0, 1, 2, 3, 4]) {
|
||||
>console.log('E %s %s', i, err) : void
|
||||
> : ^^^^
|
||||
>console.log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>console : Console
|
||||
> : ^^^^^^^
|
||||
>log : (...data: any[]) => void
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> : ^^^^ ^^ ^^^^^^^^^
|
||||
>'E %s %s' : "E %s %s"
|
||||
> : ^^^^^^^^^
|
||||
>i : number
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user