diff --git a/.custom-gcl.yml b/.custom-gcl.yml index ab7ec126b9..87078f82a3 100644 --- a/.custom-gcl.yml +++ b/.custom-gcl.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://golangci-lint.run/jsonschema/custom-gcl.jsonschema.json -version: v1.64.6 +version: v2.0.2 destination: ./_tools diff --git a/.dprint.jsonc b/.dprint.jsonc index 3aff0e7620..f6ae7e6cc1 100644 --- a/.dprint.jsonc +++ b/.dprint.jsonc @@ -58,8 +58,8 @@ // Note: if adding new languages, make sure settings.template.json is updated too. // Also, if updating typescript, update the one in package.json. "plugins": [ - "https://plugins.dprint.dev/typescript-0.93.3.wasm", - "https://plugins.dprint.dev/json-0.19.4.wasm", + "https://plugins.dprint.dev/typescript-0.94.0.wasm", + "https://plugins.dprint.dev/json-0.20.0.wasm", "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm", "https://plugins.dprint.dev/exec-0.5.1.json@492414e39dea4dccc07b4af796d2f4efdb89e84bae2bd4e1e924c0cc050855bf" ] diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index 2145b5aec2..aaa91fe6b0 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -14,13 +14,13 @@ runs: steps: - name: Install Go id: install-go - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ inputs.go-version }} cache: false - name: Go cache - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: # There is more code downloaded and built than is covered by '**/go.sum', # so give each job its own cache to try and not end up sharing the wrong diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000000..fec29d63b4 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,14 @@ +comment: false + +coverage: + precision: 5 + status: + patch: + default: + informational: true + project: + default: + informational: true + +github_checks: + annotations: false diff --git a/.github/ls-screenshot.png b/.github/ls-screenshot.png index c1c2403a16..f9bcd0327d 100644 Binary files a/.github/ls-screenshot.png and b/.github/ls-screenshot.png differ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5f72857d1..6219751a94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,9 @@ on: pull_request: branches: - main + merge_group: + branches: + - main permissions: contents: read @@ -22,7 +25,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: build @@ -31,41 +35,73 @@ jobs: - run: npx hereby build + extension: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable + + - run: npm ci + + - run: npm run extension:build + test: strategy: fail-fast: false matrix: - include: + config: - os: ubuntu-latest + coverage: true - os: windows-latest + coverage: true + skip: ${{ github.event_name == 'merge_group' }} - os: macos-latest + coverage: true + skip: ${{ github.event_name == 'merge_group' }} - os: ubuntu-latest name: 'no submodules' no-submodules: true - os: ['self-hosted', '1ES.Pool=TypeScript-1ES-GitHub-XL', '1ES.ImageOverride=mariner-2.0'] name: 'race mode' race: true + skip: ${{ github.event_name == 'merge_group' }} - os: ubuntu-latest name: 'noembed' noembed: true - os: ubuntu-latest name: 'concurrent test programs' - concurrent-test-program: true + concurrent-test-programs: true + coverage: true + exclude: + - config: + skip: true + + name: test (${{ matrix.config.name || matrix.config.os }}) - name: test (${{ matrix.name || matrix.os }}) + runs-on: ${{ matrix.config.os }} - runs-on: ${{ matrix.os }} + permissions: + id-token: write + contents: read + + env: + TSGO_HEREBY_RACE: ${{ (matrix.config.race && 'true') || 'false' }} + TSGO_HEREBY_NOEMBED: ${{ (matrix.config.noembed && 'true') || 'false' }} + TSGO_HEREBY_CONCURRENT_TEST_PROGRAMS: ${{ (matrix.config.concurrent-test-programs && 'true') || 'false' }} + TSGO_HEREBY_COVERAGE: ${{ (matrix.config.coverage && 'true') || 'false' }} steps: - run: git config --system core.longpaths true - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.config.os == 'windows-latest' }} - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - submodules: ${{ !matrix.no-submodules }} - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + submodules: ${{ !matrix.config.no-submodules }} + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 'lts/*' + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: test @@ -75,17 +111,30 @@ jobs: - run: go install gotest.tools/gotestsum@latest # Installing gotestsum is super slow on Windows. # Also, avoid using it in race mode so we get the full output. - if: ${{ matrix.os != 'windows-latest' && !matrix.race }} + if: ${{ matrix.config.os != 'windows-latest' && !matrix.config.race }} - name: Tests id: test - run: npx hereby test:all ${RACE_FLAG:+"$RACE_FLAG"} ${NOEMBED_FLAG:+"$NOEMBED_FLAG"} ${CONCURRENTTESTPROGRAM_FLAG:+"$CONCURRENTTESTPROGRAM_FLAG"} - env: - RACE_FLAG: ${{ (matrix.race && '--race') || '' }} - NOEMBED_FLAG: ${{ (matrix.noembed && '--noembed') || '' }} - CONCURRENTTESTPROGRAM_FLAG: ${{ (matrix.concurrent-test-program && '--concurrentTestPrograms') || '' }} + run: npx hereby test + + - name: Benchmarks + run: npx hereby test:benchmarks + + - name: Tools Tests + run: npx hereby test:tools + + - name: API Tests + run: npx hereby test:api - run: git add . + + - uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 + if: ${{ always() && matrix.config.coverage && github.event_name != 'merge_group' }} + with: + use_oidc: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) }} + name: ${{ matrix.config.name || matrix.config.os }} + directory: ./coverage + - run: git diff --staged --exit-code --stat - name: Print baseline diff on failure @@ -94,31 +143,55 @@ jobs: npx hereby baseline-accept git add testdata/baselines/reference git diff --staged --exit-code - - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: ${{ failure() && steps.test.conclusion == 'failure' }} with: - name: ${{ matrix.os }}-${{ (matrix.race && 'race') || 'norace' }}-new-baselines-artifact + name: ${{ matrix.config.os }}-${{ (matrix.config.race && 'race') || 'norace' }}-new-baselines-artifact path: testdata/baselines/local lint: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + config: + - os: ubuntu-latest + - os: windows-latest + skip: ${{ github.event_name == 'merge_group' }} + - os: macos-latest + skip: ${{ github.event_name == 'merge_group' }} + - os: ubuntu-latest + name: 'noembed' + noembed: true + skip: ${{ github.event_name == 'merge_group' }} + exclude: + - config: + skip: true + + name: lint (${{ matrix.config.name || matrix.config.os }}) + + runs-on: ${{ matrix.config.os }} + + env: + TSGO_HEREBY_NOEMBED: ${{ (matrix.config.noembed && 'true') || 'false' }} + steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: - cache-name: lint + cache-name: lint${{ (matrix.config.noembed && '-noembed') || ''}} - run: npm ci - - run: npx hereby install-tools - run: npx hereby lint format: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: format @@ -134,7 +207,8 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: generate @@ -143,6 +217,9 @@ jobs: - run: npx hereby generate + - run: node ./internal/lsp/lsproto/_generate/fetchModel.mjs + - run: node ./internal/lsp/lsproto/_generate/generate.mjs + - run: git add . - run: git diff --staged --exit-code --stat @@ -163,7 +240,8 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: smoke @@ -188,21 +266,77 @@ jobs: - run: go -C ./_tools run ./cmd/checkmodpaths $PWD + baselines: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: true + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable + - uses: ./.github/actions/setup-go + with: + cache-name: baselines + + - run: npm ci + + - name: Remove all baselines + run: rm -rf testdata/baselines/reference + + - name: Run tests + run: npx hereby test &> /dev/null || exit 0 + + - name: Accept baselines + run: | + npx hereby baseline-accept + git add testdata/baselines/reference + + - name: Run tests + run: npx hereby test + + - name: Check baselines + id: check-baselines + run: | + function print_diff() { + if ! git diff --staged --exit-code --quiet --diff-filter=$1; then + echo "$2:" + git diff --staged --name-only --diff-filter=$1 + fi + } + + if ! git diff --staged --exit-code --quiet; then + print_diff ACR "Missing baselines" + print_diff MTUXB "Modified baselines" + print_diff D "Unused baselines" + git diff --staged > fix_baselines.patch + exit 1 + fi + + - name: Upload baseline diff artifact + if: ${{ failure() && steps.check-baselines.conclusion == 'failure' }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: fix_baselines.patch + path: fix_baselines.patch + required: runs-on: ubuntu-latest if: ${{ always() }} needs: + - baselines - build - - test - - lint + - extension - format - generate - - tidy + - lint + - misc - smoke + - test + - tidy steps: - name: Check required jobs env: NEEDS: ${{ toJson(needs) }} run: | - ! echo $NEEDS | jq -e 'to_entries[] | { job: .key, result: .value.result } | select(.result != "success")' + ! echo $NEEDS | jq -e 'to_entries[] | { job: .key, result: .value.result } | select((.result == "success" or .result == "skipped") | not)' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d7a8f3c9e9..79a3bdf788 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -48,7 +48,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/init@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 with: config-file: ./.github/codeql/codeql-configuration.yml # Override language selection by uncommenting this and choosing your languages @@ -58,7 +58,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@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/autobuild@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 # âšī¸ 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 @@ -72,4 +72,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/analyze@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15 diff --git a/.github/workflows/merge-queue.yml b/.github/workflows/merge-queue.yml deleted file mode 100644 index 076c2d4cd5..0000000000 --- a/.github/workflows/merge-queue.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Merge Queue Checks - -on: - merge_group: - -permissions: - contents: read - -# Ensure scripts are run with pipefail. See: -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference -defaults: - run: - shell: bash - -jobs: - test: - runs-on: ['self-hosted', '1ES.Pool=TypeScript-1ES-GitHub-XL', '1ES.ImageOverride=mariner-2.0'] - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - submodules: true - - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 - with: - node-version: 'lts/*' - - uses: ./.github/actions/setup-go - with: - cache-name: merge-queue-test - - - run: npm ci - - run: npx hereby test:all - - required: - runs-on: ubuntu-latest - if: ${{ always() }} - needs: - - test - - steps: - - name: Check required jobs - env: - NEEDS: ${{ toJson(needs) }} - run: | - ! echo $NEEDS | jq -e 'to_entries[] | { job: .key, result: .value.result } | select(.result != "success")' diff --git a/.gitignore b/.gitignore index bf8e94ab6e..d4dfeecb24 100644 --- a/.gitignore +++ b/.gitignore @@ -190,3 +190,7 @@ custom-gcl.hash # macOS Finder metadata .DS_Store + +.idea + +!testdata/submoduleAccepted.txt diff --git a/.gitmodules b/.gitmodules index 63c2678952..1f01d9be17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "_submodules/TypeScript"] path = _submodules/TypeScript url = https://github.com/microsoft/TypeScript.git + branch = tsgo-port diff --git a/.golangci.yml b/.golangci.yml index 98916c5d01..373793aa33 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,21 +1,20 @@ # yaml-language-server: $schema=https://golangci-lint.run/jsonschema/golangci.jsonschema.json +version: '2' + run: allow-parallel-runners: true - timeout: 180s linters: - disable-all: true + default: none enable: # Enabled - asasalint - - inamedparam - - nakedret - - govet - bidichk - bodyclose - canonicalheader - copyloopvar + - customlint - durationcheck - errcheck - errchkjson @@ -24,26 +23,26 @@ linters: - fatcontext - gocheckcompilerdirectives - goprintffuncname - - gosimple + - govet - grouper + - inamedparam - ineffassign - intrange - makezero - mirror + - misspell - musttag + - nakedret - nolintlint - paralleltest - perfsprint - predeclared - reassign - - tenv - testableexamples - tparallel - unconvert - usestdlibvars - - whitespace - - - customlint + - usetesting # Need to add headers # - goheader @@ -54,31 +53,20 @@ linters: # - gosec # - revive # - staticcheck - # - stylecheck # - testifylint # - unparam # - unused -linters-settings: - custom: - customlint: - type: module + settings: + custom: + customlint: + type: module - wrapcheck: - ignorePackageGlobs: - - encoding/* - - github.com/go-json-experiment/* -# revive: -# enable-all-rules: true -# rules: -# - name: unused-parameter -# disabled: true + exclusions: + presets: + - comments + - std-error-handling issues: max-issues-per-linter: 0 max-same-issues: 0 - - exclude: - - '^could not import' - - '^: #' - - 'imported and not used$' diff --git a/.vscode/launch.template.json b/.vscode/launch.template.json index 81fe0ec776..769898213b 100644 --- a/.vscode/launch.template.json +++ b/.vscode/launch.template.json @@ -17,6 +17,17 @@ ], "autoAttachChildProcesses": true, "preLaunchTask": "Watch for extension run" + }, + { + "name": "Launch submodule test", + "type": "go", + "request": "launch", + "mode": "test", + "program": "${workspaceFolder}/internal/testrunner", + "args": [ + "-test.run", + "TestSubmodule/${fileBasename}" + ] } ] } diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 3efcd8dbec..c6175571be 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -21,21 +21,50 @@ const isCI = !!process.env.CI; const $pipe = _$({ verbose: "short" }); const $ = _$({ verbose: "short", stdio: "inherit" }); +/** + * @param {string} name + * @param {boolean} defaultValue + * @returns {boolean} + */ +function parseEnvBoolean(name, defaultValue = false) { + name = "TSGO_HEREBY_" + name.toUpperCase(); + + const value = process.env[name]; + if (!value) { + return defaultValue; + } + switch (value.toUpperCase()) { + case "1": + case "TRUE": + case "YES": + case "ON": + return true; + case "0": + case "FALSE": + case "NO": + case "OFF": + return false; + } + throw new Error(`Invalid value for ${name}: ${value}`); +} + const { values: options } = parseArgs({ args: process.argv.slice(2), options: { - race: { type: "boolean" }, + tests: { type: "string", short: "t" }, fix: { type: "boolean" }, - noembed: { type: "boolean" }, debug: { type: "boolean" }, - concurrentTestPrograms: { type: "boolean" }, + + insiders: { type: "boolean" }, + + race: { type: "boolean", default: parseEnvBoolean("RACE") }, + noembed: { type: "boolean", default: parseEnvBoolean("NOEMBED") }, + concurrentTestPrograms: { type: "boolean", default: parseEnvBoolean("CONCURRENT_TEST_PROGRAMS") }, + coverage: { type: "boolean", default: parseEnvBoolean("COVERAGE") }, }, strict: false, allowPositionals: true, allowNegative: true, - noembed: false, - debug: false, - concurrentTestPrograms: false, }); const defaultGoBuildTags = [ @@ -44,7 +73,7 @@ const defaultGoBuildTags = [ /** * @param {...string} extra - * @returns + * @returns {string[]} */ function goBuildTags(...extra) { const tags = new Set(defaultGoBuildTags.concat(extra)); @@ -73,16 +102,28 @@ function memoize(fn) { const typeScriptSubmodulePath = path.join(__dirname, "_submodules", "TypeScript"); -function assertTypeScriptCloned() { +const isTypeScriptSubmoduleCloned = memoize(() => { try { const stat = fs.statSync(path.join(typeScriptSubmodulePath, "package.json")); if (stat.isFile()) { - return; + return true; } } catch {} - throw new Error("_submodules/TypeScript does not exist; try running `git submodule update --init --recursive`"); + return false; +}); + +const warnIfTypeScriptSubmoduleNotCloned = memoize(() => { + if (!isTypeScriptSubmoduleCloned()) { + console.warn(pc.yellow("Warning: TypeScript submodule is not cloned; some tests may be skipped.")); + } +}); + +function assertTypeScriptCloned() { + if (!isTypeScriptSubmoduleCloned()) { + throw new Error("_submodules/TypeScript does not exist; try running `git submodule update --init --recursive`"); + } } const tools = new Map([ @@ -200,28 +241,59 @@ export const generate = task({ }, }); -const goTestFlags = [ - ...goBuildFlags, - ...goBuildTags(), -]; +const coverageDir = path.join(__dirname, "coverage"); + +const ensureCoverageDirExists = memoize(() => { + if (options.coverage) { + fs.mkdirSync(coverageDir, { recursive: true }); + } +}); + +/** + * @param {string} taskName + */ +function goTestFlags(taskName) { + ensureCoverageDirExists(); + return [ + ...goBuildFlags, + ...goBuildTags(), + ...(options.tests ? [`-run=${options.tests}`] : []), + ...(options.coverage ? [`-coverprofile=${path.join(coverageDir, "coverage." + taskName + ".out")}`, "-coverpkg=./..."] : []), + ]; +} const goTestEnv = { ...(options.concurrentTestPrograms ? { TS_TEST_PROGRAM_SINGLE_THREADED: "false" } : {}), + // Go test caching takes a long time on Windows. + // https://github.com/golang/go/issues/72992 + ...(process.platform === "win32" ? { GOFLAGS: "-count=1" } : {}), }; +const goTestSumFlags = [ + "--format-hide-empty-pkg", + ...(!isCI ? ["--hide-summary", "skipped"] : []), +]; + const $test = $({ env: goTestEnv }); -const gotestsum = memoize(() => { - const args = isInstalled("gotestsum") ? ["gotestsum", "--format-hide-empty-pkg", "--"] : ["go", "test"]; - return args.concat(goTestFlags); -}); +/** + * @param {string} taskName + */ +function gotestsum(taskName) { + const args = isInstalled("gotestsum") ? ["gotestsum", ...goTestSumFlags, "--"] : ["go", "test"]; + return args.concat(goTestFlags(taskName)); +} -const goTest = memoize(() => { - return ["go", "test"].concat(goTestFlags); -}); +/** + * @param {string} taskName + */ +function goTest(taskName) { + return ["go", "test"].concat(goTestFlags(taskName)); +} async function runTests() { - await $test`${gotestsum()} ./... ${isCI ? ["--timeout=45m"] : []}`; + warnIfTypeScriptSubmoduleNotCloned(); + await $test`${gotestsum("tests")} ./... ${isCI ? ["--timeout=45m"] : []}`; } export const test = task({ @@ -230,8 +302,9 @@ export const test = task({ }); async function runTestBenchmarks() { + warnIfTypeScriptSubmoduleNotCloned(); // Run the benchmarks once to ensure they compile and run without errors. - await $test`${goTest()} -run=- -bench=. -benchtime=1x ./...`; + await $test`${goTest("benchmarks")} -run=- -bench=. -benchtime=1x ./...`; } export const testBenchmarks = task({ @@ -240,7 +313,11 @@ export const testBenchmarks = task({ }); async function runTestTools() { - await $test({ cwd: path.join(__dirname, "_tools") })`${gotestsum()} ./...`; + await $test({ cwd: path.join(__dirname, "_tools") })`${gotestsum("tools")} ./...`; +} + +async function runTestAPI() { + await $`npm run -w @typescript/api test`; } export const testTools = task({ @@ -248,27 +325,57 @@ export const testTools = task({ run: runTestTools, }); +export const buildAPITests = task({ + name: "build:api:test", + run: async () => { + await $`npm run -w @typescript/api build:test`; + }, +}); + +export const testAPI = task({ + name: "test:api", + dependencies: [tsgo, buildAPITests], + run: runTestAPI, +}); + export const testAll = task({ name: "test:all", + dependencies: [tsgo, buildAPITests], run: async () => { // Prevent interleaving by running these directly instead of in parallel. await runTests(); await runTestBenchmarks(); await runTestTools(); + await runTestAPI(); + }, +}); + +export const installExtension = task({ + name: "install-extension", + run: async () => { + await $({ cwd: path.join(__dirname, "_extension") })`npm run package`; + await $({ cwd: path.join(__dirname, "_extension") })`${options.insiders ? "code-insiders" : "code"} --install-extension typescript-lsp.vsix`; + console.log(pc.yellowBright("\nExtension installed. ") + "Add the following to your workspace or user settings.json:\n"); + console.log(pc.whiteBright(` "typescript-go.executablePath": "${path.join(__dirname, "built", "local", process.platform === "win32" ? "tsgo.exe" : "tsgo")}"\n`)); + console.log("Select 'TypeScript: Use TypeScript Go (Experimental)' in the command palette to enable the extension and disable built-in TypeScript support.\n"); }, }); const customLinterPath = "./_tools/custom-gcl"; const customLinterHashPath = customLinterPath + ".hash"; -const golangciLintVersion = memoize(() => { +const golangciLintPackage = memoize(() => { const golangciLintYml = fs.readFileSync(".custom-gcl.yml", "utf8"); const pattern = /^version:\s*(v\d+\.\d+\.\d+).*$/m; const match = pattern.exec(golangciLintYml); if (!match) { throw new Error("Expected version in .custom-gcl.yml"); } - return match[1]; + const version = match[1]; + const major = version.split(".")[0]; + const versionSuffix = ["v0", "v1"].includes(major) ? "" : "/" + major; + + return `github.com/golangci/golangci-lint${versionSuffix}/cmd/golangci-lint@${version}`; }); const customlintHash = memoize(() => { @@ -303,7 +410,7 @@ const buildCustomLinter = memoize(async () => { return; } - await $`go run github.com/golangci/golangci-lint/cmd/golangci-lint@${golangciLintVersion()} custom`; + await $`go run ${golangciLintPackage()} custom`; await $`${customLinterPath} cache clean`; fs.writeFileSync(customLinterHashPath, hash); @@ -314,9 +421,9 @@ export const lint = task({ run: async () => { await buildCustomLinter(); - const lintArgs = ["run", "--sort-results"]; - if (isCI) { - lintArgs.push("--timeout=5m"); + const lintArgs = ["run"]; + if (defaultGoBuildTags.length) { + lintArgs.push("--build-tags", defaultGoBuildTags.join(",")); } if (options.fix) { lintArgs.push("--fix"); @@ -387,6 +494,7 @@ function baselineAcceptTask(localBaseline, refBaseline) { for (const p of toDelete) { const out = localPathToRefPath(p).replace(/\.delete$/, ""); await rimraf(out); + await rimraf(p); // also delete the .delete file so that it no longer shows up in a diff tool. } }; } diff --git a/README.md b/README.md index ff7efed4d7..0e38016d84 100644 --- a/README.md +++ b/README.md @@ -7,30 +7,30 @@ Interested developers can clone and run locally to try out things as they become ## How to Build and Run -This repo uses [Go 1.24 or higher](https://go.dev/dl/), [Node.js with npm](https://nodejs.org/), and [`hereby`](https://www.npmjs.com/package/hereby). +This repo uses [Go 1.24 or higher](https://go.dev/dl/), [Rust 1.85 or higher](https://www.rust-lang.org/tools/install), [Node.js with npm](https://nodejs.org/), and [`hereby`](https://www.npmjs.com/package/hereby). For tests and code generation, this repo contains a git submodule to the main TypeScript repo pointing to the commit being ported. When cloning, you'll want to clone with submodules: -```console -$ git clone --recurse-submodules https://github.com/microsoft/typescript-go.git +```sh +git clone --recurse-submodules https://github.com/microsoft/typescript-go.git ``` If you have already cloned the repo, you can initialize the submodule with: -```console -$ git submodule update --init --recursive +```sh +git submodule update --init --recursive ``` With the submodule in place and `npm ci`, you can run tasks via `hereby`, similar to the TypeScript repo: -```console -$ hereby build # Verify that the project builds -$ hereby test # Run all tests -$ hereby install-tools # Install additional tools such as linters -$ hereby lint # Run all linters -$ hereby format # Format all code -$ hereby generate # Generate all Go code (e.g. diagnostics, committed to repo) +```sh +hereby build # Verify that the project builds +hereby test # Run all tests +hereby install-tools # Install additional tools such as linters +hereby lint # Run all linters +hereby format # Format all code +hereby generate # Generate all Go code (e.g. diagnostics, committed to repo) ``` Additional tasks are a work in progress. @@ -45,13 +45,18 @@ This is mainly a testing entry point; for higher fidelity with regular `tsc`, ru ### Running LSP Prototype -To try the prototype LSP experience: +* Run `hereby build` to build the LSP server +* Run `hereby install-extension` to build and install the VS Code extension. (Use `--insiders` to target `code-insiders` instead of `code`.) +* Copy the `"typescript-go.executablePath"` setting printed by `hereby install-extension` to your VS Code settings. +* Select "TypeScript: Use TypeScript Go (Experimental)" from the VS Code command palette (or set `"typescript.experimental.useTsgo"` in your VS Code settings). + +Alternatively, to debug and run the VS Code extension without installing it globally: * Run VS Code in the repo workspace (`code .`) * Copy `.vscode/launch.template.json` to `.vscode/launch.json` * <kbd>F5</kbd> (or `Debug: Start Debugging` from the command palette) -This will launch a new VS Code instance which uses the Corsa LS as the backend. If correctly set up, you should see "typescript-go" as an option in the Output pane: +This will launch a new VS Code instance which uses the Corsa LS as the backend. If correctly set up, you should see "tsgo" in the status bar when a TypeScript or JavaScript file is open:  @@ -60,25 +65,22 @@ This will launch a new VS Code instance which uses the Corsa LS as the backend. This is still a work in progress and is not yet at full feature parity with TypeScript. Bugs may exist. Please check this list carefully before logging a new issue or assuming an intentional change. -Status overview: - - * Program creation (read `lib`, `target`, `reference`, `import`, `files`, `include`, and `exclude`): **done**. You should see the *same files*, with modules resolved to the *same locations*, as in a TypeScript 5.8 (TS5.8) invocation - * Not all resolution modes are supported yet - * Parsing/scanning (read source text and determine syntax shape): **done**. You should see the exact same *syntax errors* as in a TS5.8 invocation - * Commandline and `tsconfig.json` parsing: **mostly done**. Note that the entry point is slightly different (for now) - * Type resolution (resolve computed types to a concrete internal representation): **done**. You should see the same types as in TS5.8 - * Type checking (check for problems in functions, classes, and statements): **done**. You should see the same errors, in the same locations, with the same messages, as TS 5.8 - * Types printback in errors may display slightly differently; this is in progress - * JavaScript-specific inference and JS Doc: **not ready** - * JSX: **not ready** - * Declaration emit: **not ready**. Coming soon! - * Emit (JS output): **in progress**. `target: esnext` (minimal downleveling) is well-supported but other targets may have gaps - * Watch mode: **prototype** (watches the correct files and rebuilds, but doesn't do incremental rechecking) - * Build mode / project references: **not ready** - * Incremental build: **not ready** - * Language service (LSP): **prototype** only, expect minimal functionality (errors, hover, go to def). More features soon! - * ASCII files only for now - * API: **not ready** +| Feature | Status | Notes | +|---------|--------|-------| +| Program creation | done | Same files and module resolution as TS5.8. Not all resolution modes supported yet. | +| Parsing/scanning | done | Exact same syntax errors as TS5.8 | +| Commandline and `tsconfig.json` parsing | mostly done | Entry point slightly different for now | +| Type resolution | done | Same types as TS5.8 | +| Type checking | done | Same errors, locations, and messages as TS5.8. Types printback in errors may display differently (in progress) | +| JavaScript-specific inference and JS Doc | not ready | - | +| JSX | done | - | +| Declaration emit | not ready | Coming soon | +| Emit (JS output) | in progress | `target: esnext` well-supported, other targets may have gaps | +| Watch mode | prototype | Watches files and rebuilds, but no incremental rechecking | +| Build mode / project references | not ready | - | +| Incremental build | not ready | - | +| Language service (LSP) | prototype | Minimal functionality (errors, hover, go to def). More features coming soon | +| API | not ready | - | Definitions: diff --git a/_extension/package.json b/_extension/package.json index baaac1a54b..a2f3c5d074 100644 --- a/_extension/package.json +++ b/_extension/package.json @@ -7,6 +7,10 @@ "private": true, "version": "0.0.0", "type": "commonjs", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/typescript-go" + }, "engines": { "vscode": "^1.91.0" }, @@ -30,6 +34,14 @@ ], "default": "verbose", "description": "Trace TypeScript Go server communication." + }, + "typescript-go.pprofDir": { + "type": "string", + "description": "Directory to write pprof profiles to." + }, + "typescript-go.executablePath": { + "type": "string", + "description": "Path to the tsgo binary. If not specified, the extension will look for it in the default location." } } } @@ -37,26 +49,37 @@ "commands": [ { "command": "typescript-go.restart", - "title": "TypeScript Go: Restart Language Server" + "title": "TypeScript Go: Restart Language Server", + "enablement": "typescript-go.serverRunning" } ], "menus": { "commandPalette": [ { - "command": "typescript-go.restart" + "command": "typescript-go.restart", + "when": "typescript-go.serverRunning" } ] } }, "main": "./dist/extension.js", + "files": [ + "dist" + ], "scripts": { "build": "tsc", - "watch": "tsc --watch" + "watch": "tsc --watch", + "build:prod": "esbuild src/extension.ts --bundle --external:vscode --platform=node --format=cjs --outfile=dist/extension.js --minify", + "package": "vsce package --skip-license --no-dependencies --out typescript-lsp.vsix", + "install-extension": "code --install-extension typescript-lsp.vsix", + "vscode:prepublish": "npm run build:prod" }, "dependencies": { "vscode-languageclient": "^9.0.1" }, "devDependencies": { - "@types/vscode": "^1.96.0" + "@types/vscode": "^1.91.0", + "@vscode/vsce": "^3.3.2", + "esbuild": "^0.25.2" } } diff --git a/_extension/src/extension.ts b/_extension/src/extension.ts index 3f3f46e7ac..375d6dc69e 100644 --- a/_extension/src/extension.ts +++ b/_extension/src/extension.ts @@ -11,30 +11,43 @@ import { } from "vscode-languageclient/node"; let client: LanguageClient; +let statusBarItem: vscode.StatusBarItem; + +const BUILTIN_TS_EXTENSION_ID = "vscode.typescript-language-features"; export function activate(context: vscode.ExtensionContext) { - context.subscriptions.push(vscode.commands.registerCommand("typescript-go.restart", () => { - client.restart(); - })); + const tsExtension = vscode.extensions.getExtension(BUILTIN_TS_EXTENSION_ID); + if (tsExtension?.isActive && !vscode.workspace.getConfiguration("typescript").get<boolean>("experimental.useTsgo")) { + return; + } const output = vscode.window.createOutputChannel("typescript-go", "log"); const traceOutput = vscode.window.createOutputChannel("typescript-go (LSP)"); - const exe = context.asAbsolutePath( + setupStatusBar(context); + registerCommands(context, output, traceOutput); + + const config = vscode.workspace.getConfiguration("typescript-go"); + + const exe = config.get<string>("executablePath") || context.asAbsolutePath( path.join("../", "built", "local", `tsgo${process.platform === "win32" ? ".exe" : ""}`), ); output.appendLine(`Resolved to ${exe}`); + // Get pprofDir + const pprofDir = config.get<string>("pprofDir"); + const pprofArgs = pprofDir ? ["-pprofDir", pprofDir] : []; + const serverOptions: ServerOptions = { run: { command: exe, - args: ["lsp"], + args: ["lsp", ...pprofArgs], transport: TransportKind.stdio, }, debug: { command: exe, - args: ["lsp"], + args: ["lsp", ...pprofArgs], transport: TransportKind.stdio, }, }; @@ -109,13 +122,86 @@ export function activate(context: vscode.ExtensionContext) { output.appendLine(`Starting language server...`); client.start(); + vscode.commands.executeCommand("setContext", "typescript-go.serverRunning", true); +} + +/** + * Sets up the status bar item for TypeScript Go + * @param context Extension context + */ +function setupStatusBar(context: vscode.ExtensionContext): void { + statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); + statusBarItem.text = "$(beaker) tsgo"; + statusBarItem.tooltip = "TypeScript Go Language Server"; + statusBarItem.command = "typescript-go.showMenu"; + statusBarItem.backgroundColor = new vscode.ThemeColor("statusBarItem.warningBackground"); + statusBarItem.show(); + context.subscriptions.push(statusBarItem); +} + +/** + * Registers all commands for the extension + * @param context Extension context + */ +function registerCommands(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel): void { + context.subscriptions.push(vscode.commands.registerCommand("typescript-go.restart", async () => { + await client.restart(); + })); + + context.subscriptions.push(vscode.commands.registerCommand("typescript-go.output.focus", () => { + outputChannel.show(); + })); + + context.subscriptions.push(vscode.commands.registerCommand("typescript-go.lsp-trace.focus", () => { + traceOutputChannel.show(); + })); + + context.subscriptions.push(vscode.commands.registerCommand("typescript-go.showMenu", showQuickPickMenu)); } -export function deactivate(): Thenable<void> | undefined { +/** + * Shows the quick pick menu for TypeScript Go options + */ +async function showQuickPickMenu(): Promise<void> { + const selected = await vscode.window.showQuickPick([ + { label: "$(refresh) Restart Server", description: "Restart the TypeScript Go language server" }, + { label: "$(output) Show TS Server Log", description: "Show the TypeScript Go server log" }, + { label: "$(debug-console) Show LSP Messages", description: "Show the LSP communication trace" }, + { label: "$(stop-circle) Disable TypeScript Go", description: "Switch back to the built-in TypeScript extension" }, + ], { + placeHolder: "TypeScript Go Options", + }); + + if (selected) { + if (selected.label.includes("Restart Server")) { + await vscode.commands.executeCommand("typescript-go.restart"); + } + else if (selected.label.includes("Show TS Server Log")) { + await vscode.commands.executeCommand("typescript-go.output.focus"); + } + else if (selected.label.includes("Show LSP Messages")) { + await vscode.commands.executeCommand("typescript-go.lsp-trace.focus"); + } + else if (selected.label.includes("Disable TypeScript Go")) { + // Fire and forget, because this command will restart the whole extension host + // and awaiting it shows a weird cancellation error. + vscode.commands.executeCommand("typescript.experimental.disableTsgo"); + } + } +} + +export async function deactivate(): Promise<void> { + // Dispose of status bar item + if (statusBarItem) { + statusBarItem.dispose(); + } + if (!client) { - return undefined; + return; } - return client.stop(); + + await client.stop(); + return vscode.commands.executeCommand("setContext", "typescript-go.serverRunning", false); } function getLanguageForUri(uri: vscode.Uri): string | undefined { diff --git a/_packages/api/package.json b/_packages/api/package.json new file mode 100644 index 0000000000..1b8e2f2c80 --- /dev/null +++ b/_packages/api/package.json @@ -0,0 +1,51 @@ +{ + "private": true, + "name": "@typescript/api", + "version": "1.0.0", + "type": "module", + "imports": { + "#symbolFlags": { + "@typescript/source": { + "types": "./src/symbolFlags.enum.ts", + "default": "./src/symbolFlags.ts" + }, + "types": "./dist/symbolFlags.enum.d.ts", + "default": "./dist/symbolFlags.js" + }, + "#typeFlags": { + "@typescript/source": { + "types": "./src/typeFlags.enum.ts", + "default": "./src/typeFlags.ts" + }, + "types": "./dist/typeFlags.enum.d.ts", + "default": "./dist/typeFlags.js" + } + }, + "exports": { + ".": { + "@typescript/source": "./src/api.ts", + "default": "./dist/api.js" + }, + "./fs": { + "@typescript/source": "./src/fs.ts", + "default": "./dist/fs.js" + }, + "./proto": { + "@typescript/source": "./src/proto.ts", + "default": "./dist/proto.js" + } + }, + "scripts": { + "build": "tsc -b", + "build:test": "tsc -b test", + "bench": "node --experimental-strip-types --no-warnings --conditions @typescript/source test/api.bench.ts", + "test": "node --test --experimental-strip-types --no-warnings --conditions @typescript/source ./test/**/*.test.ts" + }, + "devDependencies": { + "tinybench": "^3.1.1" + }, + "dependencies": { + "@typescript/ast": "1.0.0", + "libsyncrpc": "github:microsoft/libsyncrpc#bb02d84" + } +} diff --git a/_packages/api/src/api.ts b/_packages/api/src/api.ts new file mode 100644 index 0000000000..fbfc323917 --- /dev/null +++ b/_packages/api/src/api.ts @@ -0,0 +1,179 @@ +/// <reference path="./node.ts" preserve="true" /> +import { SymbolFlags } from "#symbolFlags"; +import { TypeFlags } from "#typeFlags"; +import type { + Node, + SourceFile, +} from "@typescript/ast"; +import { Client } from "./client.ts"; +import type { FileSystem } from "./fs.ts"; +import { RemoteSourceFile } from "./node.ts"; +import { ObjectRegistry } from "./objectRegistry.ts"; +import type { + ConfigResponse, + ProjectResponse, + SymbolResponse, + TypeResponse, +} from "./proto.ts"; + +export { SymbolFlags, TypeFlags }; + +export interface APIOptions { + tsserverPath: string; + cwd?: string; + logFile?: string; + fs?: FileSystem; +} + +export class API { + private client: Client; + private objectRegistry: ObjectRegistry; + constructor(options: APIOptions) { + this.client = new Client(options); + this.objectRegistry = new ObjectRegistry(this.client); + } + + parseConfigFile(fileName: string): ConfigResponse { + return this.client.request("parseConfigFile", { fileName }); + } + + loadProject(configFileName: string): Project { + const data = this.client.request("loadProject", { configFileName }); + return this.objectRegistry.getProject(data); + } + + echo(message: string): string { + return this.client.echo(message); + } + + echoBinary(message: Uint8Array): Uint8Array { + return this.client.echoBinary(message); + } + + close(): void { + this.client.close(); + } +} + +export class DisposableObject { + private disposed: boolean = false; + protected objectRegistry: ObjectRegistry; + constructor(objectRegistry: ObjectRegistry) { + this.objectRegistry = objectRegistry; + } + [globalThis.Symbol.dispose](): void { + this.objectRegistry.release(this); + this.disposed = true; + } + dispose(): void { + this[globalThis.Symbol.dispose](); + } + isDisposed(): boolean { + return this.disposed; + } + ensureNotDisposed(): this { + if (this.disposed) { + throw new Error(`${this.constructor.name} is disposed`); + } + return this; + } +} + +export class Project extends DisposableObject { + private decoder = new TextDecoder(); + private client: Client; + + id: string; + configFileName!: string; + compilerOptions!: Record<string, unknown>; + rootFiles!: readonly string[]; + + constructor(client: Client, objectRegistry: ObjectRegistry, data: ProjectResponse) { + super(objectRegistry); + this.id = data.id; + this.client = client; + this.loadData(data); + } + + loadData(data: ProjectResponse): void { + this.configFileName = data.configFileName; + this.compilerOptions = data.compilerOptions; + this.rootFiles = data.rootFiles; + } + + reload(): void { + this.ensureNotDisposed(); + this.loadData(this.client.request("loadProject", { configFileName: this.configFileName })); + } + + getSourceFile(fileName: string): SourceFile | undefined { + this.ensureNotDisposed(); + const data = this.client.requestBinary("getSourceFile", { project: this.id, fileName }); + return data ? new RemoteSourceFile(data, this.decoder) as unknown as SourceFile : undefined; + } + + getSymbolAtLocation(node: Node): Symbol | undefined; + getSymbolAtLocation(nodes: readonly Node[]): (Symbol | undefined)[]; + getSymbolAtLocation(nodeOrNodes: Node | readonly Node[]): Symbol | (Symbol | undefined)[] | undefined { + this.ensureNotDisposed(); + if (Array.isArray(nodeOrNodes)) { + const data = this.client.request("getSymbolsAtLocations", { project: this.id, locations: nodeOrNodes.map(node => node.id) }); + return data.map((d: SymbolResponse | null) => d ? this.objectRegistry.getSymbol(d) : undefined); + } + const data = this.client.request("getSymbolAtLocation", { project: this.id, location: (nodeOrNodes as Node).id }); + return data ? this.objectRegistry.getSymbol(data) : undefined; + } + + getSymbolAtPosition(fileName: string, position: number): Symbol | undefined; + getSymbolAtPosition(fileName: string, positions: readonly number[]): (Symbol | undefined)[]; + getSymbolAtPosition(fileName: string, positionOrPositions: number | readonly number[]): Symbol | (Symbol | undefined)[] | undefined { + this.ensureNotDisposed(); + if (typeof positionOrPositions === "number") { + const data = this.client.request("getSymbolAtPosition", { project: this.id, fileName, position: positionOrPositions }); + return data ? this.objectRegistry.getSymbol(data) : undefined; + } + const data = this.client.request("getSymbolsAtPositions", { project: this.id, fileName, positions: positionOrPositions }); + return data.map((d: SymbolResponse | null) => d ? this.objectRegistry.getSymbol(d) : undefined); + } + + getTypeOfSymbol(symbol: Symbol): Type | undefined; + getTypeOfSymbol(symbols: readonly Symbol[]): (Type | undefined)[]; + getTypeOfSymbol(symbolOrSymbols: Symbol | readonly Symbol[]): Type | (Type | undefined)[] | undefined { + this.ensureNotDisposed(); + if (Array.isArray(symbolOrSymbols)) { + const data = this.client.request("getTypesOfSymbols", { project: this.id, symbols: symbolOrSymbols.map(symbol => symbol.ensureNotDisposed().id) }); + return data.map((d: TypeResponse | null) => d ? this.objectRegistry.getType(d) : undefined); + } + const data = this.client.request("getTypeOfSymbol", { project: this.id, symbol: (symbolOrSymbols as Symbol).ensureNotDisposed().id }); + return data ? this.objectRegistry.getType(data) : undefined; + } +} + +export class Symbol extends DisposableObject { + private client: Client; + id: string; + name: string; + flags: SymbolFlags; + checkFlags: number; + + constructor(client: Client, objectRegistry: ObjectRegistry, data: SymbolResponse) { + super(objectRegistry); + this.client = client; + this.id = data.id; + this.name = data.name; + this.flags = data.flags; + this.checkFlags = data.checkFlags; + } +} + +export class Type extends DisposableObject { + private client: Client; + id: string; + flags: TypeFlags; + constructor(client: Client, objectRegistry: ObjectRegistry, data: TypeResponse) { + super(objectRegistry); + this.client = client; + this.id = data.id; + this.flags = data.flags; + } +} diff --git a/_packages/api/src/client.ts b/_packages/api/src/client.ts new file mode 100644 index 0000000000..c99d0945f4 --- /dev/null +++ b/_packages/api/src/client.ts @@ -0,0 +1,65 @@ +import { SyncRpcChannel } from "libsyncrpc"; +import type { FileSystem } from "./fs.ts"; + +export interface ClientOptions { + tsserverPath: string; + cwd?: string; + logFile?: string; + fs?: FileSystem; +} + +export class Client { + private channel: SyncRpcChannel; + private decoder = new TextDecoder(); + private encoder = new TextEncoder(); + + constructor(options: ClientOptions) { + this.channel = new SyncRpcChannel(options.tsserverPath, [ + "api", + "-cwd", + options.cwd ?? process.cwd(), + ]); + + this.channel.requestSync( + "configure", + JSON.stringify({ + logFile: options.logFile, + callbacks: Object.keys(options.fs ?? {}), + }), + ); + + if (options.fs) { + for (const [key, callback] of Object.entries(options.fs)) { + this.channel.registerCallback(key, (_, arg) => { + const result = callback(JSON.parse(arg)); + return JSON.stringify(result) ?? ""; + }); + } + } + } + + request(method: string, payload: any): any { + const encodedPayload = JSON.stringify(payload); + const result = this.channel.requestSync(method, encodedPayload); + if (result.length) { + const decodedResult = JSON.parse(result); + return decodedResult; + } + } + + requestBinary(method: string, payload: any): Uint8Array { + return this.channel.requestBinarySync(method, this.encoder.encode(JSON.stringify(payload))); + } + + echo(payload: string): string { + return this.channel.requestSync("echo", payload); + } + + echoBinary(payload: Uint8Array): Uint8Array { + return this.channel.requestBinarySync("echo", payload); + } + + close(): void { + this.channel.close(); + } +} diff --git a/_packages/api/src/fs.ts b/_packages/api/src/fs.ts new file mode 100644 index 0000000000..f84d35da82 --- /dev/null +++ b/_packages/api/src/fs.ts @@ -0,0 +1,142 @@ +import { getPathComponents } from "./path.ts"; + +export interface FileSystemEntries { + files: string[]; + directories: string[]; +} + +export interface FileSystem { + directoryExists?: (directoryName: string) => boolean | undefined; + fileExists?: (fileName: string) => boolean | undefined; + getAccessibleEntries?: (directoryName: string) => FileSystemEntries | undefined; + readFile?: (fileName: string) => string | null | undefined; + realpath?: (path: string) => string | undefined; +} + +export function createVirtualFileSystem(files: Record<string, string>): FileSystem { + interface VDirectory { + type: "directory"; + children: Record<string, VNode>; + } + + interface VFile { + type: "file"; + content: string; + } + + type VNode = VDirectory | VFile; + + const root: VDirectory = { + type: "directory", + children: {}, + }; + + for (const [filePath, fileContent] of Object.entries(files)) { + createFile(filePath, fileContent); + } + + return { + directoryExists, + fileExists, + getAccessibleEntries, + readFile, + realpath: path => path, + }; + + /** + * Traverse the tree from the root according to path segments. + * Returns the node if found, or null if any segment doesn't exist. + */ + function getNodeFromPath(path: string): VNode | undefined { + if (!path || path === "/") { + return root; + } + const segments = getPathComponents(path).slice(1); + let current: VNode = root; + + for (const segment of segments) { + if (current.type !== "directory") { + return undefined; + } + const child: VNode = current.children[segment]; + if (!child) { + return undefined; // segment not found + } + current = child; + } + + return current; + } + + /** + * Ensure that the directory path (given by `segments`) exists, + * creating subdirectories as needed. Returns the final directory node. + */ + function ensureDirectory(segments: string[]): VDirectory { + let current: VDirectory = root; + for (const segment of segments) { + if (!current.children[segment]) { + // Create a new directory node + current.children[segment] = { type: "directory", children: {} }; + } + else if (current.children[segment].type !== "directory") { + // A file with the same name already exists + throw new Error(`Cannot create directory: a file already exists at "/${segments.join("/")}"`); + } + current = current.children[segment] as VDirectory; + } + return current; + } + + /** + * Create (or overwrite) a file at the given path with provided content. + * Automatically creates parent directories if needed. + */ + function createFile(path: string, content: string) { + const segments = getPathComponents(path).slice(1); + if (segments.length === 0) { + throw new Error(`Invalid file path: "${path}"`); + } + const filename = segments.pop()!; + const directorySegments = segments; + const dirNode = ensureDirectory(directorySegments); + dirNode.children[filename] = { type: "file", content }; + } + + function directoryExists(directoryName: string): boolean { + const node = getNodeFromPath(directoryName); + return !!node && node.type === "directory"; + } + + function fileExists(fileName: string): boolean { + const node = getNodeFromPath(fileName); + return !!node && node.type === "file"; + } + + function getAccessibleEntries(directoryName: string): FileSystemEntries | undefined { + const node = getNodeFromPath(directoryName); + if (!node || node.type !== "directory") { + // Not found or not a directory + return undefined; + } + const files: string[] = []; + const directories: string[] = []; + for (const [name, child] of Object.entries(node.children)) { + if (child.type === "file") { + files.push(name); + } + else { + directories.push(name); + } + } + return { files, directories }; + } + + function readFile(fileName: string): string | undefined { + const node = getNodeFromPath(fileName); + if (!node || node.type !== "file") { + return undefined; // doesn't exist or is not a file + } + return node.content; + } +} diff --git a/_packages/api/src/node.ts b/_packages/api/src/node.ts new file mode 100644 index 0000000000..d906b3310b --- /dev/null +++ b/_packages/api/src/node.ts @@ -0,0 +1,947 @@ +import { + type Node, + type NodeArray, + type SourceFile, + SyntaxKind, +} from "@typescript/ast"; + +declare module "@typescript/ast" { + export interface Node { + readonly id: string; + forEachChild<T>(visitor: (node: Node) => T): T | undefined; + getSourceFile(): SourceFile; + } + + export interface NodeArray<T> { + at(index: number): T; + } +} + +const popcount8 = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8]; + +const childProperties: Readonly<Partial<Record<SyntaxKind, readonly string[]>>> = { + [SyntaxKind.QualifiedName]: ["left", "right"], + [SyntaxKind.TypeParameter]: ["modifiers", "name", "constraint", "defaultType"], + [SyntaxKind.IfStatement]: ["expression", "thenStatement", "elseStatement"], + [SyntaxKind.DoStatement]: ["statement", "expression"], + [SyntaxKind.WhileStatement]: ["expression", "statement"], + [SyntaxKind.ForStatement]: ["initializer", "condition", "incrementor", "statement"], + [SyntaxKind.ForInStatement]: ["awaitModifier", "initializer", "expression", "statement"], + [SyntaxKind.ForOfStatement]: ["awaitModifier", "initializer", "expression", "statement"], + [SyntaxKind.WithStatement]: ["expression", "statement"], + [SyntaxKind.SwitchStatement]: ["expression", "caseBlock"], + [SyntaxKind.CaseClause]: ["expression", "statements"], + [SyntaxKind.DefaultClause]: ["expression", "statements"], + [SyntaxKind.TryStatement]: ["tryBlock", "catchClause", "finallyBlock"], + [SyntaxKind.CatchClause]: ["variableDeclaration", "block"], + [SyntaxKind.LabeledStatement]: ["label", "statement"], + [SyntaxKind.VariableStatement]: ["modifiers", "declarationList"], + [SyntaxKind.VariableDeclaration]: ["name", "exclamationToken", "type", "initializer"], + [SyntaxKind.Parameter]: ["modifiers", "dotDotDotToken", "name", "questionToken", "type", "initializer"], + [SyntaxKind.BindingElement]: ["dotDotDotToken", "propertyName", "name", "initializer"], + [SyntaxKind.FunctionDeclaration]: ["modifiers", "asteriskToken", "name", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.InterfaceDeclaration]: ["modifiers", "name", "typeParameters", "heritageClauses", "members"], + [SyntaxKind.TypeAliasDeclaration]: ["modifiers", "name", "typeParameters", "type"], + [SyntaxKind.EnumMember]: ["name", "initializer"], + [SyntaxKind.EnumDeclaration]: ["modifiers", "name", "members"], + [SyntaxKind.ModuleDeclaration]: ["modifiers", "name", "body"], + [SyntaxKind.ImportEqualsDeclaration]: ["modifiers", "name", "moduleReference"], + [SyntaxKind.ImportDeclaration]: ["modifiers", "importClause", "moduleSpecifier", "attributes"], + [SyntaxKind.ImportSpecifier]: ["propertyName", "name"], + [SyntaxKind.ImportClause]: ["name", "namedBindings"], + [SyntaxKind.ExportAssignment]: ["modifiers", "expression"], + [SyntaxKind.NamespaceExportDeclaration]: ["modifiers", "name"], + [SyntaxKind.ExportDeclaration]: ["modifiers", "exportClause", "moduleSpecifier", "attributes"], + [SyntaxKind.ExportSpecifier]: ["propertyName", "name"], + [SyntaxKind.CallSignature]: ["typeParameters", "parameters", "type"], + [SyntaxKind.ConstructSignature]: ["typeParameters", "parameters", "type"], + [SyntaxKind.Constructor]: ["modifiers", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.GetAccessor]: ["modifiers", "name", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.SetAccessor]: ["modifiers", "name", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.IndexSignature]: ["modifiers", "parameters", "type"], + [SyntaxKind.MethodSignature]: ["modifiers", "name", "postfixToken", "typeParameters", "parameters", "type"], + [SyntaxKind.MethodDeclaration]: ["modifiers", "asteriskToken", "name", "postfixToken", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.PropertySignature]: ["modifiers", "name", "postfixToken", "type", "initializer"], + [SyntaxKind.PropertyDeclaration]: ["modifiers", "name", "postfixToken", "type", "initializer"], + [SyntaxKind.BinaryExpression]: ["left", "operatorToken", "right"], + [SyntaxKind.YieldExpression]: ["asteriskToken", "expression"], + [SyntaxKind.ArrowFunction]: ["modifiers", "typeParameters", "parameters", "type", "equalsGreaterThanToken", "body"], + [SyntaxKind.FunctionExpression]: ["modifiers", "asteriskToken", "name", "typeParameters", "parameters", "type", "body"], + [SyntaxKind.AsExpression]: ["expression", "type"], + [SyntaxKind.SatisfiesExpression]: ["expression", "type"], + [SyntaxKind.ConditionalExpression]: ["condition", "questionToken", "whenTrue", "colonToken", "whenFalse"], + [SyntaxKind.PropertyAccessExpression]: ["expression", "questionDotToken", "name"], + [SyntaxKind.ElementAccessExpression]: ["expression", "questionDotToken", "argumentExpression"], + [SyntaxKind.CallExpression]: ["expression", "questionDotToken", "typeArguments", "arguments"], + [SyntaxKind.NewExpression]: ["expression", "typeArguments", "arguments"], + [SyntaxKind.TemplateExpression]: ["head", "templateSpans"], + [SyntaxKind.TemplateSpan]: ["expression", "literal"], + [SyntaxKind.TaggedTemplateExpression]: ["tag", "questionDotToken", "typeArguments", "template"], + [SyntaxKind.PropertyAssignment]: ["modifiers", "name", "postfixToken", "initializer"], + [SyntaxKind.ShorthandPropertyAssignment]: ["modifiers", "name", "postfixToken", "equalsToken", "objectAssignmentInitializer"], + [SyntaxKind.TypeAssertionExpression]: ["type", "expression"], + [SyntaxKind.ConditionalType]: ["checkType", "extendsType", "trueType", "falseType"], + [SyntaxKind.IndexedAccessType]: ["objectType", "indexType"], + [SyntaxKind.TypeReference]: ["typeName", "typeArguments"], + [SyntaxKind.ExpressionWithTypeArguments]: ["expression", "typeArguments"], + [SyntaxKind.TypePredicate]: ["assertsModifier", "parameterName", "type"], + [SyntaxKind.ImportType]: ["argument", "attributes", "qualifier", "typeArguments"], + [SyntaxKind.ImportAttribute]: ["name", "value"], + [SyntaxKind.TypeQuery]: ["exprName", "typeArguments"], + [SyntaxKind.MappedType]: ["readonlyToken", "typeParameter", "nameType", "questionToken", "type", "members"], + [SyntaxKind.NamedTupleMember]: ["dotDotDotToken", "name", "questionToken", "type"], + [SyntaxKind.FunctionType]: ["typeParameters", "parameters", "type"], + [SyntaxKind.ConstructorType]: ["modifiers", "typeParameters", "parameters", "type"], + [SyntaxKind.TemplateLiteralType]: ["head", "templateSpans"], + [SyntaxKind.TemplateLiteralTypeSpan]: ["type", "literal"], + [SyntaxKind.JsxElement]: ["openingElement", "children", "closingElement"], + [SyntaxKind.JsxNamespacedName]: ["name", "namespace"], + [SyntaxKind.JsxOpeningElement]: ["tagName", "typeArguments", "attributes"], + [SyntaxKind.JsxSelfClosingElement]: ["tagName", "typeArguments", "attributes"], + [SyntaxKind.JsxFragment]: ["openingFragment", "children", "closingFragment"], + [SyntaxKind.JsxAttribute]: ["name", "initializer"], + [SyntaxKind.JsxExpression]: ["dotDotDotToken", "expression"], + [SyntaxKind.JSDoc]: ["comment", "tags"], + [SyntaxKind.JSDocTypeTag]: ["tagName", "typeExpression", "comment"], + [SyntaxKind.JSDocTag]: ["tagName", "comment"], + [SyntaxKind.JSDocTemplateTag]: ["tagName", "constraint", "typeParameters", "comment"], + [SyntaxKind.JSDocReturnTag]: ["tagName", "typeExpression", "comment"], + [SyntaxKind.JSDocPublicTag]: ["tagName", "comment"], + [SyntaxKind.JSDocPrivateTag]: ["tagName", "comment"], + [SyntaxKind.JSDocProtectedTag]: ["tagName", "comment"], + [SyntaxKind.JSDocReadonlyTag]: ["tagName", "comment"], + [SyntaxKind.JSDocOverrideTag]: ["tagName", "comment"], + [SyntaxKind.JSDocDeprecatedTag]: ["tagName", "comment"], + [SyntaxKind.JSDocSeeTag]: ["tagName", "nameExpression", "comment"], + [SyntaxKind.JSDocImplementsTag]: ["tagName", "className", "comment"], + [SyntaxKind.JSDocAugmentsTag]: ["tagName", "className", "comment"], + [SyntaxKind.JSDocSatisfiesTag]: ["tagName", "typeExpression", "comment"], + [SyntaxKind.JSDocThisTag]: ["tagName", "typeExpression", "comment"], + [SyntaxKind.JSDocImportTag]: ["tagName", "importClause", "moduleSpecifier", "attributes", "comment"], + [SyntaxKind.JSDocCallbackTag]: ["tagName", "typeExpression", "fullName", "comment"], + [SyntaxKind.JSDocOverloadTag]: ["tagName", "typeExpression", "comment"], + [SyntaxKind.JSDocTypedefTag]: ["tagName", "typeExpression", "fullName", "comment"], + [SyntaxKind.JSDocSignature]: ["typeParameters", "parameters", "type"], + [SyntaxKind.ClassStaticBlockDeclaration]: ["modifiers", "body"], + [SyntaxKind.ClassDeclaration]: ["modifiers", "name", "typeParameters", "heritageClauses", "members"], + + // Later properties are in variable order, needs special handling + [SyntaxKind.JSDocPropertyTag]: [undefined!, undefined!], + [SyntaxKind.JSDocParameterTag]: ["tagName", undefined!, undefined!, "comment"], +}; + +const HEADER_OFFSET_RESERVED = 0; +const HEADER_OFFSET_STRING_TABLE_OFFSETS = 4; +const HEADER_OFFSET_STRING_TABLE = 8; +const HEADER_OFFSET_EXTENDED_DATA = 12; +const HEADER_OFFSET_NODES = 16; +const HEADER_SIZE = 20; + +type NodeDataType = typeof NODE_DATA_TYPE_CHILDREN | typeof NODE_DATA_TYPE_STRING | typeof NODE_DATA_TYPE_EXTENDED; +const NODE_DATA_TYPE_CHILDREN = 0x00000000; +const NODE_DATA_TYPE_STRING = 0x40000000; +const NODE_DATA_TYPE_EXTENDED = 0x80000000; +const NODE_DATA_TYPE_MASK = 0xc0_00_00_00; +const NODE_CHILD_MASK = 0x00_00_00_ff; +const NODE_STRING_INDEX_MASK = 0x00_ff_ff_ff; +const NODE_EXTENDED_DATA_MASK = 0x00_ff_ff_ff; + +const NODE_OFFSET_KIND = 0; +const NODE_OFFSET_POS = 4; +const NODE_OFFSET_END = 8; +const NODE_OFFSET_NEXT = 12; +const NODE_OFFSET_PARENT = 16; +const NODE_OFFSET_DATA = 20; +const NODE_LEN = 24; + +const KIND_NODE_LIST = 2 ** 32 - 1; + +export class RemoteNodeBase { + parent: RemoteNode; + protected view: DataView; + protected decoder: TextDecoder; + protected index: number; + /** Keys are positions */ + protected _children: Map<number, RemoteNode | RemoteNodeList> | undefined; + + constructor(view: DataView, decoder: TextDecoder, index: number, parent: RemoteNode) { + this.view = view; + this.decoder = decoder; + this.index = index; + this.parent = parent; + } + + get kind(): SyntaxKind { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_KIND, true); + } + + get pos(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_POS, true); + } + + get end(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_END, true); + } + + get next(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_NEXT, true); + } + + protected get byteIndex(): number { + return this.offsetNodes + this.index * NODE_LEN; + } + + protected get offsetStringTableOffsets(): number { + return this.view.getUint32(HEADER_OFFSET_STRING_TABLE_OFFSETS, true); + } + + protected get offsetStringTable(): number { + return this.view.getUint32(HEADER_OFFSET_STRING_TABLE, true); + } + + protected get offsetExtendedData(): number { + return this.view.getUint32(HEADER_OFFSET_EXTENDED_DATA, true); + } + + protected get offsetNodes(): number { + return this.view.getUint32(HEADER_OFFSET_NODES, true); + } + + protected get parentIndex(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_PARENT, true); + } + + protected get data(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_DATA, true); + } + + protected get dataType(): NodeDataType { + return (this.data & NODE_DATA_TYPE_MASK) as NodeDataType; + } + + protected get childMask(): number { + if (this.dataType !== NODE_DATA_TYPE_CHILDREN) { + return 0; + } + return this.data & NODE_CHILD_MASK; + } + + protected getFileText(start: number, end: number): string { + return this.decoder.decode(new Uint8Array(this.view.buffer, this.offsetStringTable + start, end - start)); + } +} + +export class RemoteNodeList extends Array<RemoteNode> implements NodeArray<RemoteNode> { + parent: RemoteNode; + protected view: DataView; + protected decoder: TextDecoder; + protected index: number; + /** Keys are positions */ + protected _children: Map<number, RemoteNode | RemoteNodeList> | undefined; + + get pos(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_POS, true); + } + + get end(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_END, true); + } + + get next(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_NEXT, true); + } + + private get data(): number { + return this.view.getUint32(this.byteIndex + NODE_OFFSET_DATA, true); + } + + private get offsetNodes(): number { + return this.view.getUint32(HEADER_OFFSET_NODES, true); + } + + private get byteIndex(): number { + return this.offsetNodes + this.index * NODE_LEN; + } + + constructor(view: DataView, decoder: TextDecoder, index: number, parent: RemoteNode) { + super(); + this.view = view; + this.decoder = decoder; + this.index = index; + this.parent = parent; + this.length = this.data; + + const length = this.length; + for (let i = 0; i < length; i++) { + Object.defineProperty(this, i, { + get() { + return this.at(i); + }, + }); + } + } + + *[Symbol.iterator](): ArrayIterator<RemoteNode> { + let next = this.index + 1; + while (next) { + const child = this.getOrCreateChildAtNodeIndex(next); + next = child.next; + yield child as RemoteNode; + } + } + + at(index: number): RemoteNode { + if (!Number.isInteger(index)) { + return undefined!; + } + if (index < 0) { + index = this.length - index; + } + let next = this.index + 1; + for (let i = 0; i < index; i++) { + const child = this.getOrCreateChildAtNodeIndex(next); + next = child.next; + } + return this.getOrCreateChildAtNodeIndex(next) as RemoteNode; + } + + private getOrCreateChildAtNodeIndex(index: number): RemoteNode | RemoteNodeList { + const pos = this.view.getUint32(this.offsetNodes + index * NODE_LEN + NODE_OFFSET_POS, true); + let child = (this._children ??= new Map()).get(pos); + if (!child) { + const kind = this.view.getUint32(this.offsetNodes + index * NODE_LEN + NODE_OFFSET_KIND, true); + if (kind === KIND_NODE_LIST) { + throw new Error("NodeList cannot directly contain another NodeList"); + } + child = new RemoteNode(this.view, this.decoder, index, this.parent); + this._children.set(pos, child); + } + return child; + } + + __print(): string { + const result = []; + result.push(`kind: NodeList`); + result.push(`index: ${this.index}`); + result.push(`byteIndex: ${this.byteIndex}`); + result.push(`length: ${this.length}`); + return result.join("\n"); + } +} + +export class RemoteNode extends RemoteNodeBase implements Node { + protected static NODE_LEN: number = NODE_LEN; + private sourceFile: SourceFile; + id: string; + + constructor(view: DataView, decoder: TextDecoder, index: number, parent: RemoteNode) { + super(view, decoder, index, parent); + let sourceFile: RemoteNode = this; + while (sourceFile && sourceFile.kind !== SyntaxKind.SourceFile) { + sourceFile = sourceFile.parent; + } + if (!sourceFile) { + throw new Error("SourceFile not found"); + } + this.sourceFile = sourceFile as unknown as SourceFile; + this.id = `${sourceFile.id}.${this.pos}.${this.kind}`; + } + + forEachChild<T>(visitNode: (node: Node) => T, visitList?: (list: NodeArray<Node>) => T): T | undefined { + if (this.hasChildren()) { + let next = this.index + 1; + do { + const child = this.getOrCreateChildAtNodeIndex(next); + if (child instanceof RemoteNodeList) { + if (visitList) { + const result = visitList(child); + if (result) { + return result; + } + } + for (const node of child) { + const result = visitNode(node); + if (result) { + return result; + } + } + } + else { + const result = visitNode(child); + if (result) { + return result; + } + } + next = child.next; + } + while (next); + } + } + + getSourceFile(): SourceFile { + return this.sourceFile; + } + + protected getString(index: number): string { + const start = this.view.getUint32(this.offsetStringTableOffsets + index * 4, true); + const end = this.view.getUint32(this.offsetStringTableOffsets + (index + 1) * 4, true); + const text = new Uint8Array(this.view.buffer, this.offsetStringTable + start, end - start); + return this.decoder.decode(text); + } + + private getOrCreateChildAtNodeIndex(index: number): RemoteNode | RemoteNodeList { + const pos = this.view.getUint32(this.offsetNodes + index * NODE_LEN + NODE_OFFSET_POS, true); + let child = (this._children ??= new Map()).get(pos); + if (!child) { + const kind = this.view.getUint32(this.offsetNodes + index * NODE_LEN + NODE_OFFSET_KIND, true); + child = kind === KIND_NODE_LIST + ? new RemoteNodeList(this.view, this.decoder, index, this) + : new RemoteNode(this.view, this.decoder, index, this); + this._children.set(pos, child); + } + return child; + } + + private hasChildren(): boolean { + if (this._children) { + return true; + } + if (this.byteIndex >= this.view.byteLength - NODE_LEN) { + return false; + } + const nextNodeParent = this.view.getUint32(this.offsetNodes + (this.index + 1) * NODE_LEN + NODE_OFFSET_PARENT, true); + return nextNodeParent === this.index; + } + + private getNamedChild(propertyName: string): RemoteNode | RemoteNodeList | undefined { + const propertyNames = childProperties[this.kind]; + if (!propertyNames) { + // `childProperties` is only defined for nodes with more than one child property. + // Get the only child if it exists. + const child = this.getOrCreateChildAtNodeIndex(this.index + 1); + if (child.next !== 0) { + throw new Error("Expected only one child"); + } + return child; + } + + let order = propertyNames.indexOf(propertyName); + if (order === -1) { + // JSDocPropertyTag and JSDocParameterTag need special handling + // because they have a conditional property order + const kind = this.kind; + if (kind === SyntaxKind.JSDocPropertyTag) { + switch (propertyName) { + case "name": + order = this.isNameFirst ? 0 : 1; + break; + case "typeExpression": + order = this.isNameFirst ? 1 : 0; + break; + } + } + else if (kind === SyntaxKind.JSDocParameterTag) { + switch (propertyName) { + case "name": + order = this.isNameFirst ? 1 : 2; + case "typeExpression": + order = this.isNameFirst ? 2 : 1; + } + } + // Node kind does not have this property + return undefined; + } + const mask = this.childMask; + if (!(mask & (1 << order))) { + // Property is not present + return undefined; + } + + // The property index is `order`, minus the number of zeros in the mask that are in bit positions less + // than the `order`th bit. Example: + // + // This is a MethodDeclaration with mask 0b01110101. The possible properties are + // ["modifiers", "asteriskToken", "name", "postfixToken", "typeParameters", "parameters", "type", "body"] + // (it has modifiers, name, typeParameters, parameters, and type). + // + // | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + // | ----- | ---- | ---- | ---------- | -------------- | ------------ | ---- | ------------- | --------- | + // | Value | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | + // | Name | body | type | parameters | typeParameters | postfixToken | name | asteriskToken | modifiers | + // + // We are trying to get the index of "parameters" (bit = 5). + // First, set all the more significant bits to 1: + // + // | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + // | ----- | ---- | ---- | ---------- | -------------- | ------------ | ---- | ------------- | --------- | + // | Value | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | + // + // Then, flip the bits: + // + // | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + // | ----- | ---- | ---- | ---------- | -------------- | ------------ | ---- | ------------- | --------- | + // | Value | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | + // + // Counting the 1s gives us the number of *missing properties* before the `order`th property. If every property + // were present, we would have `parameters = children[5]`, but since `postfixToken` and `astersiskToken` are + // missing, we have `parameters = children[5 - 2]`. + const propertyIndex = order - popcount8[~(mask | ((0xff << order) & 0xff)) & 0xff]; + return this.getOrCreateChildAtNodeIndex(this.index + 1 + propertyIndex); + } + + __print(): string { + const result = []; + result.push(`index: ${this.index}`); + result.push(`byteIndex: ${this.byteIndex}`); + result.push(`kind: ${SyntaxKind[this.kind]}`); + result.push(`pos: ${this.pos}`); + result.push(`end: ${this.end}`); + result.push(`next: ${this.next}`); + result.push(`parent: ${this.parentIndex}`); + result.push(`data: ${this.data.toString(2).padStart(32, "0")}`); + const dataType = this.dataType === NODE_DATA_TYPE_CHILDREN ? "children" : + this.dataType === NODE_DATA_TYPE_STRING ? "string" : + "extended"; + result.push(`dataType: ${dataType}`); + if (this.dataType === NODE_DATA_TYPE_CHILDREN) { + result.push(`childMask: ${this.childMask.toString(2).padStart(8, "0")}`); + result.push(`childProperties: ${childProperties[this.kind]?.join(", ")}`); + } + return result.join("\n"); + } + + __printChildren(): string { + const result = []; + let next = this.index + 1; + while (next) { + const child = this.getOrCreateChildAtNodeIndex(next); + next = child.next; + result.push(child.__print()); + } + return result.join("\n\n"); + } + + __printSubtree(): string { + const result = [this.__print()]; + this.forEachChild(function visitNode(node) { + result.push((node as RemoteNode).__print()); + node.forEachChild(visitNode); + }, visitList => { + result.push((visitList as RemoteNodeList).__print()); + }); + return result.join("\n\n"); + } + + // Boolean properties + get isArrayType(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.JSDocTypeLiteral: + return (this.data & 1 << 24) !== 0; + } + } + + get isTypeOnly(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportClause: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportDeclaration: + return (this.data & 1 << 24) !== 0; + } + } + + get isTypeOf(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.ImportType: + return (this.data & 1 << 24) !== 0; + } + } + + get multiline(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.Block: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ImportAttributes: + return (this.data & 1 << 24) !== 0; + } + } + + get isExportEquals(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.ExportAssignment: + return (this.data & 1 << 24) !== 0; + } + } + + get isBracketed(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocParameterTag: + return (this.data & 1 << 24) !== 0; + } + } + + get containsOnlyTriviaWhiteSpaces(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.JsxText: + return (this.data & 1 << 24) !== 0; + } + } + + get isNameFirst(): boolean | undefined { + switch (this.kind) { + case SyntaxKind.JSDocPropertyTag: + case SyntaxKind.JSDocParameterTag: + return (this.data & 1 << 25) !== 0; + } + } + + // Children properties + get argument(): RemoteNode | undefined { + return this.getNamedChild("argument") as RemoteNode; + } + get argumentExpression(): RemoteNode | undefined { + return this.getNamedChild("argumentExpression") as RemoteNode; + } + get arguments(): RemoteNodeList | undefined { + return this.getNamedChild("arguments") as RemoteNodeList; + } + get assertsModifier(): RemoteNode | undefined { + return this.getNamedChild("assertsModifier") as RemoteNode; + } + get asteriskToken(): RemoteNode | undefined { + return this.getNamedChild("asteriskToken") as RemoteNode; + } + get attributes(): RemoteNode | undefined { + return this.getNamedChild("attributes") as RemoteNode; + } + get awaitModifier(): RemoteNode | undefined { + return this.getNamedChild("awaitModifier") as RemoteNode; + } + get block(): RemoteNode | undefined { + return this.getNamedChild("block") as RemoteNode; + } + get body(): RemoteNode | undefined { + return this.getNamedChild("body") as RemoteNode; + } + get caseBlock(): RemoteNode | undefined { + return this.getNamedChild("caseBlock") as RemoteNode; + } + get catchClause(): RemoteNode | undefined { + return this.getNamedChild("catchClause") as RemoteNode; + } + get checkType(): RemoteNode | undefined { + return this.getNamedChild("checkType") as RemoteNode; + } + get children(): RemoteNodeList | undefined { + return this.getNamedChild("children") as RemoteNodeList; + } + get className(): RemoteNode | undefined { + return this.getNamedChild("className") as RemoteNode; + } + get closingElement(): RemoteNode | undefined { + return this.getNamedChild("closingElement") as RemoteNode; + } + get closingFragment(): RemoteNode | undefined { + return this.getNamedChild("closingFragment") as RemoteNode; + } + get colonToken(): RemoteNode | undefined { + return this.getNamedChild("colonToken") as RemoteNode; + } + get comment(): RemoteNode | undefined { + return this.getNamedChild("comment") as RemoteNode; + } + get condition(): RemoteNode | undefined { + return this.getNamedChild("condition") as RemoteNode; + } + get constraint(): RemoteNode | undefined { + return this.getNamedChild("constraint") as RemoteNode; + } + get declarationList(): RemoteNode | undefined { + return this.getNamedChild("declarationList") as RemoteNode; + } + get defaultType(): RemoteNode | undefined { + return this.getNamedChild("defaultType") as RemoteNode; + } + get dotDotDotToken(): RemoteNode | undefined { + return this.getNamedChild("dotDotDotToken") as RemoteNode; + } + get elements(): RemoteNodeList | undefined { + return this.getNamedChild("elements") as RemoteNodeList; + } + get elseStatement(): RemoteNode | undefined { + return this.getNamedChild("elseStatement") as RemoteNode; + } + get equalsGreaterThanToken(): RemoteNode | undefined { + return this.getNamedChild("equalsGreaterThanToken") as RemoteNode; + } + get equalsToken(): RemoteNode | undefined { + return this.getNamedChild("equalsToken") as RemoteNode; + } + get exclamationToken(): RemoteNode | undefined { + return this.getNamedChild("exclamationToken") as RemoteNode; + } + get exportClause(): RemoteNode | undefined { + return this.getNamedChild("exportClause") as RemoteNode; + } + get expression(): RemoteNode | undefined { + return this.getNamedChild("expression") as RemoteNode; + } + get exprName(): RemoteNode | undefined { + return this.getNamedChild("exprName") as RemoteNode; + } + get extendsType(): RemoteNode | undefined { + return this.getNamedChild("extendsType") as RemoteNode; + } + get falseType(): RemoteNode | undefined { + return this.getNamedChild("falseType") as RemoteNode; + } + get finallyBlock(): RemoteNode | undefined { + return this.getNamedChild("finallyBlock") as RemoteNode; + } + get fullName(): RemoteNode | undefined { + return this.getNamedChild("fullName") as RemoteNode; + } + get head(): RemoteNode | undefined { + return this.getNamedChild("head") as RemoteNode; + } + get heritageClauses(): RemoteNodeList | undefined { + return this.getNamedChild("heritageClauses") as RemoteNodeList; + } + get importClause(): RemoteNode | undefined { + return this.getNamedChild("importClause") as RemoteNode; + } + get incrementor(): RemoteNode | undefined { + return this.getNamedChild("incrementor") as RemoteNode; + } + get indexType(): RemoteNode | undefined { + return this.getNamedChild("indexType") as RemoteNode; + } + get initializer(): RemoteNode | undefined { + return this.getNamedChild("initializer") as RemoteNode; + } + get label(): RemoteNode | undefined { + return this.getNamedChild("label") as RemoteNode; + } + get left(): RemoteNode | undefined { + return this.getNamedChild("left") as RemoteNode; + } + get literal(): RemoteNode | undefined { + return this.getNamedChild("literal") as RemoteNode; + } + get members(): RemoteNodeList | undefined { + return this.getNamedChild("members") as RemoteNodeList; + } + get modifiers(): RemoteNodeList | undefined { + return this.getNamedChild("modifiers") as RemoteNodeList; + } + get moduleReference(): RemoteNode | undefined { + return this.getNamedChild("moduleReference") as RemoteNode; + } + get moduleSpecifier(): RemoteNode | undefined { + return this.getNamedChild("moduleSpecifier") as RemoteNode; + } + get name(): RemoteNode | undefined { + return this.getNamedChild("name") as RemoteNode; + } + get namedBindings(): RemoteNode | undefined { + return this.getNamedChild("namedBindings") as RemoteNode; + } + get nameExpression(): RemoteNode | undefined { + return this.getNamedChild("nameExpression") as RemoteNode; + } + get namespace(): RemoteNode | undefined { + return this.getNamedChild("namespace") as RemoteNode; + } + get nameType(): RemoteNode | undefined { + return this.getNamedChild("nameType") as RemoteNode; + } + get objectAssignmentInitializer(): RemoteNode | undefined { + return this.getNamedChild("objectAssignmentInitializer") as RemoteNode; + } + get objectType(): RemoteNode | undefined { + return this.getNamedChild("objectType") as RemoteNode; + } + get openingElement(): RemoteNode | undefined { + return this.getNamedChild("openingElement") as RemoteNode; + } + get openingFragment(): RemoteNode | undefined { + return this.getNamedChild("openingFragment") as RemoteNode; + } + get operatorToken(): RemoteNode | undefined { + return this.getNamedChild("operatorToken") as RemoteNode; + } + get parameterName(): RemoteNode | undefined { + return this.getNamedChild("parameterName") as RemoteNode; + } + get parameters(): RemoteNodeList | undefined { + return this.getNamedChild("parameters") as RemoteNodeList; + } + get postfixToken(): RemoteNode | undefined { + return this.getNamedChild("postfixToken") as RemoteNode; + } + get propertyName(): RemoteNode | undefined { + return this.getNamedChild("propertyName") as RemoteNode; + } + get qualifier(): RemoteNode | undefined { + return this.getNamedChild("qualifier") as RemoteNode; + } + get questionDotToken(): RemoteNode | undefined { + return this.getNamedChild("questionDotToken") as RemoteNode; + } + get questionToken(): RemoteNode | undefined { + return this.getNamedChild("questionToken") as RemoteNode; + } + get readonlyToken(): RemoteNode | undefined { + return this.getNamedChild("readonlyToken") as RemoteNode; + } + get right(): RemoteNode | undefined { + return this.getNamedChild("right") as RemoteNode; + } + get statement(): RemoteNode | undefined { + return this.getNamedChild("statement") as RemoteNode; + } + get statements(): RemoteNodeList | undefined { + return this.getNamedChild("statements") as RemoteNodeList; + } + get tag(): RemoteNode | undefined { + return this.getNamedChild("tag") as RemoteNode; + } + get tagName(): RemoteNode | undefined { + return this.getNamedChild("tagName") as RemoteNode; + } + get tags(): RemoteNodeList | undefined { + return this.getNamedChild("tags") as RemoteNodeList; + } + get template(): RemoteNode | undefined { + return this.getNamedChild("template") as RemoteNode; + } + get templateSpans(): RemoteNodeList | undefined { + return this.getNamedChild("templateSpans") as RemoteNodeList; + } + get thenStatement(): RemoteNode | undefined { + return this.getNamedChild("thenStatement") as RemoteNode; + } + get trueType(): RemoteNode | undefined { + return this.getNamedChild("trueType") as RemoteNode; + } + get tryBlock(): RemoteNode | undefined { + return this.getNamedChild("tryBlock") as RemoteNode; + } + get type(): RemoteNode | undefined { + return this.getNamedChild("type") as RemoteNode; + } + get typeArguments(): RemoteNode | undefined { + return this.getNamedChild("typeArguments") as RemoteNode; + } + get typeExpression(): RemoteNode | undefined { + return this.getNamedChild("typeExpression") as RemoteNode; + } + get typeName(): RemoteNode | undefined { + return this.getNamedChild("typeName") as RemoteNode; + } + get typeParameter(): RemoteNode | undefined { + return this.getNamedChild("typeParameter") as RemoteNode; + } + get typeParameters(): RemoteNodeList | undefined { + return this.getNamedChild("typeParameters") as RemoteNodeList; + } + get value(): RemoteNode | undefined { + return this.getNamedChild("value") as RemoteNode; + } + get variableDeclaration(): RemoteNode | undefined { + return this.getNamedChild("variableDeclaration") as RemoteNode; + } + get whenFalse(): RemoteNode | undefined { + return this.getNamedChild("whenFalse") as RemoteNode; + } + get whenTrue(): RemoteNode | undefined { + return this.getNamedChild("whenTrue") as RemoteNode; + } + + // String properties + get text(): string | undefined { + switch (this.kind) { + case SyntaxKind.JsxText: + case SyntaxKind.Identifier: + case SyntaxKind.PrivateIdentifier: + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.BigIntLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.JSDocText: { + const stringIndex = this.data & NODE_STRING_INDEX_MASK; + return this.getString(stringIndex); + } + case SyntaxKind.SourceFile: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: { + const extendedDataOffset = this.offsetExtendedData + (this.data & NODE_EXTENDED_DATA_MASK); + const stringIndex = this.view.getUint32(extendedDataOffset, true); + return this.getString(stringIndex); + } + } + } + + get rawText(): string | undefined { + switch (this.kind) { + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + const extendedDataOffset = this.offsetExtendedData + (this.data & NODE_EXTENDED_DATA_MASK); + const stringIndex = this.view.getUint32(extendedDataOffset + 4, true); + return this.getString(stringIndex); + } + } + + get fileName(): string | undefined { + switch (this.kind) { + case SyntaxKind.SourceFile: + const extendedDataOffset = this.offsetExtendedData + (this.data & NODE_EXTENDED_DATA_MASK); + const stringIndex = this.view.getUint32(extendedDataOffset + 4, true); + return this.getString(stringIndex); + } + } + + // Other properties + get flags(): number { + switch (this.kind) { + case SyntaxKind.VariableDeclarationList: + return this.data & (1 << 24 | 1 << 25) >> 24; + default: + return 0; + } + } + + get token(): SyntaxKind | undefined { + switch (this.kind) { + case SyntaxKind.ImportAttributes: + if ((this.data & 1 << 25) !== 0) { + return SyntaxKind.AssertKeyword; + } + return SyntaxKind.WithKeyword; + } + } + + get templateFlags(): number | undefined { + switch (this.kind) { + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + const extendedDataOffset = this.offsetExtendedData + (this.data & NODE_EXTENDED_DATA_MASK); + return this.view.getUint32(extendedDataOffset + 8, true); + } + } +} + +export class RemoteSourceFile extends RemoteNode { + constructor(data: Uint8Array, decoder: TextDecoder) { + const view = new DataView(data.buffer, data.byteOffset, data.byteLength); + super(view, decoder, 1, undefined!); + this.id = this.getString(this.view.getUint32(this.offsetExtendedData + 8, true)); + } +} diff --git a/_packages/api/src/objectRegistry.ts b/_packages/api/src/objectRegistry.ts new file mode 100644 index 0000000000..7a36ecb9c6 --- /dev/null +++ b/_packages/api/src/objectRegistry.ts @@ -0,0 +1,85 @@ +import { + Project, + Symbol, + Type, +} from "./api.ts"; +import type { Client } from "./client.ts"; +import type { + ProjectResponse, + SymbolResponse, + TypeResponse, +} from "./proto.ts"; + +export class ObjectRegistry { + private client: Client; + private projects: Map<string, Project> = new Map(); + private symbols: Map<string, Symbol> = new Map(); + private types: Map<string, Type> = new Map(); + + constructor(client: Client) { + this.client = client; + } + + getProject(data: ProjectResponse): Project { + let project = this.projects.get(data.id); + if (project) { + return project; + } + + project = new Project(this.client, this, data); + this.projects.set(data.id, project); + return project; + } + + getSymbol(data: SymbolResponse): Symbol { + let symbol = this.symbols.get(data.id); + if (symbol) { + return symbol; + } + + symbol = new Symbol(this.client, this, data); + this.symbols.set(data.id, symbol); + return symbol; + } + + getType(data: TypeResponse): Type { + let type = this.types.get(data.id); + if (type) { + return type; + } + + type = new Type(this.client, this, data); + this.types.set(data.id, type); + return type; + } + + release(object: object): void { + if (object instanceof Project) { + this.releaseProject(object); + } + else if (object instanceof Symbol) { + this.releaseSymbol(object); + } + else if (object instanceof Type) { + this.releaseType(object); + } + else { + throw new Error("Unknown object type"); + } + } + + releaseProject(project: Project): void { + this.projects.delete(project.id); + this.client.request("release", project.id); + } + + releaseSymbol(symbol: Symbol): void { + this.symbols.delete(symbol.id); + this.client.request("release", symbol.id); + } + + releaseType(type: Type): void { + this.types.delete(type.id); + this.client.request("release", type.id); + } +} diff --git a/_packages/api/src/path.ts b/_packages/api/src/path.ts new file mode 100644 index 0000000000..487432f057 --- /dev/null +++ b/_packages/api/src/path.ts @@ -0,0 +1,136 @@ +const CharacterCodesSlash = "/".charCodeAt(0); +const CharacterCodesBackslash = "\\".charCodeAt(0); +const CharacterCodesColon = ":".charCodeAt(0); +const CharacterCodesPercent = "%".charCodeAt(0); +const CharacterCodes3 = "3".charCodeAt(0); +const CharacterCodesa = "a".charCodeAt(0); +const CharacterCodesz = "z".charCodeAt(0); +const CharacterCodesA = "A".charCodeAt(0); +const CharacterCodesZ = "Z".charCodeAt(0); +const directorySeparator = "/"; +const altDirectorySeparator = "\\"; +const urlSchemeSeparator = "://"; + +function isVolumeCharacter(charCode: number) { + return (charCode >= CharacterCodesa && charCode <= CharacterCodesz) || + (charCode >= CharacterCodesA && charCode <= CharacterCodesZ); +} + +function getFileUrlVolumeSeparatorEnd(url: string, start: number) { + const ch0 = url.charCodeAt(start); + if (ch0 === CharacterCodesColon) return start + 1; + if (ch0 === CharacterCodesPercent && url.charCodeAt(start + 1) === CharacterCodes3) { + const ch2 = url.charCodeAt(start + 2); + if (ch2 === CharacterCodesa || ch2 === CharacterCodesA) return start + 3; + } + return -1; +} + +/** + * Returns length of the root part of a path or URL (i.e. length of "/", "x:/", "//server/share/, file:///user/files"). + * + * For example: + * ```ts + * getRootLength("a") === 0 // "" + * getRootLength("/") === 1 // "/" + * getRootLength("c:") === 2 // "c:" + * getRootLength("c:d") === 0 // "" + * getRootLength("c:/") === 3 // "c:/" + * getRootLength("c:\\") === 3 // "c:\\" + * getRootLength("//server") === 7 // "//server" + * getRootLength("//server/share") === 8 // "//server/" + * getRootLength("\\\\server") === 7 // "\\\\server" + * getRootLength("\\\\server\\share") === 8 // "\\\\server\\" + * getRootLength("file:///path") === 8 // "file:///" + * getRootLength("file:///c:") === 10 // "file:///c:" + * getRootLength("file:///c:d") === 8 // "file:///" + * getRootLength("file:///c:/path") === 11 // "file:///c:/" + * getRootLength("file://server") === 13 // "file://server" + * getRootLength("file://server/path") === 14 // "file://server/" + * getRootLength("http://server") === 13 // "http://server" + * getRootLength("http://server/path") === 14 // "http://server/" + * ``` + * + * @internal + */ +export function getRootLength(path: string): number { + const rootLength = getEncodedRootLength(path); + return rootLength < 0 ? ~rootLength : rootLength; +} + +/** + * Returns length of the root part of a path or URL (i.e. length of "/", "x:/", "//server/share/, file:///user/files"). + * If the root is part of a URL, the twos-complement of the root length is returned. + */ +function getEncodedRootLength(path: string): number { + if (!path) return 0; + const ch0 = path.charCodeAt(0); + + // POSIX or UNC + if (ch0 === CharacterCodesSlash || ch0 === CharacterCodesBackslash) { + if (path.charCodeAt(1) !== ch0) return 1; // POSIX: "/" (or non-normalized "\") + + const p1 = path.indexOf(ch0 === CharacterCodesSlash ? directorySeparator : altDirectorySeparator, 2); + if (p1 < 0) return path.length; // UNC: "//server" or "\\server" + + return p1 + 1; // UNC: "//server/" or "\\server\" + } + + // DOS + if (isVolumeCharacter(ch0) && path.charCodeAt(1) === CharacterCodesColon) { + const ch2 = path.charCodeAt(2); + if (ch2 === CharacterCodesSlash || ch2 === CharacterCodesBackslash) return 3; // DOS: "c:/" or "c:\" + if (path.length === 2) return 2; // DOS: "c:" (but not "c:d") + } + + // URL + const schemeEnd = path.indexOf(urlSchemeSeparator); + if (schemeEnd !== -1) { + const authorityStart = schemeEnd + urlSchemeSeparator.length; + const authorityEnd = path.indexOf(directorySeparator, authorityStart); + if (authorityEnd !== -1) { // URL: "file:///", "file://server/", "file://server/path" + // For local "file" URLs, include the leading DOS volume (if present). + // Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a + // special case interpreted as "the machine from which the URL is being interpreted". + const scheme = path.slice(0, schemeEnd); + const authority = path.slice(authorityStart, authorityEnd); + if ( + scheme === "file" && (authority === "" || authority === "localhost") && + isVolumeCharacter(path.charCodeAt(authorityEnd + 1)) + ) { + const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2); + if (volumeSeparatorEnd !== -1) { + if (path.charCodeAt(volumeSeparatorEnd) === CharacterCodesSlash) { + // URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/" + return ~(volumeSeparatorEnd + 1); + } + if (volumeSeparatorEnd === path.length) { + // URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a" + // but not "file:///c:d" or "file:///c%3ad" + return ~volumeSeparatorEnd; + } + } + } + return ~(authorityEnd + 1); // URL: "file://server/", "http://server/" + } + return ~path.length; // URL: "file://server", "http://server" + } + + // relative + return 0; +} + +export function getPathComponents(path: string): string[] { + return pathComponents(path, getRootLength(path)); +} + +function pathComponents(path: string, rootLength: number) { + const root = path.substring(0, rootLength); + const rest = path.substring(rootLength).split("/"); + if (rest.length && !lastOrUndefined(rest)) rest.pop(); + return [root, ...rest]; +} + +function lastOrUndefined<T>(array: T[]): T | undefined { + return array.length ? array[array.length - 1] : undefined; +} diff --git a/_packages/api/src/proto.ts b/_packages/api/src/proto.ts new file mode 100644 index 0000000000..d47eceab7e --- /dev/null +++ b/_packages/api/src/proto.ts @@ -0,0 +1,23 @@ +export interface ConfigResponse { + options: Record<string, unknown>; + fileNames: string[]; +} + +export interface ProjectResponse { + id: string; + configFileName: string; + compilerOptions: Record<string, unknown>; + rootFiles: string[]; +} + +export interface SymbolResponse { + id: string; + name: string; + flags: number; + checkFlags: number; +} + +export interface TypeResponse { + id: string; + flags: number; +} diff --git a/_packages/api/src/symbolFlags.enum.ts b/_packages/api/src/symbolFlags.enum.ts new file mode 100644 index 0000000000..8032b9fa45 --- /dev/null +++ b/_packages/api/src/symbolFlags.enum.ts @@ -0,0 +1,75 @@ +export enum SymbolFlags { + None = 0, + FunctionScopedVariable = 1 << 0, + BlockScopedVariable = 1 << 1, + Property = 1 << 2, + EnumMember = 1 << 3, + Function = 1 << 4, + Class = 1 << 5, + Interface = 1 << 6, + ConstEnum = 1 << 7, + RegularEnum = 1 << 8, + ValueModule = 1 << 9, + NamespaceModule = 1 << 10, + TypeLiteral = 1 << 11, + ObjectLiteral = 1 << 12, + Method = 1 << 13, + Constructor = 1 << 14, + GetAccessor = 1 << 15, + SetAccessor = 1 << 16, + Signature = 1 << 17, + TypeParameter = 1 << 18, + TypeAlias = 1 << 19, + ExportValue = 1 << 20, + Alias = 1 << 21, + Prototype = 1 << 22, + ExportStar = 1 << 23, + Optional = 1 << 24, + Transient = 1 << 25, + Assignment = 1 << 26, + ModuleExports = 1 << 27, + ConstEnumOnlyModule = 1 << 28, + ReplaceableByMethod = 1 << 29, + GlobalLookup = 1 << 30, + All = 1 << 30 - 1, + + Enum = RegularEnum | ConstEnum, + Variable = FunctionScopedVariable | BlockScopedVariable, + Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, + Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias, + Namespace = ValueModule | NamespaceModule | Enum, + Module = ValueModule | NamespaceModule, + Accessor = GetAccessor | SetAccessor, + + FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable, + + BlockScopedVariableExcludes = Value, + + ParameterExcludes = Value, + PropertyExcludes = Value & ~Property, + EnumMemberExcludes = Value | Type, + FunctionExcludes = Value & ~(Function | ValueModule | Class), + ClassExcludes = (Value | Type) & ~(ValueModule | Interface | Function), + InterfaceExcludes = Type & ~(Interface | Class), + RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), + ConstEnumExcludes = (Value | Type) & ~ConstEnum, + ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule), + NamespaceModuleExcludes = None, + MethodExcludes = Value & ~Method, + GetAccessorExcludes = Value & ~SetAccessor, + SetAccessorExcludes = Value & ~GetAccessor, + AccessorExcludes = Value & ~Accessor, + TypeParameterExcludes = Type & ~TypeParameter, + TypeAliasExcludes = Type, + AliasExcludes = Alias, + ModuleMember = Variable | Function | Class | Interface | Enum | Module | TypeAlias | Alias, + ExportHasLocal = Function | Class | Enum | ValueModule, + BlockScoped = BlockScopedVariable | Class | Enum, + PropertyOrAccessor = Property | Accessor, + ClassMember = Method | Accessor | Property, + ExportSupportsDefaultModifier = Class | Function | Interface, + ExportDoesNotSupportDefaultModifier = ~ExportSupportsDefaultModifier, + + Classifiable = Class | Enum | TypeAlias | Interface | TypeParameter | Module | Alias, + LateBindingContainer = Class | Interface | TypeLiteral | ObjectLiteral | Function, +} diff --git a/_packages/api/src/symbolFlags.ts b/_packages/api/src/symbolFlags.ts new file mode 100644 index 0000000000..896335fb8f --- /dev/null +++ b/_packages/api/src/symbolFlags.ts @@ -0,0 +1,71 @@ +export var SymbolFlags: any; +(function (SymbolFlags) { + SymbolFlags[SymbolFlags["None"] = 0] = "None"; + SymbolFlags[SymbolFlags["FunctionScopedVariable"] = 1] = "FunctionScopedVariable"; + SymbolFlags[SymbolFlags["BlockScopedVariable"] = 2] = "BlockScopedVariable"; + SymbolFlags[SymbolFlags["Property"] = 4] = "Property"; + SymbolFlags[SymbolFlags["EnumMember"] = 8] = "EnumMember"; + SymbolFlags[SymbolFlags["Function"] = 16] = "Function"; + SymbolFlags[SymbolFlags["Class"] = 32] = "Class"; + SymbolFlags[SymbolFlags["Interface"] = 64] = "Interface"; + SymbolFlags[SymbolFlags["ConstEnum"] = 128] = "ConstEnum"; + SymbolFlags[SymbolFlags["RegularEnum"] = 256] = "RegularEnum"; + SymbolFlags[SymbolFlags["ValueModule"] = 512] = "ValueModule"; + SymbolFlags[SymbolFlags["NamespaceModule"] = 1024] = "NamespaceModule"; + SymbolFlags[SymbolFlags["TypeLiteral"] = 2048] = "TypeLiteral"; + SymbolFlags[SymbolFlags["ObjectLiteral"] = 4096] = "ObjectLiteral"; + SymbolFlags[SymbolFlags["Method"] = 8192] = "Method"; + SymbolFlags[SymbolFlags["Constructor"] = 16384] = "Constructor"; + SymbolFlags[SymbolFlags["GetAccessor"] = 32768] = "GetAccessor"; + SymbolFlags[SymbolFlags["SetAccessor"] = 65536] = "SetAccessor"; + SymbolFlags[SymbolFlags["Signature"] = 131072] = "Signature"; + SymbolFlags[SymbolFlags["TypeParameter"] = 262144] = "TypeParameter"; + SymbolFlags[SymbolFlags["TypeAlias"] = 524288] = "TypeAlias"; + SymbolFlags[SymbolFlags["ExportValue"] = 1048576] = "ExportValue"; + SymbolFlags[SymbolFlags["Alias"] = 2097152] = "Alias"; + SymbolFlags[SymbolFlags["Prototype"] = 4194304] = "Prototype"; + SymbolFlags[SymbolFlags["ExportStar"] = 8388608] = "ExportStar"; + SymbolFlags[SymbolFlags["Optional"] = 16777216] = "Optional"; + SymbolFlags[SymbolFlags["Transient"] = 33554432] = "Transient"; + SymbolFlags[SymbolFlags["Assignment"] = 67108864] = "Assignment"; + SymbolFlags[SymbolFlags["ModuleExports"] = 134217728] = "ModuleExports"; + SymbolFlags[SymbolFlags["ConstEnumOnlyModule"] = 268435456] = "ConstEnumOnlyModule"; + SymbolFlags[SymbolFlags["ReplaceableByMethod"] = 536870912] = "ReplaceableByMethod"; + SymbolFlags[SymbolFlags["GlobalLookup"] = 1073741824] = "GlobalLookup"; + SymbolFlags[SymbolFlags["All"] = 536870912] = "All"; + SymbolFlags[SymbolFlags["Enum"] = 384] = "Enum"; + SymbolFlags[SymbolFlags["Variable"] = 3] = "Variable"; + SymbolFlags[SymbolFlags["Value"] = 111551] = "Value"; + SymbolFlags[SymbolFlags["Type"] = 788968] = "Type"; + SymbolFlags[SymbolFlags["Namespace"] = 1920] = "Namespace"; + SymbolFlags[SymbolFlags["Module"] = 1536] = "Module"; + SymbolFlags[SymbolFlags["Accessor"] = 98304] = "Accessor"; + SymbolFlags[SymbolFlags["FunctionScopedVariableExcludes"] = 111550] = "FunctionScopedVariableExcludes"; + SymbolFlags[SymbolFlags["BlockScopedVariableExcludes"] = 111551] = "BlockScopedVariableExcludes"; + SymbolFlags[SymbolFlags["ParameterExcludes"] = 111551] = "ParameterExcludes"; + SymbolFlags[SymbolFlags["PropertyExcludes"] = 111547] = "PropertyExcludes"; + SymbolFlags[SymbolFlags["EnumMemberExcludes"] = 900095] = "EnumMemberExcludes"; + SymbolFlags[SymbolFlags["FunctionExcludes"] = 110991] = "FunctionExcludes"; + SymbolFlags[SymbolFlags["ClassExcludes"] = 899503] = "ClassExcludes"; + SymbolFlags[SymbolFlags["InterfaceExcludes"] = 788872] = "InterfaceExcludes"; + SymbolFlags[SymbolFlags["RegularEnumExcludes"] = 899327] = "RegularEnumExcludes"; + SymbolFlags[SymbolFlags["ConstEnumExcludes"] = 899967] = "ConstEnumExcludes"; + SymbolFlags[SymbolFlags["ValueModuleExcludes"] = 110735] = "ValueModuleExcludes"; + SymbolFlags[SymbolFlags["NamespaceModuleExcludes"] = 0] = "NamespaceModuleExcludes"; + SymbolFlags[SymbolFlags["MethodExcludes"] = 103359] = "MethodExcludes"; + SymbolFlags[SymbolFlags["GetAccessorExcludes"] = 46015] = "GetAccessorExcludes"; + SymbolFlags[SymbolFlags["SetAccessorExcludes"] = 78783] = "SetAccessorExcludes"; + SymbolFlags[SymbolFlags["AccessorExcludes"] = 13247] = "AccessorExcludes"; + SymbolFlags[SymbolFlags["TypeParameterExcludes"] = 526824] = "TypeParameterExcludes"; + SymbolFlags[SymbolFlags["TypeAliasExcludes"] = 788968] = "TypeAliasExcludes"; + SymbolFlags[SymbolFlags["AliasExcludes"] = 2097152] = "AliasExcludes"; + SymbolFlags[SymbolFlags["ModuleMember"] = 2623475] = "ModuleMember"; + SymbolFlags[SymbolFlags["ExportHasLocal"] = 944] = "ExportHasLocal"; + SymbolFlags[SymbolFlags["BlockScoped"] = 418] = "BlockScoped"; + SymbolFlags[SymbolFlags["PropertyOrAccessor"] = 98308] = "PropertyOrAccessor"; + SymbolFlags[SymbolFlags["ClassMember"] = 106500] = "ClassMember"; + SymbolFlags[SymbolFlags["ExportSupportsDefaultModifier"] = 112] = "ExportSupportsDefaultModifier"; + SymbolFlags[SymbolFlags["ExportDoesNotSupportDefaultModifier"] = -113] = "ExportDoesNotSupportDefaultModifier"; + SymbolFlags[SymbolFlags["Classifiable"] = 2885600] = "Classifiable"; + SymbolFlags[SymbolFlags["LateBindingContainer"] = 6256] = "LateBindingContainer"; +})(SymbolFlags || (SymbolFlags = {})); diff --git a/_packages/api/src/typeFlags.enum.ts b/_packages/api/src/typeFlags.enum.ts new file mode 100644 index 0000000000..1c57bd0c31 --- /dev/null +++ b/_packages/api/src/typeFlags.enum.ts @@ -0,0 +1,32 @@ +export enum TypeFlags { + None = 0, + Any = 1 << 0, + Unknown = 1 << 1, + Undefined = 1 << 2, + Null = 1 << 3, + Void = 1 << 4, + String = 1 << 5, + Number = 1 << 6, + BigInt = 1 << 7, + Boolean = 1 << 8, + ESSymbol = 1 << 9, + StringLiteral = 1 << 10, + NumberLiteral = 1 << 11, + BigIntLiteral = 1 << 12, + BooleanLiteral = 1 << 13, + UniqueESSymbol = 1 << 14, + EnumLiteral = 1 << 15, + Enum = 1 << 16, + Never = 1 << 17, + TypeParameter = 1 << 18, + Object = 1 << 19, + Union = 1 << 20, + Intersection = 1 << 21, + Index = 1 << 22, + IndexedAccess = 1 << 23, + Conditional = 1 << 24, + Substitution = 1 << 25, + NonPrimitive = 1 << 26, + TemplateLiteral = 1 << 27, + StringMapping = 1 << 28, +} diff --git a/_packages/api/src/typeFlags.ts b/_packages/api/src/typeFlags.ts new file mode 100644 index 0000000000..a581948cb0 --- /dev/null +++ b/_packages/api/src/typeFlags.ts @@ -0,0 +1,33 @@ +export var TypeFlags: any; +(function (TypeFlags) { + TypeFlags[TypeFlags["None"] = 0] = "None"; + TypeFlags[TypeFlags["Any"] = 1] = "Any"; + TypeFlags[TypeFlags["Unknown"] = 2] = "Unknown"; + TypeFlags[TypeFlags["Undefined"] = 4] = "Undefined"; + TypeFlags[TypeFlags["Null"] = 8] = "Null"; + TypeFlags[TypeFlags["Void"] = 16] = "Void"; + TypeFlags[TypeFlags["String"] = 32] = "String"; + TypeFlags[TypeFlags["Number"] = 64] = "Number"; + TypeFlags[TypeFlags["BigInt"] = 128] = "BigInt"; + TypeFlags[TypeFlags["Boolean"] = 256] = "Boolean"; + TypeFlags[TypeFlags["ESSymbol"] = 512] = "ESSymbol"; + TypeFlags[TypeFlags["StringLiteral"] = 1024] = "StringLiteral"; + TypeFlags[TypeFlags["NumberLiteral"] = 2048] = "NumberLiteral"; + TypeFlags[TypeFlags["BigIntLiteral"] = 4096] = "BigIntLiteral"; + TypeFlags[TypeFlags["BooleanLiteral"] = 8192] = "BooleanLiteral"; + TypeFlags[TypeFlags["UniqueESSymbol"] = 16384] = "UniqueESSymbol"; + TypeFlags[TypeFlags["EnumLiteral"] = 32768] = "EnumLiteral"; + TypeFlags[TypeFlags["Enum"] = 65536] = "Enum"; + TypeFlags[TypeFlags["Never"] = 131072] = "Never"; + TypeFlags[TypeFlags["TypeParameter"] = 262144] = "TypeParameter"; + TypeFlags[TypeFlags["Object"] = 524288] = "Object"; + TypeFlags[TypeFlags["Union"] = 1048576] = "Union"; + TypeFlags[TypeFlags["Intersection"] = 2097152] = "Intersection"; + TypeFlags[TypeFlags["Index"] = 4194304] = "Index"; + TypeFlags[TypeFlags["IndexedAccess"] = 8388608] = "IndexedAccess"; + TypeFlags[TypeFlags["Conditional"] = 16777216] = "Conditional"; + TypeFlags[TypeFlags["Substitution"] = 33554432] = "Substitution"; + TypeFlags[TypeFlags["NonPrimitive"] = 67108864] = "NonPrimitive"; + TypeFlags[TypeFlags["TemplateLiteral"] = 134217728] = "TemplateLiteral"; + TypeFlags[TypeFlags["StringMapping"] = 268435456] = "StringMapping"; +})(TypeFlags || (TypeFlags = {})); diff --git a/_packages/api/test/api.bench.ts b/_packages/api/test/api.bench.ts new file mode 100644 index 0000000000..11da280dee --- /dev/null +++ b/_packages/api/test/api.bench.ts @@ -0,0 +1,303 @@ +import { + API, + type Project, +} from "@typescript/api"; +import { + type FileSystem, + type FileSystemEntries, +} from "@typescript/api/fs"; +import { + type Node, + type SourceFile, + SyntaxKind, +} from "@typescript/ast"; +import fs, { existsSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { Bench } from "tinybench"; +import ts from "typescript"; + +const isMain = process.argv[1] === fileURLToPath(import.meta.url); +if (isMain) { + await runBenchmarks(); +} + +export async function runBenchmarks(singleIteration?: boolean) { + const repoRoot = fileURLToPath(new URL("../../../", import.meta.url).toString()); + if (!existsSync(path.join(repoRoot, "_submodules/TypeScript/src/compiler"))) { + console.warn("Warning: TypeScript submodule is not cloned; skipping benchmarks."); + return; + } + + const bench = new Bench({ + name: "Sync API", + teardown, + ...singleIteration ? { + iterations: 1, + warmup: false, + time: 0, + } : undefined, + }); + + let api: API; + let project: Project; + let tsProgram: ts.Program; + let file: SourceFile; + let tsFile: ts.SourceFile; + + const programIdentifierCount = (() => { + spawnAPI(); + loadProject(); + getProgramTS(); + let count = 0; + file!.forEachChild(function visit(node) { + if (node.kind === SyntaxKind.Identifier) { + count++; + } + node.forEachChild(visit); + }); + teardown(); + return count; + })(); + + const SMALL_STRING = "ping"; + const LARGE_STRING = "a".repeat(1_000_000); + const SMALL_UINT8_ARRAY = new Uint8Array([1, 2, 3, 4]); + const LARGE_UINT8_ARRAY = new Uint8Array(1_000_000); + + bench + .add("spawn API", () => { + spawnAPI(); + }) + .add("echo (small string)", () => { + api.echo(SMALL_STRING); + }, { beforeAll: spawnAPI }) + .add("echo (large string)", () => { + api.echo(LARGE_STRING); + }, { beforeAll: spawnAPI }) + .add("echo (small Uint8Array)", () => { + api.echoBinary(SMALL_UINT8_ARRAY); + }, { beforeAll: spawnAPI }) + .add("echo (large Uint8Array)", () => { + api.echoBinary(LARGE_UINT8_ARRAY); + }, { beforeAll: spawnAPI }) + .add("load project", () => { + loadProject(); + }, { beforeAll: spawnAPI }) + .add("load project (client FS)", () => { + loadProject(); + }, { beforeAll: spawnAPIHosted }) + .add("TS - load project", () => { + tsCreateProgram(); + }) + .add("transfer debug.ts", () => { + getDebugTS(); + }, { beforeAll: all(spawnAPI, loadProject) }) + .add("transfer program.ts", () => { + getProgramTS(); + }, { beforeAll: all(spawnAPI, loadProject) }) + .add("transfer checker.ts", () => { + getCheckerTS(); + }, { beforeAll: all(spawnAPI, loadProject) }) + .add("materialize program.ts", () => { + file.forEachChild(function visit(node) { + node.forEachChild(visit); + }); + }, { beforeAll: all(spawnAPI, loadProject, getProgramTS) }) + .add("materialize checker.ts", () => { + file.forEachChild(function visit(node) { + node.forEachChild(visit); + }); + }, { beforeAll: all(spawnAPI, loadProject, getCheckerTS) }) + .add("getSymbolAtPosition - one location", () => { + project.getSymbolAtPosition("program.ts", 8895); + }, { beforeAll: all(spawnAPI, loadProject, createChecker) }) + .add("TS - getSymbolAtPosition - one location", () => { + tsProgram.getTypeChecker().getSymbolAtLocation( + // @ts-ignore internal API + ts.getTokenAtPosition(tsFile, 8895), + ); + }, { beforeAll: all(tsCreateProgram, tsCreateChecker, tsGetProgramTS) }) + .add(`getSymbolAtPosition - ${programIdentifierCount} identifiers`, () => { + file.forEachChild(function visit(node) { + if (node.kind === SyntaxKind.Identifier) { + project.getSymbolAtPosition("program.ts", node.pos); + } + node.forEachChild(visit); + }); + }, { beforeAll: all(spawnAPI, loadProject, createChecker, getProgramTS) }) + .add(`getSymbolAtPosition - ${programIdentifierCount} identifiers (batched)`, () => { + const positions: number[] = []; + file.forEachChild(function visit(node) { + if (node.kind === SyntaxKind.Identifier) { + positions.push(node.pos); + } + node.forEachChild(visit); + }); + project.getSymbolAtPosition("program.ts", positions); + }, { beforeAll: all(spawnAPI, loadProject, createChecker, getProgramTS) }) + .add(`getSymbolAtLocation - ${programIdentifierCount} identifiers`, () => { + file.forEachChild(function visit(node) { + if (node.kind === SyntaxKind.Identifier) { + project.getSymbolAtLocation(node); + } + node.forEachChild(visit); + }); + }, { beforeAll: all(spawnAPI, loadProject, createChecker, getProgramTS) }) + .add(`getSymbolAtLocation - ${programIdentifierCount} identifiers (batched)`, () => { + const nodes: Node[] = []; + file.forEachChild(function visit(node) { + if (node.kind === SyntaxKind.Identifier) { + nodes.push(node); + } + node.forEachChild(visit); + }); + project.getSymbolAtLocation(nodes); + }, { beforeAll: all(spawnAPI, loadProject, createChecker, getProgramTS) }) + .add(`TS - getSymbolAtLocation - ${programIdentifierCount} identifiers`, () => { + const checker = tsProgram.getTypeChecker(); + tsFile.forEachChild(function visit(node) { + if (node.kind === ts.SyntaxKind.Identifier) { + checker.getSymbolAtLocation(node); + } + node.forEachChild(visit); + }); + }, { beforeAll: all(tsCreateProgram, tsCreateChecker, tsGetProgramTS) }); + + await bench.run(); + console.table(bench.table()); + + function spawnAPI() { + api = new API({ + cwd: repoRoot, + tsserverPath: fileURLToPath(new URL(`../../../built/local/tsgo${process.platform === "win32" ? ".exe" : ""}`, import.meta.url).toString()), + }); + } + + function spawnAPIHosted() { + api = new API({ + cwd: repoRoot, + tsserverPath: fileURLToPath(new URL(`../../../built/local/tsgo${process.platform === "win32" ? ".exe" : ""}`, import.meta.url).toString()), + fs: createNodeFileSystem(), + }); + } + + function loadProject() { + project = api.loadProject("_submodules/TypeScript/src/compiler/tsconfig.json"); + } + + function tsCreateProgram() { + const configFileName = fileURLToPath(new URL("../../../_submodules/TypeScript/src/compiler/tsconfig.json", import.meta.url).toString()); + const configFile = ts.readConfigFile(configFileName, ts.sys.readFile); + const parsedCommandLine = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configFileName)); + const host = ts.createCompilerHost(parsedCommandLine.options); + tsProgram = ts.createProgram({ + rootNames: parsedCommandLine.fileNames, + options: parsedCommandLine.options, + host, + }); + } + + function createChecker() { + // checker is created lazily, for measuring symbol time in a loop + // we need to create it first. + project.getSymbolAtPosition("core.ts", 0); + } + + function tsCreateChecker() { + tsProgram.getTypeChecker(); + } + + function getDebugTS() { + file = project.getSourceFile("debug.ts")!; + } + + function getProgramTS() { + file = project.getSourceFile("program.ts")!; + } + + function tsGetProgramTS() { + tsFile = tsProgram.getSourceFile(fileURLToPath(new URL("../../../_submodules/TypeScript/src/compiler/program.ts", import.meta.url).toString()))!; + } + + function getCheckerTS() { + file = project.getSourceFile("checker.ts")!; + } + + function teardown() { + api?.close(); + api = undefined!; + project = undefined!; + file = undefined!; + tsProgram = undefined!; + tsFile = undefined!; + } + + function all(...fns: (() => void)[]) { + return () => { + for (const fn of fns) { + fn(); + } + }; + } + + function createNodeFileSystem(): FileSystem { + return { + directoryExists: directoryName => { + try { + return fs.statSync(directoryName).isDirectory(); + } + catch { + return false; + } + }, + fileExists: fileName => { + try { + return fs.statSync(fileName).isFile(); + } + catch { + return false; + } + }, + readFile: fileName => { + try { + return fs.readFileSync(fileName, "utf8"); + } + catch { + return undefined; + } + }, + getAccessibleEntries: dirName => { + const entries: FileSystemEntries = { + files: [], + directories: [], + }; + for (const entry of fs.readdirSync(dirName, { withFileTypes: true })) { + if (entry.isFile()) { + entries.files.push(entry.name); + } + else if (entry.isDirectory()) { + entries.directories.push(entry.name); + } + else if (entry.isSymbolicLink()) { + const fullName = path.join(dirName, entry.name); + try { + const stat = fs.statSync(fullName); + if (stat.isFile()) { + entries.files.push(entry.name); + } + else if (stat.isDirectory()) { + entries.directories.push(entry.name); + } + } + catch { + // Ignore errors + } + } + } + return entries; + }, + realpath: fs.realpathSync, + }; + } +} diff --git a/_packages/api/test/api.test.ts b/_packages/api/test/api.test.ts new file mode 100644 index 0000000000..846b44d604 --- /dev/null +++ b/_packages/api/test/api.test.ts @@ -0,0 +1,164 @@ +import { + API, + SymbolFlags, + TypeFlags, +} from "@typescript/api"; +import { createVirtualFileSystem } from "@typescript/api/fs"; +import { + cast, + isImportDeclaration, + isNamedImports, + isTemplateHead, + isTemplateMiddle, + isTemplateTail, +} from "@typescript/ast"; +import assert from "node:assert"; +import { + describe, + test, +} from "node:test"; +import { fileURLToPath } from "node:url"; +import { runBenchmarks } from "./api.bench.ts"; + +const defaultFiles = { + "/tsconfig.json": "{}", + "/src/index.ts": `import { foo } from './foo';`, + "/src/foo.ts": `export const foo = 42;`, +}; + +describe("API", () => { + test("parseConfigFile", () => { + const api = spawnAPI(); + const config = api.parseConfigFile("/tsconfig.json"); + assert.deepEqual(config.fileNames, ["/src/index.ts", "/src/foo.ts"]); + assert.deepEqual(config.options, { configFilePath: "/tsconfig.json" }); + }); +}); + +describe("Project", () => { + test("getSymbolAtPosition", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const symbol = project.getSymbolAtPosition("/src/index.ts", 9); + assert.ok(symbol); + assert.equal(symbol.name, "foo"); + assert.ok(symbol.flags & SymbolFlags.Alias); + }); + + test("getSymbolAtLocation", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const sourceFile = project.getSourceFile("/src/index.ts"); + assert.ok(sourceFile); + const node = cast( + cast(sourceFile.statements[0], isImportDeclaration).importClause?.namedBindings, + isNamedImports, + ).elements[0].name; + assert.ok(node); + const symbol = project.getSymbolAtLocation(node); + assert.ok(symbol); + assert.equal(symbol.name, "foo"); + assert.ok(symbol.flags & SymbolFlags.Alias); + }); + + test("getTypeOfSymbol", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const symbol = project.getSymbolAtPosition("/src/index.ts", 9); + assert.ok(symbol); + const type = project.getTypeOfSymbol(symbol); + assert.ok(type); + assert.ok(type.flags & TypeFlags.NumberLiteral); + }); +}); + +describe("SourceFile", () => { + test("file properties", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const sourceFile = project.getSourceFile("/src/index.ts"); + + assert.ok(sourceFile); + assert.equal(sourceFile.text, defaultFiles["/src/index.ts"]); + assert.equal(sourceFile.fileName, "/src/index.ts"); + }); + + test("extended data", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const sourceFile = project.getSourceFile("/src/index.ts"); + + assert.ok(sourceFile); + let nodeCount = 1; + sourceFile.forEachChild(function visit(node) { + if (isTemplateHead(node)) { + assert.equal(node.text, "head "); + assert.equal(node.rawText, "head "); + assert.equal(node.templateFlags, 0); + } + else if (isTemplateMiddle(node)) { + assert.equal(node.text, "middle"); + assert.equal(node.rawText, "middle"); + assert.equal(node.templateFlags, 0); + } + else if (isTemplateTail(node)) { + assert.equal(node.text, " tail"); + assert.equal(node.rawText, " tail"); + assert.equal(node.templateFlags, 0); + } + nodeCount++; + node.forEachChild(visit); + }); + assert.equal(nodeCount, 7); + }); +}); + +test("Object equality", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + assert.strictEqual(project, api.loadProject("/tsconfig.json")); + assert.strictEqual( + project.getSymbolAtPosition("/src/index.ts", 9), + project.getSymbolAtPosition("/src/index.ts", 10), + ); +}); + +test("Dispose", () => { + const api = spawnAPI(); + const project = api.loadProject("/tsconfig.json"); + const symbol = project.getSymbolAtPosition("/src/index.ts", 9); + assert.ok(symbol); + assert.ok(symbol.isDisposed() === false); + symbol.dispose(); + assert.ok(symbol.isDisposed() === true); + assert.throws(() => { + project.getTypeOfSymbol(symbol); + }, { + name: "Error", + message: "Symbol is disposed", + }); + + const symbol2 = project.getSymbolAtPosition("/src/index.ts", 9); + assert.ok(symbol2); + assert.notStrictEqual(symbol, symbol2); + // @ts-ignore private API + api.client.request("release", symbol2.id); + assert.throws(() => { + project.getTypeOfSymbol(symbol2); + }, { + name: "Error", + message: `symbol "${symbol.id}" not found`, + }); +}); + +test("Benchmarks", async () => { + await runBenchmarks(/*singleIteration*/ true); +}); + +function spawnAPI(files: Record<string, string> = defaultFiles) { + return new API({ + cwd: fileURLToPath(new URL("../../../", import.meta.url).toString()), + tsserverPath: fileURLToPath(new URL(`../../../built/local/tsgo${process.platform === "win32" ? ".exe" : ""}`, import.meta.url).toString()), + fs: createVirtualFileSystem(files), + }); +} diff --git a/_packages/api/test/tsconfig.json b/_packages/api/test/tsconfig.json new file mode 100644 index 0000000000..b1a688b3b8 --- /dev/null +++ b/_packages/api/test/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.dev.json", + "references": [ + { "path": ".." } + ] +} diff --git a/_packages/api/tsconfig.base.json b/_packages/api/tsconfig.base.json new file mode 100644 index 0000000000..c99f883b56 --- /dev/null +++ b/_packages/api/tsconfig.base.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "strict": true, + "composite": true, + "forceConsistentCasingInFileNames": true, + "rewriteRelativeImportExtensions": true, + "verbatimModuleSyntax": true + } +} diff --git a/_packages/api/tsconfig.dev.json b/_packages/api/tsconfig.dev.json new file mode 100644 index 0000000000..d3b396340e --- /dev/null +++ b/_packages/api/tsconfig.dev.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "nodenext", + "strict": true, + "noEmit": true, + "verbatimModuleSyntax": true, + "allowImportingTsExtensions": true + } +} diff --git a/_packages/api/tsconfig.json b/_packages/api/tsconfig.json new file mode 100644 index 0000000000..b3b68a0719 --- /dev/null +++ b/_packages/api/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "node16", + "isolatedDeclarations": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src"], + "references": [ + { "path": "../ast" } + ] +} diff --git a/_packages/ast/package.json b/_packages/ast/package.json new file mode 100644 index 0000000000..0bddc1cdba --- /dev/null +++ b/_packages/ast/package.json @@ -0,0 +1,39 @@ +{ + "private": true, + "name": "@typescript/ast", + "version": "1.0.0", + "description": "TypeScript AST definitions", + "type": "module", + "imports": { + "#syntaxKind": { + "@typescript/source": { + "types": "./src/syntaxKind.enum.ts", + "default": "./src/syntaxKind.ts" + }, + "types": "./dist/syntaxKind.enum.d.ts", + "default": "./dist/syntaxKind.js" + }, + "#tokenFlags": { + "@typescript/source": { + "types": "./src/tokenFlags.enum.ts", + "default": "./src/tokenFlags.ts" + }, + "types": "./dist/tokenFlags.enum.d.ts", + "default": "./dist/tokenFlags.js" + } + }, + "exports": { + ".": { + "@typescript/source": "./src/index.ts", + "default": "./dist/index.js" + }, + "./is": { + "@typescript/source": "./src/is.ts", + "default": "./dist/is.js" + }, + "./utils": { + "@typescript/source": "./src/utils.ts", + "default": "./dist/utils.js" + } + } +} diff --git a/_packages/ast/src/index.ts b/_packages/ast/src/index.ts new file mode 100644 index 0000000000..74af64f5dd --- /dev/null +++ b/_packages/ast/src/index.ts @@ -0,0 +1,4 @@ +export { SyntaxKind } from "#syntaxKind"; +export * from "./is.ts"; +export * from "./nodes.ts"; +export * from "./utils.ts"; diff --git a/_packages/ast/src/is.ts b/_packages/ast/src/is.ts new file mode 100644 index 0000000000..d9563838f5 --- /dev/null +++ b/_packages/ast/src/is.ts @@ -0,0 +1,1115 @@ +import { SyntaxKind } from "#syntaxKind"; +import type { + AbstractKeyword, + AccessorKeyword, + ArrayBindingPattern, + ArrayLiteralExpression, + ArrayTypeNode, + ArrowFunction, + AsExpression, + AssertsKeyword, + AsteriskToken, + AsyncKeyword, + AwaitExpression, + AwaitKeyword, + BigIntLiteral, + BinaryExpression, + BindingElement, + Block, + BreakStatement, + CallExpression, + CallSignatureDeclaration, + CaseBlock, + CaseClause, + CaseKeyword, + CatchClause, + ClassDeclaration, + ClassExpression, + ClassStaticBlockDeclaration, + ColonToken, + CommaListExpression, + ComputedPropertyName, + ConditionalExpression, + ConditionalTypeNode, + ConstructorDeclaration, + ConstructorTypeNode, + ConstructSignatureDeclaration, + ContinueStatement, + DebuggerStatement, + Decorator, + DefaultClause, + DefaultKeyword, + DeleteExpression, + DoStatement, + DotDotDotToken, + ElementAccessExpression, + EmptyStatement, + EnumDeclaration, + EnumMember, + EqualsGreaterThanToken, + ExclamationToken, + ExportAssignment, + ExportDeclaration, + ExportKeyword, + ExportSpecifier, + ExpressionStatement, + ExpressionWithTypeArguments, + ExternalModuleReference, + ForInStatement, + ForOfStatement, + ForStatement, + FunctionDeclaration, + FunctionExpression, + FunctionTypeNode, + GetAccessorDeclaration, + HeritageClause, + Identifier, + IfStatement, + ImportAttribute, + ImportAttributes, + ImportClause, + ImportDeclaration, + ImportEqualsDeclaration, + ImportExpression, + ImportSpecifier, + ImportTypeNode, + IndexedAccessTypeNode, + IndexSignatureDeclaration, + InferTypeNode, + InterfaceDeclaration, + IntersectionTypeNode, + JSDoc, + JSDocAllType, + JSDocAugmentsTag, + JSDocCallbackTag, + JSDocDeprecatedTag, + JSDocImplementsTag, + JSDocImportTag, + JSDocLink, + JSDocLinkCode, + JSDocLinkPlain, + JSDocMemberName, + JSDocNameReference, + JSDocNonNullableType, + JSDocNullableType, + JSDocOptionalType, + JSDocOverloadTag, + JSDocOverrideTag, + JSDocParameterTag, + JSDocPrivateTag, + JSDocPropertyTag, + JSDocProtectedTag, + JSDocPublicTag, + JSDocReadonlyTag, + JSDocReturnTag, + JSDocSatisfiesTag, + JSDocSeeTag, + JSDocSignature, + JSDocTemplateTag, + JSDocThisTag, + JSDocTypedefTag, + JSDocTypeExpression, + JSDocTypeLiteral, + JSDocTypeTag, + JSDocUnknownTag, + JSDocVariadicType, + JsxAttribute, + JsxAttributes, + JsxClosingElement, + JsxClosingFragment, + JsxElement, + JsxExpression, + JsxFragment, + JsxNamespacedName, + JsxOpeningElement, + JsxOpeningFragment, + JsxSelfClosingElement, + JsxSpreadAttribute, + JsxText, + LabeledStatement, + LiteralTypeNode, + MappedTypeNode, + MetaProperty, + MethodDeclaration, + MethodSignature, + MinusToken, + ModuleBlock, + ModuleDeclaration, + ModuleExportName, + NamedExports, + NamedImports, + NamedTupleMember, + NamespaceExport, + NamespaceExportDeclaration, + NamespaceImport, + NewExpression, + Node, + NonNullExpression, + NoSubstitutionTemplateLiteral, + NumericLiteral, + ObjectBindingPattern, + ObjectLiteralExpression, + OmittedExpression, + OptionalTypeNode, + OverrideKeyword, + ParameterDeclaration, + ParenthesizedExpression, + ParenthesizedTypeNode, + PartiallyEmittedExpression, + PlusToken, + PostfixUnaryExpression, + PrefixUnaryExpression, + PrivateIdentifier, + PropertyAccessExpression, + PropertyAssignment, + PropertyDeclaration, + PropertySignature, + QualifiedName, + QuestionDotToken, + QuestionToken, + ReadonlyKeyword, + RegularExpressionLiteral, + RestTypeNode, + ReturnStatement, + SatisfiesExpression, + SemicolonClassElement, + SetAccessorDeclaration, + ShorthandPropertyAssignment, + SourceFile, + SpreadAssignment, + SpreadElement, + StaticKeyword, + StringLiteral, + SuperExpression, + SwitchStatement, + TaggedTemplateExpression, + TemplateExpression, + TemplateHead, + TemplateLiteralTypeNode, + TemplateLiteralTypeSpan, + TemplateMiddle, + TemplateSpan, + TemplateTail, + ThisTypeNode, + ThrowStatement, + Token, + TryStatement, + TupleTypeNode, + TypeAliasDeclaration, + TypeAssertion, + TypeLiteralNode, + TypeOfExpression, + TypeOperatorNode, + TypeParameterDeclaration, + TypePredicateNode, + TypeQueryNode, + TypeReferenceNode, + UnionTypeNode, + VariableDeclaration, + VariableDeclarationList, + VariableStatement, + VoidExpression, + WhileStatement, + WithStatement, + YieldExpression, +} from "./nodes.ts"; + +// Literals + +export function isNumericLiteral(node: Node): node is NumericLiteral { + return node.kind === SyntaxKind.NumericLiteral; +} + +export function isBigIntLiteral(node: Node): node is BigIntLiteral { + return node.kind === SyntaxKind.BigIntLiteral; +} + +export function isStringLiteral(node: Node): node is StringLiteral { + return node.kind === SyntaxKind.StringLiteral; +} + +export function isJsxText(node: Node): node is JsxText { + return node.kind === SyntaxKind.JsxText; +} + +export function isRegularExpressionLiteral(node: Node): node is RegularExpressionLiteral { + return node.kind === SyntaxKind.RegularExpressionLiteral; +} + +export function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral { + return node.kind === SyntaxKind.NoSubstitutionTemplateLiteral; +} + +// Pseudo-literals + +export function isTemplateHead(node: Node): node is TemplateHead { + return node.kind === SyntaxKind.TemplateHead; +} + +export function isTemplateMiddle(node: Node): node is TemplateMiddle { + return node.kind === SyntaxKind.TemplateMiddle; +} + +export function isTemplateTail(node: Node): node is TemplateTail { + return node.kind === SyntaxKind.TemplateTail; +} + +// Punctuation + +export function isDotDotDotToken(node: Node): node is DotDotDotToken { + return node.kind === SyntaxKind.DotDotDotToken; +} + +/** @internal */ +export function isCommaToken(node: Node): node is Token<SyntaxKind.CommaToken> { + return node.kind === SyntaxKind.CommaToken; +} + +export function isPlusToken(node: Node): node is PlusToken { + return node.kind === SyntaxKind.PlusToken; +} + +export function isMinusToken(node: Node): node is MinusToken { + return node.kind === SyntaxKind.MinusToken; +} + +export function isAsteriskToken(node: Node): node is AsteriskToken { + return node.kind === SyntaxKind.AsteriskToken; +} + +export function isExclamationToken(node: Node): node is ExclamationToken { + return node.kind === SyntaxKind.ExclamationToken; +} + +export function isQuestionToken(node: Node): node is QuestionToken { + return node.kind === SyntaxKind.QuestionToken; +} + +export function isColonToken(node: Node): node is ColonToken { + return node.kind === SyntaxKind.ColonToken; +} + +export function isQuestionDotToken(node: Node): node is QuestionDotToken { + return node.kind === SyntaxKind.QuestionDotToken; +} + +export function isEqualsGreaterThanToken(node: Node): node is EqualsGreaterThanToken { + return node.kind === SyntaxKind.EqualsGreaterThanToken; +} + +// Identifiers + +export function isIdentifier(node: Node): node is Identifier { + return node.kind === SyntaxKind.Identifier; +} + +export function isPrivateIdentifier(node: Node): node is PrivateIdentifier { + return node.kind === SyntaxKind.PrivateIdentifier; +} + +// Reserved Words + +/** @internal */ +export function isExportModifier(node: Node): node is ExportKeyword { + return node.kind === SyntaxKind.ExportKeyword; +} + +/** @internal */ +export function isDefaultModifier(node: Node): node is DefaultKeyword { + return node.kind === SyntaxKind.DefaultKeyword; +} + +/** @internal */ +export function isAsyncModifier(node: Node): node is AsyncKeyword { + return node.kind === SyntaxKind.AsyncKeyword; +} + +export function isAssertsKeyword(node: Node): node is AssertsKeyword { + return node.kind === SyntaxKind.AssertsKeyword; +} + +export function isAwaitKeyword(node: Node): node is AwaitKeyword { + return node.kind === SyntaxKind.AwaitKeyword; +} + +/** @internal */ +export function isReadonlyKeyword(node: Node): node is ReadonlyKeyword { + return node.kind === SyntaxKind.ReadonlyKeyword; +} + +/** @internal */ +export function isStaticModifier(node: Node): node is StaticKeyword { + return node.kind === SyntaxKind.StaticKeyword; +} + +/** @internal */ +export function isAbstractModifier(node: Node): node is AbstractKeyword { + return node.kind === SyntaxKind.AbstractKeyword; +} + +/** @internal */ +export function isOverrideModifier(node: Node): node is OverrideKeyword { + return node.kind === SyntaxKind.OverrideKeyword; +} + +/** @internal */ +export function isAccessorModifier(node: Node): node is AccessorKeyword { + return node.kind === SyntaxKind.AccessorKeyword; +} + +/** @internal */ +export function isSuperKeyword(node: Node): node is SuperExpression { + return node.kind === SyntaxKind.SuperKeyword; +} + +/** @internal */ +export function isImportKeyword(node: Node): node is ImportExpression { + return node.kind === SyntaxKind.ImportKeyword; +} + +/** @internal */ +export function isCaseKeyword(node: Node): node is CaseKeyword { + return node.kind === SyntaxKind.CaseKeyword; +} + +// Names + +export function isQualifiedName(node: Node): node is QualifiedName { + return node.kind === SyntaxKind.QualifiedName; +} + +export function isComputedPropertyName(node: Node): node is ComputedPropertyName { + return node.kind === SyntaxKind.ComputedPropertyName; +} + +// Signature elements + +export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration { + return node.kind === SyntaxKind.TypeParameter; +} + +// TODO(rbuckton): Rename to 'isParameterDeclaration' +export function isParameter(node: Node): node is ParameterDeclaration { + return node.kind === SyntaxKind.Parameter; +} + +export function isDecorator(node: Node): node is Decorator { + return node.kind === SyntaxKind.Decorator; +} + +// TypeMember + +export function isPropertySignature(node: Node): node is PropertySignature { + return node.kind === SyntaxKind.PropertySignature; +} + +export function isPropertyDeclaration(node: Node): node is PropertyDeclaration { + return node.kind === SyntaxKind.PropertyDeclaration; +} + +export function isMethodSignature(node: Node): node is MethodSignature { + return node.kind === SyntaxKind.MethodSignature; +} + +export function isMethodDeclaration(node: Node): node is MethodDeclaration { + return node.kind === SyntaxKind.MethodDeclaration; +} + +export function isClassStaticBlockDeclaration(node: Node): node is ClassStaticBlockDeclaration { + return node.kind === SyntaxKind.ClassStaticBlockDeclaration; +} + +export function isConstructorDeclaration(node: Node): node is ConstructorDeclaration { + return node.kind === SyntaxKind.Constructor; +} + +export function isGetAccessorDeclaration(node: Node): node is GetAccessorDeclaration { + return node.kind === SyntaxKind.GetAccessor; +} + +export function isSetAccessorDeclaration(node: Node): node is SetAccessorDeclaration { + return node.kind === SyntaxKind.SetAccessor; +} + +export function isCallSignatureDeclaration(node: Node): node is CallSignatureDeclaration { + return node.kind === SyntaxKind.CallSignature; +} + +export function isConstructSignatureDeclaration(node: Node): node is ConstructSignatureDeclaration { + return node.kind === SyntaxKind.ConstructSignature; +} + +export function isIndexSignatureDeclaration(node: Node): node is IndexSignatureDeclaration { + return node.kind === SyntaxKind.IndexSignature; +} + +// Type + +export function isTypePredicateNode(node: Node): node is TypePredicateNode { + return node.kind === SyntaxKind.TypePredicate; +} + +export function isTypeReferenceNode(node: Node): node is TypeReferenceNode { + return node.kind === SyntaxKind.TypeReference; +} + +export function isFunctionTypeNode(node: Node): node is FunctionTypeNode { + return node.kind === SyntaxKind.FunctionType; +} + +export function isConstructorTypeNode(node: Node): node is ConstructorTypeNode { + return node.kind === SyntaxKind.ConstructorType; +} + +export function isTypeQueryNode(node: Node): node is TypeQueryNode { + return node.kind === SyntaxKind.TypeQuery; +} + +export function isTypeLiteralNode(node: Node): node is TypeLiteralNode { + return node.kind === SyntaxKind.TypeLiteral; +} + +export function isArrayTypeNode(node: Node): node is ArrayTypeNode { + return node.kind === SyntaxKind.ArrayType; +} + +export function isTupleTypeNode(node: Node): node is TupleTypeNode { + return node.kind === SyntaxKind.TupleType; +} + +export function isNamedTupleMember(node: Node): node is NamedTupleMember { + return node.kind === SyntaxKind.NamedTupleMember; +} + +export function isOptionalTypeNode(node: Node): node is OptionalTypeNode { + return node.kind === SyntaxKind.OptionalType; +} + +export function isRestTypeNode(node: Node): node is RestTypeNode { + return node.kind === SyntaxKind.RestType; +} + +export function isUnionTypeNode(node: Node): node is UnionTypeNode { + return node.kind === SyntaxKind.UnionType; +} + +export function isIntersectionTypeNode(node: Node): node is IntersectionTypeNode { + return node.kind === SyntaxKind.IntersectionType; +} + +export function isConditionalTypeNode(node: Node): node is ConditionalTypeNode { + return node.kind === SyntaxKind.ConditionalType; +} + +export function isInferTypeNode(node: Node): node is InferTypeNode { + return node.kind === SyntaxKind.InferType; +} + +export function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode { + return node.kind === SyntaxKind.ParenthesizedType; +} + +export function isThisTypeNode(node: Node): node is ThisTypeNode { + return node.kind === SyntaxKind.ThisType; +} + +export function isTypeOperatorNode(node: Node): node is TypeOperatorNode { + return node.kind === SyntaxKind.TypeOperator; +} + +export function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode { + return node.kind === SyntaxKind.IndexedAccessType; +} + +export function isMappedTypeNode(node: Node): node is MappedTypeNode { + return node.kind === SyntaxKind.MappedType; +} + +export function isLiteralTypeNode(node: Node): node is LiteralTypeNode { + return node.kind === SyntaxKind.LiteralType; +} + +export function isImportTypeNode(node: Node): node is ImportTypeNode { + return node.kind === SyntaxKind.ImportType; +} + +export function isTemplateLiteralTypeSpan(node: Node): node is TemplateLiteralTypeSpan { + return node.kind === SyntaxKind.TemplateLiteralTypeSpan; +} + +export function isTemplateLiteralTypeNode(node: Node): node is TemplateLiteralTypeNode { + return node.kind === SyntaxKind.TemplateLiteralType; +} + +// Binding patterns + +export function isObjectBindingPattern(node: Node): node is ObjectBindingPattern { + return node.kind === SyntaxKind.ObjectBindingPattern; +} + +export function isArrayBindingPattern(node: Node): node is ArrayBindingPattern { + return node.kind === SyntaxKind.ArrayBindingPattern; +} + +export function isBindingElement(node: Node): node is BindingElement { + return node.kind === SyntaxKind.BindingElement; +} + +// Expression + +export function isArrayLiteralExpression(node: Node): node is ArrayLiteralExpression { + return node.kind === SyntaxKind.ArrayLiteralExpression; +} + +export function isObjectLiteralExpression(node: Node): node is ObjectLiteralExpression { + return node.kind === SyntaxKind.ObjectLiteralExpression; +} + +export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression { + return node.kind === SyntaxKind.PropertyAccessExpression; +} + +export function isElementAccessExpression(node: Node): node is ElementAccessExpression { + return node.kind === SyntaxKind.ElementAccessExpression; +} + +export function isCallExpression(node: Node): node is CallExpression { + return node.kind === SyntaxKind.CallExpression; +} + +export function isNewExpression(node: Node): node is NewExpression { + return node.kind === SyntaxKind.NewExpression; +} + +export function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression { + return node.kind === SyntaxKind.TaggedTemplateExpression; +} + +export function isTypeAssertionExpression(node: Node): node is TypeAssertion { + return node.kind === SyntaxKind.TypeAssertionExpression; +} + +export function isParenthesizedExpression(node: Node): node is ParenthesizedExpression { + return node.kind === SyntaxKind.ParenthesizedExpression; +} + +export function isFunctionExpression(node: Node): node is FunctionExpression { + return node.kind === SyntaxKind.FunctionExpression; +} + +export function isArrowFunction(node: Node): node is ArrowFunction { + return node.kind === SyntaxKind.ArrowFunction; +} + +export function isDeleteExpression(node: Node): node is DeleteExpression { + return node.kind === SyntaxKind.DeleteExpression; +} + +export function isTypeOfExpression(node: Node): node is TypeOfExpression { + return node.kind === SyntaxKind.TypeOfExpression; +} + +export function isVoidExpression(node: Node): node is VoidExpression { + return node.kind === SyntaxKind.VoidExpression; +} + +export function isAwaitExpression(node: Node): node is AwaitExpression { + return node.kind === SyntaxKind.AwaitExpression; +} + +export function isPrefixUnaryExpression(node: Node): node is PrefixUnaryExpression { + return node.kind === SyntaxKind.PrefixUnaryExpression; +} + +export function isPostfixUnaryExpression(node: Node): node is PostfixUnaryExpression { + return node.kind === SyntaxKind.PostfixUnaryExpression; +} + +export function isBinaryExpression(node: Node): node is BinaryExpression { + return node.kind === SyntaxKind.BinaryExpression; +} + +export function isConditionalExpression(node: Node): node is ConditionalExpression { + return node.kind === SyntaxKind.ConditionalExpression; +} + +export function isTemplateExpression(node: Node): node is TemplateExpression { + return node.kind === SyntaxKind.TemplateExpression; +} + +export function isYieldExpression(node: Node): node is YieldExpression { + return node.kind === SyntaxKind.YieldExpression; +} + +export function isSpreadElement(node: Node): node is SpreadElement { + return node.kind === SyntaxKind.SpreadElement; +} + +export function isClassExpression(node: Node): node is ClassExpression { + return node.kind === SyntaxKind.ClassExpression; +} + +export function isOmittedExpression(node: Node): node is OmittedExpression { + return node.kind === SyntaxKind.OmittedExpression; +} + +export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments { + return node.kind === SyntaxKind.ExpressionWithTypeArguments; +} + +export function isAsExpression(node: Node): node is AsExpression { + return node.kind === SyntaxKind.AsExpression; +} + +export function isSatisfiesExpression(node: Node): node is SatisfiesExpression { + return node.kind === SyntaxKind.SatisfiesExpression; +} + +export function isNonNullExpression(node: Node): node is NonNullExpression { + return node.kind === SyntaxKind.NonNullExpression; +} + +export function isMetaProperty(node: Node): node is MetaProperty { + return node.kind === SyntaxKind.MetaProperty; +} + +export function isPartiallyEmittedExpression(node: Node): node is PartiallyEmittedExpression { + return node.kind === SyntaxKind.PartiallyEmittedExpression; +} + +export function isCommaListExpression(node: Node): node is CommaListExpression { + return node.kind === SyntaxKind.CommaListExpression; +} + +// Misc + +export function isTemplateSpan(node: Node): node is TemplateSpan { + return node.kind === SyntaxKind.TemplateSpan; +} + +export function isSemicolonClassElement(node: Node): node is SemicolonClassElement { + return node.kind === SyntaxKind.SemicolonClassElement; +} + +// Elements + +export function isBlock(node: Node): node is Block { + return node.kind === SyntaxKind.Block; +} + +export function isVariableStatement(node: Node): node is VariableStatement { + return node.kind === SyntaxKind.VariableStatement; +} + +export function isEmptyStatement(node: Node): node is EmptyStatement { + return node.kind === SyntaxKind.EmptyStatement; +} + +export function isExpressionStatement(node: Node): node is ExpressionStatement { + return node.kind === SyntaxKind.ExpressionStatement; +} + +export function isIfStatement(node: Node): node is IfStatement { + return node.kind === SyntaxKind.IfStatement; +} + +export function isDoStatement(node: Node): node is DoStatement { + return node.kind === SyntaxKind.DoStatement; +} + +export function isWhileStatement(node: Node): node is WhileStatement { + return node.kind === SyntaxKind.WhileStatement; +} + +export function isForStatement(node: Node): node is ForStatement { + return node.kind === SyntaxKind.ForStatement; +} + +export function isForInStatement(node: Node): node is ForInStatement { + return node.kind === SyntaxKind.ForInStatement; +} + +export function isForOfStatement(node: Node): node is ForOfStatement { + return node.kind === SyntaxKind.ForOfStatement; +} + +export function isContinueStatement(node: Node): node is ContinueStatement { + return node.kind === SyntaxKind.ContinueStatement; +} + +export function isBreakStatement(node: Node): node is BreakStatement { + return node.kind === SyntaxKind.BreakStatement; +} + +export function isReturnStatement(node: Node): node is ReturnStatement { + return node.kind === SyntaxKind.ReturnStatement; +} + +export function isWithStatement(node: Node): node is WithStatement { + return node.kind === SyntaxKind.WithStatement; +} + +export function isSwitchStatement(node: Node): node is SwitchStatement { + return node.kind === SyntaxKind.SwitchStatement; +} + +export function isLabeledStatement(node: Node): node is LabeledStatement { + return node.kind === SyntaxKind.LabeledStatement; +} + +export function isThrowStatement(node: Node): node is ThrowStatement { + return node.kind === SyntaxKind.ThrowStatement; +} + +export function isTryStatement(node: Node): node is TryStatement { + return node.kind === SyntaxKind.TryStatement; +} + +export function isDebuggerStatement(node: Node): node is DebuggerStatement { + return node.kind === SyntaxKind.DebuggerStatement; +} + +export function isVariableDeclaration(node: Node): node is VariableDeclaration { + return node.kind === SyntaxKind.VariableDeclaration; +} + +export function isVariableDeclarationList(node: Node): node is VariableDeclarationList { + return node.kind === SyntaxKind.VariableDeclarationList; +} + +export function isFunctionDeclaration(node: Node): node is FunctionDeclaration { + return node.kind === SyntaxKind.FunctionDeclaration; +} + +export function isClassDeclaration(node: Node): node is ClassDeclaration { + return node.kind === SyntaxKind.ClassDeclaration; +} + +export function isInterfaceDeclaration(node: Node): node is InterfaceDeclaration { + return node.kind === SyntaxKind.InterfaceDeclaration; +} + +export function isTypeAliasDeclaration(node: Node): node is TypeAliasDeclaration { + return node.kind === SyntaxKind.TypeAliasDeclaration; +} + +export function isEnumDeclaration(node: Node): node is EnumDeclaration { + return node.kind === SyntaxKind.EnumDeclaration; +} + +export function isModuleDeclaration(node: Node): node is ModuleDeclaration { + return node.kind === SyntaxKind.ModuleDeclaration; +} + +export function isModuleBlock(node: Node): node is ModuleBlock { + return node.kind === SyntaxKind.ModuleBlock; +} + +export function isCaseBlock(node: Node): node is CaseBlock { + return node.kind === SyntaxKind.CaseBlock; +} + +export function isNamespaceExportDeclaration(node: Node): node is NamespaceExportDeclaration { + return node.kind === SyntaxKind.NamespaceExportDeclaration; +} + +export function isImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { + return node.kind === SyntaxKind.ImportEqualsDeclaration; +} + +export function isImportDeclaration(node: Node): node is ImportDeclaration { + return node.kind === SyntaxKind.ImportDeclaration; +} + +export function isImportClause(node: Node): node is ImportClause { + return node.kind === SyntaxKind.ImportClause; +} + +export function isImportAttributes(node: Node): node is ImportAttributes { + return node.kind === SyntaxKind.ImportAttributes; +} + +export function isImportAttribute(node: Node): node is ImportAttribute { + return node.kind === SyntaxKind.ImportAttribute; +} + +export function isNamespaceImport(node: Node): node is NamespaceImport { + return node.kind === SyntaxKind.NamespaceImport; +} + +export function isNamespaceExport(node: Node): node is NamespaceExport { + return node.kind === SyntaxKind.NamespaceExport; +} + +export function isNamedImports(node: Node): node is NamedImports { + return node.kind === SyntaxKind.NamedImports; +} + +export function isImportSpecifier(node: Node): node is ImportSpecifier { + return node.kind === SyntaxKind.ImportSpecifier; +} + +export function isExportAssignment(node: Node): node is ExportAssignment { + return node.kind === SyntaxKind.ExportAssignment; +} + +export function isExportDeclaration(node: Node): node is ExportDeclaration { + return node.kind === SyntaxKind.ExportDeclaration; +} + +export function isNamedExports(node: Node): node is NamedExports { + return node.kind === SyntaxKind.NamedExports; +} + +export function isExportSpecifier(node: Node): node is ExportSpecifier { + return node.kind === SyntaxKind.ExportSpecifier; +} + +export function isModuleExportName(node: Node): node is ModuleExportName { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral; +} + +// Module References + +export function isExternalModuleReference(node: Node): node is ExternalModuleReference { + return node.kind === SyntaxKind.ExternalModuleReference; +} + +// JSX + +export function isJsxElement(node: Node): node is JsxElement { + return node.kind === SyntaxKind.JsxElement; +} + +export function isJsxSelfClosingElement(node: Node): node is JsxSelfClosingElement { + return node.kind === SyntaxKind.JsxSelfClosingElement; +} + +export function isJsxOpeningElement(node: Node): node is JsxOpeningElement { + return node.kind === SyntaxKind.JsxOpeningElement; +} + +export function isJsxClosingElement(node: Node): node is JsxClosingElement { + return node.kind === SyntaxKind.JsxClosingElement; +} + +export function isJsxFragment(node: Node): node is JsxFragment { + return node.kind === SyntaxKind.JsxFragment; +} + +export function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment { + return node.kind === SyntaxKind.JsxOpeningFragment; +} + +export function isJsxClosingFragment(node: Node): node is JsxClosingFragment { + return node.kind === SyntaxKind.JsxClosingFragment; +} + +export function isJsxAttribute(node: Node): node is JsxAttribute { + return node.kind === SyntaxKind.JsxAttribute; +} + +export function isJsxAttributes(node: Node): node is JsxAttributes { + return node.kind === SyntaxKind.JsxAttributes; +} + +export function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute { + return node.kind === SyntaxKind.JsxSpreadAttribute; +} + +export function isJsxExpression(node: Node): node is JsxExpression { + return node.kind === SyntaxKind.JsxExpression; +} + +export function isJsxNamespacedName(node: Node): node is JsxNamespacedName { + return node.kind === SyntaxKind.JsxNamespacedName; +} + +// Clauses + +export function isCaseClause(node: Node): node is CaseClause { + return node.kind === SyntaxKind.CaseClause; +} + +export function isDefaultClause(node: Node): node is DefaultClause { + return node.kind === SyntaxKind.DefaultClause; +} + +export function isHeritageClause(node: Node): node is HeritageClause { + return node.kind === SyntaxKind.HeritageClause; +} + +export function isCatchClause(node: Node): node is CatchClause { + return node.kind === SyntaxKind.CatchClause; +} + +// Property assignments + +export function isPropertyAssignment(node: Node): node is PropertyAssignment { + return node.kind === SyntaxKind.PropertyAssignment; +} + +export function isShorthandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment { + return node.kind === SyntaxKind.ShorthandPropertyAssignment; +} + +export function isSpreadAssignment(node: Node): node is SpreadAssignment { + return node.kind === SyntaxKind.SpreadAssignment; +} + +// Enum + +export function isEnumMember(node: Node): node is EnumMember { + return node.kind === SyntaxKind.EnumMember; +} + +// Top-level nodes +export function isSourceFile(node: Node): node is SourceFile { + return node.kind === SyntaxKind.SourceFile; +} + +// TODO(rbuckton): isInputFiles + +// JSDoc Elements + +export function isJSDocTypeExpression(node: Node): node is JSDocTypeExpression { + return node.kind === SyntaxKind.JSDocTypeExpression; +} + +export function isJSDocNameReference(node: Node): node is JSDocNameReference { + return node.kind === SyntaxKind.JSDocNameReference; +} + +export function isJSDocMemberName(node: Node): node is JSDocMemberName { + return node.kind === SyntaxKind.JSDocMemberName; +} + +export function isJSDocLink(node: Node): node is JSDocLink { + return node.kind === SyntaxKind.JSDocLink; +} + +export function isJSDocLinkCode(node: Node): node is JSDocLinkCode { + return node.kind === SyntaxKind.JSDocLinkCode; +} + +export function isJSDocLinkPlain(node: Node): node is JSDocLinkPlain { + return node.kind === SyntaxKind.JSDocLinkPlain; +} + +export function isJSDocAllType(node: Node): node is JSDocAllType { + return node.kind === SyntaxKind.JSDocAllType; +} + +export function isJSDocNullableType(node: Node): node is JSDocNullableType { + return node.kind === SyntaxKind.JSDocNullableType; +} + +export function isJSDocNonNullableType(node: Node): node is JSDocNonNullableType { + return node.kind === SyntaxKind.JSDocNonNullableType; +} + +export function isJSDocOptionalType(node: Node): node is JSDocOptionalType { + return node.kind === SyntaxKind.JSDocOptionalType; +} + +export function isJSDocVariadicType(node: Node): node is JSDocVariadicType { + return node.kind === SyntaxKind.JSDocVariadicType; +} + +export function isJSDoc(node: Node): node is JSDoc { + return node.kind === SyntaxKind.JSDoc; +} + +export function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral { + return node.kind === SyntaxKind.JSDocTypeLiteral; +} + +export function isJSDocSignature(node: Node): node is JSDocSignature { + return node.kind === SyntaxKind.JSDocSignature; +} + +// JSDoc Tags + +export function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag { + return node.kind === SyntaxKind.JSDocAugmentsTag; +} + +export function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag { + return node.kind === SyntaxKind.JSDocCallbackTag; +} + +export function isJSDocPublicTag(node: Node): node is JSDocPublicTag { + return node.kind === SyntaxKind.JSDocPublicTag; +} + +export function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag { + return node.kind === SyntaxKind.JSDocPrivateTag; +} + +export function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag { + return node.kind === SyntaxKind.JSDocProtectedTag; +} + +export function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag { + return node.kind === SyntaxKind.JSDocReadonlyTag; +} + +export function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag { + return node.kind === SyntaxKind.JSDocOverrideTag; +} + +export function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag { + return node.kind === SyntaxKind.JSDocOverloadTag; +} + +export function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag { + return node.kind === SyntaxKind.JSDocDeprecatedTag; +} + +export function isJSDocSeeTag(node: Node): node is JSDocSeeTag { + return node.kind === SyntaxKind.JSDocSeeTag; +} + +export function isJSDocParameterTag(node: Node): node is JSDocParameterTag { + return node.kind === SyntaxKind.JSDocParameterTag; +} + +export function isJSDocReturnTag(node: Node): node is JSDocReturnTag { + return node.kind === SyntaxKind.JSDocReturnTag; +} + +export function isJSDocThisTag(node: Node): node is JSDocThisTag { + return node.kind === SyntaxKind.JSDocThisTag; +} + +export function isJSDocTypeTag(node: Node): node is JSDocTypeTag { + return node.kind === SyntaxKind.JSDocTypeTag; +} + +export function isJSDocTemplateTag(node: Node): node is JSDocTemplateTag { + return node.kind === SyntaxKind.JSDocTemplateTag; +} + +export function isJSDocTypedefTag(node: Node): node is JSDocTypedefTag { + return node.kind === SyntaxKind.JSDocTypedefTag; +} + +export function isJSDocUnknownTag(node: Node): node is JSDocUnknownTag { + return node.kind === SyntaxKind.JSDocTag; +} + +export function isJSDocPropertyTag(node: Node): node is JSDocPropertyTag { + return node.kind === SyntaxKind.JSDocPropertyTag; +} + +export function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag { + return node.kind === SyntaxKind.JSDocImplementsTag; +} + +export function isJSDocSatisfiesTag(node: Node): node is JSDocSatisfiesTag { + return node.kind === SyntaxKind.JSDocSatisfiesTag; +} + +export function isJSDocImportTag(node: Node): node is JSDocImportTag { + return node.kind === SyntaxKind.JSDocImportTag; +} diff --git a/_packages/ast/src/nodes.ts b/_packages/ast/src/nodes.ts new file mode 100644 index 0000000000..a265f5545e --- /dev/null +++ b/_packages/ast/src/nodes.ts @@ -0,0 +1,2414 @@ +import { SyntaxKind } from "#syntaxKind"; +import { TokenFlags } from "#tokenFlags"; + +export interface TextRange { + pos: number; + end: number; +} + +export interface Node extends ReadonlyTextRange { + readonly kind: SyntaxKind; + readonly parent: Node; +} + +export interface SourceFile extends Node { + readonly kind: SyntaxKind.SourceFile; + readonly statements: NodeArray<Statement>; + readonly text: string; + readonly fileName: string; +} + +export type TriviaSyntaxKind = + | SyntaxKind.SingleLineCommentTrivia + | SyntaxKind.MultiLineCommentTrivia + | SyntaxKind.NewLineTrivia + | SyntaxKind.WhitespaceTrivia + | SyntaxKind.ConflictMarkerTrivia; + +export type LiteralSyntaxKind = + | SyntaxKind.NumericLiteral + | SyntaxKind.BigIntLiteral + | SyntaxKind.StringLiteral + | SyntaxKind.JsxText + | SyntaxKind.JsxTextAllWhiteSpaces + | SyntaxKind.RegularExpressionLiteral + | SyntaxKind.NoSubstitutionTemplateLiteral; + +export type PseudoLiteralSyntaxKind = + | SyntaxKind.TemplateHead + | SyntaxKind.TemplateMiddle + | SyntaxKind.TemplateTail; + +export type PunctuationSyntaxKind = + | SyntaxKind.OpenBraceToken + | SyntaxKind.CloseBraceToken + | SyntaxKind.OpenParenToken + | SyntaxKind.CloseParenToken + | SyntaxKind.OpenBracketToken + | SyntaxKind.CloseBracketToken + | SyntaxKind.DotToken + | SyntaxKind.DotDotDotToken + | SyntaxKind.SemicolonToken + | SyntaxKind.CommaToken + | SyntaxKind.QuestionDotToken + | SyntaxKind.LessThanToken + | SyntaxKind.LessThanSlashToken + | SyntaxKind.GreaterThanToken + | SyntaxKind.LessThanEqualsToken + | SyntaxKind.GreaterThanEqualsToken + | SyntaxKind.EqualsEqualsToken + | SyntaxKind.ExclamationEqualsToken + | SyntaxKind.EqualsEqualsEqualsToken + | SyntaxKind.ExclamationEqualsEqualsToken + | SyntaxKind.EqualsGreaterThanToken + | SyntaxKind.PlusToken + | SyntaxKind.MinusToken + | SyntaxKind.AsteriskToken + | SyntaxKind.AsteriskAsteriskToken + | SyntaxKind.SlashToken + | SyntaxKind.PercentToken + | SyntaxKind.PlusPlusToken + | SyntaxKind.MinusMinusToken + | SyntaxKind.LessThanLessThanToken + | SyntaxKind.GreaterThanGreaterThanToken + | SyntaxKind.GreaterThanGreaterThanGreaterThanToken + | SyntaxKind.AmpersandToken + | SyntaxKind.BarToken + | SyntaxKind.CaretToken + | SyntaxKind.ExclamationToken + | SyntaxKind.TildeToken + | SyntaxKind.AmpersandAmpersandToken + | SyntaxKind.AmpersandAmpersandEqualsToken + | SyntaxKind.BarBarToken + | SyntaxKind.BarBarEqualsToken + | SyntaxKind.QuestionQuestionToken + | SyntaxKind.QuestionQuestionEqualsToken + | SyntaxKind.QuestionToken + | SyntaxKind.ColonToken + | SyntaxKind.AtToken + | SyntaxKind.BacktickToken + | SyntaxKind.HashToken + | SyntaxKind.EqualsToken + | SyntaxKind.PlusEqualsToken + | SyntaxKind.MinusEqualsToken + | SyntaxKind.AsteriskEqualsToken + | SyntaxKind.AsteriskAsteriskEqualsToken + | SyntaxKind.SlashEqualsToken + | SyntaxKind.PercentEqualsToken + | SyntaxKind.LessThanLessThanEqualsToken + | SyntaxKind.GreaterThanGreaterThanEqualsToken + | SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken + | SyntaxKind.AmpersandEqualsToken + | SyntaxKind.BarEqualsToken + | SyntaxKind.CaretEqualsToken; + +export type KeywordSyntaxKind = + | SyntaxKind.AbstractKeyword + | SyntaxKind.AccessorKeyword + | SyntaxKind.AnyKeyword + | SyntaxKind.AsKeyword + | SyntaxKind.AssertsKeyword + | SyntaxKind.AssertKeyword + | SyntaxKind.AsyncKeyword + | SyntaxKind.AwaitKeyword + | SyntaxKind.BigIntKeyword + | SyntaxKind.BooleanKeyword + | SyntaxKind.BreakKeyword + | SyntaxKind.CaseKeyword + | SyntaxKind.CatchKeyword + | SyntaxKind.ClassKeyword + | SyntaxKind.ConstKeyword + | SyntaxKind.ConstructorKeyword + | SyntaxKind.ContinueKeyword + | SyntaxKind.DebuggerKeyword + | SyntaxKind.DeclareKeyword + | SyntaxKind.DefaultKeyword + | SyntaxKind.DeleteKeyword + | SyntaxKind.DoKeyword + | SyntaxKind.ElseKeyword + | SyntaxKind.EnumKeyword + | SyntaxKind.ExportKeyword + | SyntaxKind.ExtendsKeyword + | SyntaxKind.FalseKeyword + | SyntaxKind.FinallyKeyword + | SyntaxKind.ForKeyword + | SyntaxKind.FromKeyword + | SyntaxKind.FunctionKeyword + | SyntaxKind.GetKeyword + | SyntaxKind.GlobalKeyword + | SyntaxKind.IfKeyword + | SyntaxKind.ImplementsKeyword + | SyntaxKind.ImportKeyword + | SyntaxKind.InferKeyword + | SyntaxKind.InKeyword + | SyntaxKind.InstanceOfKeyword + | SyntaxKind.InterfaceKeyword + | SyntaxKind.IntrinsicKeyword + | SyntaxKind.IsKeyword + | SyntaxKind.KeyOfKeyword + | SyntaxKind.LetKeyword + | SyntaxKind.ModuleKeyword + | SyntaxKind.NamespaceKeyword + | SyntaxKind.NeverKeyword + | SyntaxKind.NewKeyword + | SyntaxKind.NullKeyword + | SyntaxKind.NumberKeyword + | SyntaxKind.ObjectKeyword + | SyntaxKind.OfKeyword + | SyntaxKind.PackageKeyword + | SyntaxKind.PrivateKeyword + | SyntaxKind.ProtectedKeyword + | SyntaxKind.PublicKeyword + | SyntaxKind.ReadonlyKeyword + | SyntaxKind.OutKeyword + | SyntaxKind.OverrideKeyword + | SyntaxKind.RequireKeyword + | SyntaxKind.ReturnKeyword + | SyntaxKind.SatisfiesKeyword + | SyntaxKind.SetKeyword + | SyntaxKind.StaticKeyword + | SyntaxKind.StringKeyword + | SyntaxKind.SuperKeyword + | SyntaxKind.SwitchKeyword + | SyntaxKind.SymbolKeyword + | SyntaxKind.ThisKeyword + | SyntaxKind.ThrowKeyword + | SyntaxKind.TrueKeyword + | SyntaxKind.TryKeyword + | SyntaxKind.TypeKeyword + | SyntaxKind.TypeOfKeyword + | SyntaxKind.UndefinedKeyword + | SyntaxKind.UniqueKeyword + | SyntaxKind.UnknownKeyword + | SyntaxKind.UsingKeyword + | SyntaxKind.VarKeyword + | SyntaxKind.VoidKeyword + | SyntaxKind.WhileKeyword + | SyntaxKind.WithKeyword + | SyntaxKind.YieldKeyword; + +export type ModifierSyntaxKind = + | SyntaxKind.AbstractKeyword + | SyntaxKind.AccessorKeyword + | SyntaxKind.AsyncKeyword + | SyntaxKind.ConstKeyword + | SyntaxKind.DeclareKeyword + | SyntaxKind.DefaultKeyword + | SyntaxKind.ExportKeyword + | SyntaxKind.InKeyword + | SyntaxKind.PrivateKeyword + | SyntaxKind.ProtectedKeyword + | SyntaxKind.PublicKeyword + | SyntaxKind.ReadonlyKeyword + | SyntaxKind.OutKeyword + | SyntaxKind.OverrideKeyword + | SyntaxKind.StaticKeyword; + +export type KeywordTypeSyntaxKind = + | SyntaxKind.AnyKeyword + | SyntaxKind.BigIntKeyword + | SyntaxKind.BooleanKeyword + | SyntaxKind.IntrinsicKeyword + | SyntaxKind.NeverKeyword + | SyntaxKind.NumberKeyword + | SyntaxKind.ObjectKeyword + | SyntaxKind.StringKeyword + | SyntaxKind.SymbolKeyword + | SyntaxKind.UndefinedKeyword + | SyntaxKind.UnknownKeyword + | SyntaxKind.VoidKeyword; + +export type TokenSyntaxKind = + | SyntaxKind.Unknown + | SyntaxKind.EndOfFile + | TriviaSyntaxKind + | LiteralSyntaxKind + | PseudoLiteralSyntaxKind + | PunctuationSyntaxKind + | SyntaxKind.Identifier + | KeywordSyntaxKind; + +export type JsxTokenSyntaxKind = + | SyntaxKind.LessThanSlashToken + | SyntaxKind.EndOfFile + | SyntaxKind.ConflictMarkerTrivia + | SyntaxKind.JsxText + | SyntaxKind.JsxTextAllWhiteSpaces + | SyntaxKind.OpenBraceToken + | SyntaxKind.LessThanToken; + +export type JSDocSyntaxKind = + | SyntaxKind.EndOfFile + | SyntaxKind.WhitespaceTrivia + | SyntaxKind.AtToken + | SyntaxKind.NewLineTrivia + | SyntaxKind.AsteriskToken + | SyntaxKind.OpenBraceToken + | SyntaxKind.CloseBraceToken + | SyntaxKind.LessThanToken + | SyntaxKind.GreaterThanToken + | SyntaxKind.OpenBracketToken + | SyntaxKind.CloseBracketToken + | SyntaxKind.OpenParenToken + | SyntaxKind.CloseParenToken + | SyntaxKind.EqualsToken + | SyntaxKind.CommaToken + | SyntaxKind.DotToken + | SyntaxKind.Identifier + | SyntaxKind.BacktickToken + | SyntaxKind.HashToken + | SyntaxKind.Unknown + | KeywordSyntaxKind; + +export interface ReadonlyTextRange { + readonly pos: number; + readonly end: number; +} + +export interface NodeArray<T> extends ReadonlyTextRange, ReadonlyArray<T> { + readonly length: number; + readonly pos: number; + readonly end: number; +} + +// TODO(rbuckton): Constraint 'TKind' to 'TokenSyntaxKind' +export interface Token<TKind extends SyntaxKind> extends Node { + readonly kind: TKind; +} + +export type EndOfFile = Token<SyntaxKind.EndOfFile>; + +// Punctuation +export interface PunctuationToken<TKind extends PunctuationSyntaxKind> extends Token<TKind> { +} + +export type DotToken = PunctuationToken<SyntaxKind.DotToken>; +export type DotDotDotToken = PunctuationToken<SyntaxKind.DotDotDotToken>; +export type QuestionToken = PunctuationToken<SyntaxKind.QuestionToken>; +export type ExclamationToken = PunctuationToken<SyntaxKind.ExclamationToken>; +export type ColonToken = PunctuationToken<SyntaxKind.ColonToken>; +export type EqualsToken = PunctuationToken<SyntaxKind.EqualsToken>; +export type AmpersandAmpersandEqualsToken = PunctuationToken<SyntaxKind.AmpersandAmpersandEqualsToken>; +export type BarBarEqualsToken = PunctuationToken<SyntaxKind.BarBarEqualsToken>; +export type QuestionQuestionEqualsToken = PunctuationToken<SyntaxKind.QuestionQuestionEqualsToken>; +export type AsteriskToken = PunctuationToken<SyntaxKind.AsteriskToken>; +export type EqualsGreaterThanToken = PunctuationToken<SyntaxKind.EqualsGreaterThanToken>; +export type PlusToken = PunctuationToken<SyntaxKind.PlusToken>; +export type MinusToken = PunctuationToken<SyntaxKind.MinusToken>; +export type QuestionDotToken = PunctuationToken<SyntaxKind.QuestionDotToken>; + +// Keywords +export interface KeywordToken<TKind extends KeywordSyntaxKind> extends Token<TKind> { +} + +export type AssertsKeyword = KeywordToken<SyntaxKind.AssertsKeyword>; +export type AssertKeyword = KeywordToken<SyntaxKind.AssertKeyword>; +export type AwaitKeyword = KeywordToken<SyntaxKind.AwaitKeyword>; +export type CaseKeyword = KeywordToken<SyntaxKind.CaseKeyword>; + +export interface ModifierToken<TKind extends ModifierSyntaxKind> extends KeywordToken<TKind> { +} + +export type AbstractKeyword = ModifierToken<SyntaxKind.AbstractKeyword>; +export type AccessorKeyword = ModifierToken<SyntaxKind.AccessorKeyword>; +export type AsyncKeyword = ModifierToken<SyntaxKind.AsyncKeyword>; +export type ConstKeyword = ModifierToken<SyntaxKind.ConstKeyword>; +export type DeclareKeyword = ModifierToken<SyntaxKind.DeclareKeyword>; +export type DefaultKeyword = ModifierToken<SyntaxKind.DefaultKeyword>; +export type ExportKeyword = ModifierToken<SyntaxKind.ExportKeyword>; +export type InKeyword = ModifierToken<SyntaxKind.InKeyword>; +export type PrivateKeyword = ModifierToken<SyntaxKind.PrivateKeyword>; +export type ProtectedKeyword = ModifierToken<SyntaxKind.ProtectedKeyword>; +export type PublicKeyword = ModifierToken<SyntaxKind.PublicKeyword>; +export type ReadonlyKeyword = ModifierToken<SyntaxKind.ReadonlyKeyword>; +export type OutKeyword = ModifierToken<SyntaxKind.OutKeyword>; +export type OverrideKeyword = ModifierToken<SyntaxKind.OverrideKeyword>; +export type StaticKeyword = ModifierToken<SyntaxKind.StaticKeyword>; + +export type Modifier = + | AbstractKeyword + | AccessorKeyword + | AsyncKeyword + | ConstKeyword + | DeclareKeyword + | DefaultKeyword + | ExportKeyword + | InKeyword + | PrivateKeyword + | ProtectedKeyword + | PublicKeyword + | OutKeyword + | OverrideKeyword + | ReadonlyKeyword + | StaticKeyword; + +export type ModifierLike = Modifier | Decorator; + +export type AccessibilityModifier = + | PublicKeyword + | PrivateKeyword + | ProtectedKeyword; + +export type ParameterPropertyModifier = + | AccessibilityModifier + | ReadonlyKeyword; + +export type ClassMemberModifier = + | AccessibilityModifier + | ReadonlyKeyword + | StaticKeyword + | AccessorKeyword; + +export type ModifiersArray = NodeArray<Modifier>; + +export interface Identifier extends PrimaryExpression, Declaration { + readonly kind: SyntaxKind.Identifier; + /** + * Prefer to use `id.unescapedText`. (Note: This is available only in services, not internally to the TypeScript compiler.) + * Text of identifier, but if the identifier begins with two underscores, this will begin with three. + */ + readonly text: string; +} + +export interface QualifiedName extends Node { + readonly kind: SyntaxKind.QualifiedName; + readonly left: EntityName; + readonly right: Identifier; +} + +export type EntityName = Identifier | QualifiedName; + +export type PropertyName = + | Identifier + | StringLiteral + | NoSubstitutionTemplateLiteral + | NumericLiteral + | ComputedPropertyName + | PrivateIdentifier + | BigIntLiteral; + +export type MemberName = Identifier | PrivateIdentifier; + +export type DeclarationName = + | PropertyName + | JsxAttributeName + | StringLiteralLike + | ElementAccessExpression + | BindingPattern + | EntityNameExpression; + +export interface Declaration extends Node { +} + +export interface NamedDeclaration extends Declaration { + readonly name?: DeclarationName; +} + +export interface DeclarationStatement extends NamedDeclaration, Statement { + readonly name?: Identifier | StringLiteral | NumericLiteral; +} + +export interface ComputedPropertyName extends Node { + readonly kind: SyntaxKind.ComputedPropertyName; + readonly parent: Declaration; + readonly expression: Expression; +} + +// Typed as a PrimaryExpression due to its presence in BinaryExpressions (#field in expr) +export interface PrivateIdentifier extends PrimaryExpression { + readonly kind: SyntaxKind.PrivateIdentifier; + // escaping not strictly necessary + // avoids gotchas in transforms and utils + readonly escapedText: string; +} + +export interface Decorator extends Node { + readonly kind: SyntaxKind.Decorator; + readonly parent: NamedDeclaration; + readonly expression: LeftHandSideExpression; +} + +export interface TypeParameterDeclaration extends NamedDeclaration { + readonly kind: SyntaxKind.TypeParameter; + readonly parent: DeclarationWithTypeParameterChildren | InferTypeNode; + readonly modifiers?: NodeArray<Modifier>; + readonly name: Identifier; + /** Note: Consider calling `getEffectiveConstraintOfTypeParameter` */ + readonly constraint?: TypeNode; + readonly default?: TypeNode; + + // For error recovery purposes (see `isGrammarError` in utilities.ts). + expression?: Expression; +} + +export interface SignatureDeclarationBase extends NamedDeclaration { + readonly kind: SignatureDeclaration["kind"]; + readonly name?: PropertyName; + readonly typeParameters?: NodeArray<TypeParameterDeclaration> | undefined; + readonly parameters: NodeArray<ParameterDeclaration>; + readonly type?: TypeNode | undefined; +} + +export type SignatureDeclaration = + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | MethodSignature + | IndexSignatureDeclaration + | FunctionTypeNode + | ConstructorTypeNode + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | AccessorDeclaration + | FunctionExpression + | ArrowFunction; + +export interface CallSignatureDeclaration extends SignatureDeclarationBase, TypeElement { + readonly kind: SyntaxKind.CallSignature; +} + +export interface ConstructSignatureDeclaration extends SignatureDeclarationBase, TypeElement { + readonly kind: SyntaxKind.ConstructSignature; +} + +export type BindingName = Identifier | BindingPattern; + +// dprint-ignore +export interface VariableDeclaration extends NamedDeclaration { + readonly kind: SyntaxKind.VariableDeclaration; + readonly parent: VariableDeclarationList | CatchClause; + readonly name: BindingName; // Declared variable name + readonly exclamationToken?: ExclamationToken; // Optional definite assignment assertion + readonly type?: TypeNode; // Optional type annotation + readonly initializer?: Expression; // Optional initializer +} + +export interface VariableDeclarationList extends Node { + readonly kind: SyntaxKind.VariableDeclarationList; + readonly parent: VariableStatement | ForStatement | ForOfStatement | ForInStatement; + readonly declarations: NodeArray<VariableDeclaration>; +} + +// dprint-ignore +export interface ParameterDeclaration extends NamedDeclaration { + readonly kind: SyntaxKind.Parameter; + readonly parent: SignatureDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly dotDotDotToken?: DotDotDotToken; // Present on rest parameter + readonly name: BindingName; // Declared parameter name. + readonly questionToken?: QuestionToken; // Present on optional parameter + readonly type?: TypeNode; // Optional type annotation + readonly initializer?: Expression; // Optional initializer +} + +// dprint-ignore +export interface BindingElement extends NamedDeclaration { + readonly kind: SyntaxKind.BindingElement; + readonly parent: BindingPattern; + readonly propertyName?: PropertyName; // Binding property name (in object binding pattern) + readonly dotDotDotToken?: DotDotDotToken; // Present on rest element (in object binding pattern) + readonly name: BindingName; // Declared binding element name + readonly initializer?: Expression; // Optional initializer +} + +// dprint-ignore +export interface PropertySignature extends TypeElement { + readonly kind: SyntaxKind.PropertySignature; + readonly parent: TypeLiteralNode | InterfaceDeclaration; + readonly modifiers?: NodeArray<Modifier>; + readonly name: PropertyName; // Declared property name + readonly questionToken?: QuestionToken; // Present on optional property + readonly type?: TypeNode; // Optional type annotation +} + +// dprint-ignore +export interface PropertyDeclaration extends ClassElement { + readonly kind: SyntaxKind.PropertyDeclaration; + readonly parent: ClassLikeDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: PropertyName; + readonly questionToken?: QuestionToken; // Present for use with reporting a grammar error for auto-accessors (see `isGrammarError` in utilities.ts) + readonly exclamationToken?: ExclamationToken; + readonly type?: TypeNode; + readonly initializer?: Expression; // Optional initializer +} + +export interface AutoAccessorPropertyDeclaration extends PropertyDeclaration { + _autoAccessorBrand: any; +} + +export interface ObjectLiteralElement extends NamedDeclaration { + _objectLiteralBrand: any; + readonly name?: PropertyName; +} + +/** Unlike ObjectLiteralElement, excludes JSXAttribute and JSXSpreadAttribute. */ +export type ObjectLiteralElementLike = + | PropertyAssignment + | ShorthandPropertyAssignment + | SpreadAssignment + | MethodDeclaration + | AccessorDeclaration; + +export interface PropertyAssignment extends ObjectLiteralElement { + readonly kind: SyntaxKind.PropertyAssignment; + readonly parent: ObjectLiteralExpression; + readonly name: PropertyName; + readonly initializer: Expression; +} + +export interface ShorthandPropertyAssignment extends ObjectLiteralElement { + readonly kind: SyntaxKind.ShorthandPropertyAssignment; + readonly parent: ObjectLiteralExpression; + readonly name: Identifier; + // used when ObjectLiteralExpression is used in ObjectAssignmentPattern + // it is a grammar error to appear in actual object initializer (see `isGrammarError` in utilities.ts): + readonly equalsToken?: EqualsToken; + readonly objectAssignmentInitializer?: Expression; +} + +export interface SpreadAssignment extends ObjectLiteralElement { + readonly kind: SyntaxKind.SpreadAssignment; + readonly parent: ObjectLiteralExpression; + readonly expression: Expression; +} + +export type VariableLikeDeclaration = + | VariableDeclaration + | ParameterDeclaration + | BindingElement + | PropertyDeclaration + | PropertyAssignment + | PropertySignature + | JsxAttribute + | ShorthandPropertyAssignment + | EnumMember + | JSDocPropertyTag + | JSDocParameterTag; + +export interface ObjectBindingPattern extends Node { + readonly kind: SyntaxKind.ObjectBindingPattern; + readonly parent: VariableDeclaration | ParameterDeclaration | BindingElement; + readonly elements: NodeArray<BindingElement>; +} + +export interface ArrayBindingPattern extends Node { + readonly kind: SyntaxKind.ArrayBindingPattern; + readonly parent: VariableDeclaration | ParameterDeclaration | BindingElement; + readonly elements: NodeArray<ArrayBindingElement>; +} + +export type BindingPattern = ObjectBindingPattern | ArrayBindingPattern; + +export type ArrayBindingElement = BindingElement | OmittedExpression; + +/** + * Several node kinds share function-like features such as a signature, + * a name, and a body. These nodes should extend FunctionLikeDeclarationBase. + * Examples: + * - FunctionDeclaration + * - MethodDeclaration + * - AccessorDeclaration + */ +export interface FunctionLikeDeclarationBase extends SignatureDeclarationBase { + _functionLikeDeclarationBrand: any; + + readonly asteriskToken?: AsteriskToken | undefined; + readonly questionToken?: QuestionToken | undefined; + readonly exclamationToken?: ExclamationToken | undefined; + readonly body?: Block | Expression | undefined; +} + +export type FunctionLikeDeclaration = + | FunctionDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | ConstructorDeclaration + | FunctionExpression + | ArrowFunction; +/** @deprecated Use SignatureDeclaration */ +export type FunctionLike = SignatureDeclaration; + +export interface FunctionDeclaration extends FunctionLikeDeclarationBase, DeclarationStatement { + readonly kind: SyntaxKind.FunctionDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name?: Identifier; + readonly body?: FunctionBody; +} + +export interface MethodSignature extends SignatureDeclarationBase, TypeElement { + readonly kind: SyntaxKind.MethodSignature; + readonly parent: TypeLiteralNode | InterfaceDeclaration; + readonly modifiers?: NodeArray<Modifier>; + readonly name: PropertyName; +} + +// Note that a MethodDeclaration is considered both a ClassElement and an ObjectLiteralElement. +// Both the grammars for ClassDeclaration and ObjectLiteralExpression allow for MethodDeclarations +// as child elements, and so a MethodDeclaration satisfies both interfaces. This avoids the +// alternative where we would need separate kinds/types for ClassMethodDeclaration and +// ObjectLiteralMethodDeclaration, which would look identical. +// +// Because of this, it may be necessary to determine what sort of MethodDeclaration you have +// at later stages of the compiler pipeline. In that case, you can either check the parent kind +// of the method, or use helpers like isObjectLiteralMethodDeclaration +export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement { + readonly kind: SyntaxKind.MethodDeclaration; + readonly parent: ClassLikeDeclaration | ObjectLiteralExpression; + readonly modifiers?: NodeArray<ModifierLike> | undefined; + readonly name: PropertyName; + readonly body?: FunctionBody | undefined; +} + +export interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement { + readonly kind: SyntaxKind.Constructor; + readonly parent: ClassLikeDeclaration; + readonly modifiers?: NodeArray<ModifierLike> | undefined; + readonly body?: FunctionBody | undefined; +} + +/** For when we encounter a semicolon in a class declaration. ES6 allows these as class elements. */ +export interface SemicolonClassElement extends ClassElement { + readonly kind: SyntaxKind.SemicolonClassElement; + readonly parent: ClassLikeDeclaration; +} + +// See the comment on MethodDeclaration for the intuition behind GetAccessorDeclaration being a +// ClassElement and an ObjectLiteralElement. +export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement { + readonly kind: SyntaxKind.GetAccessor; + readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: PropertyName; + readonly body?: FunctionBody; +} + +// See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a +// ClassElement and an ObjectLiteralElement. +export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement { + readonly kind: SyntaxKind.SetAccessor; + readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: PropertyName; + readonly body?: FunctionBody; +} + +export type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration; + +export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement { + readonly kind: SyntaxKind.IndexSignature; + readonly parent: ObjectTypeDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly type: TypeNode; +} + +export interface ClassStaticBlockDeclaration extends ClassElement { + readonly kind: SyntaxKind.ClassStaticBlockDeclaration; + readonly parent: ClassDeclaration | ClassExpression; + readonly body: Block; +} + +export interface TypeNode extends Node { + _typeNodeBrand: any; +} + +export interface KeywordTypeNode<TKind extends KeywordTypeSyntaxKind = KeywordTypeSyntaxKind> extends KeywordToken<TKind>, TypeNode { + readonly kind: TKind; +} + +export interface ImportTypeNode extends NodeWithTypeArguments { + readonly kind: SyntaxKind.ImportType; + readonly isTypeOf: boolean; + readonly argument: TypeNode; + readonly attributes?: ImportAttributes; + readonly qualifier?: EntityName; +} + +export interface ThisTypeNode extends TypeNode { + readonly kind: SyntaxKind.ThisType; +} + +export type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode; + +export interface FunctionOrConstructorTypeNodeBase extends TypeNode, SignatureDeclarationBase { + readonly kind: SyntaxKind.FunctionType | SyntaxKind.ConstructorType; + readonly type: TypeNode; +} + +export interface FunctionTypeNode extends FunctionOrConstructorTypeNodeBase { + readonly kind: SyntaxKind.FunctionType; +} + +export interface ConstructorTypeNode extends FunctionOrConstructorTypeNodeBase { + readonly kind: SyntaxKind.ConstructorType; + readonly modifiers?: NodeArray<Modifier>; +} + +export interface NodeWithTypeArguments extends TypeNode { + readonly typeArguments?: NodeArray<TypeNode>; +} + +export type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments; + +export interface TypeReferenceNode extends NodeWithTypeArguments { + readonly kind: SyntaxKind.TypeReference; + readonly typeName: EntityName; +} + +export interface TypePredicateNode extends TypeNode { + readonly kind: SyntaxKind.TypePredicate; + readonly parent: SignatureDeclaration | JSDocTypeExpression; + readonly assertsModifier?: AssertsKeyword; + readonly parameterName: Identifier | ThisTypeNode; + readonly type?: TypeNode; +} + +export interface TypeQueryNode extends NodeWithTypeArguments { + readonly kind: SyntaxKind.TypeQuery; + readonly exprName: EntityName; +} + +// A TypeLiteral is the declaration node for an anonymous symbol. +export interface TypeLiteralNode extends TypeNode, Declaration { + readonly kind: SyntaxKind.TypeLiteral; + readonly members: NodeArray<TypeElement>; +} + +export interface ArrayTypeNode extends TypeNode { + readonly kind: SyntaxKind.ArrayType; + readonly elementType: TypeNode; +} + +export interface TupleTypeNode extends TypeNode { + readonly kind: SyntaxKind.TupleType; + readonly elements: NodeArray<TypeNode | NamedTupleMember>; +} + +export interface NamedTupleMember extends TypeNode, Declaration { + readonly kind: SyntaxKind.NamedTupleMember; + readonly dotDotDotToken?: Token<SyntaxKind.DotDotDotToken>; + readonly name: Identifier; + readonly questionToken?: Token<SyntaxKind.QuestionToken>; + readonly type: TypeNode; +} + +export interface OptionalTypeNode extends TypeNode { + readonly kind: SyntaxKind.OptionalType; + readonly type: TypeNode; +} + +export interface RestTypeNode extends TypeNode { + readonly kind: SyntaxKind.RestType; + readonly type: TypeNode; +} + +export type UnionOrIntersectionTypeNode = UnionTypeNode | IntersectionTypeNode; + +export interface UnionTypeNode extends TypeNode { + readonly kind: SyntaxKind.UnionType; + readonly types: NodeArray<TypeNode>; +} + +export interface IntersectionTypeNode extends TypeNode { + readonly kind: SyntaxKind.IntersectionType; + readonly types: NodeArray<TypeNode>; +} + +export interface ConditionalTypeNode extends TypeNode { + readonly kind: SyntaxKind.ConditionalType; + readonly checkType: TypeNode; + readonly extendsType: TypeNode; + readonly trueType: TypeNode; + readonly falseType: TypeNode; +} + +export interface InferTypeNode extends TypeNode { + readonly kind: SyntaxKind.InferType; + readonly typeParameter: TypeParameterDeclaration; +} + +export interface ParenthesizedTypeNode extends TypeNode { + readonly kind: SyntaxKind.ParenthesizedType; + readonly type: TypeNode; +} + +export interface TypeOperatorNode extends TypeNode { + readonly kind: SyntaxKind.TypeOperator; + readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; + readonly type: TypeNode; +} + +export interface IndexedAccessTypeNode extends TypeNode { + readonly kind: SyntaxKind.IndexedAccessType; + readonly objectType: TypeNode; + readonly indexType: TypeNode; +} + +export interface MappedTypeNode extends TypeNode, Declaration { + readonly kind: SyntaxKind.MappedType; + readonly readonlyToken?: ReadonlyKeyword | PlusToken | MinusToken; + readonly typeParameter: TypeParameterDeclaration; + readonly nameType?: TypeNode; + readonly questionToken?: QuestionToken | PlusToken | MinusToken; + readonly type?: TypeNode; + /** Used only to produce grammar errors */ + readonly members?: NodeArray<TypeElement>; +} + +export interface LiteralTypeNode extends TypeNode { + readonly kind: SyntaxKind.LiteralType; + readonly literal: NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression; +} + +export interface StringLiteral extends LiteralExpression, Declaration { + readonly kind: SyntaxKind.StringLiteral; +} + +export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral; +export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName | BigIntLiteral; + +export interface TemplateLiteralTypeNode extends TypeNode { + kind: SyntaxKind.TemplateLiteralType; + readonly head: TemplateHead; + readonly templateSpans: NodeArray<TemplateLiteralTypeSpan>; +} + +export interface TemplateLiteralTypeSpan extends TypeNode { + readonly kind: SyntaxKind.TemplateLiteralTypeSpan; + readonly parent: TemplateLiteralTypeNode; + readonly type: TypeNode; + readonly literal: TemplateMiddle | TemplateTail; +} + +// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. +// Consider 'Expression'. Without the brand, 'Expression' is actually no different +// (structurally) than 'Node'. Because of this you can pass any Node to a function that +// takes an Expression without any error. By using the 'brands' we ensure that the type +// checker actually thinks you have something of the right type. Note: the brands are +// never actually given values. At runtime they have zero cost. + +export interface Expression extends Node { + _expressionBrand: any; +} + +export interface OmittedExpression extends Expression { + readonly kind: SyntaxKind.OmittedExpression; +} + +// Represents an expression that is elided as part of a transformation to emit comments on a +// not-emitted node. The 'expression' property of a PartiallyEmittedExpression should be emitted. +export interface PartiallyEmittedExpression extends LeftHandSideExpression { + readonly kind: SyntaxKind.PartiallyEmittedExpression; + readonly expression: Expression; +} + +export interface UnaryExpression extends Expression { + _unaryExpressionBrand: any; +} + +/** Deprecated, please use UpdateExpression */ +export type IncrementExpression = UpdateExpression; +export interface UpdateExpression extends UnaryExpression { + _updateExpressionBrand: any; +} + +// see: https://tc39.github.io/ecma262/#prod-UpdateExpression +// see: https://tc39.github.io/ecma262/#prod-UnaryExpression +export type PrefixUnaryOperator = + | SyntaxKind.PlusPlusToken + | SyntaxKind.MinusMinusToken + | SyntaxKind.PlusToken + | SyntaxKind.MinusToken + | SyntaxKind.TildeToken + | SyntaxKind.ExclamationToken; + +export interface PrefixUnaryExpression extends UpdateExpression { + readonly kind: SyntaxKind.PrefixUnaryExpression; + readonly operator: PrefixUnaryOperator; + readonly operand: UnaryExpression; +} + +// see: https://tc39.github.io/ecma262/#prod-UpdateExpression +export type PostfixUnaryOperator = + | SyntaxKind.PlusPlusToken + | SyntaxKind.MinusMinusToken; + +export interface PostfixUnaryExpression extends UpdateExpression { + readonly kind: SyntaxKind.PostfixUnaryExpression; + readonly operand: LeftHandSideExpression; + readonly operator: PostfixUnaryOperator; +} + +export interface LeftHandSideExpression extends UpdateExpression { + _leftHandSideExpressionBrand: any; +} + +export interface MemberExpression extends LeftHandSideExpression { + _memberExpressionBrand: any; +} + +export interface PrimaryExpression extends MemberExpression { + _primaryExpressionBrand: any; +} + +export interface NullLiteral extends PrimaryExpression { + readonly kind: SyntaxKind.NullKeyword; +} + +export interface TrueLiteral extends PrimaryExpression { + readonly kind: SyntaxKind.TrueKeyword; +} + +export interface FalseLiteral extends PrimaryExpression { + readonly kind: SyntaxKind.FalseKeyword; +} + +export type BooleanLiteral = TrueLiteral | FalseLiteral; + +export interface ThisExpression extends PrimaryExpression { + readonly kind: SyntaxKind.ThisKeyword; +} + +export interface SuperExpression extends PrimaryExpression { + readonly kind: SyntaxKind.SuperKeyword; +} + +export interface ImportExpression extends PrimaryExpression { + readonly kind: SyntaxKind.ImportKeyword; +} + +export interface DeleteExpression extends UnaryExpression { + readonly kind: SyntaxKind.DeleteExpression; + readonly expression: UnaryExpression; +} + +export interface TypeOfExpression extends UnaryExpression { + readonly kind: SyntaxKind.TypeOfExpression; + readonly expression: UnaryExpression; +} + +export interface VoidExpression extends UnaryExpression { + readonly kind: SyntaxKind.VoidExpression; + readonly expression: UnaryExpression; +} + +export interface AwaitExpression extends UnaryExpression { + readonly kind: SyntaxKind.AwaitExpression; + readonly expression: UnaryExpression; +} + +export interface YieldExpression extends Expression { + readonly kind: SyntaxKind.YieldExpression; + readonly asteriskToken?: AsteriskToken; + readonly expression?: Expression; +} + +// see: https://tc39.github.io/ecma262/#prod-ExponentiationExpression +export type ExponentiationOperator = SyntaxKind.AsteriskAsteriskToken; + +// see: https://tc39.github.io/ecma262/#prod-MultiplicativeOperator +export type MultiplicativeOperator = + | SyntaxKind.AsteriskToken + | SyntaxKind.SlashToken + | SyntaxKind.PercentToken; + +// see: https://tc39.github.io/ecma262/#prod-MultiplicativeExpression +export type MultiplicativeOperatorOrHigher = + | ExponentiationOperator + | MultiplicativeOperator; + +// see: https://tc39.github.io/ecma262/#prod-AdditiveExpression +export type AdditiveOperator = + | SyntaxKind.PlusToken + | SyntaxKind.MinusToken; + +// see: https://tc39.github.io/ecma262/#prod-AdditiveExpression +export type AdditiveOperatorOrHigher = + | MultiplicativeOperatorOrHigher + | AdditiveOperator; + +// see: https://tc39.github.io/ecma262/#prod-ShiftExpression +export type ShiftOperator = + | SyntaxKind.LessThanLessThanToken + | SyntaxKind.GreaterThanGreaterThanToken + | SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + +// see: https://tc39.github.io/ecma262/#prod-ShiftExpression +export type ShiftOperatorOrHigher = + | AdditiveOperatorOrHigher + | ShiftOperator; + +// see: https://tc39.github.io/ecma262/#prod-RelationalExpression +export type RelationalOperator = + | SyntaxKind.LessThanToken + | SyntaxKind.LessThanEqualsToken + | SyntaxKind.GreaterThanToken + | SyntaxKind.GreaterThanEqualsToken + | SyntaxKind.InstanceOfKeyword + | SyntaxKind.InKeyword; + +// see: https://tc39.github.io/ecma262/#prod-RelationalExpression +export type RelationalOperatorOrHigher = + | ShiftOperatorOrHigher + | RelationalOperator; + +// see: https://tc39.github.io/ecma262/#prod-EqualityExpression +export type EqualityOperator = + | SyntaxKind.EqualsEqualsToken + | SyntaxKind.EqualsEqualsEqualsToken + | SyntaxKind.ExclamationEqualsEqualsToken + | SyntaxKind.ExclamationEqualsToken; + +// see: https://tc39.github.io/ecma262/#prod-EqualityExpression +export type EqualityOperatorOrHigher = + | RelationalOperatorOrHigher + | EqualityOperator; + +// see: https://tc39.github.io/ecma262/#prod-BitwiseANDExpression +// see: https://tc39.github.io/ecma262/#prod-BitwiseXORExpression +// see: https://tc39.github.io/ecma262/#prod-BitwiseORExpression +export type BitwiseOperator = + | SyntaxKind.AmpersandToken + | SyntaxKind.BarToken + | SyntaxKind.CaretToken; + +// see: https://tc39.github.io/ecma262/#prod-BitwiseANDExpression +// see: https://tc39.github.io/ecma262/#prod-BitwiseXORExpression +// see: https://tc39.github.io/ecma262/#prod-BitwiseORExpression +export type BitwiseOperatorOrHigher = + | EqualityOperatorOrHigher + | BitwiseOperator; + +// see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression +// see: https://tc39.github.io/ecma262/#prod-LogicalORExpression +export type LogicalOperator = + | SyntaxKind.AmpersandAmpersandToken + | SyntaxKind.BarBarToken; + +// see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression +// see: https://tc39.github.io/ecma262/#prod-LogicalORExpression +export type LogicalOperatorOrHigher = + | BitwiseOperatorOrHigher + | LogicalOperator; + +// see: https://tc39.github.io/ecma262/#prod-AssignmentOperator +export type CompoundAssignmentOperator = + | SyntaxKind.PlusEqualsToken + | SyntaxKind.MinusEqualsToken + | SyntaxKind.AsteriskAsteriskEqualsToken + | SyntaxKind.AsteriskEqualsToken + | SyntaxKind.SlashEqualsToken + | SyntaxKind.PercentEqualsToken + | SyntaxKind.AmpersandEqualsToken + | SyntaxKind.BarEqualsToken + | SyntaxKind.CaretEqualsToken + | SyntaxKind.LessThanLessThanEqualsToken + | SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken + | SyntaxKind.GreaterThanGreaterThanEqualsToken + | SyntaxKind.BarBarEqualsToken + | SyntaxKind.AmpersandAmpersandEqualsToken + | SyntaxKind.QuestionQuestionEqualsToken; + +// see: https://tc39.github.io/ecma262/#prod-AssignmentExpression +export type AssignmentOperator = + | SyntaxKind.EqualsToken + | CompoundAssignmentOperator; + +// see: https://tc39.github.io/ecma262/#prod-AssignmentExpression +export type AssignmentOperatorOrHigher = + | SyntaxKind.QuestionQuestionToken + | LogicalOperatorOrHigher + | AssignmentOperator; + +// see: https://tc39.github.io/ecma262/#prod-Expression +export type BinaryOperator = + | AssignmentOperatorOrHigher + | SyntaxKind.CommaToken; + +export type LogicalOrCoalescingAssignmentOperator = + | SyntaxKind.AmpersandAmpersandEqualsToken + | SyntaxKind.BarBarEqualsToken + | SyntaxKind.QuestionQuestionEqualsToken; + +export type BinaryOperatorToken = Token<BinaryOperator>; + +export interface BinaryExpression extends Expression, Declaration { + readonly kind: SyntaxKind.BinaryExpression; + readonly left: Expression; + readonly operatorToken: BinaryOperatorToken; + readonly right: Expression; +} + +export type AssignmentOperatorToken = Token<AssignmentOperator>; + +export interface AssignmentExpression<TOperator extends AssignmentOperatorToken> extends BinaryExpression { + readonly left: LeftHandSideExpression; + readonly operatorToken: TOperator; +} + +export interface ObjectDestructuringAssignment extends AssignmentExpression<EqualsToken> { + readonly left: ObjectLiteralExpression; +} + +export interface ArrayDestructuringAssignment extends AssignmentExpression<EqualsToken> { + readonly left: ArrayLiteralExpression; +} + +export type DestructuringAssignment = + | ObjectDestructuringAssignment + | ArrayDestructuringAssignment; + +export type BindingOrAssignmentElement = + | VariableDeclaration + | ParameterDeclaration + | ObjectBindingOrAssignmentElement + | ArrayBindingOrAssignmentElement; + +export type ObjectBindingOrAssignmentElement = + | BindingElement + | PropertyAssignment // AssignmentProperty + | ShorthandPropertyAssignment // AssignmentProperty + | SpreadAssignment // AssignmentRestProperty +; + +export type ArrayBindingOrAssignmentElement = + | BindingElement + | OmittedExpression // Elision + | SpreadElement // AssignmentRestElement + | ArrayLiteralExpression // ArrayAssignmentPattern + | ObjectLiteralExpression // ObjectAssignmentPattern + | AssignmentExpression<EqualsToken> // AssignmentElement + | Identifier // DestructuringAssignmentTarget + | PropertyAccessExpression // DestructuringAssignmentTarget + | ElementAccessExpression // DestructuringAssignmentTarget +; + +export type BindingOrAssignmentElementRestIndicator = + | DotDotDotToken // from BindingElement + | SpreadElement // AssignmentRestElement + | SpreadAssignment // AssignmentRestProperty +; + +export type BindingOrAssignmentElementTarget = + | BindingOrAssignmentPattern + | Identifier + | PropertyAccessExpression + | ElementAccessExpression + | OmittedExpression; + +export type ObjectBindingOrAssignmentPattern = + | ObjectBindingPattern + | ObjectLiteralExpression // ObjectAssignmentPattern +; + +export type ArrayBindingOrAssignmentPattern = + | ArrayBindingPattern + | ArrayLiteralExpression // ArrayAssignmentPattern +; + +export type AssignmentPattern = ObjectLiteralExpression | ArrayLiteralExpression; + +export type BindingOrAssignmentPattern = ObjectBindingOrAssignmentPattern | ArrayBindingOrAssignmentPattern; + +export interface ConditionalExpression extends Expression { + readonly kind: SyntaxKind.ConditionalExpression; + readonly condition: Expression; + readonly questionToken: QuestionToken; + readonly whenTrue: Expression; + readonly colonToken: ColonToken; + readonly whenFalse: Expression; +} + +export type FunctionBody = Block; +export type ConciseBody = FunctionBody | Expression; + +export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase { + readonly kind: SyntaxKind.FunctionExpression; + readonly modifiers?: NodeArray<Modifier>; + readonly name?: Identifier; + readonly body: FunctionBody; // Required, whereas the member inherited from FunctionDeclaration is optional +} + +export interface ArrowFunction extends Expression, FunctionLikeDeclarationBase { + readonly kind: SyntaxKind.ArrowFunction; + readonly modifiers?: NodeArray<Modifier>; + readonly equalsGreaterThanToken: EqualsGreaterThanToken; + readonly body: ConciseBody; + readonly name: never; +} + +// The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, +// or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. +// For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". +export interface LiteralLikeNode extends Node { + text: string; + isUnterminated?: boolean; + hasExtendedUnicodeEscape?: boolean; +} + +export interface TemplateLiteralLikeNode extends LiteralLikeNode { + rawText?: string; + templateFlags?: TokenFlags; +} + +// The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, +// or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. +// For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". +export interface LiteralExpression extends LiteralLikeNode, PrimaryExpression { + _literalExpressionBrand: any; +} + +export interface RegularExpressionLiteral extends LiteralExpression { + readonly kind: SyntaxKind.RegularExpressionLiteral; +} + +// dprint-ignore +export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode, Declaration { + readonly kind: SyntaxKind.NoSubstitutionTemplateLiteral; +} + +export interface NumericLiteral extends LiteralExpression, Declaration { + readonly kind: SyntaxKind.NumericLiteral; + readonly numericLiteralFlags: TokenFlags; +} + +export interface BigIntLiteral extends LiteralExpression { + readonly kind: SyntaxKind.BigIntLiteral; +} + +export type LiteralToken = + | NumericLiteral + | BigIntLiteral + | StringLiteral + | JsxText + | RegularExpressionLiteral + | NoSubstitutionTemplateLiteral; + +export interface TemplateHead extends TemplateLiteralLikeNode { + readonly kind: SyntaxKind.TemplateHead; + readonly parent: TemplateExpression | TemplateLiteralTypeNode; + templateFlags: TokenFlags; +} + +export interface TemplateMiddle extends TemplateLiteralLikeNode { + readonly kind: SyntaxKind.TemplateMiddle; + readonly parent: TemplateSpan | TemplateLiteralTypeSpan; + templateFlags: TokenFlags; +} + +export interface TemplateTail extends TemplateLiteralLikeNode { + readonly kind: SyntaxKind.TemplateTail; + readonly parent: TemplateSpan | TemplateLiteralTypeSpan; + templateFlags: TokenFlags; +} + +export type PseudoLiteralToken = + | TemplateHead + | TemplateMiddle + | TemplateTail; + +export type TemplateLiteralToken = + | NoSubstitutionTemplateLiteral + | PseudoLiteralToken; + +export interface TemplateExpression extends PrimaryExpression { + readonly kind: SyntaxKind.TemplateExpression; + readonly head: TemplateHead; + readonly templateSpans: NodeArray<TemplateSpan>; +} + +export type TemplateLiteral = + | TemplateExpression + | NoSubstitutionTemplateLiteral; + +// Each of these corresponds to a substitution expression and a template literal, in that order. +// The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral. +export interface TemplateSpan extends Node { + readonly kind: SyntaxKind.TemplateSpan; + readonly parent: TemplateExpression; + readonly expression: Expression; + readonly literal: TemplateMiddle | TemplateTail; +} + +export interface ParenthesizedExpression extends PrimaryExpression { + readonly kind: SyntaxKind.ParenthesizedExpression; + readonly expression: Expression; +} + +export interface ArrayLiteralExpression extends PrimaryExpression { + readonly kind: SyntaxKind.ArrayLiteralExpression; + readonly elements: NodeArray<Expression>; + multiLine?: boolean; +} + +export interface SpreadElement extends Expression { + readonly kind: SyntaxKind.SpreadElement; + readonly parent: ArrayLiteralExpression | CallExpression | NewExpression; + readonly expression: Expression; +} + +/** + * This interface is a base interface for ObjectLiteralExpression and JSXAttributes to extend from. JSXAttributes is similar to + * ObjectLiteralExpression in that it contains array of properties; however, JSXAttributes' properties can only be + * JSXAttribute or JSXSpreadAttribute. ObjectLiteralExpression, on the other hand, can only have properties of type + * ObjectLiteralElement (e.g. PropertyAssignment, ShorthandPropertyAssignment etc.) + */ +export interface ObjectLiteralExpressionBase<T extends ObjectLiteralElement> extends PrimaryExpression, Declaration { + readonly properties: NodeArray<T>; +} + +// An ObjectLiteralExpression is the declaration node for an anonymous symbol. +export interface ObjectLiteralExpression extends ObjectLiteralExpressionBase<ObjectLiteralElementLike> { + readonly kind: SyntaxKind.ObjectLiteralExpression; + multiLine?: boolean; +} + +export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression; +export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; +export type AccessExpression = PropertyAccessExpression | ElementAccessExpression; + +export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration { + readonly kind: SyntaxKind.PropertyAccessExpression; + readonly expression: LeftHandSideExpression; + readonly questionDotToken?: QuestionDotToken; + readonly name: MemberName; +} + +export interface PropertyAccessChain extends PropertyAccessExpression { + _optionalChainBrand: any; + readonly name: MemberName; +} + +export interface SuperPropertyAccessExpression extends PropertyAccessExpression { + readonly expression: SuperExpression; +} + +/** Brand for a PropertyAccessExpression which, like a QualifiedName, consists of a sequence of identifiers separated by dots. */ +export interface PropertyAccessEntityNameExpression extends PropertyAccessExpression { + _propertyAccessExpressionLikeQualifiedNameBrand?: any; + readonly expression: EntityNameExpression; + readonly name: Identifier; +} + +export interface ElementAccessExpression extends MemberExpression, Declaration { + readonly kind: SyntaxKind.ElementAccessExpression; + readonly expression: LeftHandSideExpression; + readonly questionDotToken?: QuestionDotToken; + readonly argumentExpression: Expression; +} + +export interface ElementAccessChain extends ElementAccessExpression { + _optionalChainBrand: any; +} + +export interface SuperElementAccessExpression extends ElementAccessExpression { + readonly expression: SuperExpression; +} + +// see: https://tc39.github.io/ecma262/#prod-SuperProperty +export type SuperProperty = SuperPropertyAccessExpression | SuperElementAccessExpression; + +export interface CallExpression extends LeftHandSideExpression, Declaration { + readonly kind: SyntaxKind.CallExpression; + readonly expression: LeftHandSideExpression; + readonly questionDotToken?: QuestionDotToken; + readonly typeArguments?: NodeArray<TypeNode>; + readonly arguments: NodeArray<Expression>; +} + +export interface CallChain extends CallExpression { + _optionalChainBrand: any; +} + +export type OptionalChain = + | PropertyAccessChain + | ElementAccessChain + | CallChain + | NonNullChain; + +// see: https://tc39.github.io/ecma262/#prod-SuperCall +export interface SuperCall extends CallExpression { + readonly expression: SuperExpression; +} + +export interface ImportCall extends CallExpression { + readonly expression: ImportExpression; +} + +export interface ExpressionWithTypeArguments extends MemberExpression, NodeWithTypeArguments { + readonly kind: SyntaxKind.ExpressionWithTypeArguments; + readonly expression: LeftHandSideExpression; +} + +export interface NewExpression extends PrimaryExpression, Declaration { + readonly kind: SyntaxKind.NewExpression; + readonly expression: LeftHandSideExpression; + readonly typeArguments?: NodeArray<TypeNode>; + readonly arguments?: NodeArray<Expression>; +} + +export interface TaggedTemplateExpression extends MemberExpression { + readonly kind: SyntaxKind.TaggedTemplateExpression; + readonly tag: LeftHandSideExpression; + readonly typeArguments?: NodeArray<TypeNode>; + readonly template: TemplateLiteral; +} + +export interface InstanceofExpression extends BinaryExpression { + readonly operatorToken: Token<SyntaxKind.InstanceOfKeyword>; +} + +export type CallLikeExpression = + | CallExpression + | NewExpression + | TaggedTemplateExpression + | Decorator + | JsxOpeningLikeElement + | InstanceofExpression; + +export interface AsExpression extends Expression { + readonly kind: SyntaxKind.AsExpression; + readonly expression: Expression; + readonly type: TypeNode; +} + +export interface TypeAssertion extends UnaryExpression { + readonly kind: SyntaxKind.TypeAssertionExpression; + readonly type: TypeNode; + readonly expression: UnaryExpression; +} + +export interface SatisfiesExpression extends Expression { + readonly kind: SyntaxKind.SatisfiesExpression; + readonly expression: Expression; + readonly type: TypeNode; +} + +export type AssertionExpression = + | TypeAssertion + | AsExpression; + +export interface NonNullExpression extends LeftHandSideExpression { + readonly kind: SyntaxKind.NonNullExpression; + readonly expression: Expression; +} + +export interface NonNullChain extends NonNullExpression { + _optionalChainBrand: any; +} + +// NOTE: MetaProperty is really a MemberExpression, but we consider it a PrimaryExpression +// for the same reasons we treat NewExpression as a PrimaryExpression. +export interface MetaProperty extends PrimaryExpression { + readonly kind: SyntaxKind.MetaProperty; + readonly keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword; + readonly name: Identifier; +} + +/// A JSX expression of the form <TagName attrs>...</TagName> +export interface JsxElement extends PrimaryExpression { + readonly kind: SyntaxKind.JsxElement; + readonly openingElement: JsxOpeningElement; + readonly children: NodeArray<JsxChild>; + readonly closingElement: JsxClosingElement; +} + +/// Either the opening tag in a <Tag>...</Tag> pair or the lone <Tag /> in a self-closing form +export type JsxOpeningLikeElement = + | JsxSelfClosingElement + | JsxOpeningElement; + +export type JsxAttributeLike = + | JsxAttribute + | JsxSpreadAttribute; + +export type JsxAttributeName = + | Identifier + | JsxNamespacedName; + +export type JsxTagNameExpression = + | Identifier + | ThisExpression + | JsxTagNamePropertyAccess + | JsxNamespacedName; + +export interface JsxTagNamePropertyAccess extends PropertyAccessExpression { + readonly expression: Identifier | ThisExpression | JsxTagNamePropertyAccess; +} + +export interface JsxAttributes extends PrimaryExpression, Declaration { + readonly properties: NodeArray<JsxAttributeLike>; + readonly kind: SyntaxKind.JsxAttributes; + readonly parent: JsxOpeningLikeElement; +} + +export interface JsxNamespacedName extends Node { + readonly kind: SyntaxKind.JsxNamespacedName; + readonly name: Identifier; + readonly namespace: Identifier; +} + +/// The opening element of a <Tag>...</Tag> JsxElement +export interface JsxOpeningElement extends Expression { + readonly kind: SyntaxKind.JsxOpeningElement; + readonly parent: JsxElement; + readonly tagName: JsxTagNameExpression; + readonly typeArguments?: NodeArray<TypeNode>; + readonly attributes: JsxAttributes; +} + +/// A JSX expression of the form <TagName attrs /> +export interface JsxSelfClosingElement extends PrimaryExpression { + readonly kind: SyntaxKind.JsxSelfClosingElement; + readonly tagName: JsxTagNameExpression; + readonly typeArguments?: NodeArray<TypeNode>; + readonly attributes: JsxAttributes; +} + +/// A JSX expression of the form <>...</> +export interface JsxFragment extends PrimaryExpression { + readonly kind: SyntaxKind.JsxFragment; + readonly openingFragment: JsxOpeningFragment; + readonly children: NodeArray<JsxChild>; + readonly closingFragment: JsxClosingFragment; +} + +/// The opening element of a <>...</> JsxFragment +export interface JsxOpeningFragment extends Expression { + readonly kind: SyntaxKind.JsxOpeningFragment; + readonly parent: JsxFragment; +} + +/// The closing element of a <>...</> JsxFragment +export interface JsxClosingFragment extends Expression { + readonly kind: SyntaxKind.JsxClosingFragment; + readonly parent: JsxFragment; +} + +export interface JsxAttribute extends Declaration { + readonly kind: SyntaxKind.JsxAttribute; + readonly parent: JsxAttributes; + readonly name: JsxAttributeName; + /// JSX attribute initializers are optional; <X y /> is sugar for <X y={true} /> + readonly initializer?: JsxAttributeValue; +} + +export type JsxAttributeValue = + | StringLiteral + | JsxExpression + | JsxElement + | JsxSelfClosingElement + | JsxFragment; + +export interface JsxSpreadAttribute extends ObjectLiteralElement { + readonly kind: SyntaxKind.JsxSpreadAttribute; + readonly parent: JsxAttributes; + readonly expression: Expression; +} + +export interface JsxClosingElement extends Node { + readonly kind: SyntaxKind.JsxClosingElement; + readonly parent: JsxElement; + readonly tagName: JsxTagNameExpression; +} + +export interface JsxExpression extends Expression { + readonly kind: SyntaxKind.JsxExpression; + readonly parent: JsxElement | JsxFragment | JsxAttributeLike; + readonly dotDotDotToken?: Token<SyntaxKind.DotDotDotToken>; + readonly expression?: Expression; +} + +export interface JsxText extends LiteralLikeNode { + readonly kind: SyntaxKind.JsxText; + readonly parent: JsxElement | JsxFragment; + readonly containsOnlyTriviaWhiteSpaces: boolean; +} + +export type JsxChild = + | JsxText + | JsxExpression + | JsxElement + | JsxSelfClosingElement + | JsxFragment; + +export interface Statement extends Node { + _statementBrand: any; +} + +/** + * A list of comma-separated expressions. This node is only created by transformations. + */ +export interface CommaListExpression extends Expression { + readonly kind: SyntaxKind.CommaListExpression; + readonly elements: NodeArray<Expression>; +} + +export interface EmptyStatement extends Statement { + readonly kind: SyntaxKind.EmptyStatement; +} + +export interface DebuggerStatement extends Statement { + readonly kind: SyntaxKind.DebuggerStatement; +} + +export interface Block extends Statement { + readonly kind: SyntaxKind.Block; + readonly statements: NodeArray<Statement>; + multiLine?: boolean; +} + +export interface VariableStatement extends Statement { + readonly kind: SyntaxKind.VariableStatement; + readonly modifiers?: NodeArray<ModifierLike>; + readonly declarationList: VariableDeclarationList; +} + +export interface ExpressionStatement extends Statement { + readonly kind: SyntaxKind.ExpressionStatement; + readonly expression: Expression; +} + +export interface IfStatement extends Statement { + readonly kind: SyntaxKind.IfStatement; + readonly expression: Expression; + readonly thenStatement: Statement; + readonly elseStatement?: Statement; +} + +export interface IterationStatement extends Statement { + readonly statement: Statement; +} + +export interface DoStatement extends IterationStatement { + readonly kind: SyntaxKind.DoStatement; + readonly expression: Expression; +} + +export interface WhileStatement extends IterationStatement { + readonly kind: SyntaxKind.WhileStatement; + readonly expression: Expression; +} + +export type ForInitializer = + | VariableDeclarationList + | Expression; + +export interface ForStatement extends IterationStatement { + readonly kind: SyntaxKind.ForStatement; + readonly initializer?: ForInitializer; + readonly condition?: Expression; + readonly incrementor?: Expression; +} + +export type ForInOrOfStatement = + | ForInStatement + | ForOfStatement; + +export interface ForInStatement extends IterationStatement { + readonly kind: SyntaxKind.ForInStatement; + readonly initializer: ForInitializer; + readonly expression: Expression; +} + +export interface ForOfStatement extends IterationStatement { + readonly kind: SyntaxKind.ForOfStatement; + readonly awaitModifier?: AwaitKeyword; + readonly initializer: ForInitializer; + readonly expression: Expression; +} + +export interface BreakStatement extends Statement { + readonly kind: SyntaxKind.BreakStatement; + readonly label?: Identifier; +} + +export interface ContinueStatement extends Statement { + readonly kind: SyntaxKind.ContinueStatement; + readonly label?: Identifier; +} + +export type BreakOrContinueStatement = + | BreakStatement + | ContinueStatement; + +export interface ReturnStatement extends Statement { + readonly kind: SyntaxKind.ReturnStatement; + readonly expression?: Expression; +} + +export interface WithStatement extends Statement { + readonly kind: SyntaxKind.WithStatement; + readonly expression: Expression; + readonly statement: Statement; +} + +export interface SwitchStatement extends Statement { + readonly kind: SyntaxKind.SwitchStatement; + readonly expression: Expression; + readonly caseBlock: CaseBlock; + possiblyExhaustive?: boolean; // initialized by binding +} + +export interface CaseBlock extends Node { + readonly kind: SyntaxKind.CaseBlock; + readonly parent: SwitchStatement; + readonly clauses: NodeArray<CaseOrDefaultClause>; +} + +export interface CaseClause extends Node { + readonly kind: SyntaxKind.CaseClause; + readonly parent: CaseBlock; + readonly expression: Expression; + readonly statements: NodeArray<Statement>; +} + +export interface DefaultClause extends Node { + readonly kind: SyntaxKind.DefaultClause; + readonly parent: CaseBlock; + readonly statements: NodeArray<Statement>; +} + +export type CaseOrDefaultClause = + | CaseClause + | DefaultClause; + +export interface LabeledStatement extends Statement { + readonly kind: SyntaxKind.LabeledStatement; + readonly label: Identifier; + readonly statement: Statement; +} + +export interface ThrowStatement extends Statement { + readonly kind: SyntaxKind.ThrowStatement; + readonly expression: Expression; +} + +export interface TryStatement extends Statement { + readonly kind: SyntaxKind.TryStatement; + readonly tryBlock: Block; + readonly catchClause?: CatchClause; + readonly finallyBlock?: Block; +} + +export interface CatchClause extends Node { + readonly kind: SyntaxKind.CatchClause; + readonly parent: TryStatement; + readonly variableDeclaration?: VariableDeclaration; + readonly block: Block; +} + +export type ObjectTypeDeclaration = + | ClassLikeDeclaration + | InterfaceDeclaration + | TypeLiteralNode; + +export type DeclarationWithTypeParameters = + | DeclarationWithTypeParameterChildren + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocSignature; + +export type DeclarationWithTypeParameterChildren = + | SignatureDeclaration + | ClassLikeDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTemplateTag; + +export interface ClassLikeDeclarationBase extends NamedDeclaration { + readonly kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression; + readonly name?: Identifier; + readonly typeParameters?: NodeArray<TypeParameterDeclaration>; + readonly heritageClauses?: NodeArray<HeritageClause>; + readonly members: NodeArray<ClassElement>; +} + +export interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement { + readonly kind: SyntaxKind.ClassDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + /** May be undefined in `export default class { ... }`. */ + readonly name?: Identifier; +} + +export interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { + readonly kind: SyntaxKind.ClassExpression; + readonly modifiers?: NodeArray<ModifierLike>; +} + +export type ClassLikeDeclaration = + | ClassDeclaration + | ClassExpression; + +export interface ClassElement extends NamedDeclaration { + _classElementBrand: any; + readonly name?: PropertyName; +} + +export interface TypeElement extends NamedDeclaration { + _typeElementBrand: any; + readonly name?: PropertyName; + readonly questionToken?: QuestionToken | undefined; +} + +export interface InterfaceDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.InterfaceDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: Identifier; + readonly typeParameters?: NodeArray<TypeParameterDeclaration>; + readonly heritageClauses?: NodeArray<HeritageClause>; + readonly members: NodeArray<TypeElement>; +} + +export interface HeritageClause extends Node { + readonly kind: SyntaxKind.HeritageClause; + readonly parent: InterfaceDeclaration | ClassLikeDeclaration; + readonly token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword; + readonly types: NodeArray<ExpressionWithTypeArguments>; +} + +export interface TypeAliasDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.TypeAliasDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: Identifier; + readonly typeParameters?: NodeArray<TypeParameterDeclaration>; + readonly type: TypeNode; +} + +export interface EnumMember extends NamedDeclaration { + readonly kind: SyntaxKind.EnumMember; + readonly parent: EnumDeclaration; + // This does include ComputedPropertyName, but the parser will give an error + // if it parses a ComputedPropertyName in an EnumMember + readonly name: PropertyName; + readonly initializer?: Expression; +} + +export interface EnumDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.EnumDeclaration; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: Identifier; + readonly members: NodeArray<EnumMember>; +} + +export type ModuleName = + | Identifier + | StringLiteral; + +export type ModuleBody = + | NamespaceBody + | JSDocNamespaceBody; + +export interface ModuleDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.ModuleDeclaration; + readonly parent: ModuleBody | SourceFile; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: ModuleName; + readonly body?: ModuleBody | JSDocNamespaceDeclaration; +} + +export type NamespaceBody = + | ModuleBlock + | NamespaceDeclaration; + +export interface NamespaceDeclaration extends ModuleDeclaration { + readonly name: Identifier; + readonly body: NamespaceBody; +} + +export type JSDocNamespaceBody = + | Identifier + | JSDocNamespaceDeclaration; + +export interface JSDocNamespaceDeclaration extends ModuleDeclaration { + readonly name: Identifier; + readonly body?: JSDocNamespaceBody; +} + +export interface ModuleBlock extends Node, Statement { + readonly kind: SyntaxKind.ModuleBlock; + readonly parent: ModuleDeclaration; + readonly statements: NodeArray<Statement>; +} + +export type ModuleReference = + | EntityName + | ExternalModuleReference; + +/** + * One of: + * - import x = require("mod"); + * - import x = M.x; + */ +export interface ImportEqualsDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.ImportEqualsDeclaration; + readonly parent: SourceFile | ModuleBlock; + readonly modifiers?: NodeArray<ModifierLike>; + readonly name: Identifier; + readonly isTypeOnly: boolean; + + // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external + // module reference. + readonly moduleReference: ModuleReference; +} + +export interface ExternalModuleReference extends Node { + readonly kind: SyntaxKind.ExternalModuleReference; + readonly parent: ImportEqualsDeclaration; + readonly expression: Expression; +} + +// In case of: +// import "mod" => importClause = undefined, moduleSpecifier = "mod" +// In rest of the cases, module specifier is string literal corresponding to module +// ImportClause information is shown at its declaration below. +export interface ImportDeclaration extends Statement { + readonly kind: SyntaxKind.ImportDeclaration; + readonly parent: SourceFile | ModuleBlock; + readonly modifiers?: NodeArray<ModifierLike>; + readonly importClause?: ImportClause; + /** If this is not a StringLiteral it will be a grammar error. */ + readonly moduleSpecifier: Expression; + /** @deprecated */ readonly assertClause?: AssertClause; + readonly attributes?: ImportAttributes; +} + +export type NamedImportBindings = + | NamespaceImport + | NamedImports; + +export type NamedExportBindings = + | NamespaceExport + | NamedExports; + +// In case of: +// import d from "mod" => name = d, namedBinding = undefined +// import * as ns from "mod" => name = undefined, namedBinding: NamespaceImport = { name: ns } +// import d, * as ns from "mod" => name = d, namedBinding: NamespaceImport = { name: ns } +// import { a, b as x } from "mod" => name = undefined, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} +// import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} +export interface ImportClause extends NamedDeclaration { + readonly kind: SyntaxKind.ImportClause; + readonly parent: ImportDeclaration | JSDocImportTag; + readonly isTypeOnly: boolean; + readonly name?: Identifier; // Default binding + readonly namedBindings?: NamedImportBindings; +} + +/** @deprecated */ +export type AssertionKey = ImportAttributeName; + +/** @deprecated */ +export interface AssertEntry extends ImportAttribute {} + +/** @deprecated */ +export interface AssertClause extends ImportAttributes {} + +export type ImportAttributeName = Identifier | StringLiteral; + +export interface ImportAttribute extends Node { + readonly kind: SyntaxKind.ImportAttribute; + readonly parent: ImportAttributes; + readonly name: ImportAttributeName; + readonly value: Expression; +} + +export interface ImportAttributes extends Node { + readonly token: SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword; + readonly kind: SyntaxKind.ImportAttributes; + readonly parent: ImportDeclaration | ExportDeclaration; + readonly elements: NodeArray<ImportAttribute>; + readonly multiLine?: boolean; +} + +export interface NamespaceImport extends NamedDeclaration { + readonly kind: SyntaxKind.NamespaceImport; + readonly parent: ImportClause; + readonly name: Identifier; +} + +export interface NamespaceExport extends NamedDeclaration { + readonly kind: SyntaxKind.NamespaceExport; + readonly parent: ExportDeclaration; + readonly name: ModuleExportName; +} + +export interface NamespaceExportDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.NamespaceExportDeclaration; + readonly name: Identifier; +} + +export interface ExportDeclaration extends DeclarationStatement { + readonly kind: SyntaxKind.ExportDeclaration; + readonly parent: SourceFile | ModuleBlock; + readonly modifiers?: NodeArray<ModifierLike>; + readonly isTypeOnly: boolean; + /** Will not be assigned in the case of `export * from "foo";` */ + readonly exportClause?: NamedExportBindings; + /** If this is not a StringLiteral it will be a grammar error. */ + readonly moduleSpecifier?: Expression; + /** @deprecated */ readonly assertClause?: AssertClause; + readonly attributes?: ImportAttributes; +} + +export interface NamedImports extends Node { + readonly kind: SyntaxKind.NamedImports; + readonly parent: ImportClause; + readonly elements: NodeArray<ImportSpecifier>; +} + +export interface NamedExports extends Node { + readonly kind: SyntaxKind.NamedExports; + readonly parent: ExportDeclaration; + readonly elements: NodeArray<ExportSpecifier>; +} + +export type NamedImportsOrExports = NamedImports | NamedExports; + +export interface ImportSpecifier extends NamedDeclaration { + readonly kind: SyntaxKind.ImportSpecifier; + readonly parent: NamedImports; + readonly propertyName?: ModuleExportName; // Name preceding "as" keyword (or undefined when "as" is absent) + readonly name: Identifier; // Declared name + readonly isTypeOnly: boolean; +} + +export interface ExportSpecifier extends NamedDeclaration { + readonly kind: SyntaxKind.ExportSpecifier; + readonly parent: NamedExports; + readonly isTypeOnly: boolean; + readonly propertyName?: ModuleExportName; // Name preceding "as" keyword (or undefined when "as" is absent) + readonly name: ModuleExportName; // Declared name +} + +export type ModuleExportName = Identifier | StringLiteral; + +export type ImportOrExportSpecifier = + | ImportSpecifier + | ExportSpecifier; + +export type TypeOnlyCompatibleAliasDeclaration = + | ImportClause + | ImportEqualsDeclaration + | NamespaceImport + | ImportOrExportSpecifier + | ExportDeclaration + | NamespaceExport; + +export type TypeOnlyImportDeclaration = + | ImportClause & { readonly isTypeOnly: true; readonly name: Identifier; } + | ImportEqualsDeclaration & { readonly isTypeOnly: true; } + | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; } + | ImportSpecifier & ({ readonly isTypeOnly: true; } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; }; }); + +export type TypeOnlyExportDeclaration = + | ExportSpecifier & ({ readonly isTypeOnly: true; } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true; }; }; }) + | ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; } // export * from "mod" + | NamespaceExport & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }; } // export * as ns from "mod" +; + +export type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration; + +/** + * This is either an `export =` or an `export default` declaration. + * Unless `isExportEquals` is set, this node was parsed as an `export default`. + */ +export interface ExportAssignment extends DeclarationStatement { + readonly kind: SyntaxKind.ExportAssignment; + readonly parent: SourceFile; + readonly modifiers?: NodeArray<ModifierLike>; + readonly isExportEquals?: boolean; + readonly expression: Expression; +} + +// represents a top level: { type } expression in a JSDoc comment. +export interface JSDocTypeExpression extends TypeNode { + readonly kind: SyntaxKind.JSDocTypeExpression; + readonly type: TypeNode; +} + +export interface JSDocNameReference extends Node { + readonly kind: SyntaxKind.JSDocNameReference; + readonly name: EntityName | JSDocMemberName; +} + +/** Class#method reference in JSDoc */ +export interface JSDocMemberName extends Node { + readonly kind: SyntaxKind.JSDocMemberName; + readonly left: EntityName | JSDocMemberName; + readonly right: Identifier; +} + +export interface JSDocType extends TypeNode { + _jsDocTypeBrand: any; +} + +export interface JSDocAllType extends JSDocType { + readonly kind: SyntaxKind.JSDocAllType; +} + +export interface JSDocNonNullableType extends JSDocType { + readonly kind: SyntaxKind.JSDocNonNullableType; + readonly type: TypeNode; + readonly postfix: boolean; +} + +export interface JSDocNullableType extends JSDocType { + readonly kind: SyntaxKind.JSDocNullableType; + readonly type: TypeNode; + readonly postfix: boolean; +} + +export interface JSDocOptionalType extends JSDocType { + readonly kind: SyntaxKind.JSDocOptionalType; + readonly type: TypeNode; +} + +export interface JSDocVariadicType extends JSDocType { + readonly kind: SyntaxKind.JSDocVariadicType; + readonly type: TypeNode; +} + +export type JSDocTypeReferencingNode = + | JSDocVariadicType + | JSDocOptionalType + | JSDocNullableType + | JSDocNonNullableType; + +export interface JSDoc extends Node { + readonly kind: SyntaxKind.JSDoc; + readonly parent: HasJSDoc; + readonly tags?: NodeArray<JSDocTag>; + readonly comment?: string | NodeArray<JSDocComment>; +} + +export interface JSDocTag extends Node { + readonly parent: JSDoc | JSDocTypeLiteral; + readonly tagName: Identifier; + readonly comment?: string | NodeArray<JSDocComment>; +} + +export interface JSDocLink extends Node { + readonly kind: SyntaxKind.JSDocLink; + readonly name?: EntityName | JSDocMemberName; + text: string; +} + +export interface JSDocLinkCode extends Node { + readonly kind: SyntaxKind.JSDocLinkCode; + readonly name?: EntityName | JSDocMemberName; + text: string; +} + +export interface JSDocLinkPlain extends Node { + readonly kind: SyntaxKind.JSDocLinkPlain; + readonly name?: EntityName | JSDocMemberName; + text: string; +} + +export type JSDocComment = JSDocText | JSDocLink | JSDocLinkCode | JSDocLinkPlain; + +export interface JSDocText extends Node { + readonly kind: SyntaxKind.JSDocText; + text: string; +} + +export interface JSDocUnknownTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocTag; +} + +/** + * Note that `@extends` is a synonym of `@augments`. + * Both tags are represented by this interface. + */ +export interface JSDocAugmentsTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAugmentsTag; + readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; +} + +export interface JSDocImplementsTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImplementsTag; + readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; +} + +export interface JSDocDeprecatedTag extends JSDocTag { + kind: SyntaxKind.JSDocDeprecatedTag; +} + +export interface JSDocPublicTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocPublicTag; +} + +export interface JSDocPrivateTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocPrivateTag; +} + +export interface JSDocProtectedTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocProtectedTag; +} + +export interface JSDocReadonlyTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocReadonlyTag; +} + +export interface JSDocOverrideTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocOverrideTag; +} + +export interface JSDocThisTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocThisTag; + readonly typeExpression: JSDocTypeExpression; +} + +export interface JSDocTemplateTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocTemplateTag; + readonly constraint: JSDocTypeExpression | undefined; + readonly typeParameters: NodeArray<TypeParameterDeclaration>; +} + +export interface JSDocSeeTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocSeeTag; + readonly name?: JSDocNameReference; +} + +export interface JSDocReturnTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocReturnTag; + readonly typeExpression?: JSDocTypeExpression; +} + +export interface JSDocTypeTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocTypeTag; + readonly typeExpression: JSDocTypeExpression; +} + +export interface JSDocTypedefTag extends JSDocTag, NamedDeclaration { + readonly kind: SyntaxKind.JSDocTypedefTag; + readonly parent: JSDoc; + readonly fullName?: JSDocNamespaceDeclaration | Identifier; + readonly name?: Identifier; + readonly typeExpression?: JSDocTypeExpression | JSDocTypeLiteral; +} + +export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration { + readonly kind: SyntaxKind.JSDocCallbackTag; + readonly parent: JSDoc; + readonly fullName?: JSDocNamespaceDeclaration | Identifier; + readonly name?: Identifier; + readonly typeExpression: JSDocSignature; +} + +export interface JSDocOverloadTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocOverloadTag; + readonly parent: JSDoc; + readonly typeExpression: JSDocSignature; +} + +export interface JSDocSignature extends JSDocType, Declaration { + readonly kind: SyntaxKind.JSDocSignature; + readonly typeParameters?: readonly JSDocTemplateTag[]; + readonly parameters: readonly JSDocParameterTag[]; + readonly type: JSDocReturnTag | undefined; +} + +export interface JSDocPropertyLikeTag extends JSDocTag, Declaration { + readonly parent: JSDoc; + readonly name: EntityName; + readonly typeExpression?: JSDocTypeExpression; + /** Whether the property name came before the type -- non-standard for JSDoc, but Typescript-like */ + readonly isNameFirst: boolean; + readonly isBracketed: boolean; +} + +export interface JSDocPropertyTag extends JSDocPropertyLikeTag { + readonly kind: SyntaxKind.JSDocPropertyTag; +} + +export interface JSDocParameterTag extends JSDocPropertyLikeTag { + readonly kind: SyntaxKind.JSDocParameterTag; +} + +export interface JSDocTypeLiteral extends JSDocType, Declaration { + readonly kind: SyntaxKind.JSDocTypeLiteral; + readonly jsDocPropertyTags?: readonly JSDocPropertyLikeTag[]; + /** If true, then this type literal represents an *array* of its type. */ + readonly isArrayType: boolean; +} + +export interface JSDocSatisfiesTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocSatisfiesTag; + readonly typeExpression: JSDocTypeExpression; +} + +export interface JSDocImportTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocImportTag; + readonly parent: JSDoc; + readonly importClause?: ImportClause; + readonly moduleSpecifier: Expression; + readonly attributes?: ImportAttributes; +} + +export type HasJSDoc = + | AccessorDeclaration + | ArrowFunction + | BinaryExpression + | Block + | BreakStatement + | CallSignatureDeclaration + | CaseClause + | ClassLikeDeclaration + | ClassStaticBlockDeclaration + | ConstructorDeclaration + | ConstructorTypeNode + | ConstructSignatureDeclaration + | ContinueStatement + | DebuggerStatement + | DoStatement + | ElementAccessExpression + | EmptyStatement + | EndOfFile + | EnumDeclaration + | EnumMember + | ExportAssignment + | ExportDeclaration + | ExportSpecifier + | ExpressionStatement + | ForInStatement + | ForOfStatement + | ForStatement + | FunctionDeclaration + | FunctionExpression + | FunctionTypeNode + | Identifier + | IfStatement + | ImportDeclaration + | ImportEqualsDeclaration + | IndexSignatureDeclaration + | InterfaceDeclaration + | JSDocSignature + | LabeledStatement + | MethodDeclaration + | MethodSignature + | ModuleDeclaration + | NamedTupleMember + | NamespaceExportDeclaration + | ObjectLiteralExpression + | ParameterDeclaration + | ParenthesizedExpression + | PropertyAccessExpression + | PropertyAssignment + | PropertyDeclaration + | PropertySignature + | ReturnStatement + | SemicolonClassElement + | ShorthandPropertyAssignment + | SpreadAssignment + | SwitchStatement + | ThrowStatement + | TryStatement + | TypeAliasDeclaration + | TypeParameterDeclaration + | VariableDeclaration + | VariableStatement + | WhileStatement + | WithStatement; diff --git a/_packages/ast/src/syntaxKind.enum.ts b/_packages/ast/src/syntaxKind.enum.ts new file mode 100644 index 0000000000..31fdf059d7 --- /dev/null +++ b/_packages/ast/src/syntaxKind.enum.ts @@ -0,0 +1,352 @@ +export enum SyntaxKind { + Unknown, + EndOfFile, + SingleLineCommentTrivia, + MultiLineCommentTrivia, + NewLineTrivia, + WhitespaceTrivia, + ConflictMarkerTrivia, + NonTextFileMarkerTrivia, + NumericLiteral, + BigIntLiteral, + StringLiteral, + JsxText, + JsxTextAllWhiteSpaces, + RegularExpressionLiteral, + NoSubstitutionTemplateLiteral, + TemplateHead, + TemplateMiddle, + TemplateTail, + OpenBraceToken, + CloseBraceToken, + OpenParenToken, + CloseParenToken, + OpenBracketToken, + CloseBracketToken, + DotToken, + DotDotDotToken, + SemicolonToken, + CommaToken, + QuestionDotToken, + LessThanToken, + LessThanSlashToken, + GreaterThanToken, + LessThanEqualsToken, + GreaterThanEqualsToken, + EqualsEqualsToken, + ExclamationEqualsToken, + EqualsEqualsEqualsToken, + ExclamationEqualsEqualsToken, + EqualsGreaterThanToken, + PlusToken, + MinusToken, + AsteriskToken, + AsteriskAsteriskToken, + SlashToken, + PercentToken, + PlusPlusToken, + MinusMinusToken, + LessThanLessThanToken, + GreaterThanGreaterThanToken, + GreaterThanGreaterThanGreaterThanToken, + AmpersandToken, + BarToken, + CaretToken, + ExclamationToken, + TildeToken, + AmpersandAmpersandToken, + BarBarToken, + QuestionToken, + ColonToken, + AtToken, + QuestionQuestionToken, + BacktickToken, + HashToken, + EqualsToken, + PlusEqualsToken, + MinusEqualsToken, + AsteriskEqualsToken, + AsteriskAsteriskEqualsToken, + SlashEqualsToken, + PercentEqualsToken, + LessThanLessThanEqualsToken, + GreaterThanGreaterThanEqualsToken, + GreaterThanGreaterThanGreaterThanEqualsToken, + AmpersandEqualsToken, + BarEqualsToken, + BarBarEqualsToken, + AmpersandAmpersandEqualsToken, + QuestionQuestionEqualsToken, + CaretEqualsToken, + Identifier, + PrivateIdentifier, + JSDocCommentTextToken, + BreakKeyword, + CaseKeyword, + CatchKeyword, + ClassKeyword, + ConstKeyword, + ContinueKeyword, + DebuggerKeyword, + DefaultKeyword, + DeleteKeyword, + DoKeyword, + ElseKeyword, + EnumKeyword, + ExportKeyword, + ExtendsKeyword, + FalseKeyword, + FinallyKeyword, + ForKeyword, + FunctionKeyword, + IfKeyword, + ImportKeyword, + InKeyword, + InstanceOfKeyword, + NewKeyword, + NullKeyword, + ReturnKeyword, + SuperKeyword, + SwitchKeyword, + ThisKeyword, + ThrowKeyword, + TrueKeyword, + TryKeyword, + TypeOfKeyword, + VarKeyword, + VoidKeyword, + WhileKeyword, + WithKeyword, + ImplementsKeyword, + InterfaceKeyword, + LetKeyword, + PackageKeyword, + PrivateKeyword, + ProtectedKeyword, + PublicKeyword, + StaticKeyword, + YieldKeyword, + AbstractKeyword, + AccessorKeyword, + AsKeyword, + AssertsKeyword, + AssertKeyword, + AnyKeyword, + AsyncKeyword, + AwaitKeyword, + BooleanKeyword, + ConstructorKeyword, + DeclareKeyword, + GetKeyword, + ImmediateKeyword, + InferKeyword, + IntrinsicKeyword, + IsKeyword, + KeyOfKeyword, + ModuleKeyword, + NamespaceKeyword, + NeverKeyword, + OutKeyword, + ReadonlyKeyword, + RequireKeyword, + NumberKeyword, + ObjectKeyword, + SatisfiesKeyword, + SetKeyword, + StringKeyword, + SymbolKeyword, + TypeKeyword, + UndefinedKeyword, + UniqueKeyword, + UnknownKeyword, + UsingKeyword, + FromKeyword, + GlobalKeyword, + BigIntKeyword, + OverrideKeyword, + OfKeyword, + QualifiedName, + ComputedPropertyName, + TypeParameter, + Parameter, + Decorator, + PropertySignature, + PropertyDeclaration, + MethodSignature, + MethodDeclaration, + ClassStaticBlockDeclaration, + Constructor, + GetAccessor, + SetAccessor, + CallSignature, + ConstructSignature, + IndexSignature, + TypePredicate, + TypeReference, + FunctionType, + ConstructorType, + TypeQuery, + TypeLiteral, + ArrayType, + TupleType, + OptionalType, + RestType, + UnionType, + IntersectionType, + ConditionalType, + InferType, + ParenthesizedType, + ThisType, + TypeOperator, + IndexedAccessType, + MappedType, + LiteralType, + NamedTupleMember, + TemplateLiteralType, + TemplateLiteralTypeSpan, + ImportType, + ObjectBindingPattern, + ArrayBindingPattern, + BindingElement, + ArrayLiteralExpression, + ObjectLiteralExpression, + PropertyAccessExpression, + ElementAccessExpression, + CallExpression, + NewExpression, + TaggedTemplateExpression, + TypeAssertionExpression, + ParenthesizedExpression, + FunctionExpression, + ArrowFunction, + DeleteExpression, + TypeOfExpression, + VoidExpression, + AwaitExpression, + PrefixUnaryExpression, + PostfixUnaryExpression, + BinaryExpression, + ConditionalExpression, + TemplateExpression, + YieldExpression, + SpreadElement, + ClassExpression, + OmittedExpression, + ExpressionWithTypeArguments, + AsExpression, + NonNullExpression, + MetaProperty, + SyntheticExpression, + SatisfiesExpression, + TemplateSpan, + SemicolonClassElement, + Block, + EmptyStatement, + VariableStatement, + ExpressionStatement, + IfStatement, + DoStatement, + WhileStatement, + ForStatement, + ForInStatement, + ForOfStatement, + ContinueStatement, + BreakStatement, + ReturnStatement, + WithStatement, + SwitchStatement, + LabeledStatement, + ThrowStatement, + TryStatement, + DebuggerStatement, + VariableDeclaration, + VariableDeclarationList, + FunctionDeclaration, + ClassDeclaration, + InterfaceDeclaration, + TypeAliasDeclaration, + EnumDeclaration, + ModuleDeclaration, + ModuleBlock, + CaseBlock, + NamespaceExportDeclaration, + ImportEqualsDeclaration, + ImportDeclaration, + ImportClause, + NamespaceImport, + NamedImports, + ImportSpecifier, + ExportAssignment, + ExportDeclaration, + NamedExports, + NamespaceExport, + ExportSpecifier, + MissingDeclaration, + ExternalModuleReference, + JsxElement, + JsxSelfClosingElement, + JsxOpeningElement, + JsxClosingElement, + JsxFragment, + JsxOpeningFragment, + JsxClosingFragment, + JsxAttribute, + JsxAttributes, + JsxSpreadAttribute, + JsxExpression, + JsxNamespacedName, + CaseClause, + DefaultClause, + HeritageClause, + CatchClause, + ImportAttributes, + ImportAttribute, + PropertyAssignment, + ShorthandPropertyAssignment, + SpreadAssignment, + EnumMember, + SourceFile, + Bundle, + JSDocTypeExpression, + JSDocNameReference, + JSDocMemberName, + JSDocAllType, + JSDocNullableType, + JSDocNonNullableType, + JSDocOptionalType, + JSDocVariadicType, + JSDoc, + JSDocText, + JSDocTypeLiteral, + JSDocSignature, + JSDocLink, + JSDocLinkCode, + JSDocLinkPlain, + JSDocTag, + JSDocAugmentsTag, + JSDocImplementsTag, + JSDocDeprecatedTag, + JSDocPublicTag, + JSDocPrivateTag, + JSDocProtectedTag, + JSDocReadonlyTag, + JSDocOverrideTag, + JSDocCallbackTag, + JSDocOverloadTag, + JSDocParameterTag, + JSDocReturnTag, + JSDocThisTag, + JSDocTypeTag, + JSDocTemplateTag, + JSDocTypedefTag, + JSDocSeeTag, + JSDocPropertyTag, + JSDocSatisfiesTag, + JSDocImportTag, + SyntaxList, + NotEmittedStatement, + PartiallyEmittedExpression, + CommaListExpression, + SyntheticReferenceExpression, + Count, +} diff --git a/_packages/ast/src/syntaxKind.ts b/_packages/ast/src/syntaxKind.ts new file mode 100644 index 0000000000..4d86197027 --- /dev/null +++ b/_packages/ast/src/syntaxKind.ts @@ -0,0 +1,355 @@ +export var SyntaxKind: any; +(function (SyntaxKind) { + SyntaxKind[SyntaxKind["Unknown"] = 0] = "Unknown"; + SyntaxKind[SyntaxKind["EndOfFile"] = 1] = "EndOfFile"; + SyntaxKind[SyntaxKind["SingleLineCommentTrivia"] = 2] = "SingleLineCommentTrivia"; + SyntaxKind[SyntaxKind["MultiLineCommentTrivia"] = 3] = "MultiLineCommentTrivia"; + SyntaxKind[SyntaxKind["NewLineTrivia"] = 4] = "NewLineTrivia"; + SyntaxKind[SyntaxKind["WhitespaceTrivia"] = 5] = "WhitespaceTrivia"; + SyntaxKind[SyntaxKind["ConflictMarkerTrivia"] = 6] = "ConflictMarkerTrivia"; + SyntaxKind[SyntaxKind["NonTextFileMarkerTrivia"] = 7] = "NonTextFileMarkerTrivia"; + SyntaxKind[SyntaxKind["NumericLiteral"] = 8] = "NumericLiteral"; + SyntaxKind[SyntaxKind["BigIntLiteral"] = 9] = "BigIntLiteral"; + SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral"; + SyntaxKind[SyntaxKind["JsxText"] = 11] = "JsxText"; + SyntaxKind[SyntaxKind["JsxTextAllWhiteSpaces"] = 12] = "JsxTextAllWhiteSpaces"; + SyntaxKind[SyntaxKind["RegularExpressionLiteral"] = 13] = "RegularExpressionLiteral"; + SyntaxKind[SyntaxKind["NoSubstitutionTemplateLiteral"] = 14] = "NoSubstitutionTemplateLiteral"; + SyntaxKind[SyntaxKind["TemplateHead"] = 15] = "TemplateHead"; + SyntaxKind[SyntaxKind["TemplateMiddle"] = 16] = "TemplateMiddle"; + SyntaxKind[SyntaxKind["TemplateTail"] = 17] = "TemplateTail"; + SyntaxKind[SyntaxKind["OpenBraceToken"] = 18] = "OpenBraceToken"; + SyntaxKind[SyntaxKind["CloseBraceToken"] = 19] = "CloseBraceToken"; + SyntaxKind[SyntaxKind["OpenParenToken"] = 20] = "OpenParenToken"; + SyntaxKind[SyntaxKind["CloseParenToken"] = 21] = "CloseParenToken"; + SyntaxKind[SyntaxKind["OpenBracketToken"] = 22] = "OpenBracketToken"; + SyntaxKind[SyntaxKind["CloseBracketToken"] = 23] = "CloseBracketToken"; + SyntaxKind[SyntaxKind["DotToken"] = 24] = "DotToken"; + SyntaxKind[SyntaxKind["DotDotDotToken"] = 25] = "DotDotDotToken"; + SyntaxKind[SyntaxKind["SemicolonToken"] = 26] = "SemicolonToken"; + SyntaxKind[SyntaxKind["CommaToken"] = 27] = "CommaToken"; + SyntaxKind[SyntaxKind["QuestionDotToken"] = 28] = "QuestionDotToken"; + SyntaxKind[SyntaxKind["LessThanToken"] = 29] = "LessThanToken"; + SyntaxKind[SyntaxKind["LessThanSlashToken"] = 30] = "LessThanSlashToken"; + SyntaxKind[SyntaxKind["GreaterThanToken"] = 31] = "GreaterThanToken"; + SyntaxKind[SyntaxKind["LessThanEqualsToken"] = 32] = "LessThanEqualsToken"; + SyntaxKind[SyntaxKind["GreaterThanEqualsToken"] = 33] = "GreaterThanEqualsToken"; + SyntaxKind[SyntaxKind["EqualsEqualsToken"] = 34] = "EqualsEqualsToken"; + SyntaxKind[SyntaxKind["ExclamationEqualsToken"] = 35] = "ExclamationEqualsToken"; + SyntaxKind[SyntaxKind["EqualsEqualsEqualsToken"] = 36] = "EqualsEqualsEqualsToken"; + SyntaxKind[SyntaxKind["ExclamationEqualsEqualsToken"] = 37] = "ExclamationEqualsEqualsToken"; + SyntaxKind[SyntaxKind["EqualsGreaterThanToken"] = 38] = "EqualsGreaterThanToken"; + SyntaxKind[SyntaxKind["PlusToken"] = 39] = "PlusToken"; + SyntaxKind[SyntaxKind["MinusToken"] = 40] = "MinusToken"; + SyntaxKind[SyntaxKind["AsteriskToken"] = 41] = "AsteriskToken"; + SyntaxKind[SyntaxKind["AsteriskAsteriskToken"] = 42] = "AsteriskAsteriskToken"; + SyntaxKind[SyntaxKind["SlashToken"] = 43] = "SlashToken"; + SyntaxKind[SyntaxKind["PercentToken"] = 44] = "PercentToken"; + SyntaxKind[SyntaxKind["PlusPlusToken"] = 45] = "PlusPlusToken"; + SyntaxKind[SyntaxKind["MinusMinusToken"] = 46] = "MinusMinusToken"; + SyntaxKind[SyntaxKind["LessThanLessThanToken"] = 47] = "LessThanLessThanToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanToken"] = 48] = "GreaterThanGreaterThanToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanGreaterThanToken"] = 49] = "GreaterThanGreaterThanGreaterThanToken"; + SyntaxKind[SyntaxKind["AmpersandToken"] = 50] = "AmpersandToken"; + SyntaxKind[SyntaxKind["BarToken"] = 51] = "BarToken"; + SyntaxKind[SyntaxKind["CaretToken"] = 52] = "CaretToken"; + SyntaxKind[SyntaxKind["ExclamationToken"] = 53] = "ExclamationToken"; + SyntaxKind[SyntaxKind["TildeToken"] = 54] = "TildeToken"; + SyntaxKind[SyntaxKind["AmpersandAmpersandToken"] = 55] = "AmpersandAmpersandToken"; + SyntaxKind[SyntaxKind["BarBarToken"] = 56] = "BarBarToken"; + SyntaxKind[SyntaxKind["QuestionToken"] = 57] = "QuestionToken"; + SyntaxKind[SyntaxKind["ColonToken"] = 58] = "ColonToken"; + SyntaxKind[SyntaxKind["AtToken"] = 59] = "AtToken"; + SyntaxKind[SyntaxKind["QuestionQuestionToken"] = 60] = "QuestionQuestionToken"; + SyntaxKind[SyntaxKind["BacktickToken"] = 61] = "BacktickToken"; + SyntaxKind[SyntaxKind["HashToken"] = 62] = "HashToken"; + SyntaxKind[SyntaxKind["EqualsToken"] = 63] = "EqualsToken"; + SyntaxKind[SyntaxKind["PlusEqualsToken"] = 64] = "PlusEqualsToken"; + SyntaxKind[SyntaxKind["MinusEqualsToken"] = 65] = "MinusEqualsToken"; + SyntaxKind[SyntaxKind["AsteriskEqualsToken"] = 66] = "AsteriskEqualsToken"; + SyntaxKind[SyntaxKind["AsteriskAsteriskEqualsToken"] = 67] = "AsteriskAsteriskEqualsToken"; + SyntaxKind[SyntaxKind["SlashEqualsToken"] = 68] = "SlashEqualsToken"; + SyntaxKind[SyntaxKind["PercentEqualsToken"] = 69] = "PercentEqualsToken"; + SyntaxKind[SyntaxKind["LessThanLessThanEqualsToken"] = 70] = "LessThanLessThanEqualsToken"; + SyntaxKind[SyntaxKind["GreaterThanGreaterThanEqualsToken"] = 71] = "GreaterThanGreaterThanEqualsToken"; + SyntaxKind[ + SyntaxKind["GreaterThanGreaterThanGreaterThanEqualsToken"] = 72 + ] = "GreaterThanGreaterThanGreaterThanEqualsToken"; + SyntaxKind[SyntaxKind["AmpersandEqualsToken"] = 73] = "AmpersandEqualsToken"; + SyntaxKind[SyntaxKind["BarEqualsToken"] = 74] = "BarEqualsToken"; + SyntaxKind[SyntaxKind["BarBarEqualsToken"] = 75] = "BarBarEqualsToken"; + SyntaxKind[SyntaxKind["AmpersandAmpersandEqualsToken"] = 76] = "AmpersandAmpersandEqualsToken"; + SyntaxKind[SyntaxKind["QuestionQuestionEqualsToken"] = 77] = "QuestionQuestionEqualsToken"; + SyntaxKind[SyntaxKind["CaretEqualsToken"] = 78] = "CaretEqualsToken"; + SyntaxKind[SyntaxKind["Identifier"] = 79] = "Identifier"; + SyntaxKind[SyntaxKind["PrivateIdentifier"] = 80] = "PrivateIdentifier"; + SyntaxKind[SyntaxKind["JSDocCommentTextToken"] = 81] = "JSDocCommentTextToken"; + SyntaxKind[SyntaxKind["BreakKeyword"] = 82] = "BreakKeyword"; + SyntaxKind[SyntaxKind["CaseKeyword"] = 83] = "CaseKeyword"; + SyntaxKind[SyntaxKind["CatchKeyword"] = 84] = "CatchKeyword"; + SyntaxKind[SyntaxKind["ClassKeyword"] = 85] = "ClassKeyword"; + SyntaxKind[SyntaxKind["ConstKeyword"] = 86] = "ConstKeyword"; + SyntaxKind[SyntaxKind["ContinueKeyword"] = 87] = "ContinueKeyword"; + SyntaxKind[SyntaxKind["DebuggerKeyword"] = 88] = "DebuggerKeyword"; + SyntaxKind[SyntaxKind["DefaultKeyword"] = 89] = "DefaultKeyword"; + SyntaxKind[SyntaxKind["DeleteKeyword"] = 90] = "DeleteKeyword"; + SyntaxKind[SyntaxKind["DoKeyword"] = 91] = "DoKeyword"; + SyntaxKind[SyntaxKind["ElseKeyword"] = 92] = "ElseKeyword"; + SyntaxKind[SyntaxKind["EnumKeyword"] = 93] = "EnumKeyword"; + SyntaxKind[SyntaxKind["ExportKeyword"] = 94] = "ExportKeyword"; + SyntaxKind[SyntaxKind["ExtendsKeyword"] = 95] = "ExtendsKeyword"; + SyntaxKind[SyntaxKind["FalseKeyword"] = 96] = "FalseKeyword"; + SyntaxKind[SyntaxKind["FinallyKeyword"] = 97] = "FinallyKeyword"; + SyntaxKind[SyntaxKind["ForKeyword"] = 98] = "ForKeyword"; + SyntaxKind[SyntaxKind["FunctionKeyword"] = 99] = "FunctionKeyword"; + SyntaxKind[SyntaxKind["IfKeyword"] = 100] = "IfKeyword"; + SyntaxKind[SyntaxKind["ImportKeyword"] = 101] = "ImportKeyword"; + SyntaxKind[SyntaxKind["InKeyword"] = 102] = "InKeyword"; + SyntaxKind[SyntaxKind["InstanceOfKeyword"] = 103] = "InstanceOfKeyword"; + SyntaxKind[SyntaxKind["NewKeyword"] = 104] = "NewKeyword"; + SyntaxKind[SyntaxKind["NullKeyword"] = 105] = "NullKeyword"; + SyntaxKind[SyntaxKind["ReturnKeyword"] = 106] = "ReturnKeyword"; + SyntaxKind[SyntaxKind["SuperKeyword"] = 107] = "SuperKeyword"; + SyntaxKind[SyntaxKind["SwitchKeyword"] = 108] = "SwitchKeyword"; + SyntaxKind[SyntaxKind["ThisKeyword"] = 109] = "ThisKeyword"; + SyntaxKind[SyntaxKind["ThrowKeyword"] = 110] = "ThrowKeyword"; + SyntaxKind[SyntaxKind["TrueKeyword"] = 111] = "TrueKeyword"; + SyntaxKind[SyntaxKind["TryKeyword"] = 112] = "TryKeyword"; + SyntaxKind[SyntaxKind["TypeOfKeyword"] = 113] = "TypeOfKeyword"; + SyntaxKind[SyntaxKind["VarKeyword"] = 114] = "VarKeyword"; + SyntaxKind[SyntaxKind["VoidKeyword"] = 115] = "VoidKeyword"; + SyntaxKind[SyntaxKind["WhileKeyword"] = 116] = "WhileKeyword"; + SyntaxKind[SyntaxKind["WithKeyword"] = 117] = "WithKeyword"; + SyntaxKind[SyntaxKind["ImplementsKeyword"] = 118] = "ImplementsKeyword"; + SyntaxKind[SyntaxKind["InterfaceKeyword"] = 119] = "InterfaceKeyword"; + SyntaxKind[SyntaxKind["LetKeyword"] = 120] = "LetKeyword"; + SyntaxKind[SyntaxKind["PackageKeyword"] = 121] = "PackageKeyword"; + SyntaxKind[SyntaxKind["PrivateKeyword"] = 122] = "PrivateKeyword"; + SyntaxKind[SyntaxKind["ProtectedKeyword"] = 123] = "ProtectedKeyword"; + SyntaxKind[SyntaxKind["PublicKeyword"] = 124] = "PublicKeyword"; + SyntaxKind[SyntaxKind["StaticKeyword"] = 125] = "StaticKeyword"; + SyntaxKind[SyntaxKind["YieldKeyword"] = 126] = "YieldKeyword"; + SyntaxKind[SyntaxKind["AbstractKeyword"] = 127] = "AbstractKeyword"; + SyntaxKind[SyntaxKind["AccessorKeyword"] = 128] = "AccessorKeyword"; + SyntaxKind[SyntaxKind["AsKeyword"] = 129] = "AsKeyword"; + SyntaxKind[SyntaxKind["AssertsKeyword"] = 130] = "AssertsKeyword"; + SyntaxKind[SyntaxKind["AssertKeyword"] = 131] = "AssertKeyword"; + SyntaxKind[SyntaxKind["AnyKeyword"] = 132] = "AnyKeyword"; + SyntaxKind[SyntaxKind["AsyncKeyword"] = 133] = "AsyncKeyword"; + SyntaxKind[SyntaxKind["AwaitKeyword"] = 134] = "AwaitKeyword"; + SyntaxKind[SyntaxKind["BooleanKeyword"] = 135] = "BooleanKeyword"; + SyntaxKind[SyntaxKind["ConstructorKeyword"] = 136] = "ConstructorKeyword"; + SyntaxKind[SyntaxKind["DeclareKeyword"] = 137] = "DeclareKeyword"; + SyntaxKind[SyntaxKind["GetKeyword"] = 138] = "GetKeyword"; + SyntaxKind[SyntaxKind["ImmediateKeyword"] = 139] = "ImmediateKeyword"; + SyntaxKind[SyntaxKind["InferKeyword"] = 140] = "InferKeyword"; + SyntaxKind[SyntaxKind["IntrinsicKeyword"] = 141] = "IntrinsicKeyword"; + SyntaxKind[SyntaxKind["IsKeyword"] = 142] = "IsKeyword"; + SyntaxKind[SyntaxKind["KeyOfKeyword"] = 143] = "KeyOfKeyword"; + SyntaxKind[SyntaxKind["ModuleKeyword"] = 144] = "ModuleKeyword"; + SyntaxKind[SyntaxKind["NamespaceKeyword"] = 145] = "NamespaceKeyword"; + SyntaxKind[SyntaxKind["NeverKeyword"] = 146] = "NeverKeyword"; + SyntaxKind[SyntaxKind["OutKeyword"] = 147] = "OutKeyword"; + SyntaxKind[SyntaxKind["ReadonlyKeyword"] = 148] = "ReadonlyKeyword"; + SyntaxKind[SyntaxKind["RequireKeyword"] = 149] = "RequireKeyword"; + SyntaxKind[SyntaxKind["NumberKeyword"] = 150] = "NumberKeyword"; + SyntaxKind[SyntaxKind["ObjectKeyword"] = 151] = "ObjectKeyword"; + SyntaxKind[SyntaxKind["SatisfiesKeyword"] = 152] = "SatisfiesKeyword"; + SyntaxKind[SyntaxKind["SetKeyword"] = 153] = "SetKeyword"; + SyntaxKind[SyntaxKind["StringKeyword"] = 154] = "StringKeyword"; + SyntaxKind[SyntaxKind["SymbolKeyword"] = 155] = "SymbolKeyword"; + SyntaxKind[SyntaxKind["TypeKeyword"] = 156] = "TypeKeyword"; + SyntaxKind[SyntaxKind["UndefinedKeyword"] = 157] = "UndefinedKeyword"; + SyntaxKind[SyntaxKind["UniqueKeyword"] = 158] = "UniqueKeyword"; + SyntaxKind[SyntaxKind["UnknownKeyword"] = 159] = "UnknownKeyword"; + SyntaxKind[SyntaxKind["UsingKeyword"] = 160] = "UsingKeyword"; + SyntaxKind[SyntaxKind["FromKeyword"] = 161] = "FromKeyword"; + SyntaxKind[SyntaxKind["GlobalKeyword"] = 162] = "GlobalKeyword"; + SyntaxKind[SyntaxKind["BigIntKeyword"] = 163] = "BigIntKeyword"; + SyntaxKind[SyntaxKind["OverrideKeyword"] = 164] = "OverrideKeyword"; + SyntaxKind[SyntaxKind["OfKeyword"] = 165] = "OfKeyword"; + SyntaxKind[SyntaxKind["QualifiedName"] = 166] = "QualifiedName"; + SyntaxKind[SyntaxKind["ComputedPropertyName"] = 167] = "ComputedPropertyName"; + SyntaxKind[SyntaxKind["TypeParameter"] = 168] = "TypeParameter"; + SyntaxKind[SyntaxKind["Parameter"] = 169] = "Parameter"; + SyntaxKind[SyntaxKind["Decorator"] = 170] = "Decorator"; + SyntaxKind[SyntaxKind["PropertySignature"] = 171] = "PropertySignature"; + SyntaxKind[SyntaxKind["PropertyDeclaration"] = 172] = "PropertyDeclaration"; + SyntaxKind[SyntaxKind["MethodSignature"] = 173] = "MethodSignature"; + SyntaxKind[SyntaxKind["MethodDeclaration"] = 174] = "MethodDeclaration"; + SyntaxKind[SyntaxKind["ClassStaticBlockDeclaration"] = 175] = "ClassStaticBlockDeclaration"; + SyntaxKind[SyntaxKind["Constructor"] = 176] = "Constructor"; + SyntaxKind[SyntaxKind["GetAccessor"] = 177] = "GetAccessor"; + SyntaxKind[SyntaxKind["SetAccessor"] = 178] = "SetAccessor"; + SyntaxKind[SyntaxKind["CallSignature"] = 179] = "CallSignature"; + SyntaxKind[SyntaxKind["ConstructSignature"] = 180] = "ConstructSignature"; + SyntaxKind[SyntaxKind["IndexSignature"] = 181] = "IndexSignature"; + SyntaxKind[SyntaxKind["TypePredicate"] = 182] = "TypePredicate"; + SyntaxKind[SyntaxKind["TypeReference"] = 183] = "TypeReference"; + SyntaxKind[SyntaxKind["FunctionType"] = 184] = "FunctionType"; + SyntaxKind[SyntaxKind["ConstructorType"] = 185] = "ConstructorType"; + SyntaxKind[SyntaxKind["TypeQuery"] = 186] = "TypeQuery"; + SyntaxKind[SyntaxKind["TypeLiteral"] = 187] = "TypeLiteral"; + SyntaxKind[SyntaxKind["ArrayType"] = 188] = "ArrayType"; + SyntaxKind[SyntaxKind["TupleType"] = 189] = "TupleType"; + SyntaxKind[SyntaxKind["OptionalType"] = 190] = "OptionalType"; + SyntaxKind[SyntaxKind["RestType"] = 191] = "RestType"; + SyntaxKind[SyntaxKind["UnionType"] = 192] = "UnionType"; + SyntaxKind[SyntaxKind["IntersectionType"] = 193] = "IntersectionType"; + SyntaxKind[SyntaxKind["ConditionalType"] = 194] = "ConditionalType"; + SyntaxKind[SyntaxKind["InferType"] = 195] = "InferType"; + SyntaxKind[SyntaxKind["ParenthesizedType"] = 196] = "ParenthesizedType"; + SyntaxKind[SyntaxKind["ThisType"] = 197] = "ThisType"; + SyntaxKind[SyntaxKind["TypeOperator"] = 198] = "TypeOperator"; + SyntaxKind[SyntaxKind["IndexedAccessType"] = 199] = "IndexedAccessType"; + SyntaxKind[SyntaxKind["MappedType"] = 200] = "MappedType"; + SyntaxKind[SyntaxKind["LiteralType"] = 201] = "LiteralType"; + SyntaxKind[SyntaxKind["NamedTupleMember"] = 202] = "NamedTupleMember"; + SyntaxKind[SyntaxKind["TemplateLiteralType"] = 203] = "TemplateLiteralType"; + SyntaxKind[SyntaxKind["TemplateLiteralTypeSpan"] = 204] = "TemplateLiteralTypeSpan"; + SyntaxKind[SyntaxKind["ImportType"] = 205] = "ImportType"; + SyntaxKind[SyntaxKind["ObjectBindingPattern"] = 206] = "ObjectBindingPattern"; + SyntaxKind[SyntaxKind["ArrayBindingPattern"] = 207] = "ArrayBindingPattern"; + SyntaxKind[SyntaxKind["BindingElement"] = 208] = "BindingElement"; + SyntaxKind[SyntaxKind["ArrayLiteralExpression"] = 209] = "ArrayLiteralExpression"; + SyntaxKind[SyntaxKind["ObjectLiteralExpression"] = 210] = "ObjectLiteralExpression"; + SyntaxKind[SyntaxKind["PropertyAccessExpression"] = 211] = "PropertyAccessExpression"; + SyntaxKind[SyntaxKind["ElementAccessExpression"] = 212] = "ElementAccessExpression"; + SyntaxKind[SyntaxKind["CallExpression"] = 213] = "CallExpression"; + SyntaxKind[SyntaxKind["NewExpression"] = 214] = "NewExpression"; + SyntaxKind[SyntaxKind["TaggedTemplateExpression"] = 215] = "TaggedTemplateExpression"; + SyntaxKind[SyntaxKind["TypeAssertionExpression"] = 216] = "TypeAssertionExpression"; + SyntaxKind[SyntaxKind["ParenthesizedExpression"] = 217] = "ParenthesizedExpression"; + SyntaxKind[SyntaxKind["FunctionExpression"] = 218] = "FunctionExpression"; + SyntaxKind[SyntaxKind["ArrowFunction"] = 219] = "ArrowFunction"; + SyntaxKind[SyntaxKind["DeleteExpression"] = 220] = "DeleteExpression"; + SyntaxKind[SyntaxKind["TypeOfExpression"] = 221] = "TypeOfExpression"; + SyntaxKind[SyntaxKind["VoidExpression"] = 222] = "VoidExpression"; + SyntaxKind[SyntaxKind["AwaitExpression"] = 223] = "AwaitExpression"; + SyntaxKind[SyntaxKind["PrefixUnaryExpression"] = 224] = "PrefixUnaryExpression"; + SyntaxKind[SyntaxKind["PostfixUnaryExpression"] = 225] = "PostfixUnaryExpression"; + SyntaxKind[SyntaxKind["BinaryExpression"] = 226] = "BinaryExpression"; + SyntaxKind[SyntaxKind["ConditionalExpression"] = 227] = "ConditionalExpression"; + SyntaxKind[SyntaxKind["TemplateExpression"] = 228] = "TemplateExpression"; + SyntaxKind[SyntaxKind["YieldExpression"] = 229] = "YieldExpression"; + SyntaxKind[SyntaxKind["SpreadElement"] = 230] = "SpreadElement"; + SyntaxKind[SyntaxKind["ClassExpression"] = 231] = "ClassExpression"; + SyntaxKind[SyntaxKind["OmittedExpression"] = 232] = "OmittedExpression"; + SyntaxKind[SyntaxKind["ExpressionWithTypeArguments"] = 233] = "ExpressionWithTypeArguments"; + SyntaxKind[SyntaxKind["AsExpression"] = 234] = "AsExpression"; + SyntaxKind[SyntaxKind["NonNullExpression"] = 235] = "NonNullExpression"; + SyntaxKind[SyntaxKind["MetaProperty"] = 236] = "MetaProperty"; + SyntaxKind[SyntaxKind["SyntheticExpression"] = 237] = "SyntheticExpression"; + SyntaxKind[SyntaxKind["SatisfiesExpression"] = 238] = "SatisfiesExpression"; + SyntaxKind[SyntaxKind["TemplateSpan"] = 239] = "TemplateSpan"; + SyntaxKind[SyntaxKind["SemicolonClassElement"] = 240] = "SemicolonClassElement"; + SyntaxKind[SyntaxKind["Block"] = 241] = "Block"; + SyntaxKind[SyntaxKind["EmptyStatement"] = 242] = "EmptyStatement"; + SyntaxKind[SyntaxKind["VariableStatement"] = 243] = "VariableStatement"; + SyntaxKind[SyntaxKind["ExpressionStatement"] = 244] = "ExpressionStatement"; + SyntaxKind[SyntaxKind["IfStatement"] = 245] = "IfStatement"; + SyntaxKind[SyntaxKind["DoStatement"] = 246] = "DoStatement"; + SyntaxKind[SyntaxKind["WhileStatement"] = 247] = "WhileStatement"; + SyntaxKind[SyntaxKind["ForStatement"] = 248] = "ForStatement"; + SyntaxKind[SyntaxKind["ForInStatement"] = 249] = "ForInStatement"; + SyntaxKind[SyntaxKind["ForOfStatement"] = 250] = "ForOfStatement"; + SyntaxKind[SyntaxKind["ContinueStatement"] = 251] = "ContinueStatement"; + SyntaxKind[SyntaxKind["BreakStatement"] = 252] = "BreakStatement"; + SyntaxKind[SyntaxKind["ReturnStatement"] = 253] = "ReturnStatement"; + SyntaxKind[SyntaxKind["WithStatement"] = 254] = "WithStatement"; + SyntaxKind[SyntaxKind["SwitchStatement"] = 255] = "SwitchStatement"; + SyntaxKind[SyntaxKind["LabeledStatement"] = 256] = "LabeledStatement"; + SyntaxKind[SyntaxKind["ThrowStatement"] = 257] = "ThrowStatement"; + SyntaxKind[SyntaxKind["TryStatement"] = 258] = "TryStatement"; + SyntaxKind[SyntaxKind["DebuggerStatement"] = 259] = "DebuggerStatement"; + SyntaxKind[SyntaxKind["VariableDeclaration"] = 260] = "VariableDeclaration"; + SyntaxKind[SyntaxKind["VariableDeclarationList"] = 261] = "VariableDeclarationList"; + SyntaxKind[SyntaxKind["FunctionDeclaration"] = 262] = "FunctionDeclaration"; + SyntaxKind[SyntaxKind["ClassDeclaration"] = 263] = "ClassDeclaration"; + SyntaxKind[SyntaxKind["InterfaceDeclaration"] = 264] = "InterfaceDeclaration"; + SyntaxKind[SyntaxKind["TypeAliasDeclaration"] = 265] = "TypeAliasDeclaration"; + SyntaxKind[SyntaxKind["EnumDeclaration"] = 266] = "EnumDeclaration"; + SyntaxKind[SyntaxKind["ModuleDeclaration"] = 267] = "ModuleDeclaration"; + SyntaxKind[SyntaxKind["ModuleBlock"] = 268] = "ModuleBlock"; + SyntaxKind[SyntaxKind["CaseBlock"] = 269] = "CaseBlock"; + SyntaxKind[SyntaxKind["NamespaceExportDeclaration"] = 270] = "NamespaceExportDeclaration"; + SyntaxKind[SyntaxKind["ImportEqualsDeclaration"] = 271] = "ImportEqualsDeclaration"; + SyntaxKind[SyntaxKind["ImportDeclaration"] = 272] = "ImportDeclaration"; + SyntaxKind[SyntaxKind["ImportClause"] = 273] = "ImportClause"; + SyntaxKind[SyntaxKind["NamespaceImport"] = 274] = "NamespaceImport"; + SyntaxKind[SyntaxKind["NamedImports"] = 275] = "NamedImports"; + SyntaxKind[SyntaxKind["ImportSpecifier"] = 276] = "ImportSpecifier"; + SyntaxKind[SyntaxKind["ExportAssignment"] = 277] = "ExportAssignment"; + SyntaxKind[SyntaxKind["ExportDeclaration"] = 278] = "ExportDeclaration"; + SyntaxKind[SyntaxKind["NamedExports"] = 279] = "NamedExports"; + SyntaxKind[SyntaxKind["NamespaceExport"] = 280] = "NamespaceExport"; + SyntaxKind[SyntaxKind["ExportSpecifier"] = 281] = "ExportSpecifier"; + SyntaxKind[SyntaxKind["MissingDeclaration"] = 282] = "MissingDeclaration"; + SyntaxKind[SyntaxKind["ExternalModuleReference"] = 283] = "ExternalModuleReference"; + SyntaxKind[SyntaxKind["JsxElement"] = 284] = "JsxElement"; + SyntaxKind[SyntaxKind["JsxSelfClosingElement"] = 285] = "JsxSelfClosingElement"; + SyntaxKind[SyntaxKind["JsxOpeningElement"] = 286] = "JsxOpeningElement"; + SyntaxKind[SyntaxKind["JsxClosingElement"] = 287] = "JsxClosingElement"; + SyntaxKind[SyntaxKind["JsxFragment"] = 288] = "JsxFragment"; + SyntaxKind[SyntaxKind["JsxOpeningFragment"] = 289] = "JsxOpeningFragment"; + SyntaxKind[SyntaxKind["JsxClosingFragment"] = 290] = "JsxClosingFragment"; + SyntaxKind[SyntaxKind["JsxAttribute"] = 291] = "JsxAttribute"; + SyntaxKind[SyntaxKind["JsxAttributes"] = 292] = "JsxAttributes"; + SyntaxKind[SyntaxKind["JsxSpreadAttribute"] = 293] = "JsxSpreadAttribute"; + SyntaxKind[SyntaxKind["JsxExpression"] = 294] = "JsxExpression"; + SyntaxKind[SyntaxKind["JsxNamespacedName"] = 295] = "JsxNamespacedName"; + SyntaxKind[SyntaxKind["CaseClause"] = 296] = "CaseClause"; + SyntaxKind[SyntaxKind["DefaultClause"] = 297] = "DefaultClause"; + SyntaxKind[SyntaxKind["HeritageClause"] = 298] = "HeritageClause"; + SyntaxKind[SyntaxKind["CatchClause"] = 299] = "CatchClause"; + SyntaxKind[SyntaxKind["ImportAttributes"] = 300] = "ImportAttributes"; + SyntaxKind[SyntaxKind["ImportAttribute"] = 301] = "ImportAttribute"; + SyntaxKind[SyntaxKind["PropertyAssignment"] = 302] = "PropertyAssignment"; + SyntaxKind[SyntaxKind["ShorthandPropertyAssignment"] = 303] = "ShorthandPropertyAssignment"; + SyntaxKind[SyntaxKind["SpreadAssignment"] = 304] = "SpreadAssignment"; + SyntaxKind[SyntaxKind["EnumMember"] = 305] = "EnumMember"; + SyntaxKind[SyntaxKind["SourceFile"] = 306] = "SourceFile"; + SyntaxKind[SyntaxKind["Bundle"] = 307] = "Bundle"; + SyntaxKind[SyntaxKind["JSDocTypeExpression"] = 308] = "JSDocTypeExpression"; + SyntaxKind[SyntaxKind["JSDocNameReference"] = 309] = "JSDocNameReference"; + SyntaxKind[SyntaxKind["JSDocMemberName"] = 310] = "JSDocMemberName"; + SyntaxKind[SyntaxKind["JSDocAllType"] = 311] = "JSDocAllType"; + SyntaxKind[SyntaxKind["JSDocNullableType"] = 312] = "JSDocNullableType"; + SyntaxKind[SyntaxKind["JSDocNonNullableType"] = 313] = "JSDocNonNullableType"; + SyntaxKind[SyntaxKind["JSDocOptionalType"] = 314] = "JSDocOptionalType"; + SyntaxKind[SyntaxKind["JSDocVariadicType"] = 315] = "JSDocVariadicType"; + SyntaxKind[SyntaxKind["JSDoc"] = 316] = "JSDoc"; + SyntaxKind[SyntaxKind["JSDocText"] = 317] = "JSDocText"; + SyntaxKind[SyntaxKind["JSDocTypeLiteral"] = 318] = "JSDocTypeLiteral"; + SyntaxKind[SyntaxKind["JSDocSignature"] = 319] = "JSDocSignature"; + SyntaxKind[SyntaxKind["JSDocLink"] = 320] = "JSDocLink"; + SyntaxKind[SyntaxKind["JSDocLinkCode"] = 321] = "JSDocLinkCode"; + SyntaxKind[SyntaxKind["JSDocLinkPlain"] = 322] = "JSDocLinkPlain"; + SyntaxKind[SyntaxKind["JSDocTag"] = 323] = "JSDocTag"; + SyntaxKind[SyntaxKind["JSDocAugmentsTag"] = 324] = "JSDocAugmentsTag"; + SyntaxKind[SyntaxKind["JSDocImplementsTag"] = 325] = "JSDocImplementsTag"; + SyntaxKind[SyntaxKind["JSDocDeprecatedTag"] = 326] = "JSDocDeprecatedTag"; + SyntaxKind[SyntaxKind["JSDocPublicTag"] = 327] = "JSDocPublicTag"; + SyntaxKind[SyntaxKind["JSDocPrivateTag"] = 328] = "JSDocPrivateTag"; + SyntaxKind[SyntaxKind["JSDocProtectedTag"] = 329] = "JSDocProtectedTag"; + SyntaxKind[SyntaxKind["JSDocReadonlyTag"] = 330] = "JSDocReadonlyTag"; + SyntaxKind[SyntaxKind["JSDocOverrideTag"] = 331] = "JSDocOverrideTag"; + SyntaxKind[SyntaxKind["JSDocCallbackTag"] = 332] = "JSDocCallbackTag"; + SyntaxKind[SyntaxKind["JSDocOverloadTag"] = 333] = "JSDocOverloadTag"; + SyntaxKind[SyntaxKind["JSDocParameterTag"] = 334] = "JSDocParameterTag"; + SyntaxKind[SyntaxKind["JSDocReturnTag"] = 335] = "JSDocReturnTag"; + SyntaxKind[SyntaxKind["JSDocThisTag"] = 336] = "JSDocThisTag"; + SyntaxKind[SyntaxKind["JSDocTypeTag"] = 337] = "JSDocTypeTag"; + SyntaxKind[SyntaxKind["JSDocTemplateTag"] = 338] = "JSDocTemplateTag"; + SyntaxKind[SyntaxKind["JSDocTypedefTag"] = 339] = "JSDocTypedefTag"; + SyntaxKind[SyntaxKind["JSDocSeeTag"] = 340] = "JSDocSeeTag"; + SyntaxKind[SyntaxKind["JSDocPropertyTag"] = 341] = "JSDocPropertyTag"; + SyntaxKind[SyntaxKind["JSDocSatisfiesTag"] = 342] = "JSDocSatisfiesTag"; + SyntaxKind[SyntaxKind["JSDocImportTag"] = 343] = "JSDocImportTag"; + SyntaxKind[SyntaxKind["SyntaxList"] = 344] = "SyntaxList"; + SyntaxKind[SyntaxKind["NotEmittedStatement"] = 345] = "NotEmittedStatement"; + SyntaxKind[SyntaxKind["PartiallyEmittedExpression"] = 346] = "PartiallyEmittedExpression"; + SyntaxKind[SyntaxKind["CommaListExpression"] = 347] = "CommaListExpression"; + SyntaxKind[SyntaxKind["SyntheticReferenceExpression"] = 348] = "SyntheticReferenceExpression"; + SyntaxKind[SyntaxKind["Count"] = 349] = "Count"; +})(SyntaxKind || (SyntaxKind = {})); diff --git a/_packages/ast/src/tokenFlags.enum.ts b/_packages/ast/src/tokenFlags.enum.ts new file mode 100644 index 0000000000..1e5160421c --- /dev/null +++ b/_packages/ast/src/tokenFlags.enum.ts @@ -0,0 +1,26 @@ +// dprint-ignore +export const enum TokenFlags { + None = 0, + PrecedingLineBreak = 1 << 0, + PrecedingJSDocComment = 1 << 1, + Unterminated = 1 << 2, + ExtendedUnicodeEscape = 1 << 3, // e.g. `\u{10ffff}` + Scientific = 1 << 4, // e.g. `10e2` + Octal = 1 << 5, // e.g. `0777` + HexSpecifier = 1 << 6, // e.g. `0x00000000` + BinarySpecifier = 1 << 7, // e.g. `0b0110010000000000` + OctalSpecifier = 1 << 8, // e.g. `0o777` + ContainsSeparator = 1 << 9, // e.g. `0b1100_0101` + UnicodeEscape = 1 << 10, // e.g. `\u00a0` + ContainsInvalidEscape = 1 << 11, // e.g. `\uhello` + HexEscape = 1 << 12, // e.g. `\xa0` + ContainsLeadingZero = 1 << 13, // e.g. `0888` + ContainsInvalidSeparator = 1 << 14, // e.g. `0_1` + PrecedingJSDocLeadingAsterisks = 1 << 15, + BinaryOrOctalSpecifier = BinarySpecifier | OctalSpecifier, + WithSpecifier = HexSpecifier | BinaryOrOctalSpecifier, + StringLiteralFlags = HexEscape | UnicodeEscape | ExtendedUnicodeEscape | ContainsInvalidEscape, + NumericLiteralFlags = Scientific | Octal | ContainsLeadingZero | WithSpecifier | ContainsSeparator | ContainsInvalidSeparator, + TemplateLiteralLikeFlags = HexEscape | UnicodeEscape | ExtendedUnicodeEscape | ContainsInvalidEscape, + IsInvalid = Octal | ContainsLeadingZero | ContainsInvalidSeparator | ContainsInvalidEscape, +} diff --git a/_packages/ast/src/tokenFlags.ts b/_packages/ast/src/tokenFlags.ts new file mode 100644 index 0000000000..4b0a8cd272 --- /dev/null +++ b/_packages/ast/src/tokenFlags.ts @@ -0,0 +1,27 @@ +// dprint-ignore +export var TokenFlags: any; +(function (TokenFlags) { + TokenFlags[TokenFlags["None"] = 0] = "None"; + TokenFlags[TokenFlags["PrecedingLineBreak"] = 1] = "PrecedingLineBreak"; + TokenFlags[TokenFlags["PrecedingJSDocComment"] = 2] = "PrecedingJSDocComment"; + TokenFlags[TokenFlags["Unterminated"] = 4] = "Unterminated"; + TokenFlags[TokenFlags["ExtendedUnicodeEscape"] = 8] = "ExtendedUnicodeEscape"; + TokenFlags[TokenFlags["Scientific"] = 16] = "Scientific"; + TokenFlags[TokenFlags["Octal"] = 32] = "Octal"; + TokenFlags[TokenFlags["HexSpecifier"] = 64] = "HexSpecifier"; + TokenFlags[TokenFlags["BinarySpecifier"] = 128] = "BinarySpecifier"; + TokenFlags[TokenFlags["OctalSpecifier"] = 256] = "OctalSpecifier"; + TokenFlags[TokenFlags["ContainsSeparator"] = 512] = "ContainsSeparator"; + TokenFlags[TokenFlags["UnicodeEscape"] = 1024] = "UnicodeEscape"; + TokenFlags[TokenFlags["ContainsInvalidEscape"] = 2048] = "ContainsInvalidEscape"; + TokenFlags[TokenFlags["HexEscape"] = 4096] = "HexEscape"; + TokenFlags[TokenFlags["ContainsLeadingZero"] = 8192] = "ContainsLeadingZero"; + TokenFlags[TokenFlags["ContainsInvalidSeparator"] = 16384] = "ContainsInvalidSeparator"; + TokenFlags[TokenFlags["PrecedingJSDocLeadingAsterisks"] = 32768] = "PrecedingJSDocLeadingAsterisks"; + TokenFlags[TokenFlags["BinaryOrOctalSpecifier"] = 384] = "BinaryOrOctalSpecifier"; + TokenFlags[TokenFlags["WithSpecifier"] = 448] = "WithSpecifier"; + TokenFlags[TokenFlags["StringLiteralFlags"] = 7176] = "StringLiteralFlags"; + TokenFlags[TokenFlags["NumericLiteralFlags"] = 25584] = "NumericLiteralFlags"; + TokenFlags[TokenFlags["TemplateLiteralLikeFlags"] = 7176] = "TemplateLiteralLikeFlags"; + TokenFlags[TokenFlags["IsInvalid"] = 26656] = "IsInvalid"; +})(TokenFlags || (TokenFlags = {})); diff --git a/_packages/ast/src/utils.ts b/_packages/ast/src/utils.ts new file mode 100644 index 0000000000..0b77d02fb6 --- /dev/null +++ b/_packages/ast/src/utils.ts @@ -0,0 +1,9 @@ +export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined { + return value !== undefined && test(value) ? value : undefined; +} + +export function cast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut { + if (value !== undefined && test(value)) return value; + + throw new Error(`Invalid cast. The supplied value ${value} did not pass the test '${test.name}'.`); +} diff --git a/_packages/ast/tsconfig.json b/_packages/ast/tsconfig.json new file mode 100644 index 0000000000..5be4954833 --- /dev/null +++ b/_packages/ast/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "node16", + "strict": true, + "composite": true, + "forceConsistentCasingInFileNames": true, + "rewriteRelativeImportExtensions": true, + "verbatimModuleSyntax": true, + "isolatedDeclarations": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src"] +} diff --git a/_submodules/TypeScript b/_submodules/TypeScript index 52c59dbcbe..0693cc72e6 160000 --- a/_submodules/TypeScript +++ b/_submodules/TypeScript @@ -1 +1 @@ -Subproject commit 52c59dbcbee274e523ef39e6c8be1bd5e110c2f1 +Subproject commit 0693cc72e6ddb6c7468a14e05888efa2f43ac7b0 diff --git a/_tools/customlint/emptycase.go b/_tools/customlint/emptycase.go index 7f646002a1..a6c060a809 100644 --- a/_tools/customlint/emptycase.go +++ b/_tools/customlint/emptycase.go @@ -19,7 +19,7 @@ var emptyCaseAnalyzer = &analysis.Analyzer{ }, } -func runEmptyCase(pass *analysis.Pass) (interface{}, error) { +func runEmptyCase(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ diff --git a/cmd/tsgo/api.go b/cmd/tsgo/api.go new file mode 100644 index 0000000000..702ce143a2 --- /dev/null +++ b/cmd/tsgo/api.go @@ -0,0 +1,38 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "io" + "os" + + "github.com/microsoft/typescript-go/internal/api" + "github.com/microsoft/typescript-go/internal/bundled" + "github.com/microsoft/typescript-go/internal/core" +) + +func runAPI(args []string) int { + flag := flag.NewFlagSet("api", flag.ContinueOnError) + cwd := flag.String("cwd", core.Must(os.Getwd()), "current working directory") + if err := flag.Parse(args); err != nil { + return 2 + } + + defaultLibraryPath := bundled.LibPath() + + s := api.NewServer(&api.ServerOptions{ + In: os.Stdin, + Out: os.Stdout, + Err: os.Stderr, + Cwd: *cwd, + NewLine: "\n", + DefaultLibraryPath: defaultLibraryPath, + }) + + if err := s.Run(); err != nil && !errors.Is(err, io.EOF) { + fmt.Println(err) + return 1 + } + return 0 +} diff --git a/cmd/tsgo/enablevtprocessing_windows.go b/cmd/tsgo/enablevtprocessing_windows.go index d7197595db..a71f5b9388 100644 --- a/cmd/tsgo/enablevtprocessing_windows.go +++ b/cmd/tsgo/enablevtprocessing_windows.go @@ -5,12 +5,18 @@ import ( ) func enableVirtualTerminalProcessing() { - hStdout, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) - if err == nil && hStdout != windows.InvalidHandle { + h, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) + if err != nil || h == windows.InvalidHandle { + return + } + fileType, err := windows.GetFileType(h) + if err != nil || fileType == windows.FILE_TYPE_CHAR { var mode uint32 - err = windows.GetConsoleMode(windows.Handle(hStdout), &mode) - if err == nil { - windows.SetConsoleMode(windows.Handle(hStdout), mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) + if err := windows.GetConsoleMode(h, &mode); err != nil { + return + } + if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { + _ = windows.SetConsoleMode(h, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) } } } diff --git a/cmd/tsgo/lsp.go b/cmd/tsgo/lsp.go index 3c44466dc0..cdc8d6e9ed 100644 --- a/cmd/tsgo/lsp.go +++ b/cmd/tsgo/lsp.go @@ -10,12 +10,14 @@ import ( "github.com/microsoft/typescript-go/internal/bundled" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/lsp" + "github.com/microsoft/typescript-go/internal/pprof" "github.com/microsoft/typescript-go/internal/vfs/osvfs" ) func runLSP(args []string) int { flag := flag.NewFlagSet("lsp", flag.ContinueOnError) stdio := flag.Bool("stdio", false, "use stdio for communication") + pprofDir := flag.String("pprofDir", "", "Generate pprof CPU/memory profiles to the given directory.") pipe := flag.String("pipe", "", "use named pipe for communication") _ = pipe socket := flag.String("socket", "", "use socket for communication") @@ -29,6 +31,12 @@ func runLSP(args []string) int { return 1 } + if *pprofDir != "" { + fmt.Fprintf(os.Stderr, "pprof profiles will be written to: %v\n", *pprofDir) + profileSession := pprof.BeginProfiling(*pprofDir, os.Stderr) + defer profileSession.Stop() + } + fs := bundled.WrapFS(osvfs.FS()) defaultLibraryPath := bundled.LibPath() diff --git a/cmd/tsgo/main.go b/cmd/tsgo/main.go index 8f910f85bc..1dfac1881b 100644 --- a/cmd/tsgo/main.go +++ b/cmd/tsgo/main.go @@ -6,9 +6,8 @@ import ( "flag" "fmt" "os" - "path/filepath" "runtime" - "runtime/pprof" + "runtime/debug" "slices" "strconv" "strings" @@ -16,11 +15,12 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/bundled" - ts "github.com/microsoft/typescript-go/internal/compiler" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" + "github.com/microsoft/typescript-go/internal/compiler" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/diagnosticwriter" "github.com/microsoft/typescript-go/internal/execute" + "github.com/microsoft/typescript-go/internal/pprof" "github.com/microsoft/typescript-go/internal/scanner" "github.com/microsoft/typescript-go/internal/tspath" "github.com/microsoft/typescript-go/internal/vfs/osvfs" @@ -60,6 +60,7 @@ type cliOptions struct { listFiles tristateFlag listFilesOnly tristateFlag showConfig tristateFlag + version bool } devel struct { @@ -104,6 +105,7 @@ func parseArgs() *cliOptions { flag.Var(&opts.tsc.listFiles, "listFiles", diagnostics.Print_all_of_the_files_read_during_the_compilation.Format()) flag.Var(&opts.tsc.listFilesOnly, "listFilesOnly", diagnostics.Print_names_of_files_that_are_part_of_the_compilation_and_then_stop_processing.Format()) flag.Var(&opts.tsc.showConfig, "showConfig", diagnostics.Print_the_final_configuration_instead_of_building.Format()) + flag.BoolVar(&opts.tsc.version, "version", false, diagnostics.Print_the_compiler_s_version.Format()) flag.BoolVar(&opts.devel.quiet, "q", false, "Do not print diagnostics.") flag.BoolVar(&opts.devel.quiet, "quiet", false, "Do not print diagnostics.") @@ -121,22 +123,43 @@ func parseArgs() *cliOptions { } func main() { + os.Exit(runMain()) +} + +func runMain() int { // TypeScript uses ANSI escape sequences which cmd.exe won't parse without enabling virtual terminal processing. enableVirtualTerminalProcessing() if args := os.Args[1:]; len(args) > 0 { switch args[0] { case "tsc": - os.Exit(int(execute.CommandLine(newSystem(), nil, args[1:]))) + return int(execute.CommandLine(newSystem(), nil, args[1:])) case "lsp": - os.Exit(runLSP(args[1:])) + return runLSP(args[1:]) + case "api": + return runAPI(args[1:]) } } opts := parseArgs() if opts.devel.pprofDir != "" { - profileSession := beginProfiling(opts.devel.pprofDir) - defer profileSession.stop() + profileSession := pprof.BeginProfiling(opts.devel.pprofDir, os.Stdout) + defer profileSession.Stop() + } + + if opts.tsc.version { + // Get build info to extract the commit SHA + buildInfo, _ := debug.ReadBuildInfo() + version := core.Version + for _, setting := range buildInfo.Settings { + if setting.Key == "vcs.revision" { + version += "-" + setting.Value + break + } + } + + fmt.Println(diagnostics.Version_0.Format(version)) + return 0 } startTime := time.Now() @@ -144,7 +167,7 @@ func main() { currentDirectory, err := os.Getwd() if err != nil { fmt.Fprintf(os.Stderr, "Error getting current directory: %v\n", err) - os.Exit(1) + return 1 } fs := bundled.WrapFS(osvfs.FS()) @@ -155,7 +178,7 @@ func main() { configFileName = tspath.CombinePaths(configFileName, "tsconfig.json") if !fs.FileExists(configFileName) { fmt.Fprintf(os.Stderr, "Error: The file %v does not exist.\n", configFileName) - os.Exit(1) + return 1 } } @@ -164,10 +187,10 @@ func main() { currentDirectory = tspath.GetDirectoryPath(configFileName) // !!! is the working directory actually the config path? - host := ts.NewCompilerHost(compilerOptions, currentDirectory, fs, defaultLibraryPath) + host := compiler.NewCachedFSCompilerHost(compilerOptions, currentDirectory, fs, defaultLibraryPath) parseStart := time.Now() - program := ts.NewProgram(ts.ProgramOptions{ + program := compiler.NewProgram(compiler.ProgramOptions{ ConfigFileName: configFileName, Options: compilerOptions, SingleThreaded: opts.devel.singleThreaded, @@ -179,7 +202,7 @@ func main() { if compilerOptions.ListFilesOnly.IsTrue() { listFiles(program) - os.Exit(0) + return 0 } if compilerOptions.ShowConfig.IsTrue() { @@ -187,9 +210,9 @@ func main() { enc.SetIndent("", " ") if err := enc.Encode(compilerOptions); err != nil { fmt.Fprintf(os.Stderr, "Error encoding JSON: %v\n", err) - os.Exit(1) + return 1 } - os.Exit(0) + return 0 } var bindTime, checkTime time.Duration @@ -197,7 +220,7 @@ func main() { diagnostics := program.GetConfigFileParsingDiagnostics() if len(diagnostics) != 0 { printDiagnostics(diagnostics, host, compilerOptions) - os.Exit(1) + return 1 } diagnostics = program.GetSyntacticDiagnostics(nil) @@ -221,7 +244,7 @@ func main() { var emitTime time.Duration if compilerOptions.NoEmit.IsFalseOrUnknown() { emitStart := time.Now() - result := program.Emit(&ts.EmitOptions{}) + result := program.Emit(compiler.EmitOptions{}) diagnostics = append(diagnostics, result.Diagnostics...) emitTime = time.Since(emitStart) } @@ -234,19 +257,16 @@ func main() { runtime.GC() runtime.ReadMemStats(&memStats) - if !opts.devel.quiet && len(diagnostics) != 0 { - printDiagnostics(ts.SortAndDeduplicateDiagnostics(diagnostics), host, compilerOptions) - } - - var unsupportedExtensions []string - for _, file := range program.SourceFiles() { - extension := tspath.TryGetExtensionFromPath(file.FileName()) - if extension == tspath.ExtensionTsx || slices.Contains(tspath.SupportedJSExtensionsFlat, extension) { - unsupportedExtensions = core.AppendIfUnique(unsupportedExtensions, extension) + exitCode := 0 + if len(diagnostics) != 0 { + if !opts.devel.quiet { + printDiagnostics(compiler.SortAndDeduplicateDiagnostics(diagnostics), host, compilerOptions) } + exitCode = 1 } - if len(unsupportedExtensions) != 0 { - fmt.Fprintf(os.Stderr, "Warning: The project contains unsupported file types (%s), which are currently not fully type-checked.\n", strings.Join(unsupportedExtensions, ", ")) + + if exts := program.UnsupportedExtensions(); len(exts) != 0 { + fmt.Fprintf(os.Stderr, "Warning: The project contains unsupported file types (%s), which are currently not fully type-checked.\n", strings.Join(exts, ", ")) } if compilerOptions.ListFiles.IsTrue() { @@ -256,7 +276,13 @@ func main() { var stats table stats.add("Files", len(program.SourceFiles())) + stats.add("Lines", program.LineCount()) + stats.add("Identifiers", program.IdentifierCount()) + stats.add("Symbols", program.SymbolCount()) stats.add("Types", program.TypeCount()) + stats.add("Instantiations", program.InstantiationCount()) + stats.add("Memory used", fmt.Sprintf("%vK", memStats.Alloc/1024)) + stats.add("Memory allocs", strconv.FormatUint(memStats.Mallocs, 10)) stats.add("Parse time", parseTime) if bindTime != 0 { stats.add("Bind time", bindTime) @@ -268,10 +294,10 @@ func main() { stats.add("Emit time", emitTime) } stats.add("Total time", totalTime) - stats.add("Memory used", fmt.Sprintf("%vK", memStats.Alloc/1024)) - stats.add("Memory allocs", strconv.FormatUint(memStats.Mallocs, 10)) stats.print() + + return exitCode } type tableRow struct { @@ -307,13 +333,21 @@ func formatDuration(d time.Duration) string { return fmt.Sprintf("%.3fs", d.Seconds()) } -func listFiles(p *ts.Program) { +func identifierCount(p *compiler.Program) int { + count := 0 + for _, file := range p.SourceFiles() { + count += file.IdentifierCount + } + return count +} + +func listFiles(p *compiler.Program) { for _, file := range p.SourceFiles() { fmt.Println(file.FileName()) } } -func getFormatOpts(host ts.CompilerHost) *diagnosticwriter.FormattingOptions { +func getFormatOpts(host compiler.CompilerHost) *diagnosticwriter.FormattingOptions { return &diagnosticwriter.FormattingOptions{ NewLine: host.NewLine(), ComparePathsOptions: tspath.ComparePathsOptions{ @@ -323,7 +357,7 @@ func getFormatOpts(host ts.CompilerHost) *diagnosticwriter.FormattingOptions { } } -func printDiagnostics(diagnostics []*ast.Diagnostic, host ts.CompilerHost, compilerOptions *core.CompilerOptions) { +func printDiagnostics(diagnostics []*ast.Diagnostic, host compiler.CompilerHost, compilerOptions *core.CompilerOptions) { formatOpts := getFormatOpts(host) if compilerOptions.Pretty.IsTrueOrUnknown() { diagnosticwriter.FormatDiagnosticsWithColorAndContext(os.Stdout, diagnostics, formatOpts) @@ -335,54 +369,3 @@ func printDiagnostics(diagnostics []*ast.Diagnostic, host ts.CompilerHost, compi } } } - -type profileSession struct { - cpuFilePath string - memFilePath string - cpuFile *os.File - memFile *os.File -} - -func beginProfiling(profileDir string) *profileSession { - if err := os.MkdirAll(profileDir, 0o755); err != nil { - panic(err) - } - - pid := os.Getpid() - - cpuProfilePath := filepath.Join(profileDir, fmt.Sprintf("%d-cpuprofile.pb.gz", pid)) - memProfilePath := filepath.Join(profileDir, fmt.Sprintf("%d-memprofile.pb.gz", pid)) - cpuFile, err := os.Create(cpuProfilePath) - if err != nil { - panic(err) - } - memFile, err := os.Create(memProfilePath) - if err != nil { - panic(err) - } - - if err := pprof.StartCPUProfile(cpuFile); err != nil { - panic(err) - } - - return &profileSession{ - cpuFilePath: cpuProfilePath, - memFilePath: memProfilePath, - cpuFile: cpuFile, - memFile: memFile, - } -} - -func (p *profileSession) stop() { - pprof.StopCPUProfile() - err := pprof.Lookup("allocs").WriteTo(p.memFile, 0) - if err != nil { - panic(err) - } - - p.cpuFile.Close() - p.memFile.Close() - - fmt.Printf("CPU profile: %v\n", p.cpuFilePath) - fmt.Printf("Memory profile: %v\n", p.memFilePath) -} diff --git a/go.mod b/go.mod index cc8b9cc3a7..067f388aa4 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,13 @@ require ( ) require ( + github.com/matryer/moq v0.5.3 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/tools v0.30.0 // indirect ) -tool golang.org/x/tools/cmd/stringer +tool ( + github.com/matryer/moq + golang.org/x/tools/cmd/stringer +) diff --git a/go.sum b/go.sum index f925c1a408..1a460f2534 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,12 @@ github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6 github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/matryer/moq v0.5.3 h1:4femQCFmBUwFPYs8VfM5ID7AI67/DTEDRBbTtSWy7GU= +github.com/matryer/moq v0.5.3/go.mod h1:8288Qkw7gMZhUP3cIN86GG7g5p9jRuZH8biXLW4RXvQ= github.com/pkg/diff v0.0.0-20241224192749-4e6772a4315c h1:8TRxBMS/YsupXoOiGKHr9ZOXo+5DezGWPgBAhBHEHto= github.com/pkg/diff v0.0.0-20241224192749-4e6772a4315c/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= diff --git a/internal/api/api.go b/internal/api/api.go new file mode 100644 index 0000000000..6b04c741aa --- /dev/null +++ b/internal/api/api.go @@ -0,0 +1,375 @@ +package api + +import ( + "encoding/json" + "errors" + "fmt" + "sync" + + "github.com/microsoft/typescript-go/internal/api/encoder" + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/astnav" + "github.com/microsoft/typescript-go/internal/checker" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/lsp/lsproto" + "github.com/microsoft/typescript-go/internal/project" + "github.com/microsoft/typescript-go/internal/tsoptions" + "github.com/microsoft/typescript-go/internal/tspath" + "github.com/microsoft/typescript-go/internal/vfs" +) + +type handleMap[T any] map[Handle[T]]*T + +type APIOptions struct { + Logger *project.Logger +} + +type API struct { + host APIHost + options APIOptions + + documentRegistry *project.DocumentRegistry + scriptInfosMu sync.RWMutex + scriptInfos map[tspath.Path]*project.ScriptInfo + + projects handleMap[project.Project] + filesMu sync.Mutex + files handleMap[ast.SourceFile] + symbolsMu sync.Mutex + symbols handleMap[ast.Symbol] + typesMu sync.Mutex + types handleMap[checker.Type] +} + +var _ project.ProjectHost = (*API)(nil) + +func NewAPI(host APIHost, options APIOptions) *API { + api := &API{ + host: host, + options: options, + scriptInfos: make(map[tspath.Path]*project.ScriptInfo), + projects: make(handleMap[project.Project]), + files: make(handleMap[ast.SourceFile]), + symbols: make(handleMap[ast.Symbol]), + types: make(handleMap[checker.Type]), + } + api.documentRegistry = &project.DocumentRegistry{ + Options: tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: host.FS().UseCaseSensitiveFileNames(), + CurrentDirectory: host.GetCurrentDirectory(), + }, + Hooks: project.DocumentRegistryHooks{ + OnReleaseDocument: func(file *ast.SourceFile) { + _ = api.releaseHandle(string(FileHandle(file))) + }, + }, + } + return api +} + +// DefaultLibraryPath implements ProjectHost. +func (api *API) DefaultLibraryPath() string { + return api.host.DefaultLibraryPath() +} + +// DocumentRegistry implements ProjectHost. +func (api *API) DocumentRegistry() *project.DocumentRegistry { + return api.documentRegistry +} + +// FS implements ProjectHost. +func (api *API) FS() vfs.FS { + return api.host.FS() +} + +// GetCurrentDirectory implements ProjectHost. +func (api *API) GetCurrentDirectory() string { + return api.host.GetCurrentDirectory() +} + +// GetOrCreateScriptInfoForFile implements ProjectHost. +func (api *API) GetOrCreateScriptInfoForFile(fileName string, path tspath.Path, scriptKind core.ScriptKind) *project.ScriptInfo { + return api.getOrCreateScriptInfo(fileName, path, scriptKind) +} + +// GetScriptInfoByPath implements ProjectHost. +func (api *API) GetScriptInfoByPath(path tspath.Path) *project.ScriptInfo { + api.scriptInfosMu.RLock() + defer api.scriptInfosMu.RUnlock() + return api.scriptInfos[path] +} + +// OnDiscoveredSymlink implements ProjectHost. +func (api *API) OnDiscoveredSymlink(info *project.ScriptInfo) { + // !!! +} + +// Log implements ProjectHost. +func (api *API) Log(s string) { + api.options.Logger.Info(s) +} + +// NewLine implements ProjectHost. +func (api *API) NewLine() string { + return api.host.NewLine() +} + +// PositionEncoding implements ProjectHost. +func (api *API) PositionEncoding() lsproto.PositionEncodingKind { + return lsproto.PositionEncodingKindUTF8 +} + +func (api *API) HandleRequest(id int, method string, payload []byte) ([]byte, error) { + params, err := unmarshalPayload(method, payload) + if err != nil { + return nil, err + } + + switch Method(method) { + case MethodRelease: + if id, ok := params.(*string); ok { + return nil, api.releaseHandle(*id) + } else { + return nil, fmt.Errorf("expected string for release handle, got %T", params) + } + case MethodGetSourceFile: + params := params.(*GetSourceFileParams) + sourceFile, err := api.GetSourceFile(params.Project, params.FileName) + if err != nil { + return nil, err + } + return encoder.EncodeSourceFile(sourceFile, string(FileHandle(sourceFile))) + case MethodParseConfigFile: + return encodeJSON(api.ParseConfigFile(params.(*ParseConfigFileParams).FileName)) + case MethodLoadProject: + return encodeJSON(api.LoadProject(params.(*LoadProjectParams).ConfigFileName)) + case MethodGetSymbolAtPosition: + params := params.(*GetSymbolAtPositionParams) + return encodeJSON(api.GetSymbolAtPosition(params.Project, params.FileName, int(params.Position))) + case MethodGetSymbolsAtPositions: + params := params.(*GetSymbolsAtPositionsParams) + return encodeJSON(core.TryMap(params.Positions, func(position uint32) (any, error) { + return api.GetSymbolAtPosition(params.Project, params.FileName, int(position)) + })) + case MethodGetSymbolAtLocation: + params := params.(*GetSymbolAtLocationParams) + return encodeJSON(api.GetSymbolAtLocation(params.Project, params.Location)) + case MethodGetSymbolsAtLocations: + params := params.(*GetSymbolsAtLocationsParams) + return encodeJSON(core.TryMap(params.Locations, func(location Handle[ast.Node]) (any, error) { + return api.GetSymbolAtLocation(params.Project, location) + })) + case MethodGetTypeOfSymbol: + params := params.(*GetTypeOfSymbolParams) + return encodeJSON(api.GetTypeOfSymbol(params.Project, params.Symbol)) + case MethodGetTypesOfSymbols: + params := params.(*GetTypesOfSymbolsParams) + return encodeJSON(core.TryMap(params.Symbols, func(symbol Handle[ast.Symbol]) (any, error) { + return api.GetTypeOfSymbol(params.Project, symbol) + })) + default: + return nil, fmt.Errorf("unhandled API method %q", method) + } +} + +func (api *API) Close() { + api.options.Logger.Close() +} + +func (api *API) ParseConfigFile(configFileName string) (*ConfigFileResponse, error) { + configFileName = api.toAbsoluteFileName(configFileName) + configFileContent, ok := api.host.FS().ReadFile(configFileName) + if !ok { + return nil, fmt.Errorf("could not read file %q", configFileName) + } + configDir := tspath.GetDirectoryPath(configFileName) + tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(configFileName, api.toPath(configFileName), configFileContent) + parsedCommandLine := tsoptions.ParseJsonSourceFileConfigFileContent( + tsConfigSourceFile, + api.host, + configDir, + nil, /*existingOptions*/ + configFileName, + nil, /*resolutionStack*/ + nil, /*extraFileExtensions*/ + nil, /*extendedConfigCache*/ + ) + return &ConfigFileResponse{ + FileNames: parsedCommandLine.FileNames(), + Options: parsedCommandLine.CompilerOptions(), + }, nil +} + +func (api *API) LoadProject(configFileName string) (*ProjectResponse, error) { + configFileName = api.toAbsoluteFileName(configFileName) + configFilePath := api.toPath(configFileName) + p := project.NewConfiguredProject(configFileName, configFilePath, api) + if err := p.LoadConfig(); err != nil { + return nil, err + } + p.GetProgram() + data := NewProjectResponse(p) + api.projects[data.Id] = p + return data, nil +} + +func (api *API) GetSymbolAtPosition(projectId Handle[project.Project], fileName string, position int) (*SymbolResponse, error) { + project, ok := api.projects[projectId] + if !ok { + return nil, errors.New("project not found") + } + symbol, err := project.LanguageService().GetSymbolAtPosition(fileName, position) + if err != nil || symbol == nil { + return nil, err + } + data := NewSymbolResponse(symbol) + api.symbolsMu.Lock() + defer api.symbolsMu.Unlock() + api.symbols[data.Id] = symbol + return data, nil +} + +func (api *API) GetSymbolAtLocation(projectId Handle[project.Project], location Handle[ast.Node]) (*SymbolResponse, error) { + project, ok := api.projects[projectId] + if !ok { + return nil, errors.New("project not found") + } + fileHandle, pos, kind, err := parseNodeHandle(location) + if err != nil { + return nil, err + } + api.filesMu.Lock() + defer api.filesMu.Unlock() + sourceFile, ok := api.files[fileHandle] + if !ok { + return nil, fmt.Errorf("file %q not found", fileHandle) + } + token := astnav.GetTokenAtPosition(sourceFile, pos) + if token == nil { + return nil, fmt.Errorf("token not found at position %d in file %q", pos, sourceFile.FileName()) + } + node := ast.FindAncestorKind(token, kind) + if node == nil { + return nil, fmt.Errorf("node of kind %s not found at position %d in file %q", kind.String(), pos, sourceFile.FileName()) + } + symbol := project.LanguageService().GetSymbolAtLocation(node) + if symbol == nil { + return nil, nil + } + data := NewSymbolResponse(symbol) + api.symbolsMu.Lock() + defer api.symbolsMu.Unlock() + api.symbols[data.Id] = symbol + return data, nil +} + +func (api *API) GetTypeOfSymbol(projectId Handle[project.Project], symbolHandle Handle[ast.Symbol]) (*TypeResponse, error) { + project, ok := api.projects[projectId] + if !ok { + return nil, errors.New("project not found") + } + api.symbolsMu.Lock() + defer api.symbolsMu.Unlock() + symbol, ok := api.symbols[symbolHandle] + if !ok { + return nil, fmt.Errorf("symbol %q not found", symbolHandle) + } + t := project.LanguageService().GetTypeOfSymbol(symbol) + if t == nil { + return nil, nil + } + return NewTypeData(t), nil +} + +func (api *API) GetSourceFile(projectId Handle[project.Project], fileName string) (*ast.SourceFile, error) { + project, ok := api.projects[projectId] + if !ok { + return nil, errors.New("project not found") + } + sourceFile := project.GetProgram().GetSourceFile(fileName) + if sourceFile == nil { + return nil, fmt.Errorf("source file %q not found", fileName) + } + api.filesMu.Lock() + defer api.filesMu.Unlock() + api.files[FileHandle(sourceFile)] = sourceFile + return sourceFile, nil +} + +func (api *API) releaseHandle(handle string) error { + switch handle[0] { + case handlePrefixProject: + projectId := Handle[project.Project](handle) + project, ok := api.projects[projectId] + if !ok { + return fmt.Errorf("project %q not found", handle) + } + delete(api.projects, projectId) + project.Close() + case handlePrefixFile: + fileId := Handle[ast.SourceFile](handle) + api.filesMu.Lock() + defer api.filesMu.Unlock() + _, ok := api.files[fileId] + if !ok { + return fmt.Errorf("file %q not found", handle) + } + delete(api.files, fileId) + case handlePrefixSymbol: + symbolId := Handle[ast.Symbol](handle) + api.symbolsMu.Lock() + defer api.symbolsMu.Unlock() + _, ok := api.symbols[symbolId] + if !ok { + return fmt.Errorf("symbol %q not found", handle) + } + delete(api.symbols, symbolId) + case handlePrefixType: + typeId := Handle[checker.Type](handle) + api.typesMu.Lock() + defer api.typesMu.Unlock() + _, ok := api.types[typeId] + if !ok { + return fmt.Errorf("type %q not found", handle) + } + delete(api.types, typeId) + default: + return fmt.Errorf("unhandled handle type %q", handle[0]) + } + return nil +} + +func (api *API) getOrCreateScriptInfo(fileName string, path tspath.Path, scriptKind core.ScriptKind) *project.ScriptInfo { + api.scriptInfosMu.RLock() + info, ok := api.scriptInfos[path] + api.scriptInfosMu.RUnlock() + if ok { + return info + } + + content, ok := api.host.FS().ReadFile(fileName) + if !ok { + return nil + } + info = project.NewScriptInfo(fileName, path, scriptKind) + info.SetTextFromDisk(content) + api.scriptInfosMu.Lock() + defer api.scriptInfosMu.Unlock() + api.scriptInfos[path] = info + return info +} + +func (api *API) toAbsoluteFileName(fileName string) string { + return tspath.GetNormalizedAbsolutePath(fileName, api.host.GetCurrentDirectory()) +} + +func (api *API) toPath(fileName string) tspath.Path { + return tspath.ToPath(fileName, api.host.GetCurrentDirectory(), api.host.FS().UseCaseSensitiveFileNames()) +} + +func encodeJSON(v any, err error) ([]byte, error) { + if err != nil { + return nil, err + } + return json.Marshal(v) +} diff --git a/internal/api/encoder/encoder.go b/internal/api/encoder/encoder.go new file mode 100644 index 0000000000..5a1502eba3 --- /dev/null +++ b/internal/api/encoder/encoder.go @@ -0,0 +1,824 @@ +package encoder + +import ( + "encoding/binary" + "fmt" + "slices" + + "github.com/microsoft/typescript-go/internal/ast" +) + +const ( + NodeOffsetKind = iota * 4 + NodeOffsetPos + NodeOffsetEnd + NodeOffsetNext + NodeOffsetParent + NodeOffsetData + // NodeSize is the number of bytes that represents a single node in the encoded format. + NodeSize +) + +const ( + NodeDataTypeChildren uint32 = iota << 30 + NodeDataTypeString + NodeDataTypeExtendedData +) + +const ( + NodeDataTypeMask uint32 = 0xc0_00_00_00 + NodeDataChildMask uint32 = 0x00_00_00_ff + NodeDataStringIndexMask uint32 = 0x00_ff_ff_ff +) + +const ( + SyntaxKindNodeList uint32 = 1<<32 - 1 +) + +const ( + HeaderOffsetMetadata = iota * 4 + HeaderOffsetStringOffsets + HeaderOffsetStringData + HeaderOffsetExtendedData + HeaderOffsetNodes + HeaderSize +) + +const ( + ProtocolVersion uint8 = 1 +) + +// Source File Binary Format +// ========================= +// +// The following defines a protocol for serializing TypeScript SourceFile objects to a compact binary format. All integer +// values are little-endian. +// +// Overview +// -------- +// +// The format comprises six sections: +// +// | Section | Length | Description | +// | ------------------ | ------------------ | ---------------------------------------------------------------------------------------- | +// | Header | 20 bytes | Contains byte offsets to the start of each section. | +// | String offsets | 8 bytes per string | Pairs of starting byte offsets and ending byte offsets into the **string data** section. | +// | String data | variable | UTF-8 encoded string data. | +// | Extended node data | variable | Extra data for some kinds of nodes. | +// | Nodes | 24 bytes per node | Defines the AST structure of the file, with references to strings and extended data. | +// +// Header (20 bytes) +// ----------------- +// +// The header contains the following fields: +// +// | Byte offset | Type | Field | +// | ----------- | ------ | ----------------------------------------- | +// | 0 | uint8 | Protocol version | +// | 1-4 | | Reserved | +// | 4-8 | uint32 | Byte offset to string offsets section | +// | 8-12 | uint32 | Byte offset to string data section | +// | 12-16 | uint32 | Byte offset to extended node data section | +// | 16-20 | uint32 | Byte offset to nodes section | +// +// String offsets (8 bytes per string) +// ----------------------------------- +// +// Each string offset entry consists of two 4-byte unsigned integers, representing the start and end byte offsets into the +// **string data** section. +// +// String data (variable) +// ---------------------- +// +// The string data section contains UTF-8 encoded string data. In typical cases, the entirety of the string data is the +// source file text, and individual nodes with string properties reference their positional slice of the file text. In +// cases where a node's string property is not equal to the slice of file text at its position, the unique string is +// appended to the string data section after the file text. +// +// Extended node data (variable) +// ----------------------------- +// +// The extended node data section contains additional data for specific node types. The length and meaning of each entry +// is defined by the node type. +// +// Currently, the only node types that use this section are `TemplateHead`, `TemplateMiddle`, `TemplateTail`, and +// `SourceFile`. The extended data format for the first three is: +// +// | Byte offset | Type | Field | +// | ----------- | ------ | ------------------------------------------------ | +// | 0-4 | uint32 | Index of `text` in the string offsets section | +// | 4-8 | uint32 | Index of `rawText` in the string offsets section | +// | 8-12 | uint32 | Value of `templateFlags` | +// +// and for `SourceFile` is: +// +// | Byte offset | Type | Field | +// | ----------- | ------ | ------------------------------------------------- | +// | 0-4 | uint32 | Index of `text` in the string offsets section | +// | 4-8 | uint32 | Index of `fileName` in the string offsets section | +// | 8-12 | uint32 | Index of `id` in the string offsets section | +// +// Nodes (24 bytes per node) +// ------------------------- +// +// The nodes section contains the AST structure of the file. Nodes are represented in a flat array in source order, +// heavily inspired by https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-11/. Each node has the following +// structure: +// +// | Byte offset | Type | Field | +// | ----------- | ------ | -------------------------- | +// | 0-4 | uint32 | Kind | +// | 4-8 | uint32 | Pos | +// | 8-12 | uint32 | End | +// | 12-16 | uint32 | Node index of next sibling | +// | 16-20 | uint32 | Node index of parent | +// | 20-24 | | Node data | +// +// The first 24 bytes of the nodes section are zeros representing a nil node, such that nodes without a parent or next +// sibling can unambiuously use `0` for those indices. +// +// NodeLists are represented as normal nodes with the special `kind` value `0xff_ff_ff_ff`. They are considered the parent +// of their contents in the encoded format. A client reconstructing an AST similar to TypeScript's internal representation +// should instead set the `parent` pointers of a NodeList's children to the NodeList's parent. A NodeList's `data` field +// is the uint32 length of the list, and does not use one of the data types described below. +// +// For node types other than NodeList, the node data field encodes one of the following, determined by the first 2 bits of +// the field: +// +// | Value | Data type | Description | +// | ----- | --------- | ------------------------------------------------------------------------------------ | +// | 0b00 | Children | Disambiguates which named properties of the node its children should be assigned to. | +// | 0b01 | String | The index of the node's string property in the **string offsets** section. | +// | 0b10 | Extended | The byte offset of the node's extended data into the **extended node data** section. | +// | 0b11 | Reserved | Reserved for future use. | +// +// In all node data types, the remaining 6 bits of the first byte are used to encode booleans specific to the node type: +// +// | Node type | Bits 2-5 | Bit 1 | Bit 0 | +// | ------------------------- | -------- | ------------- | ------------------------------- | +// | `ImportSpecifier` | | | `isTypeOnly` | +// | `ImportClause` | | | `isTypeOnly` | +// | `ExportSpecifier` | | | `isTypeOnly` | +// | `ImportEqualsDeclaration` | | | `isTypeOnly` | +// | `ExportDeclaration` | | | `isTypeOnly` | +// | `ImportTypeNode` | | | `isTypeOf` | +// | `ExportAssignment` | | | `isExportEquals` | +// | `Block` | | | `multiline` | +// | `ArrayLiteralExpression` | | | `multiline` | +// | `ObjectLiteralExpression` | | | `multiline` | +// | `JsxText` | | | `containsOnlyTriviaWhiteSpaces` | +// | `JSDocTypeLiteral` | | | `isArrayType` | +// | `JsDocPropertyTag` | | `isNameFirst` | `isBracketed` | +// | `JsDocParameterTag` | | `isNameFirst` | `isBracketed` | +// | `VariableDeclarationList` | | is `const` | is `let` | +// | `ImportAttributes` | | is `assert` | `multiline` | +// +// The remaining 3 bytes of the node data field vary by data type: +// +// ### Children (0b00) +// +// If a node has fewer children than its type allows, additional data is needed to determine which properties the children +// correspond to. The last byte of the 4-byte data field is a bitmask representing the child properties of the node type, +// in visitor order, where `1` indicates that the child at that property is present and `0` indicates that the property is +// nil. For example, a `MethodDeclaration` has the following child properties: +// +// | Property name | Bit position | +// | -------------- | ------------ | +// | modifiers | 0 | +// | asteriskToken | 1 | +// | name | 2 | +// | postfixToken | 3 | +// | typeParameters | 4 | +// | parameters | 5 | +// | returnType | 6 | +// | body | 7 | +// +// A bitmask with value `0b01100101` would indicate that the next four direct descendants (i.e., node records that have a +// `parent` set to the node index of the `MethodDeclaration`) of the node are its `modifiers`, `name`, `parameters`, and +// `body` properties, in that order. The remaining properties are nil. (To reconstruct the node with named properties, the +// client must consult a static table of each node type's child property names.) +// +// The bitmask may be zero for node types that can only have a single child, since no disambiguation is needed. +// Additionally, the children data type may be used for nodes that can never have children, but do not require other +// data types. +// +// ### String (0b01) +// +// The string data type is used for nodes with a single string property. (Currently, the name of that property is always +// `text`.) The last three bytes of the 4-byte data field form a single 24-bit unsigned integer (i.e., +// `uint32(0x00_ff_ff_ff & node.data)`) _N_ that is an index into the **string offsets** section. The *N*th 32-bit +// unsigned integer in the **string offsets** section is the byte offset of the start of the string in the **string data** +// section, and the *N+1*th 32-bit unsigned integer is the byte offset of the end of the string in the +// **string data** section. +// +// ### Extended (0b10) +// +// The extended data type is used for nodes with properties that don't fit into either the children or string data types. +// The last three bytes of the 4-byte data field form a single 24-bit unsigned integer (i.e., +// `uint32(0x00_ff_ff_ff & node.data)`) _N_ that is a byte offset into the **extended node data** section. The length and +// meaning of the data at that offset is defined by the node type. See the **Extended node data** section for details on +// the format of the extended data for specific node types. + +func EncodeSourceFile(sourceFile *ast.SourceFile, id string) ([]byte, error) { + var parentIndex, nodeCount, prevIndex uint32 + var extendedData []byte + strs := newStringTable(sourceFile.Text(), sourceFile.TextCount) + nodes := make([]byte, 0, (sourceFile.NodeCount+1)*NodeSize) + + visitor := &ast.NodeVisitor{ + Hooks: ast.NodeVisitorHooks{ + VisitNodes: func(nodeList *ast.NodeList, visitor *ast.NodeVisitor) *ast.NodeList { + if nodeList == nil || len(nodeList.Nodes) == 0 { + return nodeList + } + + nodeCount++ + if prevIndex != 0 { + // this is the next sibling of `prevNode` + b0, b1, b2, b3 := uint8(nodeCount), uint8(nodeCount>>8), uint8(nodeCount>>16), uint8(nodeCount>>24) + nodes[prevIndex*NodeSize+NodeOffsetNext+0] = b0 + nodes[prevIndex*NodeSize+NodeOffsetNext+1] = b1 + nodes[prevIndex*NodeSize+NodeOffsetNext+2] = b2 + nodes[prevIndex*NodeSize+NodeOffsetNext+3] = b3 + } + + nodes = appendUint32s(nodes, SyntaxKindNodeList, uint32(nodeList.Pos()), uint32(nodeList.End()), 0, parentIndex, uint32(len(nodeList.Nodes))) + + saveParentIndex := parentIndex + + currentIndex := nodeCount + prevIndex = 0 + parentIndex = currentIndex + visitor.VisitSlice(nodeList.Nodes) + prevIndex = currentIndex + parentIndex = saveParentIndex + + return nodeList + }, + VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList { + if modifiers != nil && len(modifiers.Nodes) > 0 { + visitor.Hooks.VisitNodes(&modifiers.NodeList, visitor) + } + return modifiers + }, + }, + } + visitor.Visit = func(node *ast.Node) *ast.Node { + nodeCount++ + if prevIndex != 0 { + // this is the next sibling of `prevNode` + b0, b1, b2, b3 := uint8(nodeCount), uint8(nodeCount>>8), uint8(nodeCount>>16), uint8(nodeCount>>24) + nodes[prevIndex*NodeSize+NodeOffsetNext+0] = b0 + nodes[prevIndex*NodeSize+NodeOffsetNext+1] = b1 + nodes[prevIndex*NodeSize+NodeOffsetNext+2] = b2 + nodes[prevIndex*NodeSize+NodeOffsetNext+3] = b3 + } + + nodes = appendUint32s(nodes, uint32(node.Kind), uint32(node.Pos()), uint32(node.End()), 0, parentIndex, getNodeData(node, strs, &extendedData)) + + saveParentIndex := parentIndex + + currentIndex := nodeCount + prevIndex = 0 + parentIndex = currentIndex + visitor.VisitEachChild(node) + prevIndex = currentIndex + parentIndex = saveParentIndex + return node + } + + nodes = appendUint32s(nodes, 0, 0, 0, 0, 0, 0) + + nodeCount++ + parentIndex++ + nodes = appendUint32s(nodes, uint32(sourceFile.Kind), uint32(sourceFile.Pos()), uint32(sourceFile.End()), 0, 0, getSourceFileData(sourceFile, id, strs, &extendedData)) + + visitor.VisitEachChild(sourceFile.AsNode()) + + metadata := uint32(ProtocolVersion) << 24 + offsetStringTableOffsets := HeaderSize + offsetStringTableData := HeaderSize + len(strs.offsets)*4 + offsetExtendedData := offsetStringTableData + strs.stringLength() + offsetNodes := offsetExtendedData + len(extendedData) + + header := []uint32{ + metadata, + uint32(offsetStringTableOffsets), + uint32(offsetStringTableData), + uint32(offsetExtendedData), + uint32(offsetNodes), + } + + var headerBytes, strsBytes []byte + headerBytes = appendUint32s(nil, header...) + strsBytes = strs.encode() + + return slices.Concat( + headerBytes, + strsBytes, + extendedData, + nodes, + ), nil +} + +func appendUint32s(buf []byte, values ...uint32) []byte { + for _, value := range values { + var err error + if buf, err = binary.Append(buf, binary.LittleEndian, value); err != nil { + // The only error binary.Append can return is for values that are not fixed-size. + // This can never happen here, since we are always appending uint32. + panic(fmt.Sprintf("failed to append uint32: %v", err)) + } + } + return buf +} + +func getSourceFileData(sourceFile *ast.SourceFile, id string, strs *stringTable, extendedData *[]byte) uint32 { + t := NodeDataTypeExtendedData + extendedDataOffset := len(*extendedData) + textIndex := strs.add(sourceFile.Text(), sourceFile.Kind, sourceFile.Pos(), sourceFile.End()) + fileNameIndex := strs.add(sourceFile.FileName(), 0, 0, 0) + idIndex := strs.add(id, 0, 0, 0) + *extendedData = appendUint32s(*extendedData, textIndex, fileNameIndex, idIndex) + return t | uint32(extendedDataOffset) +} + +func getNodeData(node *ast.Node, strs *stringTable, extendedData *[]byte) uint32 { + t := getNodeDataType(node) + switch t { + case NodeDataTypeChildren: + return t | getNodeDefinedData(node) | uint32(getChildrenPropertyMask(node)) + case NodeDataTypeString: + return t | getNodeDefinedData(node) | recordNodeStrings(node, strs) + case NodeDataTypeExtendedData: + return t | getNodeDefinedData(node) | recordExtendedData(node, strs, extendedData) + default: + panic("unreachable") + } +} + +func getNodeDataType(node *ast.Node) uint32 { + switch node.Kind { + case ast.KindJsxText, + ast.KindIdentifier, + ast.KindPrivateIdentifier, + ast.KindStringLiteral, + ast.KindNumericLiteral, + ast.KindBigIntLiteral, + ast.KindRegularExpressionLiteral, + ast.KindNoSubstitutionTemplateLiteral, + ast.KindJSDocText: + return NodeDataTypeString + case ast.KindTemplateHead, + ast.KindTemplateMiddle, + ast.KindTemplateTail, + ast.KindSourceFile: + return NodeDataTypeExtendedData + default: + return NodeDataTypeChildren + } +} + +// getChildrenPropertyMask returns a mask of which children properties are present in the node. +// It is defined for node kinds that have more than one property that is a pointer to a child node. +// Example: QualifiedName has two children properties: Left and Right, which are visited in that order. +// result&1 is non-zero if Left is present, and result&2 is non-zero if Right is present. If the client +// knows that QualifiedName has properties ["Left", "Right"] and sees an encoded node with only one +// child, it can use the mask to determine which property is present. +func getChildrenPropertyMask(node *ast.Node) uint8 { + switch node.Kind { + case ast.KindQualifiedName: + n := node.AsQualifiedName() + return (boolToByte(n.Left != nil) << 0) | (boolToByte(n.Right != nil) << 1) + case ast.KindTypeParameter: + n := node.AsTypeParameter() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Constraint != nil) << 2) | (boolToByte(n.DefaultType != nil) << 3) + case ast.KindIfStatement: + n := node.AsIfStatement() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.ThenStatement != nil) << 1) | (boolToByte(n.ElseStatement != nil) << 2) + case ast.KindDoStatement: + n := node.AsDoStatement() + return (boolToByte(n.Statement != nil) << 0) | (boolToByte(n.Expression != nil) << 1) + case ast.KindWhileStatement: + n := node.AsWhileStatement() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statement != nil) << 1) + case ast.KindForStatement: + n := node.AsForStatement() + return (boolToByte(n.Initializer != nil) << 0) | (boolToByte(n.Condition != nil) << 1) | (boolToByte(n.Incrementor != nil) << 2) | (boolToByte(n.Statement != nil) << 3) + case ast.KindForInStatement, ast.KindForOfStatement: + n := node.AsForInOrOfStatement() + return (boolToByte(n.AwaitModifier != nil) << 0) | (boolToByte(n.Initializer != nil) << 1) | (boolToByte(n.Expression != nil) << 2) | (boolToByte(n.Statement != nil) << 3) + case ast.KindWithStatement: + n := node.AsWithStatement() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statement != nil) << 1) + case ast.KindSwitchStatement: + n := node.AsSwitchStatement() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.CaseBlock != nil) << 1) + case ast.KindCaseClause, ast.KindDefaultClause: + n := node.AsCaseOrDefaultClause() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Statements != nil) << 1) + case ast.KindTryStatement: + n := node.AsTryStatement() + return (boolToByte(n.TryBlock != nil) << 0) | (boolToByte(n.CatchClause != nil) << 1) | (boolToByte(n.FinallyBlock != nil) << 2) + case ast.KindCatchClause: + n := node.AsCatchClause() + return (boolToByte(n.VariableDeclaration != nil) << 0) | (boolToByte(n.Block != nil) << 1) + case ast.KindLabeledStatement: + n := node.AsLabeledStatement() + return (boolToByte(n.Label != nil) << 0) | (boolToByte(n.Statement != nil) << 1) + case ast.KindVariableStatement: + n := node.AsVariableStatement() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.DeclarationList != nil) << 1) + case ast.KindVariableDeclaration: + n := node.AsVariableDeclaration() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.ExclamationToken != nil) << 1) | (boolToByte(n.Type != nil) << 2) | (boolToByte(n.Initializer != nil) << 3) + case ast.KindParameter: + n := node.AsParameterDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.DotDotDotToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.QuestionToken != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Initializer != nil) << 5) + case ast.KindBindingElement: + n := node.AsBindingElement() + return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.PropertyName != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Initializer != nil) << 3) + case ast.KindFunctionDeclaration: + n := node.AsFunctionDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5) | (boolToByte(n.Body != nil) << 6) + case ast.KindInterfaceDeclaration: + n := node.AsInterfaceDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.HeritageClauses != nil) << 3) | (boolToByte(n.Members != nil) << 4) + case ast.KindTypeAliasDeclaration: + n := node.AsTypeAliasDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) + case ast.KindEnumMember: + n := node.AsEnumMember() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Initializer != nil) << 1) + case ast.KindEnumDeclaration: + n := node.AsEnumDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Members != nil) << 2) + case ast.KindModuleDeclaration: + n := node.AsModuleDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.Body != nil) << 2) + case ast.KindImportEqualsDeclaration: + n := node.AsImportEqualsDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.ModuleReference != nil) << 2) + case ast.KindImportDeclaration: + n := node.AsImportDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.ImportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3) + case ast.KindImportSpecifier: + n := node.AsImportSpecifier() + return (boolToByte(n.PropertyName != nil) << 0) | (boolToByte(n.Name() != nil) << 1) + case ast.KindImportClause: + n := node.AsImportClause() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.NamedBindings != nil) << 1) + case ast.KindExportAssignment: + n := node.AsExportAssignment() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Expression != nil) << 1) + case ast.KindNamespaceExportDeclaration: + n := node.AsNamespaceExportDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) + case ast.KindExportDeclaration: + n := node.AsExportDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.ExportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3) + case ast.KindExportSpecifier: + n := node.AsExportSpecifier() + return (boolToByte(n.PropertyName != nil) << 0) | (boolToByte(n.Name() != nil) << 1) + case ast.KindCallSignature: + n := node.AsCallSignatureDeclaration() + return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindConstructSignature: + n := node.AsConstructSignatureDeclaration() + return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindConstructor: + n := node.AsConstructorDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Body != nil) << 4) + case ast.KindGetAccessor: + n := node.AsGetAccessorDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Parameters != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Body != nil) << 5) + case ast.KindSetAccessor: + n := node.AsSetAccessorDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.Parameters != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Body != nil) << 5) + case ast.KindIndexSignature: + n := node.AsIndexSignatureDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindMethodSignature: + n := node.AsMethodSignatureDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5) + case ast.KindMethodDeclaration: + n := node.AsMethodDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.PostfixToken != nil) << 3) | (boolToByte(n.TypeParameters != nil) << 4) | (boolToByte(n.Parameters != nil) << 5) | (boolToByte(n.Type != nil) << 6) | (boolToByte(n.Body != nil) << 7) + case ast.KindPropertySignature: + n := node.AsPropertySignatureDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Initializer != nil) << 4) + case ast.KindPropertyDeclaration: + n := node.AsPropertyDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.Initializer != nil) << 4) + case ast.KindBinaryExpression: + n := node.AsBinaryExpression() + return (boolToByte(n.Left != nil) << 0) | (boolToByte(n.OperatorToken != nil) << 1) | (boolToByte(n.Right != nil) << 2) + case ast.KindYieldExpression: + n := node.AsYieldExpression() + return (boolToByte(n.AsteriskToken != nil) << 0) | (boolToByte(n.Expression != nil) << 1) + case ast.KindArrowFunction: + n := node.AsArrowFunction() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) | (boolToByte(n.EqualsGreaterThanToken != nil) << 4) | (boolToByte(n.Body != nil) << 5) + case ast.KindFunctionExpression: + n := node.AsFunctionExpression() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.AsteriskToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.TypeParameters != nil) << 3) | (boolToByte(n.Parameters != nil) << 4) | (boolToByte(n.Type != nil) << 5) | (boolToByte(n.Body != nil) << 6) + case ast.KindAsExpression: + n := node.AsAsExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Type != nil) << 1) + case ast.KindSatisfiesExpression: + n := node.AsSatisfiesExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Type != nil) << 1) + case ast.KindConditionalExpression: + n := node.AsConditionalExpression() + return (boolToByte(n.Condition != nil) << 0) | (boolToByte(n.QuestionToken != nil) << 1) | (boolToByte(n.WhenTrue != nil) << 2) | (boolToByte(n.ColonToken != nil) << 3) | (boolToByte(n.WhenFalse != nil) << 4) + case ast.KindPropertyAccessExpression: + n := node.AsPropertyAccessExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.Name() != nil) << 2) + case ast.KindElementAccessExpression: + n := node.AsElementAccessExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.ArgumentExpression != nil) << 2) + case ast.KindCallExpression: + n := node.AsCallExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.TypeArguments != nil) << 2) | (boolToByte(n.Arguments != nil) << 3) + case ast.KindNewExpression: + n := node.AsNewExpression() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Arguments != nil) << 2) + case ast.KindTemplateExpression: + n := node.AsTemplateExpression() + return (boolToByte(n.Head != nil) << 0) | (boolToByte(n.TemplateSpans != nil) << 1) + case ast.KindTemplateSpan: + n := node.AsTemplateSpan() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.Literal != nil) << 1) + case ast.KindTaggedTemplateExpression: + n := node.AsTaggedTemplateExpression() + return (boolToByte(n.Tag != nil) << 0) | (boolToByte(n.QuestionDotToken != nil) << 1) | (boolToByte(n.TypeArguments != nil) << 2) | (boolToByte(n.Template != nil) << 3) + case ast.KindPropertyAssignment: + n := node.AsPropertyAssignment() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.Initializer != nil) << 3) + case ast.KindShorthandPropertyAssignment: + n := node.AsShorthandPropertyAssignment() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.PostfixToken != nil) << 2) | (boolToByte(n.EqualsToken != nil) << 3) | (boolToByte(n.ObjectAssignmentInitializer != nil) << 4) + case ast.KindTypeAssertionExpression: + n := node.AsTypeAssertion() + return (boolToByte(n.Type != nil) << 0) | (boolToByte(n.Expression != nil) << 1) + case ast.KindConditionalType: + n := node.AsConditionalTypeNode() + return (boolToByte(n.CheckType != nil) << 0) | (boolToByte(n.ExtendsType != nil) << 1) | (boolToByte(n.TrueType != nil) << 2) | (boolToByte(n.FalseType != nil) << 3) + case ast.KindIndexedAccessType: + n := node.AsIndexedAccessTypeNode() + return (boolToByte(n.ObjectType != nil) << 0) | (boolToByte(n.IndexType != nil) << 1) + case ast.KindTypeReference: + n := node.AsTypeReferenceNode() + return (boolToByte(n.TypeName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) + case ast.KindExpressionWithTypeArguments: + n := node.AsExpressionWithTypeArguments() + return (boolToByte(n.Expression != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) + case ast.KindTypePredicate: + n := node.AsTypePredicateNode() + return (boolToByte(n.AssertsModifier != nil) << 0) | (boolToByte(n.ParameterName != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindImportType: + n := node.AsImportTypeNode() + return (boolToByte(n.Argument != nil) << 0) | (boolToByte(n.Attributes != nil) << 1) | (boolToByte(n.Qualifier != nil) << 2) | (boolToByte(n.TypeArguments != nil) << 3) + case ast.KindImportAttribute: + n := node.AsImportAttribute() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Value != nil) << 1) + case ast.KindTypeQuery: + n := node.AsTypeQueryNode() + return (boolToByte(n.ExprName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) + case ast.KindMappedType: + n := node.AsMappedTypeNode() + return (boolToByte(n.ReadonlyToken != nil) << 0) | (boolToByte(n.TypeParameter != nil) << 1) | (boolToByte(n.NameType != nil) << 2) | (boolToByte(n.QuestionToken != nil) << 3) | (boolToByte(n.Type != nil) << 4) | (boolToByte(n.Members != nil) << 5) + case ast.KindNamedTupleMember: + n := node.AsNamedTupleMember() + return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.QuestionToken != nil) << 2) | (boolToByte(n.Type != nil) << 3) + case ast.KindFunctionType: + n := node.AsFunctionTypeNode() + return (boolToByte(n.TypeParameters != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindConstructorType: + n := node.AsConstructorTypeNode() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.TypeParameters != nil) << 1) | (boolToByte(n.Parameters != nil) << 2) | (boolToByte(n.Type != nil) << 3) + case ast.KindTemplateLiteralType: + n := node.AsTemplateLiteralTypeNode() + return (boolToByte(n.Head != nil) << 0) | (boolToByte(n.TemplateSpans != nil) << 1) + case ast.KindTemplateLiteralTypeSpan: + n := node.AsTemplateLiteralTypeSpan() + return (boolToByte(n.Type != nil) << 0) | (boolToByte(n.Literal != nil) << 1) + case ast.KindJsxElement: + n := node.AsJsxElement() + return (boolToByte(n.OpeningElement != nil) << 0) | (boolToByte(n.Children != nil) << 1) | (boolToByte(n.ClosingElement != nil) << 2) + case ast.KindJsxNamespacedName: + n := node.AsJsxNamespacedName() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Namespace != nil) << 1) + case ast.KindJsxOpeningElement: + n := node.AsJsxOpeningElement() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Attributes != nil) << 2) + case ast.KindJsxSelfClosingElement: + n := node.AsJsxSelfClosingElement() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeArguments != nil) << 1) | (boolToByte(n.Attributes != nil) << 2) + case ast.KindJsxFragment: + n := node.AsJsxFragment() + return (boolToByte(n.OpeningFragment != nil) << 0) | (boolToByte(n.Children != nil) << 1) | (boolToByte(n.ClosingFragment != nil) << 2) + case ast.KindJsxAttribute: + n := node.AsJsxAttribute() + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.Initializer != nil) << 1) + case ast.KindJsxExpression: + n := node.AsJsxExpression() + return (boolToByte(n.DotDotDotToken != nil) << 0) | (boolToByte(n.Expression != nil) << 1) + case ast.KindJSDoc: + n := node.AsJSDoc() + return (boolToByte(n.Comment != nil) << 0) | (boolToByte(n.Tags != nil) << 1) + case ast.KindJSDocTypeTag: + n := node.AsJSDocTypeTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocTag: + n := node.AsJSDocUnknownTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocTemplateTag: + n := node.AsJSDocTemplateTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Constraint != nil) << 1) | (boolToByte(n.TypeParameters() != nil) << 2) | (boolToByte(n.Comment != nil) << 3) + case ast.KindJSDocReturnTag: + n := node.AsJSDocReturnTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocPublicTag: + n := node.AsJSDocPublicTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocPrivateTag: + n := node.AsJSDocPrivateTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocProtectedTag: + n := node.AsJSDocProtectedTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocReadonlyTag: + n := node.AsJSDocReadonlyTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocOverrideTag: + n := node.AsJSDocOverrideTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocDeprecatedTag: + n := node.AsJSDocDeprecatedTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Comment != nil) << 1) + case ast.KindJSDocSeeTag: + n := node.AsJSDocSeeTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.NameExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocImplementsTag: + n := node.AsJSDocImplementsTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ClassName != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocAugmentsTag: + n := node.AsJSDocAugmentsTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ClassName != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocSatisfiesTag: + n := node.AsJSDocSatisfiesTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocThisTag: + n := node.AsJSDocThisTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocImportTag: + n := node.AsJSDocImportTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.ImportClause != nil) << 1) | (boolToByte(n.ModuleSpecifier != nil) << 2) | (boolToByte(n.Attributes != nil) << 3) | (boolToByte(n.Comment != nil) << 4) + case ast.KindJSDocCallbackTag: + n := node.AsJSDocCallbackTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.FullName != nil) << 2) | (boolToByte(n.Comment != nil) << 3) + case ast.KindJSDocOverloadTag: + n := node.AsJSDocOverloadTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Comment != nil) << 2) + case ast.KindJSDocTypedefTag: + n := node.AsJSDocTypedefTag() + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Comment != nil) << 3) + case ast.KindJSDocSignature: + n := node.AsJSDocSignature() + return (boolToByte(n.TypeParameters() != nil) << 0) | (boolToByte(n.Parameters != nil) << 1) | (boolToByte(n.Type != nil) << 2) + case ast.KindClassStaticBlockDeclaration: + n := node.AsClassStaticBlockDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Body != nil) << 1) + case ast.KindClassDeclaration: + n := node.AsClassDeclaration() + return (boolToByte(n.Modifiers() != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeParameters != nil) << 2) | (boolToByte(n.HeritageClauses != nil) << 3) | (boolToByte(n.Members != nil) << 4) + case ast.KindJSDocPropertyTag: + n := node.AsJSDocPropertyTag() + if n.IsNameFirst { + return (boolToByte(n.Name() != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) + } + return (boolToByte(n.TypeExpression != nil) << 0) | (boolToByte(n.Name() != nil) << 1) + case ast.KindJSDocParameterTag: + n := node.AsJSDocParameterTag() + if n.IsNameFirst { + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.Name() != nil) << 1) | (boolToByte(n.TypeExpression != nil) << 2) | (boolToByte(n.Comment != nil) << 3) + } + return (boolToByte(n.TagName != nil) << 0) | (boolToByte(n.TypeExpression != nil) << 1) | (boolToByte(n.Name() != nil) << 2) | (boolToByte(n.Comment != nil) << 3) + default: + return 0 + } +} + +func getNodeDefinedData(node *ast.Node) uint32 { + switch node.Kind { + case ast.KindJSDocTypeLiteral: + n := node.AsJSDocTypeLiteral() + return uint32(boolToByte(n.IsArrayType)) << 24 + case ast.KindImportSpecifier: + n := node.AsImportSpecifier() + return uint32(boolToByte(n.IsTypeOnly)) << 24 + case ast.KindImportClause: + n := node.AsImportClause() + return uint32(boolToByte(n.IsTypeOnly)) << 24 + case ast.KindExportSpecifier: + n := node.AsExportSpecifier() + return uint32(boolToByte(n.IsTypeOnly)) << 24 + case ast.KindImportType: + n := node.AsImportTypeNode() + return uint32(boolToByte(n.IsTypeOf)) << 24 + case ast.KindImportEqualsDeclaration: + n := node.AsImportEqualsDeclaration() + return uint32(boolToByte(n.IsTypeOnly)) << 24 + case ast.KindExportAssignment: + n := node.AsExportAssignment() + return uint32(boolToByte(n.IsExportEquals)) << 24 + case ast.KindExportDeclaration: + n := node.AsExportDeclaration() + return uint32(boolToByte(n.IsTypeOnly)) << 24 + case ast.KindBlock: + n := node.AsBlock() + return uint32(boolToByte(n.Multiline)) << 24 + case ast.KindArrayLiteralExpression: + n := node.AsArrayLiteralExpression() + return uint32(boolToByte(n.MultiLine)) << 24 + case ast.KindObjectLiteralExpression: + n := node.AsObjectLiteralExpression() + return uint32(boolToByte(n.MultiLine)) << 24 + case ast.KindJSDocPropertyTag: + n := node.AsJSDocPropertyTag() + return uint32(boolToByte(n.IsBracketed))<<24 | uint32(boolToByte(n.IsNameFirst))<<25 + case ast.KindJSDocParameterTag: + n := node.AsJSDocParameterTag() + return uint32(boolToByte(n.IsBracketed))<<24 | uint32(boolToByte(n.IsNameFirst))<<25 + case ast.KindJsxText: + n := node.AsJsxText() + return uint32(boolToByte(n.ContainsOnlyTriviaWhiteSpaces)) << 24 + case ast.KindVariableDeclarationList: + n := node.AsVariableDeclarationList() + return uint32(n.Flags & (ast.NodeFlagsLet | ast.NodeFlagsConst) << 24) + case ast.KindImportAttributes: + n := node.AsImportAttributes() + return uint32(boolToByte(n.MultiLine))<<24 | uint32(boolToByte(n.Token == ast.KindAssertKeyword))<<25 + } + return 0 +} + +func recordNodeStrings(node *ast.Node, strs *stringTable) uint32 { + switch node.Kind { + case ast.KindJsxText: + return strs.add(node.AsJsxText().Text, node.Kind, node.Pos(), node.End()) + case ast.KindIdentifier: + return strs.add(node.AsIdentifier().Text, node.Kind, node.Pos(), node.End()) + case ast.KindPrivateIdentifier: + return strs.add(node.AsPrivateIdentifier().Text, node.Kind, node.Pos(), node.End()) + case ast.KindStringLiteral: + return strs.add(node.AsStringLiteral().Text, node.Kind, node.Pos(), node.End()) + case ast.KindNumericLiteral: + return strs.add(node.AsNumericLiteral().Text, node.Kind, node.Pos(), node.End()) + case ast.KindBigIntLiteral: + return strs.add(node.AsBigIntLiteral().Text, node.Kind, node.Pos(), node.End()) + case ast.KindRegularExpressionLiteral: + return strs.add(node.AsRegularExpressionLiteral().Text, node.Kind, node.Pos(), node.End()) + case ast.KindNoSubstitutionTemplateLiteral: + return strs.add(node.AsNoSubstitutionTemplateLiteral().Text, node.Kind, node.Pos(), node.End()) + case ast.KindJSDocText: + return strs.add(node.AsJSDocText().Text, node.Kind, node.Pos(), node.End()) + default: + panic(fmt.Sprintf("Unexpected node kind %v", node.Kind)) + } +} + +func recordExtendedData(node *ast.Node, strs *stringTable, extendedData *[]byte) uint32 { + offset := uint32(len(*extendedData)) + var text, rawText string + var templateFlags uint32 + switch node.Kind { + case ast.KindTemplateTail: + n := node.AsTemplateTail() + text = n.Text + rawText = n.RawText + templateFlags = uint32(n.TemplateFlags) + case ast.KindTemplateMiddle: + n := node.AsTemplateMiddle() + text = n.Text + rawText = n.RawText + templateFlags = uint32(n.TemplateFlags) + case ast.KindTemplateHead: + n := node.AsTemplateHead() + text = n.Text + rawText = n.RawText + templateFlags = uint32(n.TemplateFlags) + } + textIndex := strs.add(text, node.Kind, node.Pos(), node.End()) + rawTextIndex := strs.add(rawText, node.Kind, node.Pos(), node.End()) + *extendedData = appendUint32s(*extendedData, textIndex, rawTextIndex, templateFlags) + return offset +} + +func boolToByte(b bool) byte { + if b { + return 1 + } + return 0 +} diff --git a/internal/api/encoder/encoder_test.go b/internal/api/encoder/encoder_test.go new file mode 100644 index 0000000000..ce616dfc26 --- /dev/null +++ b/internal/api/encoder/encoder_test.go @@ -0,0 +1,95 @@ +package encoder_test + +import ( + "encoding/binary" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/microsoft/typescript-go/internal/api/encoder" + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/parser" + "github.com/microsoft/typescript-go/internal/repo" + "github.com/microsoft/typescript-go/internal/scanner" + "github.com/microsoft/typescript-go/internal/testutil/baseline" + "gotest.tools/v3/assert" +) + +func TestEncodeSourceFile(t *testing.T) { + t.Parallel() + sourceFile := parser.ParseSourceFile("/test.ts", "/test.ts", "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", core.ScriptTargetESNext, scanner.JSDocParsingModeParseAll) + t.Run("baseline", func(t *testing.T) { + t.Parallel() + buf, err := encoder.EncodeSourceFile(sourceFile, "") + assert.NilError(t, err) + + str := formatEncodedSourceFile(buf) + baseline.Run(t, "encodeSourceFile.txt", str, baseline.Options{ + Subfolder: "api", + }) + }) +} + +func BenchmarkEncodeSourceFile(b *testing.B) { + repo.SkipIfNoTypeScriptSubmodule(b) + filePath := filepath.Join(repo.TypeScriptSubmodulePath, "src/compiler/checker.ts") + fileContent, err := os.ReadFile(filePath) + assert.NilError(b, err) + sourceFile := parser.ParseSourceFile( + "/checker.ts", + "/checker.ts", + string(fileContent), + core.ScriptTargetESNext, + scanner.JSDocParsingModeParseAll, + ) + + for b.Loop() { + _, err := encoder.EncodeSourceFile(sourceFile, "") + assert.NilError(b, err) + } +} + +func readUint32(buf []byte, offset int) uint32 { + return binary.LittleEndian.Uint32(buf[offset : offset+4]) +} + +func formatEncodedSourceFile(encoded []byte) string { + var result strings.Builder + var getIndent func(parentIndex uint32) string + offsetNodes := readUint32(encoded, encoder.HeaderOffsetNodes) + offsetStringOffsets := readUint32(encoded, encoder.HeaderOffsetStringOffsets) + offsetStrings := readUint32(encoded, encoder.HeaderOffsetStringData) + getIndent = func(parentIndex uint32) string { + if parentIndex == 0 { + return "" + } + return " " + getIndent(readUint32(encoded, int(offsetNodes)+int(parentIndex)*encoder.NodeSize+encoder.NodeOffsetParent)) + } + j := 1 + for i := int(offsetNodes) + encoder.NodeSize; i < len(encoded); i += encoder.NodeSize { + kind := readUint32(encoded, i+encoder.NodeOffsetKind) + pos := readUint32(encoded, i+encoder.NodeOffsetPos) + end := readUint32(encoded, i+encoder.NodeOffsetEnd) + parentIndex := readUint32(encoded, i+encoder.NodeOffsetParent) + result.WriteString(getIndent(parentIndex)) + if kind == encoder.SyntaxKindNodeList { + result.WriteString("NodeList") + } else { + result.WriteString(ast.Kind(kind).String()) + } + if ast.Kind(kind) == ast.KindIdentifier || ast.Kind(kind) == ast.KindStringLiteral { + stringIndex := readUint32(encoded, i+encoder.NodeOffsetData) & encoder.NodeDataStringIndexMask + strStart := readUint32(encoded, int(offsetStringOffsets+stringIndex*4)) + strEnd := readUint32(encoded, int(offsetStringOffsets+stringIndex*4)+4) + str := string(encoded[offsetStrings+strStart : offsetStrings+strEnd]) + result.WriteString(fmt.Sprintf(" \"%s\"", str)) + } + fmt.Fprintf(&result, " [%d, %d), i=%d, next=%d", pos, end, j, encoded[i+encoder.NodeOffsetNext]) + result.WriteString("\n") + j++ + } + return result.String() +} diff --git a/internal/api/encoder/stringtable.go b/internal/api/encoder/stringtable.go new file mode 100644 index 0000000000..098015d87a --- /dev/null +++ b/internal/api/encoder/stringtable.go @@ -0,0 +1,68 @@ +package encoder + +import ( + "strings" + + "github.com/microsoft/typescript-go/internal/ast" +) + +type stringTable struct { + fileText string + otherStrings *strings.Builder + // offsets are pos/end pairs + offsets []uint32 +} + +func newStringTable(fileText string, stringCount int) *stringTable { + builder := &strings.Builder{} + return &stringTable{ + fileText: fileText, + otherStrings: builder, + offsets: make([]uint32, 0, stringCount*2), + } +} + +func (t *stringTable) add(text string, kind ast.Kind, pos int, end int) uint32 { + index := uint32(len(t.offsets)) + if kind == ast.KindSourceFile { + t.offsets = append(t.offsets, uint32(pos), uint32(end)) + return index + } + length := len(text) + if end-pos > 0 { + // pos includes leading trivia, but we can usually infer the actual start of the + // string from the kind and end + endOffset := 0 + if kind == ast.KindStringLiteral || kind == ast.KindTemplateTail || kind == ast.KindNoSubstitutionTemplateLiteral { + endOffset = 1 + } + end = end - endOffset + start := end - length + fileSlice := t.fileText[start:end] + if fileSlice == text { + t.offsets = append(t.offsets, uint32(start), uint32(end)) + return index + } + } + // no exact match, so we need to add it to the string table + offset := len(t.fileText) + t.otherStrings.Len() + t.otherStrings.WriteString(text) + t.offsets = append(t.offsets, uint32(offset), uint32(offset+length)) + return index +} + +func (t *stringTable) encode() []byte { + result := make([]byte, 0, t.encodedLength()) + result = appendUint32s(result, t.offsets...) + result = append(result, t.fileText...) + result = append(result, t.otherStrings.String()...) + return result +} + +func (t *stringTable) stringLength() int { + return len(t.fileText) + t.otherStrings.Len() +} + +func (t *stringTable) encodedLength() int { + return len(t.offsets)*4 + len(t.fileText) + t.otherStrings.Len() +} diff --git a/internal/api/host.go b/internal/api/host.go new file mode 100644 index 0000000000..83d45a8c60 --- /dev/null +++ b/internal/api/host.go @@ -0,0 +1,10 @@ +package api + +import "github.com/microsoft/typescript-go/internal/vfs" + +type APIHost interface { + FS() vfs.FS + DefaultLibraryPath() string + GetCurrentDirectory() string + NewLine() string +} diff --git a/internal/api/proto.go b/internal/api/proto.go new file mode 100644 index 0000000000..e50684783f --- /dev/null +++ b/internal/api/proto.go @@ -0,0 +1,217 @@ +package api + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/checker" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/project" +) + +var ( + ErrInvalidRequest = errors.New("api: invalid request") + ErrClientError = errors.New("api: client error") +) + +type Method string + +type Handle[T any] string + +const ( + handlePrefixProject = 'p' + handlePrefixSymbol = 's' + handlePrefixType = 't' + handlePrefixFile = 'f' + handlePrefixNode = 'n' +) + +func ProjectHandle(p *project.Project) Handle[project.Project] { + return createHandle[project.Project](handlePrefixProject, p.Name()) +} + +func SymbolHandle(symbol *ast.Symbol) Handle[ast.Symbol] { + return createHandle[ast.Symbol](handlePrefixSymbol, ast.GetSymbolId(symbol)) +} + +func TypeHandle(t *checker.Type) Handle[checker.Type] { + return createHandle[checker.Type](handlePrefixType, t.Id()) +} + +func FileHandle(file *ast.SourceFile) Handle[ast.SourceFile] { + return createHandle[ast.SourceFile](handlePrefixFile, ast.GetNodeId(file.AsNode())) +} + +func NodeHandle(node *ast.Node) Handle[ast.Node] { + fileHandle := FileHandle(ast.GetSourceFileOfNode(node)) + return Handle[ast.Node](fmt.Sprintf("%s.%d.%d", fileHandle, node.Pos(), node.Kind)) +} + +func parseNodeHandle(handle Handle[ast.Node]) (Handle[ast.SourceFile], int, ast.Kind, error) { + parts := strings.SplitN(string(handle), ".", 3) + if len(parts) != 3 { + return "", 0, 0, fmt.Errorf("invalid node handle %q", handle) + } + + fileHandle := Handle[ast.SourceFile](parts[0]) + pos, err := strconv.ParseInt(parts[1], 10, 32) + if err != nil { + return "", 0, 0, fmt.Errorf("invalid node handle %q: %w", handle, err) + } + kind, err := strconv.ParseInt(parts[2], 10, 16) + if err != nil { + return "", 0, 0, fmt.Errorf("invalid node handle %q: %w", handle, err) + } + return fileHandle, int(pos), ast.Kind(kind), nil +} + +func createHandle[T any](prefix rune, id any) Handle[T] { + return Handle[T](fmt.Sprintf("%c%016x", prefix, id)) +} + +const ( + MethodConfigure Method = "configure" + MethodRelease Method = "release" + + MethodParseConfigFile Method = "parseConfigFile" + MethodLoadProject Method = "loadProject" + MethodGetSymbolAtPosition Method = "getSymbolAtPosition" + MethodGetSymbolsAtPositions Method = "getSymbolsAtPositions" + MethodGetSymbolAtLocation Method = "getSymbolAtLocation" + MethodGetSymbolsAtLocations Method = "getSymbolsAtLocations" + MethodGetTypeOfSymbol Method = "getTypeOfSymbol" + MethodGetTypesOfSymbols Method = "getTypesOfSymbols" + MethodGetSourceFile Method = "getSourceFile" +) + +var unmarshalers = map[Method]func([]byte) (any, error){ + MethodRelease: unmarshallerFor[string], + MethodParseConfigFile: unmarshallerFor[ParseConfigFileParams], + MethodLoadProject: unmarshallerFor[LoadProjectParams], + MethodGetSourceFile: unmarshallerFor[GetSourceFileParams], + MethodGetSymbolAtPosition: unmarshallerFor[GetSymbolAtPositionParams], + MethodGetSymbolsAtPositions: unmarshallerFor[GetSymbolsAtPositionsParams], + MethodGetSymbolAtLocation: unmarshallerFor[GetSymbolAtLocationParams], + MethodGetSymbolsAtLocations: unmarshallerFor[GetSymbolsAtLocationsParams], + MethodGetTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams], + MethodGetTypesOfSymbols: unmarshallerFor[GetTypesOfSymbolsParams], +} + +type ConfigureParams struct { + Callbacks []string `json:"callbacks"` + LogFile string `json:"logFile"` +} + +type ParseConfigFileParams struct { + FileName string `json:"fileName"` +} + +type ConfigFileResponse struct { + FileNames []string `json:"fileNames"` + Options *core.CompilerOptions `json:"options"` +} + +type LoadProjectParams struct { + ConfigFileName string `json:"configFileName"` +} + +type ProjectResponse struct { + Id Handle[project.Project] `json:"id"` + ConfigFileName string `json:"configFileName"` + RootFiles []string `json:"rootFiles"` + CompilerOptions *core.CompilerOptions `json:"compilerOptions"` +} + +func NewProjectResponse(project *project.Project) *ProjectResponse { + return &ProjectResponse{ + Id: ProjectHandle(project), + ConfigFileName: project.Name(), + RootFiles: project.GetRootFileNames(), + CompilerOptions: project.GetCompilerOptions(), + } +} + +type GetSymbolAtPositionParams struct { + Project Handle[project.Project] `json:"project"` + FileName string `json:"fileName"` + Position uint32 `json:"position"` +} + +type GetSymbolsAtPositionsParams struct { + Project Handle[project.Project] `json:"project"` + FileName string `json:"fileName"` + Positions []uint32 `json:"positions"` +} + +type GetSymbolAtLocationParams struct { + Project Handle[project.Project] `json:"project"` + Location Handle[ast.Node] `json:"location"` +} + +type GetSymbolsAtLocationsParams struct { + Project Handle[project.Project] `json:"project"` + Locations []Handle[ast.Node] `json:"locations"` +} + +type SymbolResponse struct { + Id Handle[ast.Symbol] `json:"id"` + Name string `json:"name"` + Flags uint32 `json:"flags"` + CheckFlags uint32 `json:"checkFlags"` +} + +func NewSymbolResponse(symbol *ast.Symbol) *SymbolResponse { + return &SymbolResponse{ + Id: SymbolHandle(symbol), + Name: symbol.Name, + Flags: uint32(symbol.Flags), + CheckFlags: uint32(symbol.CheckFlags), + } +} + +type GetTypeOfSymbolParams struct { + Project Handle[project.Project] `json:"project"` + Symbol Handle[ast.Symbol] `json:"symbol"` +} + +type GetTypesOfSymbolsParams struct { + Project Handle[project.Project] `json:"project"` + Symbols []Handle[ast.Symbol] `json:"symbols"` +} + +type TypeResponse struct { + Id Handle[checker.Type] `json:"id"` + Flags uint32 `json:"flags"` +} + +func NewTypeData(t *checker.Type) *TypeResponse { + return &TypeResponse{ + Id: TypeHandle(t), + Flags: uint32(t.Flags()), + } +} + +type GetSourceFileParams struct { + Project Handle[project.Project] `json:"project"` + FileName string `json:"fileName"` +} + +func unmarshalPayload(method string, payload json.RawMessage) (any, error) { + unmarshaler, ok := unmarshalers[Method(method)] + if !ok { + return nil, fmt.Errorf("unknown API method %q", method) + } + return unmarshaler(payload) +} + +func unmarshallerFor[T any](data []byte) (any, error) { + var v T + if err := json.Unmarshal(data, &v); err != nil { + return nil, fmt.Errorf("failed to unmarshal %T: %w", (*T)(nil), err) + } + return &v, nil +} diff --git a/internal/api/server.go b/internal/api/server.go new file mode 100644 index 0000000000..2b60dd855a --- /dev/null +++ b/internal/api/server.go @@ -0,0 +1,477 @@ +package api + +import ( + "bufio" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "sync" + + "github.com/microsoft/typescript-go/internal/bundled" + "github.com/microsoft/typescript-go/internal/project" + "github.com/microsoft/typescript-go/internal/vfs" + "github.com/microsoft/typescript-go/internal/vfs/osvfs" +) + +//go:generate go tool golang.org/x/tools/cmd/stringer -type=MessageType -output=stringer_generated.go + +type MessageType uint8 + +const ( + MessageTypeUnknown MessageType = iota + MessageTypeRequest + MessageTypeCallResponse + MessageTypeCallError + MessageTypeResponse + MessageTypeError + MessageTypeCall +) + +func (m MessageType) IsValid() bool { + return m >= MessageTypeRequest && m <= MessageTypeCall +} + +type MessagePackType uint8 + +const ( + MessagePackTypeFixedArray3 MessagePackType = 0x93 + MessagePackTypeBin8 MessagePackType = 0xC4 + MessagePackTypeBin16 MessagePackType = 0xC5 + MessagePackTypeBin32 MessagePackType = 0xC6 + MessagePackTypeU8 MessagePackType = 0xCC +) + +type Callback int + +const ( + CallbackDirectoryExists Callback = 1 << iota + CallbackFileExists + CallbackGetAccessibleEntries + CallbackReadFile + CallbackRealpath +) + +type ServerOptions struct { + In io.Reader + Out io.Writer + Err io.Writer + Cwd string + NewLine string + DefaultLibraryPath string +} + +var ( + _ APIHost = (*Server)(nil) + _ vfs.FS = (*Server)(nil) +) + +type Server struct { + r *bufio.Reader + w *bufio.Writer + stderr io.Writer + + cwd string + newLine string + fs vfs.FS + defaultLibraryPath string + + callbackMu sync.Mutex + enabledCallbacks Callback + logger *project.Logger + api *API + + requestId int +} + +func NewServer(options *ServerOptions) *Server { + if options.Cwd == "" { + panic("Cwd is required") + } + + server := &Server{ + r: bufio.NewReader(options.In), + w: bufio.NewWriter(options.Out), + stderr: options.Err, + cwd: options.Cwd, + newLine: options.NewLine, + fs: bundled.WrapFS(osvfs.FS()), + defaultLibraryPath: options.DefaultLibraryPath, + } + logger := project.NewLogger([]io.Writer{options.Err}, "", project.LogLevelVerbose) + api := NewAPI(server, APIOptions{ + Logger: logger, + }) + server.logger = logger + server.api = api + return server +} + +// DefaultLibraryPath implements APIHost. +func (s *Server) DefaultLibraryPath() string { + return s.defaultLibraryPath +} + +// FS implements APIHost. +func (s *Server) FS() vfs.FS { + return s +} + +// GetCurrentDirectory implements APIHost. +func (s *Server) GetCurrentDirectory() string { + return s.cwd +} + +// NewLine implements APIHost. +func (s *Server) NewLine() string { + return s.newLine +} + +func (s *Server) Run() error { + for { + messageType, method, payload, err := s.readRequest("") + if err != nil { + return err + } + + switch messageType { + case MessageTypeRequest: + result, err := s.handleRequest(method, payload) + + if err != nil { + if err := s.sendError(method, err); err != nil { + return err + } + } else { + if err := s.sendResponse(method, result); err != nil { + return err + } + } + default: + return fmt.Errorf("%w: expected request, received: %s", ErrInvalidRequest, messageType.String()) + } + } +} + +func (s *Server) readRequest(expectedMethod string) (messageType MessageType, method string, payload []byte, err error) { + t, err := s.r.ReadByte() + if err != nil { + return messageType, method, payload, err + } + if MessagePackType(t) != MessagePackTypeFixedArray3 { + return messageType, method, payload, fmt.Errorf("%w: expected message to be encoded as fixed 3-element array (0x93), received: 0x%2x", ErrInvalidRequest, t) + } + t, err = s.r.ReadByte() + if err != nil { + return messageType, method, payload, err + } + if MessagePackType(t) != MessagePackTypeU8 { + return messageType, method, payload, fmt.Errorf("%w: expected first element of message tuple to be encoded as unsigned 8-bit int (0xcc), received: 0x%2x", ErrInvalidRequest, t) + } + rawMessageType, err := s.r.ReadByte() + if err != nil { + return messageType, method, payload, err + } + messageType = MessageType(rawMessageType) + if !messageType.IsValid() { + return messageType, method, payload, fmt.Errorf("%w: unknown message type: %d", ErrInvalidRequest, messageType) + } + rawMethod, err := s.readBin() + if err != nil { + return messageType, method, payload, err + } + method = string(rawMethod) + if expectedMethod != "" && method != expectedMethod { + return messageType, method, payload, fmt.Errorf("%w: expected method %q, received %q", ErrInvalidRequest, expectedMethod, method) + } + payload, err = s.readBin() + return messageType, method, payload, err +} + +func (s *Server) readBin() ([]byte, error) { + // https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family + t, err := s.r.ReadByte() + if err != nil { + return nil, err + } + var size uint + switch MessagePackType(t) { + case MessagePackTypeBin8: + var size8 uint8 + if err = binary.Read(s.r, binary.BigEndian, &size8); err != nil { + return nil, err + } + size = uint(size8) + case MessagePackTypeBin16: + var size16 uint16 + if err = binary.Read(s.r, binary.BigEndian, &size16); err != nil { + return nil, err + } + size = uint(size16) + case MessagePackTypeBin32: + var size32 uint32 + if err = binary.Read(s.r, binary.BigEndian, &size32); err != nil { + return nil, err + } + size = uint(size32) + default: + return nil, fmt.Errorf("%w: expected binary data length (0xc4-0xc6), received: 0x%2x", ErrInvalidRequest, t) + } + payload := make([]byte, size) + bytesRead, err := io.ReadFull(s.r, payload) + if err != nil { + return nil, err + } + if bytesRead != int(size) { + return nil, fmt.Errorf("%w: expected %d bytes, read %d", ErrInvalidRequest, size, bytesRead) + } + return payload, nil +} + +func (s *Server) enableCallback(callback string) error { + switch callback { + case "directoryExists": + s.enabledCallbacks |= CallbackDirectoryExists + case "fileExists": + s.enabledCallbacks |= CallbackFileExists + case "getAccessibleEntries": + s.enabledCallbacks |= CallbackGetAccessibleEntries + case "readFile": + s.enabledCallbacks |= CallbackReadFile + case "realpath": + s.enabledCallbacks |= CallbackRealpath + default: + return fmt.Errorf("unknown callback: %s", callback) + } + return nil +} + +func (s *Server) handleRequest(method string, payload []byte) ([]byte, error) { + s.requestId++ + switch method { + case "configure": + return nil, s.handleConfigure(payload) + case "echo": + return payload, nil + default: + return s.api.HandleRequest(s.requestId, method, payload) + } +} + +func (s *Server) handleConfigure(payload []byte) error { + var params *ConfigureParams + if err := json.Unmarshal(payload, ¶ms); err != nil { + return fmt.Errorf("%w: %w", ErrInvalidRequest, err) + } + for _, callback := range params.Callbacks { + if err := s.enableCallback(callback); err != nil { + return err + } + } + if params.LogFile != "" { + s.logger.SetFile(params.LogFile) + } else { + s.logger.SetFile("") + } + return nil +} + +func (s *Server) sendResponse(method string, result []byte) error { + return s.writeMessage(MessageTypeResponse, method, result) +} + +func (s *Server) sendError(method string, err error) error { + return s.writeMessage(MessageTypeError, method, []byte(err.Error())) +} + +func (s *Server) writeMessage(messageType MessageType, method string, payload []byte) error { + if err := s.w.WriteByte(byte(MessagePackTypeFixedArray3)); err != nil { + return err + } + if err := s.w.WriteByte(byte(MessagePackTypeU8)); err != nil { + return err + } + if err := s.w.WriteByte(byte(messageType)); err != nil { + return err + } + if err := s.writeBin([]byte(method)); err != nil { + return err + } + if err := s.writeBin(payload); err != nil { + return err + } + return s.w.Flush() +} + +func (s *Server) writeBin(payload []byte) error { + length := len(payload) + if length < 256 { + if err := s.w.WriteByte(byte(MessagePackTypeBin8)); err != nil { + return err + } + if err := s.w.WriteByte(byte(length)); err != nil { + return err + } + } else if length < 1<<16 { + if err := s.w.WriteByte(byte(MessagePackTypeBin16)); err != nil { + return err + } + if err := binary.Write(s.w, binary.BigEndian, uint16(length)); err != nil { + return err + } + } else { + if err := s.w.WriteByte(byte(MessagePackTypeBin32)); err != nil { + return err + } + if err := binary.Write(s.w, binary.BigEndian, uint32(length)); err != nil { + return err + } + } + _, err := s.w.Write(payload) + return err +} + +func (s *Server) call(method string, payload any) ([]byte, error) { + s.callbackMu.Lock() + defer s.callbackMu.Unlock() + jsonPayload, err := json.Marshal(payload) + if err != nil { + return nil, err + } + if err = s.writeMessage(MessageTypeCall, method, jsonPayload); err != nil { + return nil, err + } + + messageType, _, responsePayload, err := s.readRequest(method) + if err != nil { + return nil, err + } + + if messageType != MessageTypeCallResponse && messageType != MessageTypeCallError { + return nil, fmt.Errorf("%w: expected call-response or call-error, received: %s", ErrInvalidRequest, messageType.String()) + } + + if messageType == MessageTypeCallError { + return nil, fmt.Errorf("%w: %s", ErrClientError, responsePayload) + } + + return responsePayload, nil +} + +// DirectoryExists implements vfs.FS. +func (s *Server) DirectoryExists(path string) bool { + if s.enabledCallbacks&CallbackDirectoryExists != 0 { + result, err := s.call("directoryExists", path) + if err != nil { + panic(err) + } + if len(result) > 0 { + return string(result) == "true" + } + } + return s.fs.DirectoryExists(path) +} + +// FileExists implements vfs.FS. +func (s *Server) FileExists(path string) bool { + if s.enabledCallbacks&CallbackFileExists != 0 { + result, err := s.call("fileExists", path) + if err != nil { + panic(err) + } + if len(result) > 0 { + return string(result) == "true" + } + } + return s.fs.FileExists(path) +} + +// GetAccessibleEntries implements vfs.FS. +func (s *Server) GetAccessibleEntries(path string) vfs.Entries { + if s.enabledCallbacks&CallbackGetAccessibleEntries != 0 { + result, err := s.call("getAccessibleEntries", path) + if err != nil { + panic(err) + } + if len(result) > 0 { + var rawEntries *struct { + Files []string `json:"files"` + Directories []string `json:"directories"` + } + if err := json.Unmarshal(result, &rawEntries); err != nil { + panic(err) + } + if rawEntries != nil { + return vfs.Entries{ + Files: rawEntries.Files, + Directories: rawEntries.Directories, + } + } + } + } + return s.fs.GetAccessibleEntries(path) +} + +// ReadFile implements vfs.FS. +func (s *Server) ReadFile(path string) (contents string, ok bool) { + if s.enabledCallbacks&CallbackReadFile != 0 { + data, err := s.call("readFile", path) + if err != nil { + panic(err) + } + if string(data) == "null" { + return "", false + } + if len(data) > 0 { + var result string + if err := json.Unmarshal(data, &result); err != nil { + panic(err) + } + return result, true + } + } + return s.fs.ReadFile(path) +} + +// Realpath implements vfs.FS. +func (s *Server) Realpath(path string) string { + if s.enabledCallbacks&CallbackRealpath != 0 { + data, err := s.call("realpath", path) + if err != nil { + panic(err) + } + if len(data) > 0 { + var result string + if err := json.Unmarshal(data, &result); err != nil { + panic(err) + } + return result + } + } + return s.fs.Realpath(path) +} + +// UseCaseSensitiveFileNames implements vfs.FS. +func (s *Server) UseCaseSensitiveFileNames() bool { + return s.fs.UseCaseSensitiveFileNames() +} + +// WriteFile implements vfs.FS. +func (s *Server) WriteFile(path string, data string, writeByteOrderMark bool) error { + return s.fs.WriteFile(path, data, writeByteOrderMark) +} + +// WalkDir implements vfs.FS. +func (s *Server) WalkDir(root string, walkFn vfs.WalkDirFunc) error { + panic("unimplemented") +} + +// Stat implements vfs.FS. +func (s *Server) Stat(path string) vfs.FileInfo { + panic("unimplemented") +} + +// Remove implements vfs.FS. +func (s *Server) Remove(path string) error { + panic("unimplemented") +} diff --git a/internal/api/stringer_generated.go b/internal/api/stringer_generated.go new file mode 100644 index 0000000000..0a740d353b --- /dev/null +++ b/internal/api/stringer_generated.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type=MessageType -output=stringer_generated.go"; DO NOT EDIT. + +package api + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[MessageTypeUnknown-0] + _ = x[MessageTypeRequest-1] + _ = x[MessageTypeCallResponse-2] + _ = x[MessageTypeCallError-3] + _ = x[MessageTypeResponse-4] + _ = x[MessageTypeError-5] + _ = x[MessageTypeCall-6] +} + +const _MessageType_name = "MessageTypeUnknownMessageTypeRequestMessageTypeCallResponseMessageTypeCallErrorMessageTypeResponseMessageTypeErrorMessageTypeCall" + +var _MessageType_index = [...]uint8{0, 18, 36, 59, 79, 98, 114, 129} + +func (i MessageType) String() string { + if i >= MessageType(len(_MessageType_index)-1) { + return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _MessageType_name[_MessageType_index[i]:_MessageType_index[i+1]] +} diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 9acacd6396..67f0afc4e3 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -72,6 +72,9 @@ type NodeFactory struct { variableDeclarationListPool core.Pool[VariableDeclarationList] variableDeclarationPool core.Pool[VariableDeclaration] variableStatementPool core.Pool[VariableStatement] + + nodeCount int + textCount int } type NodeFactoryHooks struct { @@ -80,6 +83,10 @@ type NodeFactoryHooks struct { OnClone func(node *Node, original *Node) // Hooks the cloning of a node. } +type NodeFactoryCoercible interface { + AsNodeFactory() *NodeFactory +} + func NewNodeFactory(hooks NodeFactoryHooks) *NodeFactory { return &NodeFactory{hooks: hooks} } @@ -95,8 +102,26 @@ func newNode(kind Kind, data nodeData, hooks NodeFactoryHooks) *Node { return n } +func (f *NodeFactory) newNode(kind Kind, data nodeData) *Node { + f.nodeCount++ + return newNode(kind, data, f.hooks) +} + +func (f *NodeFactory) NodeCount() int { + return f.nodeCount +} + +func (f *NodeFactory) TextCount() int { + return f.textCount +} + +func (f *NodeFactory) AsNodeFactory() *NodeFactory { + return f +} + func updateNode(updated *Node, original *Node, hooks NodeFactoryHooks) *Node { if updated != original { + updated.Flags = original.Flags updated.Loc = original.Loc if hooks.OnUpdate != nil { hooks.OnUpdate(updated, original) @@ -138,8 +163,8 @@ func (list *NodeList) HasTrailingComma() bool { return !PositionIsSynthesized(last.End()) && last.End() < list.End() } -func (list *NodeList) Clone(f *NodeFactory) *NodeList { - result := f.NewNodeList(list.Nodes) +func (list *NodeList) Clone(f NodeFactoryCoercible) *NodeList { + result := f.AsNodeFactory().NewNodeList(list.Nodes) result.Loc = list.Loc return result } @@ -188,7 +213,7 @@ func (n *Node) AsNode() *Node { return n } func (n *Node) Pos() int { return n.Loc.Pos() } func (n *Node) End() int { return n.Loc.End() } func (n *Node) ForEachChild(v Visitor) bool { return n.data.ForEachChild(v) } -func (n *Node) Clone(f *NodeFactory) *Node { return n.data.Clone(f) } +func (n *Node) Clone(f NodeFactoryCoercible) *Node { return n.data.Clone(f) } func (n *Node) VisitEachChild(v *NodeVisitor) *Node { return n.data.VisitEachChild(v) } func (n *Node) Name() *DeclarationName { return n.data.Name() } func (n *Node) Modifiers() *ModifierList { return n.data.Modifiers() } @@ -201,13 +226,19 @@ func (n *Node) ParameterList() *ParameterList { return n.data.Functi func (n *Node) Parameters() []*ParameterDeclarationNode { return n.ParameterList().Nodes } func (n *Node) ClassLikeData() *ClassLikeBase { return n.data.ClassLikeData() } func (n *Node) BodyData() *BodyBase { return n.data.BodyData() } +func (n *Node) SubtreeFacts() SubtreeFacts { return n.data.SubtreeFacts() } +func (n *Node) propagateSubtreeFacts() SubtreeFacts { return n.data.propagateSubtreeFacts() } func (n *Node) LiteralLikeData() *LiteralLikeBase { return n.data.LiteralLikeData() } func (n *Node) TemplateLiteralLikeData() *TemplateLiteralLikeBase { return n.data.TemplateLiteralLikeData() } func (n *Node) Symbol() *Symbol { - return n.DeclarationData().Symbol + data := n.DeclarationData() + if data != nil { + return data.Symbol + } + return nil } func (n *Node) LocalSymbol() *Symbol { @@ -255,7 +286,7 @@ func (n *Node) Text() string { case KindTemplateTail: return n.AsTemplateTail().Text case KindJsxNamespacedName: - return n.AsJsxNamespacedName().Namespace.Text() + ":" + n.AsJsxNamespacedName().Name().Text() + return n.AsJsxNamespacedName().Namespace.Text() + ":" + n.AsJsxNamespacedName().name.Text() case KindRegularExpressionLiteral: return n.AsRegularExpressionLiteral().Text } @@ -326,10 +357,14 @@ func (n *Node) Expression() *Node { return n.AsThrowStatement().Expression case KindExternalModuleReference: return n.AsExternalModuleReference().Expression - case KindExportAssignment: + case KindExportAssignment, KindJSExportAssignment: return n.AsExportAssignment().Expression case KindDecorator: return n.AsDecorator().Expression + case KindJsxExpression: + return n.AsJsxExpression().Expression + case KindJsxSpreadAttribute: + return n.AsJsxSpreadAttribute().Expression } panic("Unhandled case in Node.Expression") } @@ -392,7 +427,7 @@ func (n *Node) TypeParameterList() *NodeList { return n.AsClassExpression().TypeParameters case KindInterfaceDeclaration: return n.AsInterfaceDeclaration().TypeParameters - case KindTypeAliasDeclaration: + case KindTypeAliasDeclaration, KindJSTypeAliasDeclaration: return n.AsTypeAliasDeclaration().TypeParameters default: funcLike := n.FunctionLikeData() @@ -426,7 +461,7 @@ func (n *Node) MemberList() *NodeList { case KindMappedType: return n.AsMappedTypeNode().Members } - panic("Unhandled case in Node.MemberList") + panic("Unhandled case in Node.MemberList: " + n.Kind.String()) } func (n *Node) Members() []*Node { @@ -477,7 +512,7 @@ func (n *Node) Type() *Node { return n.AsAsExpression().Type case KindSatisfiesExpression: return n.AsSatisfiesExpression().Type - case KindTypeAliasDeclaration: + case KindTypeAliasDeclaration, KindJSTypeAliasDeclaration: return n.AsTypeAliasDeclaration().Type case KindNamedTupleMember: return n.AsNamedTupleMember().Type @@ -489,13 +524,15 @@ func (n *Node) Type() *Node { return n.AsTemplateLiteralTypeSpan().Type case KindJSDocTypeExpression: return n.AsJSDocTypeExpression().Type + case KindJSDocPropertyTag: + return n.AsJSDocPropertyTag().TypeExpression case KindJSDocNullableType: return n.AsJSDocNullableType().Type case KindJSDocNonNullableType: return n.AsJSDocNonNullableType().Type case KindJSDocOptionalType: return n.AsJSDocOptionalType().Type - case KindEnumMember, KindBindingElement, KindExportAssignment, KindBinaryExpression: + case KindEnumMember, KindBindingElement, KindExportAssignment, KindJSExportAssignment, KindBinaryExpression, KindCommonJSExport: return nil default: funcLike := n.FunctionLikeData() @@ -503,7 +540,7 @@ func (n *Node) Type() *Node { return funcLike.Type } } - panic("Unhandled case in Node.Type") + panic("Unhandled case in Node.Type: " + n.Kind.String()) } func (n *Node) Initializer() *Node { @@ -692,6 +729,38 @@ func (n *Node) Label() *Node { panic("Unhandled case in Node.Label: " + n.Kind.String()) } +func (n *Node) Attributes() *Node { + switch n.Kind { + case KindJsxOpeningElement: + return n.AsJsxOpeningElement().Attributes + case KindJsxSelfClosingElement: + return n.AsJsxSelfClosingElement().Attributes + } + panic("Unhandled case in Node.Attributes: " + n.Kind.String()) +} + +func (n *Node) Children() *NodeList { + switch n.Kind { + case KindJsxElement: + return n.AsJsxElement().Children + case KindJsxFragment: + return n.AsJsxFragment().Children + } + panic("Unhandled case in Node.Children: " + n.Kind.String()) +} + +func (n *Node) ModuleSpecifier() *Expression { + switch n.Kind { + case KindImportDeclaration: + return n.AsImportDeclaration().ModuleSpecifier + case KindExportDeclaration: + return n.AsExportDeclaration().ModuleSpecifier + case KindJSDocImportTag: + return n.AsJSDocImportTag().ModuleSpecifier + } + panic("Unhandled case in Node.ModuleSpecifier: " + n.Kind.String()) +} + // Determines if `n` contains `descendant` by walking up the `Parent` pointers from `descendant`. This method panics if // `descendant` or one of its ancestors is not parented except when that node is a `SourceFile`. func (n *Node) Contains(descendant *Node) bool { @@ -838,6 +907,10 @@ func (n *Node) AsExportAssignment() *ExportAssignment { return n.data.(*ExportAssignment) } +func (n *Node) AsCommonJSExport() *CommonJSExport { + return n.data.(*CommonJSExport) +} + func (n *Node) AsObjectLiteralExpression() *ObjectLiteralExpression { return n.data.(*ObjectLiteralExpression) } @@ -1302,6 +1375,10 @@ func (n *Node) AsEnumDeclaration() *EnumDeclaration { return n.data.(*EnumDeclaration) } +func (n *Node) AsNotEmittedStatement() *NotEmittedStatement { + return n.data.(*NotEmittedStatement) +} + func (n *Node) AsJSDoc() *JSDoc { return n.data.(*JSDoc) } @@ -1484,7 +1561,7 @@ type nodeData interface { AsNode() *Node ForEachChild(v Visitor) bool VisitEachChild(v *NodeVisitor) *Node - Clone(v *NodeFactory) *Node + Clone(v NodeFactoryCoercible) *Node Name() *DeclarationName Modifiers() *ModifierList FlowNodeData() *FlowNodeBase @@ -1496,6 +1573,10 @@ type nodeData interface { BodyData() *BodyBase LiteralLikeData() *LiteralLikeBase TemplateLiteralLikeData() *TemplateLiteralLikeBase + SubtreeFacts() SubtreeFacts + computeSubtreeFacts() SubtreeFacts + subtreeFactsWorker(self nodeData) SubtreeFacts + propagateSubtreeFacts() SubtreeFacts } // NodeDefault @@ -1507,7 +1588,7 @@ type NodeDefault struct { func (node *NodeDefault) AsNode() *Node { return &node.Node } func (node *NodeDefault) ForEachChild(v Visitor) bool { return false } func (node *NodeDefault) VisitEachChild(v *NodeVisitor) *Node { return node.AsNode() } -func (node *NodeDefault) Clone(v *NodeFactory) *Node { return nil } +func (node *NodeDefault) Clone(v NodeFactoryCoercible) *Node { return nil } func (node *NodeDefault) Name() *DeclarationName { return nil } func (node *NodeDefault) Modifiers() *ModifierList { return nil } func (node *NodeDefault) FlowNodeData() *FlowNodeBase { return nil } @@ -1519,6 +1600,25 @@ func (node *NodeDefault) ClassLikeData() *ClassLikeBase { re func (node *NodeDefault) BodyData() *BodyBase { return nil } func (node *NodeDefault) LiteralLikeData() *LiteralLikeBase { return nil } func (node *NodeDefault) TemplateLiteralLikeData() *TemplateLiteralLikeBase { return nil } +func (node *NodeDefault) SubtreeFacts() SubtreeFacts { + return node.data.subtreeFactsWorker(node.data) +} + +func (node *NodeDefault) subtreeFactsWorker(self nodeData) SubtreeFacts { + // To avoid excessive conditional checks, the default implementation of subtreeFactsWorker directly invokes + // computeSubtreeFacts. More complex nodes should implement CompositeNodeBase, which overrides this + // method to cache the result. `self` is passed along to ensure we lookup `computeSubtreeFacts` on the + // correct type, as `CompositeNodeBase` does not, itself, inherit from `Node`. + return self.computeSubtreeFacts() +} + +func (node *NodeDefault) computeSubtreeFacts() SubtreeFacts { + return SubtreeFactsNone +} + +func (node *NodeDefault) propagateSubtreeFacts() SubtreeFacts { + return node.data.SubtreeFacts() & ^SubtreeExclusionsNode +} // NodeBase @@ -1571,6 +1671,10 @@ type ( JSDocComment = Node // JSDocText | JSDocLink | JSDocLinkCode | JSDocLinkPlain; JSDocTag = Node // Node with JSDocTagBase SignatureDeclaration = Node // CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | AccessorDeclaration | FunctionExpression | ArrowFunction; + StringLiteralLike = Node // StringLiteral | NoSubstitutionTemplateLiteral + AnyValidImportOrReExport = Node // (ImportDeclaration | ExportDeclaration | JSDocImportTag) & { moduleSpecifier: StringLiteral } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral }} | RequireOrImportCall | ValidImportTypeNode + ValidImportTypeNode = Node // ImportTypeNode & { argument: LiteralTypeNode & { literal: StringLiteral } } + NumericOrStringLikeLiteral = Node // StringLiteralLike | NumericLiteral ) // Aliases for node singletons @@ -1589,6 +1693,7 @@ type ( CatchClauseNode = Node CaseBlockNode = Node CaseOrDefaultClauseNode = Node + CaseClauseNode = Node VariableDeclarationNode = Node VariableDeclarationListNode = Node BindingElementNode = Node @@ -1611,6 +1716,7 @@ type ( JsxOpeningFragmentNode = Node JsxClosingFragmentNode = Node SourceFileNode = Node + PropertyAccessExpressionNode = Node ) type ( @@ -1745,6 +1851,38 @@ func (node *Node) JSDoc(file *SourceFile) []*Node { return nil } +// compositeNodeBase + +// A composite node is a node that contains a complex subtree. This struct is intended to be +// embedded in a node that requires caching for its subtree facts. +type compositeNodeBase struct { + facts atomic.Uint32 // caches the SubtreeFacts for this node and its subtree +} + +func (node *compositeNodeBase) subtreeFactsWorker(self nodeData) SubtreeFacts { + // computeSubtreeFacts() is expected to be idempotent, so races will only impact time, not correctness. + facts := SubtreeFacts(node.facts.Load()) + if facts&SubtreeFactsComputed == 0 { + facts |= self.computeSubtreeFacts() | SubtreeFactsComputed + node.facts.Store(uint32(facts)) + } + return facts &^ SubtreeFactsComputed +} + +func (node *compositeNodeBase) computeSubtreeFacts() SubtreeFacts { + // This method must be implemented by the concrete node type. + panic("not implemented") +} + +// typeSyntaxBase + +// A "type-syntax" node is a node whose subtree may only consist of TypeScript syntax. This struct is intended to be +// embedded in a node that only ever returns `SubtreeContainsTypeScript` for its subtree facts. +type typeSyntaxBase struct{} + +func (node *typeSyntaxBase) computeSubtreeFacts() SubtreeFacts { return SubtreeContainsTypeScript } +func (node *typeSyntaxBase) propagateSubtreeFacts() SubtreeFacts { return SubtreeContainsTypeScript } + // Token type Token struct { @@ -1752,11 +1890,52 @@ type Token struct { } func (f *NodeFactory) NewToken(kind Kind) *Node { - return newNode(kind, f.tokenPool.New(), f.hooks) -} - -func (node *Token) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewToken(node.Kind), node.AsNode(), f.hooks) + return f.newNode(kind, f.tokenPool.New()) +} + +func (node *Token) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewToken(node.Kind), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *Token) computeSubtreeFacts() SubtreeFacts { + switch node.Kind { + case KindAsyncKeyword: + return SubtreeContainsES2017 | SubtreeContainsES2018 + case KindUsingKeyword: + return SubtreeContainsESNext + case KindPublicKeyword, + KindPrivateKeyword, + KindProtectedKeyword, + KindReadonlyKeyword, + KindAbstractKeyword, + KindDeclareKeyword, + KindConstKeyword, + KindAnyKeyword, + KindNumberKeyword, + KindBigIntKeyword, + KindNeverKeyword, + KindObjectKeyword, + KindInKeyword, + KindOutKeyword, + KindOverrideKeyword, + KindStringKeyword, + KindBooleanKeyword, + KindSymbolKeyword, + KindVoidKeyword, + KindUnknownKeyword, + KindUndefinedKeyword, // `undefined` is an Identifier in the expression case. + KindExportKeyword: // `export` is TypeScript syntax in a namespace + return SubtreeContainsTypeScript + case KindAccessorKeyword: + return SubtreeContainsClassFields + case KindAsteriskAsteriskToken, KindAsteriskAsteriskEqualsToken: + return SubtreeContainsES2016 + case KindQuestionQuestionToken, KindQuestionDotToken: + return SubtreeContainsES2020 + case KindQuestionQuestionEqualsToken, KindBarBarEqualsToken, KindAmpersandAmpersandEqualsToken: + return SubtreeContainsES2021 + } + return SubtreeFactsNone } // Identifier @@ -1770,11 +1949,16 @@ type Identifier struct { func (f *NodeFactory) NewIdentifier(text string) *Node { data := f.identifierPool.New() data.Text = text - return newNode(KindIdentifier, data, f.hooks) + f.textCount++ + return f.newNode(KindIdentifier, data) +} + +func (node *Identifier) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewIdentifier(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *Identifier) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewIdentifier(node.Text), node.AsNode(), f.hooks) +func (node *Identifier) SubtreeFacts() SubtreeFacts { + return SubtreeContainsIdentifier } func IsIdentifier(node *Node) bool { @@ -1791,11 +1975,16 @@ type PrivateIdentifier struct { func (f *NodeFactory) NewPrivateIdentifier(text string) *Node { data := &PrivateIdentifier{} data.Text = text - return newNode(KindPrivateIdentifier, data, f.hooks) + f.textCount++ + return f.newNode(KindPrivateIdentifier, data) +} + +func (node *PrivateIdentifier) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPrivateIdentifier(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *PrivateIdentifier) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPrivateIdentifier(node.Text), node.AsNode(), f.hooks) +func (node *PrivateIdentifier) computeSubtreeFacts() SubtreeFacts { + return SubtreeContainsClassFields } func IsPrivateIdentifier(node *Node) bool { @@ -1807,6 +1996,7 @@ func IsPrivateIdentifier(node *Node) bool { type QualifiedName struct { NodeBase FlowNodeBase + compositeNodeBase Left *EntityName // EntityName Right *IdentifierNode // IdentifierNode } @@ -1815,7 +2005,7 @@ func (f *NodeFactory) NewQualifiedName(left *EntityName, right *IdentifierNode) data := &QualifiedName{} data.Left = left data.Right = right - return newNode(KindQualifiedName, data, f.hooks) + return f.newNode(KindQualifiedName, data) } func (f *NodeFactory) UpdateQualifiedName(node *QualifiedName, left *EntityName, right *IdentifierNode) *Node { @@ -1833,20 +2023,26 @@ func (node *QualifiedName) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateQualifiedName(node, v.visitNode(node.Left), v.visitNode(node.Right)) } -func (node *QualifiedName) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewQualifiedName(node.Left, node.Right), node.AsNode(), f.hooks) +func (node *QualifiedName) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewQualifiedName(node.Left, node.Right), node.AsNode(), f.AsNodeFactory().hooks) } func IsQualifiedName(node *Node) bool { return node.Kind == KindQualifiedName } +func (node *QualifiedName) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Left) | + propagateSubtreeFacts(node.Right) +} + // TypeParameterDeclaration type TypeParameterDeclaration struct { NodeBase DeclarationBase ModifiersBase + typeSyntaxBase name *IdentifierNode // IdentifierNode Constraint *TypeNode // TypeNode. Optional DefaultType *TypeNode // TypeNode. Optional @@ -1859,7 +2055,7 @@ func (f *NodeFactory) NewTypeParameterDeclaration(modifiers *ModifierList, name data.name = name data.Constraint = constraint data.DefaultType = defaultType - return newNode(KindTypeParameter, data, f.hooks) + return f.newNode(KindTypeParameter, data) } func (f *NodeFactory) UpdateTypeParameterDeclaration(node *TypeParameterDeclaration, modifiers *ModifierList, name *IdentifierNode, constraint *TypeNode, defaultType *TypeNode) *Node { @@ -1877,8 +2073,8 @@ func (node *TypeParameterDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeParameterDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNode(node.Constraint), v.visitNode(node.DefaultType)) } -func (node *TypeParameterDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeParameterDeclaration(node.Modifiers(), node.Name(), node.Constraint, node.DefaultType), node.AsNode(), f.hooks) +func (node *TypeParameterDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeParameterDeclaration(node.Modifiers(), node.Name(), node.Constraint, node.DefaultType), node.AsNode(), f.AsNodeFactory().hooks) } func (node *TypeParameterDeclaration) Name() *DeclarationName { @@ -1893,13 +2089,14 @@ func IsTypeParameterDeclaration(node *Node) bool { type ComputedPropertyName struct { NodeBase + compositeNodeBase Expression *Expression // Expression } func (f *NodeFactory) NewComputedPropertyName(expression *Expression) *Node { data := &ComputedPropertyName{} data.Expression = expression - return newNode(KindComputedPropertyName, data, f.hooks) + return f.newNode(KindComputedPropertyName, data) } func (f *NodeFactory) UpdateComputedPropertyName(node *ComputedPropertyName, expression *Expression) *Node { @@ -1917,8 +2114,12 @@ func (node *ComputedPropertyName) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateComputedPropertyName(node, v.visitNode(node.Expression)) } -func (node *ComputedPropertyName) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewComputedPropertyName(node.Expression), node.AsNode(), f.hooks) +func (node *ComputedPropertyName) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewComputedPropertyName(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ComputedPropertyName) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsComputedPropertyName(node *Node) bool { @@ -1935,13 +2136,14 @@ func (f *NodeFactory) NewModifier(kind Kind) *Node { type Decorator struct { NodeBase + compositeNodeBase Expression *LeftHandSideExpression // LeftHandSideExpression } func (f *NodeFactory) NewDecorator(expression *LeftHandSideExpression) *Node { data := &Decorator{} data.Expression = expression - return newNode(KindDecorator, data, f.hooks) + return f.newNode(KindDecorator, data) } func (f *NodeFactory) UpdateDecorator(node *Decorator, expression *Expression) *Node { @@ -1959,8 +2161,14 @@ func (node *Decorator) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateDecorator(node, v.visitNode(node.Expression)) } -func (node *Decorator) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewDecorator(node.Expression), node.AsNode(), f.hooks) +func (node *Decorator) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewDecorator(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *Decorator) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + SubtreeContainsTypeScript | // Decorator metadata + SubtreeContainsDecorators // legacy or ES decorators } func IsDecorator(node *Node) bool { @@ -1981,11 +2189,11 @@ type EmptyStatement struct { } func (f *NodeFactory) NewEmptyStatement() *Node { - return newNode(KindEmptyStatement, &EmptyStatement{}, f.hooks) + return f.newNode(KindEmptyStatement, &EmptyStatement{}) } -func (node *EmptyStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewEmptyStatement(), node.AsNode(), f.hooks) +func (node *EmptyStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewEmptyStatement(), node.AsNode(), f.AsNodeFactory().hooks) } func IsEmptyStatement(node *Node) bool { @@ -1996,6 +2204,7 @@ func IsEmptyStatement(node *Node) bool { type IfStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression ThenStatement *Statement // Statement ElseStatement *Statement // Statement. Optional @@ -2006,7 +2215,7 @@ func (f *NodeFactory) NewIfStatement(expression *Expression, thenStatement *Stat data.Expression = expression data.ThenStatement = thenStatement data.ElseStatement = elseStatement - return newNode(KindIfStatement, data, f.hooks) + return f.newNode(KindIfStatement, data) } func (f *NodeFactory) UpdateIfStatement(node *IfStatement, expression *Expression, thenStatement *Statement, elseStatement *Statement) *Node { @@ -2024,18 +2233,36 @@ func (node *IfStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateIfStatement(node, v.visitNode(node.Expression), v.visitEmbeddedStatement(node.ThenStatement), v.visitEmbeddedStatement(node.ElseStatement)) } -func (node *IfStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewIfStatement(node.Expression, node.ThenStatement, node.ElseStatement), node.AsNode(), f.hooks) +func (node *IfStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewIfStatement(node.Expression, node.ThenStatement, node.ElseStatement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *IfStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.ThenStatement) | + propagateSubtreeFacts(node.ElseStatement) +} + +func IsIfStatement(node *Node) bool { + return node.Kind == KindIfStatement } // DoStatement type DoStatement struct { StatementBase + compositeNodeBase Statement *Statement // Statement Expression *Expression // Expression } +func (f *NodeFactory) NewDoStatement(statement *Statement, expression *Expression) *Node { + data := &DoStatement{} + data.Statement = statement + data.Expression = expression + return f.newNode(KindDoStatement, data) +} + func (f *NodeFactory) UpdateDoStatement(node *DoStatement, statement *Statement, expression *Expression) *Node { if statement != node.Statement || expression != node.Expression { return updateNode(f.NewDoStatement(statement, expression), node.AsNode(), f.hooks) @@ -2043,13 +2270,6 @@ func (f *NodeFactory) UpdateDoStatement(node *DoStatement, statement *Statement, return node.AsNode() } -func (f *NodeFactory) NewDoStatement(statement *Statement, expression *Expression) *Node { - data := &DoStatement{} - data.Statement = statement - data.Expression = expression - return newNode(KindDoStatement, data, f.hooks) -} - func (node *DoStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateDoStatement(node, v.visitIterationBody(node.Statement), v.visitNode(node.Expression)) } @@ -2058,14 +2278,20 @@ func (node *DoStatement) ForEachChild(v Visitor) bool { return visit(v, node.Statement) || visit(v, node.Expression) } -func (node *DoStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewDoStatement(node.Statement, node.Expression), node.AsNode(), f.hooks) +func (node *DoStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewDoStatement(node.Statement, node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *DoStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Statement) | + propagateSubtreeFacts(node.Expression) } // WhileStatement type WhileStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression Statement *Statement // Statement } @@ -2074,7 +2300,7 @@ func (f *NodeFactory) NewWhileStatement(expression *Expression, statement *State data := &WhileStatement{} data.Expression = expression data.Statement = statement - return newNode(KindWhileStatement, data, f.hooks) + return f.newNode(KindWhileStatement, data) } func (f *NodeFactory) UpdateWhileStatement(node *WhileStatement, expression *Expression, statement *Statement) *Node { @@ -2092,8 +2318,12 @@ func (node *WhileStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateWhileStatement(node, v.visitNode(node.Expression), v.visitIterationBody(node.Statement)) } -func (node *WhileStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewWhileStatement(node.Expression, node.Statement), node.AsNode(), f.hooks) +func (node *WhileStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewWhileStatement(node.Expression, node.Statement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *WhileStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | propagateSubtreeFacts(node.Statement) } // ForStatement @@ -2101,6 +2331,7 @@ func (node *WhileStatement) Clone(f *NodeFactory) *Node { type ForStatement struct { StatementBase LocalsContainerBase + compositeNodeBase Initializer *ForInitializer // ForInitializer. Optional Condition *Expression // Expression. Optional Incrementor *Expression // Expression. Optional @@ -2113,7 +2344,7 @@ func (f *NodeFactory) NewForStatement(initializer *ForInitializer, condition *Ex data.Condition = condition data.Incrementor = incrementor data.Statement = statement - return newNode(KindForStatement, data, f.hooks) + return f.newNode(KindForStatement, data) } func (f *NodeFactory) UpdateForStatement(node *ForStatement, initializer *ForInitializer, condition *Expression, incrementor *Expression, statement *Statement) *Node { @@ -2131,8 +2362,15 @@ func (node *ForStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateForStatement(node, v.visitNode(node.Initializer), v.visitNode(node.Condition), v.visitNode(node.Incrementor), v.visitIterationBody(node.Statement)) } -func (node *ForStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewForStatement(node.Initializer, node.Expression(), node.Incrementor, node.Statement), node.AsNode(), f.hooks) +func (node *ForStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewForStatement(node.Initializer, node.Expression(), node.Incrementor, node.Statement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ForStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Initializer) | + propagateSubtreeFacts(node.Condition) | + propagateSubtreeFacts(node.Incrementor) | + propagateSubtreeFacts(node.Statement) } func IsForStatement(node *Node) bool { @@ -2144,6 +2382,7 @@ func IsForStatement(node *Node) bool { type ForInOrOfStatement struct { StatementBase LocalsContainerBase + compositeNodeBase AwaitModifier *TokenNode // TokenNode. Optional Initializer *ForInitializer // ForInitializer Expression *Expression // Expression @@ -2156,7 +2395,7 @@ func (f *NodeFactory) NewForInOrOfStatement(kind Kind, awaitModifier *TokenNode, data.Initializer = initializer data.Expression = expression data.Statement = statement - return newNode(kind, data, f.hooks) + return f.newNode(kind, data) } func (f *NodeFactory) UpdateForInOrOfStatement(node *ForInOrOfStatement, awaitModifier *TokenNode, initializer *ForInitializer, expression *Expression, statement *Statement) *Node { @@ -2174,8 +2413,15 @@ func (node *ForInOrOfStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateForInOrOfStatement(node, v.visitToken(node.AwaitModifier), v.visitNode(node.Initializer), v.visitNode(node.Expression), v.visitIterationBody(node.Statement)) } -func (node *ForInOrOfStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewForInOrOfStatement(node.Kind, node.AwaitModifier, node.Initializer, node.Expression, node.Statement), node.AsNode(), f.hooks) +func (node *ForInOrOfStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewForInOrOfStatement(node.Kind, node.AwaitModifier, node.Initializer, node.Expression, node.Statement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ForInOrOfStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Initializer) | + propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.Statement) | + core.IfElse(node.AwaitModifier != nil, SubtreeContainsES2018, SubtreeFactsNone) } func IsForInStatement(node *Node) bool { @@ -2200,7 +2446,7 @@ type BreakStatement struct { func (f *NodeFactory) NewBreakStatement(label *IdentifierNode) *Node { data := &BreakStatement{} data.Label = label - return newNode(KindBreakStatement, data, f.hooks) + return f.newNode(KindBreakStatement, data) } func (f *NodeFactory) UpdateBreakStatement(node *BreakStatement, label *IdentifierNode) *Node { @@ -2218,8 +2464,8 @@ func (node *BreakStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateBreakStatement(node, v.visitNode(node.Label)) } -func (node *BreakStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBreakStatement(node.Label), node.AsNode(), f.hooks) +func (node *BreakStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBreakStatement(node.Label), node.AsNode(), f.AsNodeFactory().hooks) } // ContinueStatement @@ -2232,7 +2478,7 @@ type ContinueStatement struct { func (f *NodeFactory) NewContinueStatement(label *IdentifierNode) *Node { data := &ContinueStatement{} data.Label = label - return newNode(KindContinueStatement, data, f.hooks) + return f.newNode(KindContinueStatement, data) } func (f *NodeFactory) UpdateContinueStatement(node *ContinueStatement, label *IdentifierNode) *Node { @@ -2250,21 +2496,22 @@ func (node *ContinueStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateContinueStatement(node, v.visitNode(node.Label)) } -func (node *ContinueStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewContinueStatement(node.Label), node.AsNode(), f.hooks) +func (node *ContinueStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewContinueStatement(node.Label), node.AsNode(), f.AsNodeFactory().hooks) } // ReturnStatement type ReturnStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression. Optional } func (f *NodeFactory) NewReturnStatement(expression *Expression) *Node { data := f.returnStatementPool.New() data.Expression = expression - return newNode(KindReturnStatement, data, f.hooks) + return f.newNode(KindReturnStatement, data) } func (f *NodeFactory) UpdateReturnStatement(node *ReturnStatement, expression *Expression) *Node { @@ -2282,8 +2529,12 @@ func (node *ReturnStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateReturnStatement(node, v.visitNode(node.Expression)) } -func (node *ReturnStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewReturnStatement(node.Expression), node.AsNode(), f.hooks) +func (node *ReturnStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewReturnStatement(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ReturnStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsReturnStatement(node *Node) bool { @@ -2294,6 +2545,7 @@ func IsReturnStatement(node *Node) bool { type WithStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression Statement *Statement // Statement } @@ -2302,7 +2554,7 @@ func (f *NodeFactory) NewWithStatement(expression *Expression, statement *Statem data := &WithStatement{} data.Expression = expression data.Statement = statement - return newNode(KindWithStatement, data, f.hooks) + return f.newNode(KindWithStatement, data) } func (f *NodeFactory) UpdateWithStatement(node *WithStatement, expression *Expression, statement *Statement) *Node { @@ -2320,14 +2572,19 @@ func (node *WithStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateWithStatement(node, v.visitNode(node.Expression), v.visitEmbeddedStatement(node.Statement)) } -func (node *WithStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewWithStatement(node.Expression, node.Statement), node.AsNode(), f.hooks) +func (node *WithStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewWithStatement(node.Expression, node.Statement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *WithStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | propagateSubtreeFacts(node.Statement) } // SwitchStatement type SwitchStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression CaseBlock *CaseBlockNode // CaseBlockNode } @@ -2336,7 +2593,7 @@ func (f *NodeFactory) NewSwitchStatement(expression *Expression, caseBlock *Case data := &SwitchStatement{} data.Expression = expression data.CaseBlock = caseBlock - return newNode(KindSwitchStatement, data, f.hooks) + return f.newNode(KindSwitchStatement, data) } func (f *NodeFactory) UpdateSwitchStatement(node *SwitchStatement, expression *Expression, caseBlock *CaseBlockNode) *Node { @@ -2354,8 +2611,13 @@ func (node *SwitchStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateSwitchStatement(node, v.visitNode(node.Expression), v.visitNode(node.CaseBlock)) } -func (node *SwitchStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSwitchStatement(node.Expression, node.CaseBlock), node.AsNode(), f.hooks) +func (node *SwitchStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSwitchStatement(node.Expression, node.CaseBlock), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *SwitchStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.CaseBlock) } // CaseBlock @@ -2363,13 +2625,14 @@ func (node *SwitchStatement) Clone(f *NodeFactory) *Node { type CaseBlock struct { NodeBase LocalsContainerBase + compositeNodeBase Clauses *NodeList // NodeList[*CaseOrDefaultClauseNode] } func (f *NodeFactory) NewCaseBlock(clauses *NodeList) *Node { data := &CaseBlock{} data.Clauses = clauses - return newNode(KindCaseBlock, data, f.hooks) + return f.newNode(KindCaseBlock, data) } func (f *NodeFactory) UpdateCaseBlock(node *CaseBlock, clauses *CaseClausesList) *Node { @@ -2387,14 +2650,19 @@ func (node *CaseBlock) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateCaseBlock(node, v.visitNodes(node.Clauses)) } -func (node *CaseBlock) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewCaseBlock(node.Clauses), node.AsNode(), f.hooks) +func (node *CaseBlock) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCaseBlock(node.Clauses), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *CaseBlock) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Clauses, propagateSubtreeFacts) } // CaseOrDefaultClause type CaseOrDefaultClause struct { NodeBase + compositeNodeBase Expression *Expression // Expression. nil in default clause Statements *NodeList // NodeList[*Statement] FallthroughFlowNode *FlowNode @@ -2404,7 +2672,7 @@ func (f *NodeFactory) NewCaseOrDefaultClause(kind Kind, expression *Expression, data := &CaseOrDefaultClause{} data.Expression = expression data.Statements = statements - return newNode(kind, data, f.hooks) + return f.newNode(kind, data) } func (f *NodeFactory) UpdateCaseOrDefaultClause(node *CaseOrDefaultClause, expression *Expression, statements *StatementList) *Node { @@ -2422,8 +2690,12 @@ func (node *CaseOrDefaultClause) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateCaseOrDefaultClause(node, v.visitNode(node.Expression), v.visitNodes(node.Statements)) } -func (node *CaseOrDefaultClause) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewCaseOrDefaultClause(node.Kind, node.Expression, node.Statements), node.AsNode(), f.hooks) +func (node *CaseOrDefaultClause) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCaseOrDefaultClause(node.Kind, node.Expression, node.Statements), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *CaseOrDefaultClause) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts) } func IsCaseClause(node *Node) bool { @@ -2438,13 +2710,14 @@ func IsDefaultClause(node *Node) bool { type ThrowStatement struct { StatementBase + compositeNodeBase Expression *Expression // Expression } func (f *NodeFactory) NewThrowStatement(expression *Expression) *Node { data := &ThrowStatement{} data.Expression = expression - return newNode(KindThrowStatement, data, f.hooks) + return f.newNode(KindThrowStatement, data) } func (f *NodeFactory) UpdateThrowStatement(node *ThrowStatement, expression *Expression) *Node { @@ -2462,14 +2735,19 @@ func (node *ThrowStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateThrowStatement(node, v.visitNode(node.Expression)) } -func (node *ThrowStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewThrowStatement(node.Expression), node.AsNode(), f.hooks) +func (node *ThrowStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewThrowStatement(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ThrowStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } // TryStatement type TryStatement struct { StatementBase + compositeNodeBase TryBlock *BlockNode // BlockNode CatchClause *CatchClauseNode // CatchClauseNode. Optional FinallyBlock *BlockNode // BlockNode. Optional @@ -2480,7 +2758,7 @@ func (f *NodeFactory) NewTryStatement(tryBlock *BlockNode, catchClause *CatchCla data.TryBlock = tryBlock data.CatchClause = catchClause data.FinallyBlock = finallyBlock - return newNode(KindTryStatement, data, f.hooks) + return f.newNode(KindTryStatement, data) } func (f *NodeFactory) UpdateTryStatement(node *TryStatement, tryBlock *BlockNode, catchClause *CatchClauseNode, finallyBlock *BlockNode) *Node { @@ -2498,8 +2776,14 @@ func (node *TryStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTryStatement(node, v.visitNode(node.TryBlock), v.visitNode(node.CatchClause), v.visitNode(node.FinallyBlock)) } -func (node *TryStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTryStatement(node.TryBlock, node.CatchClause, node.FinallyBlock), node.AsNode(), f.hooks) +func (node *TryStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTryStatement(node.TryBlock, node.CatchClause, node.FinallyBlock), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TryStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.TryBlock) | + propagateSubtreeFacts(node.CatchClause) | + propagateSubtreeFacts(node.FinallyBlock) } func IsTryStatement(node *Node) bool { @@ -2511,6 +2795,7 @@ func IsTryStatement(node *Node) bool { type CatchClause struct { NodeBase LocalsContainerBase + compositeNodeBase VariableDeclaration *VariableDeclarationNode // VariableDeclarationNode. Optional Block *BlockNode // BlockNode } @@ -2519,7 +2804,7 @@ func (f *NodeFactory) NewCatchClause(variableDeclaration *VariableDeclarationNod data := &CatchClause{} data.VariableDeclaration = variableDeclaration data.Block = block - return newNode(KindCatchClause, data, f.hooks) + return f.newNode(KindCatchClause, data) } func (f *NodeFactory) UpdateCatchClause(node *CatchClause, variableDeclaration *VariableDeclarationNode, block *BlockNode) *Node { @@ -2537,8 +2822,17 @@ func (node *CatchClause) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateCatchClause(node, v.visitNode(node.VariableDeclaration), v.visitNode(node.Block)) } -func (node *CatchClause) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewCatchClause(node.VariableDeclaration, node.Block), node.AsNode(), f.hooks) +func (node *CatchClause) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCatchClause(node.VariableDeclaration, node.Block), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *CatchClause) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.VariableDeclaration) | + propagateSubtreeFacts(node.Block) +} + +func (node *CatchClause) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsCatchClause } func IsCatchClause(node *Node) bool { @@ -2552,11 +2846,11 @@ type DebuggerStatement struct { } func (f *NodeFactory) NewDebuggerStatement() *Node { - return newNode(KindDebuggerStatement, &DebuggerStatement{}, f.hooks) + return f.newNode(KindDebuggerStatement, &DebuggerStatement{}) } -func (node *DebuggerStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewDebuggerStatement(), node.AsNode(), f.hooks) +func (node *DebuggerStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewDebuggerStatement(), node.AsNode(), f.AsNodeFactory().hooks) } // LabeledStatement @@ -2571,7 +2865,7 @@ func (f *NodeFactory) NewLabeledStatement(label *IdentifierNode, statement *Stat data := &LabeledStatement{} data.Label = label data.Statement = statement - return newNode(KindLabeledStatement, data, f.hooks) + return f.newNode(KindLabeledStatement, data) } func (f *NodeFactory) UpdateLabeledStatement(node *LabeledStatement, label *IdentifierNode, statement *Statement) *Node { @@ -2589,8 +2883,12 @@ func (node *LabeledStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateLabeledStatement(node, v.visitNode(node.Label), v.visitEmbeddedStatement(node.Statement)) } -func (node *LabeledStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewLabeledStatement(node.Label, node.Statement), node.AsNode(), f.hooks) +func (node *LabeledStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewLabeledStatement(node.Label, node.Statement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *LabeledStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Statement) } func IsLabeledStatement(node *Node) bool { @@ -2607,7 +2905,7 @@ type ExpressionStatement struct { func (f *NodeFactory) NewExpressionStatement(expression *Expression) *Node { data := f.expressionStatementPool.New() data.Expression = expression - return newNode(KindExpressionStatement, data, f.hooks) + return f.newNode(KindExpressionStatement, data) } func (f *NodeFactory) UpdateExpressionStatement(node *ExpressionStatement, expression *Expression) *Node { @@ -2625,8 +2923,12 @@ func (node *ExpressionStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateExpressionStatement(node, v.visitNode(node.Expression)) } -func (node *ExpressionStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExpressionStatement(node.Expression), node.AsNode(), f.hooks) +func (node *ExpressionStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewExpressionStatement(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ExpressionStatement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsExpressionStatement(node *Node) bool { @@ -2638,6 +2940,7 @@ func IsExpressionStatement(node *Node) bool { type Block struct { StatementBase LocalsContainerBase + compositeNodeBase Statements *NodeList // NodeList[*Statement] Multiline bool } @@ -2646,7 +2949,7 @@ func (f *NodeFactory) NewBlock(statements *NodeList, multiline bool) *Node { data := f.blockPool.New() data.Statements = statements data.Multiline = multiline - return newNode(KindBlock, data, f.hooks) + return f.newNode(KindBlock, data) } func (f *NodeFactory) UpdateBlock(node *Block, statements *StatementList) *Node { @@ -2664,8 +2967,12 @@ func (node *Block) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateBlock(node, v.visitNodes(node.Statements)) } -func (node *Block) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBlock(node.Statements, node.Multiline), node.AsNode(), f.hooks) +func (node *Block) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBlock(node.Statements, node.Multiline), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *Block) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts) } func IsBlock(node *Node) bool { @@ -2677,6 +2984,7 @@ func IsBlock(node *Node) bool { type VariableStatement struct { StatementBase ModifiersBase + compositeNodeBase DeclarationList *VariableDeclarationListNode // VariableDeclarationListNode } @@ -2684,7 +2992,7 @@ func (f *NodeFactory) NewVariableStatement(modifiers *ModifierList, declarationL data := f.variableStatementPool.New() data.modifiers = modifiers data.DeclarationList = declarationList - return newNode(KindVariableStatement, data, f.hooks) + return f.newNode(KindVariableStatement, data) } func (f *NodeFactory) UpdateVariableStatement(node *VariableStatement, modifiers *ModifierList, declarationList *VariableDeclarationListNode) *Node { @@ -2702,8 +3010,17 @@ func (node *VariableStatement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateVariableStatement(node, v.visitModifiers(node.modifiers), v.visitNode(node.DeclarationList)) } -func (node *VariableStatement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewVariableStatement(node.Modifiers(), node.DeclarationList), node.AsNode(), f.hooks) +func (node *VariableStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewVariableStatement(node.Modifiers(), node.DeclarationList), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *VariableStatement) computeSubtreeFacts() SubtreeFacts { + if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.DeclarationList) + } } func IsVariableStatement(node *Node) bool { @@ -2716,6 +3033,7 @@ type VariableDeclaration struct { NodeBase DeclarationBase ExportableBase + compositeNodeBase name *BindingName // BindingName ExclamationToken *TokenNode // TokenNode. Optional Type *TypeNode // TypeNode. Optional @@ -2728,7 +3046,7 @@ func (f *NodeFactory) NewVariableDeclaration(name *BindingName, exclamationToken data.ExclamationToken = exclamationToken data.Type = typeNode data.Initializer = initializer - return newNode(KindVariableDeclaration, data, f.hooks) + return f.newNode(KindVariableDeclaration, data) } func (f *NodeFactory) UpdateVariableDeclaration(node *VariableDeclaration, name *BindingName, exclamationToken *TokenNode, typeNode *TypeNode, initializer *Expression) *Node { @@ -2746,14 +3064,21 @@ func (node *VariableDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateVariableDeclaration(node, v.visitNode(node.name), v.visitToken(node.ExclamationToken), v.visitNode(node.Type), v.visitNode(node.Initializer)) } -func (node *VariableDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewVariableDeclaration(node.Name(), node.ExclamationToken, node.Type, node.Initializer), node.AsNode(), f.hooks) +func (node *VariableDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewVariableDeclaration(node.Name(), node.ExclamationToken, node.Type, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) } func (node *VariableDeclaration) Name() *DeclarationName { return node.name } +func (node *VariableDeclaration) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxSubtreeFacts(node.ExclamationToken) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Initializer) +} + func IsVariableDeclaration(node *Node) bool { return node.Kind == KindVariableDeclaration } @@ -2762,14 +3087,15 @@ func IsVariableDeclaration(node *Node) bool { type VariableDeclarationList struct { NodeBase + compositeNodeBase Declarations *NodeList // NodeList[*VariableDeclarationNode] } func (f *NodeFactory) NewVariableDeclarationList(flags NodeFlags, declarations *NodeList) *Node { data := f.variableDeclarationListPool.New() data.Declarations = declarations - node := newNode(KindVariableDeclarationList, data, f.hooks) - node.Flags |= flags + node := f.newNode(KindVariableDeclarationList, data) + node.Flags = flags return node } @@ -2788,8 +3114,17 @@ func (node *VariableDeclarationList) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateVariableDeclarationList(node, v.visitNodes(node.Declarations)) } -func (node *VariableDeclarationList) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewVariableDeclarationList(node.Flags, node.Declarations), node.AsNode(), f.hooks) +func (node *VariableDeclarationList) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewVariableDeclarationList(node.Flags, node.Declarations), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *VariableDeclarationList) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Declarations, propagateSubtreeFacts) | + core.IfElse(node.Flags&NodeFlagsUsing != 0, SubtreeContainsESNext, SubtreeFactsNone) +} + +func (node *VariableDeclarationList) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsVariableDeclarationList } func IsVariableDeclarationList(node *Node) bool { @@ -2800,13 +3135,14 @@ func IsVariableDeclarationList(node *Node) bool { type BindingPattern struct { NodeBase + compositeNodeBase Elements *NodeList // NodeList[*BindingElementNode] } func (f *NodeFactory) NewBindingPattern(kind Kind, elements *NodeList) *Node { data := &BindingPattern{} data.Elements = elements - return newNode(kind, data, f.hooks) + return f.newNode(kind, data) } func (f *NodeFactory) UpdateBindingPattern(node *BindingPattern, elements *BindingElementList) *Node { @@ -2824,8 +3160,23 @@ func (node *BindingPattern) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateBindingPattern(node, v.visitNodes(node.Elements)) } -func (node *BindingPattern) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBindingPattern(node.Kind, node.Elements), node.AsNode(), f.hooks) +func (node *BindingPattern) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBindingPattern(node.Kind, node.Elements), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *BindingPattern) computeSubtreeFacts() SubtreeFacts { + switch node.Kind { + case KindObjectBindingPattern: + return propagateNodeListSubtreeFacts(node.Elements, propagateObjectBindingElementSubtreeFacts) + case KindArrayBindingPattern: + return propagateNodeListSubtreeFacts(node.Elements, propagateBindingElementSubtreeFacts) + default: + return SubtreeFactsNone + } +} + +func (node *BindingPattern) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsBindingPattern } func IsObjectBindingPattern(node *Node) bool { @@ -2846,6 +3197,7 @@ type ParameterDeclaration struct { NodeBase DeclarationBase ModifiersBase + compositeNodeBase DotDotDotToken *TokenNode // TokenNode. Present on rest parameter name *BindingName // BindingName. Declared parameter name QuestionToken *TokenNode // TokenNode. Present on optional parameter @@ -2861,7 +3213,7 @@ func (f *NodeFactory) NewParameterDeclaration(modifiers *ModifierList, dotDotDot data.QuestionToken = questionToken data.Type = typeNode data.Initializer = initializer - return newNode(KindParameter, data, f.hooks) + return f.newNode(KindParameter, data) } func (f *NodeFactory) UpdateParameterDeclaration(node *ParameterDeclaration, modifiers *ModifierList, dotDotDotToken *TokenNode, name *BindingName, questionToken *TokenNode, typeNode *TypeNode, initializer *Expression) *Node { @@ -2880,8 +3232,24 @@ func (node *ParameterDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateParameterDeclaration(node, v.visitModifiers(node.modifiers), v.visitToken(node.DotDotDotToken), v.visitNode(node.name), v.visitToken(node.QuestionToken), v.visitNode(node.Type), v.visitNode(node.Initializer)) } -func (node *ParameterDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewParameterDeclaration(node.Modifiers(), node.DotDotDotToken, node.Name(), node.QuestionToken, node.Type, node.Initializer), node.AsNode(), f.hooks) +func (node *ParameterDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewParameterDeclaration(node.Modifiers(), node.DotDotDotToken, node.Name(), node.QuestionToken, node.Type, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ParameterDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.name != nil && IsThisIdentifier(node.name) { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxSubtreeFacts(node.QuestionToken) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Initializer) + } +} + +func (node *ParameterDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsParameter } func (node *ParameterDeclaration) Name() *DeclarationName { @@ -2899,6 +3267,7 @@ type BindingElement struct { DeclarationBase ExportableBase FlowNodeBase + compositeNodeBase DotDotDotToken *TokenNode // TokenNode. Present on rest element (in object binding pattern) PropertyName *PropertyName // PropertyName. Optional binding property name in object binding pattern name *BindingName // BindingName. Optional (nil for missing element) @@ -2911,7 +3280,7 @@ func (f *NodeFactory) NewBindingElement(dotDotDotToken *TokenNode, propertyName data.PropertyName = propertyName data.name = name data.Initializer = initializer - return newNode(KindBindingElement, data, f.hooks) + return f.newNode(KindBindingElement, data) } func (f *NodeFactory) UpdateBindingElement(node *BindingElement, dotDotDotToken *TokenNode, propertyName *PropertyName, name *BindingName, initializer *Expression) *Node { @@ -2929,14 +3298,21 @@ func (node *BindingElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateBindingElement(node, v.visitToken(node.DotDotDotToken), v.visitNode(node.PropertyName), v.visitNode(node.name), v.visitNode(node.Initializer)) } -func (node *BindingElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBindingElement(node.DotDotDotToken, node.PropertyName, node.Name(), node.Initializer), node.AsNode(), f.hooks) +func (node *BindingElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBindingElement(node.DotDotDotToken, node.PropertyName, node.Name(), node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) } func (node *BindingElement) Name() *DeclarationName { return node.name } +func (node *BindingElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.PropertyName) | + propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Initializer) | + core.IfElse(node.DotDotDotToken != nil, SubtreeContainsRest, SubtreeFactsNone) +} + func IsBindingElement(node *Node) bool { return node.Kind == KindBindingElement } @@ -2952,7 +3328,7 @@ type MissingDeclaration struct { func (f *NodeFactory) NewMissingDeclaration(modifiers *ModifierList) *Node { data := &MissingDeclaration{} data.modifiers = modifiers - return newNode(KindMissingDeclaration, data, f.hooks) + return f.newNode(KindMissingDeclaration, data) } func (f *NodeFactory) UpdateMissingDeclaration(node *MissingDeclaration, modifiers *ModifierList) *Node { @@ -2970,8 +3346,8 @@ func (node *MissingDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateMissingDeclaration(node, v.visitModifiers(node.modifiers)) } -func (node *MissingDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewMissingDeclaration(node.Modifiers()), node.AsNode(), f.hooks) +func (node *MissingDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewMissingDeclaration(node.Modifiers()), node.AsNode(), f.AsNodeFactory().hooks) } // FunctionDeclaration @@ -2982,6 +3358,7 @@ type FunctionDeclaration struct { ExportableBase ModifiersBase FunctionLikeWithBodyBase + compositeNodeBase name *IdentifierNode // IdentifierNode ReturnFlowNode *FlowNode } @@ -2995,7 +3372,7 @@ func (f *NodeFactory) NewFunctionDeclaration(modifiers *ModifierList, asteriskTo data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindFunctionDeclaration, data, f.hooks) + return f.newNode(KindFunctionDeclaration, data) } func (f *NodeFactory) UpdateFunctionDeclaration(node *FunctionDeclaration, modifiers *ModifierList, asteriskToken *TokenNode, name *IdentifierNode, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { @@ -3014,14 +3391,36 @@ func (node *FunctionDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateFunctionDeclaration(node, v.visitModifiers(node.modifiers), v.visitToken(node.AsteriskToken), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *FunctionDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewFunctionDeclaration(node.Modifiers(), node.AsteriskToken, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *FunctionDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewFunctionDeclaration(node.Modifiers(), node.AsteriskToken, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func (node *FunctionDeclaration) Name() *DeclarationName { return node.name } +func (node *FunctionDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.Body == nil || node.ModifierFlags()&ModifierFlagsAmbient != 0 { + return SubtreeContainsTypeScript + } else { + isAsync := node.ModifierFlags()&ModifierFlagsAsync != 0 + isGenerator := node.AsteriskToken != nil + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.AsteriskToken) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Body) | + core.IfElse(isAsync && isGenerator, SubtreeContainsES2018, SubtreeFactsNone) | + core.IfElse(isAsync && !isGenerator, SubtreeContainsES2017, SubtreeFactsNone) + } +} + +func (node *FunctionDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsFunction +} + func IsFunctionDeclaration(node *Node) bool { return node.Kind == KindFunctionDeclaration } @@ -3032,6 +3431,8 @@ type ClassLikeBase struct { DeclarationBase ExportableBase ModifiersBase + LocalsContainerBase + compositeNodeBase name *IdentifierNode // IdentifierNode TypeParameters *NodeList // NodeList[*TypeParameterDeclarationNode]. Optional HeritageClauses *NodeList // NodeList[*HeritageClauseNode]. Optional @@ -3046,6 +3447,18 @@ func (node *ClassLikeBase) ForEachChild(v Visitor) bool { func (node *ClassLikeBase) Name() *DeclarationName { return node.name } func (node *ClassLikeBase) ClassLikeData() *ClassLikeBase { return node } +func (node *ClassLikeBase) computeSubtreeFacts() SubtreeFacts { + if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.HeritageClauses, propagateSubtreeFacts) | + propagateNodeListSubtreeFacts(node.Members, propagateSubtreeFacts) + } +} + // ClassDeclaration type ClassDeclaration struct { @@ -3053,13 +3466,6 @@ type ClassDeclaration struct { ClassLikeBase } -func (f *NodeFactory) UpdateClassDeclaration(node *ClassDeclaration, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, heritageClauses *HeritageClauseList, members *ClassElementList) *Node { - if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || heritageClauses != node.HeritageClauses || members != node.Members { - return updateNode(f.NewClassDeclaration(modifiers, name, typeParameters, heritageClauses, members), node.AsNode(), f.hooks) - } - return node.AsNode() -} - func (f *NodeFactory) NewClassDeclaration(modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, heritageClauses *NodeList, members *NodeList) *Node { data := &ClassDeclaration{} data.modifiers = modifiers @@ -3067,7 +3473,14 @@ func (f *NodeFactory) NewClassDeclaration(modifiers *ModifierList, name *Identif data.TypeParameters = typeParameters data.HeritageClauses = heritageClauses data.Members = members - return newNode(KindClassDeclaration, data, f.hooks) + return f.newNode(KindClassDeclaration, data) +} + +func (f *NodeFactory) UpdateClassDeclaration(node *ClassDeclaration, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, heritageClauses *HeritageClauseList, members *ClassElementList) *Node { + if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || heritageClauses != node.HeritageClauses || members != node.Members { + return updateNode(f.NewClassDeclaration(modifiers, name, typeParameters, heritageClauses, members), node.AsNode(), f.hooks) + } + return node.AsNode() } func (node *ClassDeclaration) VisitEachChild(v *NodeVisitor) *Node { @@ -3082,8 +3495,12 @@ func (node *ClassDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateClassDeclaration(node, modifiers, name, typeParameters, heritageClauses, members) } -func (node *ClassDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewClassDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.hooks) +func (node *ClassDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewClassDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ClassDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsClass } func IsClassDeclaration(node *Node) bool { @@ -3097,13 +3514,6 @@ type ClassExpression struct { ClassLikeBase } -func (f *NodeFactory) UpdateClassExpression(node *ClassExpression, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, heritageClauses *HeritageClauseList, members *ClassElementList) *Node { - if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || heritageClauses != node.HeritageClauses || members != node.Members { - return updateNode(f.NewClassExpression(modifiers, name, typeParameters, heritageClauses, members), node.AsNode(), f.hooks) - } - return node.AsNode() -} - func (f *NodeFactory) NewClassExpression(modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, heritageClauses *NodeList, members *NodeList) *Node { data := &ClassExpression{} data.modifiers = modifiers @@ -3111,7 +3521,14 @@ func (f *NodeFactory) NewClassExpression(modifiers *ModifierList, name *Identifi data.TypeParameters = typeParameters data.HeritageClauses = heritageClauses data.Members = members - return newNode(KindClassExpression, data, f.hooks) + return f.newNode(KindClassExpression, data) +} + +func (f *NodeFactory) UpdateClassExpression(node *ClassExpression, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, heritageClauses *HeritageClauseList, members *ClassElementList) *Node { + if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || heritageClauses != node.HeritageClauses || members != node.Members { + return updateNode(f.NewClassExpression(modifiers, name, typeParameters, heritageClauses, members), node.AsNode(), f.hooks) + } + return node.AsNode() } func (node *ClassExpression) VisitEachChild(v *NodeVisitor) *Node { @@ -3126,8 +3543,12 @@ func (node *ClassExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateClassExpression(node, modifiers, name, typeParameters, heritageClauses, members) } -func (node *ClassExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewClassExpression(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.hooks) +func (node *ClassExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewClassExpression(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ClassExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsClass } func IsClassExpression(node *Node) bool { @@ -3138,6 +3559,7 @@ func IsClassExpression(node *Node) bool { type HeritageClause struct { NodeBase + compositeNodeBase Token Kind Types *NodeList // NodeList[*ExpressionWithTypeArgumentsNode] } @@ -3146,7 +3568,7 @@ func (f *NodeFactory) NewHeritageClause(token Kind, types *NodeList) *Node { data := &HeritageClause{} data.Token = token data.Types = types - return newNode(KindHeritageClause, data, f.hooks) + return f.newNode(KindHeritageClause, data) } func (f *NodeFactory) UpdateHeritageClause(node *HeritageClause, types *ExpressionWithTypeArgumentsList) *Node { @@ -3164,8 +3586,19 @@ func (node *HeritageClause) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateHeritageClause(node, v.visitNodes(node.Types)) } -func (node *HeritageClause) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewHeritageClause(node.Kind, node.Types), node.AsNode(), f.hooks) +func (node *HeritageClause) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewHeritageClause(node.Kind, node.Types), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *HeritageClause) computeSubtreeFacts() SubtreeFacts { + switch node.Token { + case KindExtendsKeyword: + return propagateNodeListSubtreeFacts(node.Types, propagateSubtreeFacts) + case KindImplementsKeyword: + return SubtreeContainsTypeScript + default: + return SubtreeFactsNone + } } func IsHeritageClause(node *Node) bool { @@ -3179,6 +3612,7 @@ type InterfaceDeclaration struct { DeclarationBase ExportableBase ModifiersBase + typeSyntaxBase name *IdentifierNode TypeParameters *NodeList // NodeList[*TypeParameterDeclarationNode]. Optional HeritageClauses *NodeList // NodeList[*HeritageClauseNode]. Optional @@ -3192,7 +3626,7 @@ func (f *NodeFactory) NewInterfaceDeclaration(modifiers *ModifierList, name *Ide data.TypeParameters = typeParameters data.HeritageClauses = heritageClauses data.Members = members - return newNode(KindInterfaceDeclaration, data, f.hooks) + return f.newNode(KindInterfaceDeclaration, data) } func (f *NodeFactory) UpdateInterfaceDeclaration(node *InterfaceDeclaration, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, heritageClauses *HeritageClauseList, members *TypeElementList) *Node { @@ -3211,8 +3645,8 @@ func (node *InterfaceDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateInterfaceDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitNodes(node.HeritageClauses), v.visitNodes(node.Members)) } -func (node *InterfaceDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewInterfaceDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.hooks) +func (node *InterfaceDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewInterfaceDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.HeritageClauses, node.Members), node.AsNode(), f.AsNodeFactory().hooks) } func (node *InterfaceDeclaration) Name() *DeclarationName { return node.name } @@ -3229,18 +3663,23 @@ type TypeAliasDeclaration struct { ExportableBase ModifiersBase LocalsContainerBase + typeSyntaxBase name *IdentifierNode // IdentifierNode TypeParameters *NodeList // NodeList[*TypeParameterDeclarationNode]. Optional Type *TypeNode // TypeNode } -func (f *NodeFactory) NewTypeAliasDeclaration(modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, typeNode *TypeNode) *Node { +func (f *NodeFactory) newTypeOrJSTypeAliasDeclaration(kind Kind, modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, typeNode *TypeNode) *Node { data := &TypeAliasDeclaration{} data.modifiers = modifiers data.name = name data.TypeParameters = typeParameters data.Type = typeNode - return newNode(KindTypeAliasDeclaration, data, f.hooks) + return f.newNode(kind, data) +} + +func (f *NodeFactory) NewTypeAliasDeclaration(modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, typeNode *TypeNode) *Node { + return f.newTypeOrJSTypeAliasDeclaration(KindTypeAliasDeclaration, modifiers, name, typeParameters, typeNode) } func (f *NodeFactory) UpdateTypeAliasDeclaration(node *TypeAliasDeclaration, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, typeNode *TypeNode) *Node { @@ -3255,11 +3694,14 @@ func (node *TypeAliasDeclaration) ForEachChild(v Visitor) bool { } func (node *TypeAliasDeclaration) VisitEachChild(v *NodeVisitor) *Node { + if node.Kind == KindJSTypeAliasDeclaration { + return v.Factory.UpdateJSTypeAliasDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitNode(node.Type)) + } return v.Factory.UpdateTypeAliasDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitNode(node.Type)) } -func (node *TypeAliasDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeAliasDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.Type), node.AsNode(), f.hooks) +func (node *TypeAliasDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeAliasDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func (node *TypeAliasDeclaration) Name() *DeclarationName { return node.name } @@ -3268,11 +3710,31 @@ func IsTypeAliasDeclaration(node *Node) bool { return node.Kind == KindTypeAliasDeclaration } +func IsTypeOrJSTypeAliasDeclaration(node *Node) bool { + return node.Kind == KindTypeAliasDeclaration || node.Kind == KindJSTypeAliasDeclaration +} + +func (f *NodeFactory) NewJSTypeAliasDeclaration(modifiers *ModifierList, name *IdentifierNode, typeParameters *NodeList, typeNode *TypeNode) *Node { + return f.newTypeOrJSTypeAliasDeclaration(KindJSTypeAliasDeclaration, modifiers, name, typeParameters, typeNode) +} + +func (f *NodeFactory) UpdateJSTypeAliasDeclaration(node *TypeAliasDeclaration, modifiers *ModifierList, name *IdentifierNode, typeParameters *TypeParameterList, typeNode *TypeNode) *Node { + if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || typeNode != node.Type { + return updateNode(f.NewJSTypeAliasDeclaration(modifiers, name, typeParameters, typeNode), node.AsNode(), f.hooks) + } + return node.AsNode() +} + +func IsJSTypeAliasDeclaration(node *Node) bool { + return node.Kind == KindJSTypeAliasDeclaration +} + // EnumMember type EnumMember struct { NodeBase NamedMemberBase + compositeNodeBase Initializer *Expression // Expression. Optional } @@ -3280,7 +3742,7 @@ func (f *NodeFactory) NewEnumMember(name *PropertyName, initializer *Expression) data := &EnumMember{} data.name = name data.Initializer = initializer - return newNode(KindEnumMember, data, f.hooks) + return f.newNode(KindEnumMember, data) } func (f *NodeFactory) UpdateEnumMember(node *EnumMember, name *PropertyName, initializer *Expression) *Node { @@ -3298,14 +3760,20 @@ func (node *EnumMember) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateEnumMember(node, v.visitNode(node.name), v.visitNode(node.Initializer)) } -func (node *EnumMember) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewEnumMember(node.Name(), node.Initializer), node.AsNode(), f.hooks) +func (node *EnumMember) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewEnumMember(node.Name(), node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) } func (node *EnumMember) Name() *DeclarationName { return node.name } +func (node *EnumMember) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Initializer) | + SubtreeContainsTypeScript +} + func IsEnumMember(node *Node) bool { return node.Kind == KindEnumMember } @@ -3317,6 +3785,7 @@ type EnumDeclaration struct { DeclarationBase ExportableBase ModifiersBase + compositeNodeBase name *IdentifierNode // IdentifierNode Members *NodeList // NodeList[*EnumMemberNode] } @@ -3326,7 +3795,7 @@ func (f *NodeFactory) NewEnumDeclaration(modifiers *ModifierList, name *Identifi data.modifiers = modifiers data.name = name data.Members = members - return newNode(KindEnumDeclaration, data, f.hooks) + return f.newNode(KindEnumDeclaration, data) } func (f *NodeFactory) UpdateEnumDeclaration(node *EnumDeclaration, modifiers *ModifierList, name *IdentifierNode, members *EnumMemberList) *Node { @@ -3344,14 +3813,25 @@ func (node *EnumDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateEnumDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.Members)) } -func (node *EnumDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewEnumDeclaration(node.Modifiers(), node.Name(), node.Members), node.AsNode(), f.hooks) +func (node *EnumDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewEnumDeclaration(node.Modifiers(), node.Name(), node.Members), node.AsNode(), f.AsNodeFactory().hooks) } func (node *EnumDeclaration) Name() *DeclarationName { return node.name } +func (node *EnumDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateNodeListSubtreeFacts(node.Members, propagateSubtreeFacts) | + SubtreeContainsTypeScript + } +} + func IsEnumDeclaration(node *Node) bool { return node.Kind == KindEnumDeclaration } @@ -3360,13 +3840,14 @@ func IsEnumDeclaration(node *Node) bool { type ModuleBlock struct { StatementBase + compositeNodeBase Statements *NodeList // NodeList[*Statement] } func (f *NodeFactory) NewModuleBlock(statements *NodeList) *Node { data := &ModuleBlock{} data.Statements = statements - return newNode(KindModuleBlock, data, f.hooks) + return f.newNode(KindModuleBlock, data) } func (f *NodeFactory) UpdateModuleBlock(node *ModuleBlock, statements *StatementList) *Node { @@ -3384,8 +3865,12 @@ func (node *ModuleBlock) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateModuleBlock(node, v.visitNodes(node.Statements)) } -func (node *ModuleBlock) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewModuleBlock(node.Statements), node.AsNode(), f.hooks) +func (node *ModuleBlock) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewModuleBlock(node.Statements), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ModuleBlock) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts) } func IsModuleBlock(node *Node) bool { @@ -3401,22 +3886,24 @@ type ModuleDeclaration struct { ModifiersBase LocalsContainerBase BodyBase - name *ModuleName // ModuleName + compositeNodeBase + name *ModuleName // ModuleName + Keyword Kind // KindModuleKeyword, KindNamespaceKeyword, KindGlobalKeyword (global augmentation) } -func (f *NodeFactory) NewModuleDeclaration(modifiers *ModifierList, name *ModuleName, body *ModuleBody, flags NodeFlags) *Node { +func (f *NodeFactory) NewModuleDeclaration(modifiers *ModifierList, keyword Kind, name *ModuleName, body *ModuleBody) *Node { data := &ModuleDeclaration{} data.modifiers = modifiers + data.Keyword = keyword data.name = name data.Body = body - node := newNode(KindModuleDeclaration, data, f.hooks) - node.Flags |= flags & (NodeFlagsNamespace | NodeFlagsNestedNamespace | NodeFlagsGlobalAugmentation) + node := f.newNode(KindModuleDeclaration, data) return node } -func (f *NodeFactory) UpdateModuleDeclaration(node *ModuleDeclaration, modifiers *ModifierList, name *ModuleName, body *ModuleBody) *Node { - if modifiers != node.modifiers || name != node.name || body != node.Body { - return updateNode(f.NewModuleDeclaration(modifiers, name, body, node.Flags), node.AsNode(), f.hooks) +func (f *NodeFactory) UpdateModuleDeclaration(node *ModuleDeclaration, modifiers *ModifierList, keyword Kind, name *ModuleName, body *ModuleBody) *Node { + if modifiers != node.modifiers || keyword != node.Keyword || name != node.name || body != node.Body { + return updateNode(f.NewModuleDeclaration(modifiers, keyword, name, body), node.AsNode(), f.hooks) } return node.AsNode() } @@ -3426,28 +3913,65 @@ func (node *ModuleDeclaration) ForEachChild(v Visitor) bool { } func (node *ModuleDeclaration) VisitEachChild(v *NodeVisitor) *Node { - return v.Factory.UpdateModuleDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNode(node.Body)) + return v.Factory.UpdateModuleDeclaration(node, v.visitModifiers(node.modifiers), node.Keyword, v.visitNode(node.name), v.visitNode(node.Body)) } -func (node *ModuleDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewModuleDeclaration(node.Modifiers(), node.Name(), node.Body, node.Flags), node.AsNode(), f.hooks) +func (node *ModuleDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewModuleDeclaration(node.Modifiers(), node.Keyword, node.Name(), node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ModuleDeclaration) Name() *DeclarationName { return node.name } +func (node *ModuleDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.ModifierFlags()&ModifierFlagsAmbient != 0 { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Body) | + SubtreeContainsTypeScript + } +} + +func (node *ModuleDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsModule +} + func IsModuleDeclaration(node *Node) bool { return node.Kind == KindModuleDeclaration } -// ModuleEqualsDeclaration +// NotEmittedStatement + +// Represents a statement that is elided as part of a transformation to emit comments on a +// not-emitted node. +type NotEmittedStatement struct { + StatementBase +} + +func (f *NodeFactory) NewNotEmittedStatement() *Node { + data := &NotEmittedStatement{} + return newNode(KindNotEmittedStatement, data, f.hooks) +} + +func (node *NotEmittedStatement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNotEmittedStatement(), node.AsNode(), f.AsNodeFactory().hooks) +} + +func IsNotEmittedStatement(node *Node) bool { + return node.Kind == KindNotEmittedStatement +} + +// ImportEqualsDeclaration type ImportEqualsDeclaration struct { StatementBase DeclarationBase ExportableBase ModifiersBase + compositeNodeBase IsTypeOnly bool name *IdentifierNode // IdentifierNode // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external @@ -3461,7 +3985,7 @@ func (f *NodeFactory) NewImportEqualsDeclaration(modifiers *ModifierList, isType data.IsTypeOnly = isTypeOnly data.name = name data.ModuleReference = moduleReference - return newNode(KindImportEqualsDeclaration, data, f.hooks) + return f.newNode(KindImportEqualsDeclaration, data) } func (f *NodeFactory) UpdateImportEqualsDeclaration(node *ImportEqualsDeclaration, modifiers *ModifierList, isTypeOnly bool, name *IdentifierNode, moduleReference *ModuleReference) *Node { @@ -3479,14 +4003,24 @@ func (node *ImportEqualsDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportEqualsDeclaration(node, v.visitModifiers(node.modifiers), node.IsTypeOnly, v.visitNode(node.name), v.visitNode(node.ModuleReference)) } -func (node *ImportEqualsDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportEqualsDeclaration(node.Modifiers(), node.IsTypeOnly, node.Name(), node.ModuleReference), node.AsNode(), f.hooks) +func (node *ImportEqualsDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportEqualsDeclaration(node.Modifiers(), node.IsTypeOnly, node.Name(), node.ModuleReference), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ImportEqualsDeclaration) Name() *DeclarationName { return node.name } +func (node *ImportEqualsDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.IsTypeOnly || !IsExternalModuleReference(node.ModuleReference) { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.ModuleReference) + } +} + func IsImportEqualsDeclaration(node *Node) bool { return node.Kind == KindImportEqualsDeclaration } @@ -3496,6 +4030,7 @@ func IsImportEqualsDeclaration(node *Node) bool { type ImportDeclaration struct { StatementBase ModifiersBase + compositeNodeBase ImportClause *ImportClauseNode // ImportClauseNode. Optional ModuleSpecifier *Expression // Expression Attributes *ImportAttributesNode // ImportAttributesNode. Optional @@ -3507,7 +4042,7 @@ func (f *NodeFactory) NewImportDeclaration(modifiers *ModifierList, importClause data.ImportClause = importClause data.ModuleSpecifier = moduleSpecifier data.Attributes = attributes - return newNode(KindImportDeclaration, data, f.hooks) + return f.newNode(KindImportDeclaration, data) } func (f *NodeFactory) UpdateImportDeclaration(node *ImportDeclaration, modifiers *ModifierList, importClause *ImportClauseNode, moduleSpecifier *Expression, attributes *ImportAttributesNode) *Node { @@ -3525,8 +4060,15 @@ func (node *ImportDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.ImportClause), v.visitNode(node.ModuleSpecifier), v.visitNode(node.Attributes)) } -func (node *ImportDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportDeclaration(node.Modifiers(), node.ImportClause, node.ModuleSpecifier, node.Attributes), node.AsNode(), f.hooks) +func (node *ImportDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportDeclaration(node.Modifiers(), node.ImportClause, node.ModuleSpecifier, node.Attributes), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ImportDeclaration) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.ImportClause) | + propagateSubtreeFacts(node.ModuleSpecifier) | + propagateSubtreeFacts(node.Attributes) } func IsImportDeclaration(node *Node) bool { @@ -3539,6 +4081,7 @@ type ImportSpecifier struct { NodeBase DeclarationBase ExportableBase + compositeNodeBase IsTypeOnly bool PropertyName *ModuleExportName // ModuleExportName. Optional name *IdentifierNode // IdentifierNode @@ -3549,7 +4092,7 @@ func (f *NodeFactory) NewImportSpecifier(isTypeOnly bool, propertyName *ModuleEx data.IsTypeOnly = isTypeOnly data.PropertyName = propertyName data.name = name - return newNode(KindImportSpecifier, data, f.hooks) + return f.newNode(KindImportSpecifier, data) } func (f *NodeFactory) UpdateImportSpecifier(node *ImportSpecifier, isTypeOnly bool, propertyName *ModuleExportName, name *IdentifierNode) *Node { @@ -3567,14 +4110,23 @@ func (node *ImportSpecifier) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportSpecifier(node, node.IsTypeOnly, v.visitNode(node.PropertyName), v.visitNode(node.name)) } -func (node *ImportSpecifier) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportSpecifier(node.IsTypeOnly, node.PropertyName, node.Name()), node.AsNode(), f.hooks) +func (node *ImportSpecifier) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportSpecifier(node.IsTypeOnly, node.PropertyName, node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ImportSpecifier) Name() *DeclarationName { return node.name } +func (node *ImportSpecifier) computeSubtreeFacts() SubtreeFacts { + if node.IsTypeOnly { + return SubtreeContainsTypeScript + } else { + return propagateSubtreeFacts(node.PropertyName) | + propagateSubtreeFacts(node.name) + } +} + func IsImportSpecifier(node *Node) bool { return node.Kind == KindImportSpecifier } @@ -3589,7 +4141,7 @@ type ExternalModuleReference struct { func (f *NodeFactory) NewExternalModuleReference(expression *Expression) *Node { data := &ExternalModuleReference{} data.Expression = expression - return newNode(KindExternalModuleReference, data, f.hooks) + return f.newNode(KindExternalModuleReference, data) } func (f *NodeFactory) UpdateExternalModuleReference(node *ExternalModuleReference, expression *Expression) *Node { @@ -3607,8 +4159,12 @@ func (node *ExternalModuleReference) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateExternalModuleReference(node, v.visitNode(node.Expression)) } -func (node *ExternalModuleReference) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExternalModuleReference(node.Expression), node.AsNode(), f.hooks) +func (node *ExternalModuleReference) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewExternalModuleReference(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ExternalModuleReference) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsExternalModuleReference(node *Node) bool { @@ -3621,6 +4177,7 @@ type ImportClause struct { NodeBase DeclarationBase ExportableBase + compositeNodeBase IsTypeOnly bool NamedBindings *NamedImportBindings // NamedImportBindings. Optional, named bindings name *IdentifierNode // IdentifierNode. Optional, default binding @@ -3631,7 +4188,7 @@ func (f *NodeFactory) NewImportClause(isTypeOnly bool, name *IdentifierNode, nam data.IsTypeOnly = isTypeOnly data.name = name data.NamedBindings = namedBindings - return newNode(KindImportClause, data, f.hooks) + return f.newNode(KindImportClause, data) } func (f *NodeFactory) UpdateImportClause(node *ImportClause, isTypeOnly bool, name *IdentifierNode, namedBindings *NamedImportBindings) *Node { @@ -3649,14 +4206,23 @@ func (node *ImportClause) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportClause(node, node.IsTypeOnly, v.visitNode(node.name), v.visitNode(node.NamedBindings)) } -func (node *ImportClause) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportClause(node.IsTypeOnly, node.Name(), node.NamedBindings), node.AsNode(), f.hooks) +func (node *ImportClause) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportClause(node.IsTypeOnly, node.Name(), node.NamedBindings), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ImportClause) Name() *DeclarationName { return node.name } +func (node *ImportClause) computeSubtreeFacts() SubtreeFacts { + if node.IsTypeOnly { + return SubtreeContainsTypeScript + } else { + return propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.NamedBindings) + } +} + func IsImportClause(node *Node) bool { return node.Kind == KindImportClause } @@ -3673,7 +4239,7 @@ type NamespaceImport struct { func (f *NodeFactory) NewNamespaceImport(name *IdentifierNode) *Node { data := &NamespaceImport{} data.name = name - return newNode(KindNamespaceImport, data, f.hooks) + return f.newNode(KindNamespaceImport, data) } func (f *NodeFactory) UpdateNamespaceImport(node *NamespaceImport, name *IdentifierNode) *Node { @@ -3691,14 +4257,18 @@ func (node *NamespaceImport) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamespaceImport(node, v.visitNode(node.name)) } -func (node *NamespaceImport) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamespaceImport(node.Name()), node.AsNode(), f.hooks) +func (node *NamespaceImport) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamespaceImport(node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *NamespaceImport) Name() *DeclarationName { return node.name } +func (node *NamespaceImport) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) +} + func IsNamespaceImport(node *Node) bool { return node.Kind == KindNamespaceImport } @@ -3707,13 +4277,14 @@ func IsNamespaceImport(node *Node) bool { type NamedImports struct { NodeBase + compositeNodeBase Elements *ImportSpecifierList // NodeList[*ImportSpecifierNode] } func (f *NodeFactory) NewNamedImports(elements *ImportSpecifierList) *Node { data := &NamedImports{} data.Elements = elements - return newNode(KindNamedImports, data, f.hooks) + return f.newNode(KindNamedImports, data) } func (f *NodeFactory) UpdateNamedImports(node *NamedImports, elements *ImportSpecifierList) *Node { @@ -3731,8 +4302,12 @@ func (node *NamedImports) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamedImports(node, v.visitNodes(node.Elements)) } -func (node *NamedImports) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamedImports(node.Elements), node.AsNode(), f.hooks) +func (node *NamedImports) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamedImports(node.Elements), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *NamedImports) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Elements, propagateSubtreeFacts) } func IsNamedImports(node *Node) bool { @@ -3743,25 +4318,35 @@ func IsNamedImports(node *Node) bool { // This is either an `export =` or an `export default` declaration. // Unless `isExportEquals` is set, this node was parsed as an `export default`. +// If Kind is KindJSExportAssignment, it is a synthetic declaration for `module.exports =`. type ExportAssignment struct { StatementBase DeclarationBase ModifiersBase + compositeNodeBase IsExportEquals bool Expression *Expression // Expression } -func (f *NodeFactory) NewExportAssignment(modifiers *ModifierList, isExportEquals bool, expression *Expression) *Node { +func (f *NodeFactory) newExportOrJSExportAssignment(kind Kind, modifiers *ModifierList, isExportEquals bool, expression *Expression) *Node { data := &ExportAssignment{} data.modifiers = modifiers data.IsExportEquals = isExportEquals data.Expression = expression - return newNode(KindExportAssignment, data, f.hooks) + return f.newNode(kind, data) +} + +func (f *NodeFactory) NewExportAssignment(modifiers *ModifierList, isExportEquals bool, expression *Expression) *Node { + return f.newExportOrJSExportAssignment(KindExportAssignment, modifiers, isExportEquals, expression) +} + +func (f *NodeFactory) NewJSExportAssignment(expression *Expression) *Node { + return f.newExportOrJSExportAssignment(KindJSExportAssignment, nil /*modifiers*/, true, expression) } func (f *NodeFactory) UpdateExportAssignment(node *ExportAssignment, modifiers *ModifierList, expression *Expression) *Node { if modifiers != node.modifiers || expression != node.Expression { - return updateNode(f.NewExportAssignment(modifiers, node.IsExportEquals, expression), node.AsNode(), f.hooks) + return updateNode(f.newExportOrJSExportAssignment(node.Kind, modifiers, node.IsExportEquals, expression), node.AsNode(), f.hooks) } return node.AsNode() } @@ -3770,16 +4355,74 @@ func (node *ExportAssignment) ForEachChild(v Visitor) bool { return visitModifiers(v, node.modifiers) || visit(v, node.Expression) } -func (node *ExportAssignment) VisitEachChild(v *NodeVisitor) *Node { - return v.Factory.UpdateExportAssignment(node, v.visitModifiers(node.modifiers), v.visitNode(node.Expression)) +func (node *ExportAssignment) VisitEachChild(v *NodeVisitor) *Node { + return v.Factory.UpdateExportAssignment(node, v.visitModifiers(node.modifiers), v.visitNode(node.Expression)) +} + +func (node *ExportAssignment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().newExportOrJSExportAssignment(node.Kind, node.Modifiers(), node.IsExportEquals, node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ExportAssignment) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | propagateSubtreeFacts(node.Expression) +} + +func IsExportAssignment(node *Node) bool { + return node.Kind == KindExportAssignment +} + +func IsJSExportAssignment(node *Node) bool { + return node.Kind == KindJSExportAssignment +} + +func IsAnyExportAssignment(node *Node) bool { + return node.Kind == KindExportAssignment || node.Kind == KindJSExportAssignment +} + +// CommonJSExport + +type CommonJSExport struct { + StatementBase + DeclarationBase + ExportableBase + ModifiersBase + name *IdentifierNode + Initializer *Expression +} + +func (f *NodeFactory) NewCommonJSExport(modifiers *ModifierList, name *IdentifierNode, initializer *Expression) *Node { + data := &CommonJSExport{} + data.modifiers = modifiers + data.name = name + data.Initializer = initializer + return newNode(KindCommonJSExport, data, f.hooks) +} + +func (f *NodeFactory) UpdateCommonJSExport(node *CommonJSExport, modifiers *ModifierList, name *IdentifierNode, initializer *Expression) *Node { + if modifiers != node.modifiers || initializer != node.Initializer || name != node.name { + return updateNode(f.NewCommonJSExport(node.modifiers, name, initializer), node.AsNode(), f.hooks) + } + return node.AsNode() +} + +func (node *CommonJSExport) ForEachChild(v Visitor) bool { + return visitModifiers(v, node.modifiers) || visit(v, node.name) || visit(v, node.Initializer) +} + +func (node *CommonJSExport) VisitEachChild(v *NodeVisitor) *Node { + return v.Factory.UpdateCommonJSExport(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNode(node.Initializer)) +} + +func (node *CommonJSExport) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCommonJSExport(node.Modifiers(), node.name, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *ExportAssignment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExportAssignment(node.Modifiers(), node.IsExportEquals, node.Expression), node.AsNode(), f.hooks) +func IsCommonJSExport(node *Node) bool { + return node.Kind == KindCommonJSExport } -func IsExportAssignment(node *Node) bool { - return node.Kind == KindExportAssignment +func (node *CommonJSExport) Name() *DeclarationName { + return node.name } // NamespaceExportDeclaration @@ -3788,6 +4431,7 @@ type NamespaceExportDeclaration struct { StatementBase DeclarationBase ModifiersBase + typeSyntaxBase name *IdentifierNode // IdentifierNode } @@ -3795,7 +4439,7 @@ func (f *NodeFactory) NewNamespaceExportDeclaration(modifiers *ModifierList, nam data := &NamespaceExportDeclaration{} data.modifiers = modifiers data.name = name - return newNode(KindNamespaceExportDeclaration, data, f.hooks) + return f.newNode(KindNamespaceExportDeclaration, data) } func (f *NodeFactory) UpdateNamespaceExportDeclaration(node *NamespaceExportDeclaration, modifiers *ModifierList, name *IdentifierNode) *Node { @@ -3813,8 +4457,8 @@ func (node *NamespaceExportDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamespaceExportDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name)) } -func (node *NamespaceExportDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamespaceExportDeclaration(node.Modifiers(), node.Name()), node.AsNode(), f.hooks) +func (node *NamespaceExportDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamespaceExportDeclaration(node.Modifiers(), node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *NamespaceExportDeclaration) Name() *DeclarationName { @@ -3831,6 +4475,7 @@ type ExportDeclaration struct { StatementBase DeclarationBase ModifiersBase + compositeNodeBase IsTypeOnly bool ExportClause *NamedExportBindings // NamedExportBindings. Optional ModuleSpecifier *Expression // Expression. Optional @@ -3844,7 +4489,7 @@ func (f *NodeFactory) NewExportDeclaration(modifiers *ModifierList, isTypeOnly b data.ExportClause = exportClause data.ModuleSpecifier = moduleSpecifier data.Attributes = attributes - return newNode(KindExportDeclaration, data, f.hooks) + return f.newNode(KindExportDeclaration, data) } func (f *NodeFactory) UpdateExportDeclaration(node *ExportDeclaration, modifiers *ModifierList, isTypeOnly bool, exportClause *NamedExportBindings, moduleSpecifier *Expression, attributes *ImportAttributesNode) *Node { @@ -3862,8 +4507,16 @@ func (node *ExportDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateExportDeclaration(node, v.visitModifiers(node.modifiers), node.IsTypeOnly, v.visitNode(node.ExportClause), v.visitNode(node.ModuleSpecifier), v.visitNode(node.Attributes)) } -func (node *ExportDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExportDeclaration(node.Modifiers(), node.IsTypeOnly, node.ExportClause, node.ModuleSpecifier, node.Attributes), node.AsNode(), f.hooks) +func (node *ExportDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewExportDeclaration(node.Modifiers(), node.IsTypeOnly, node.ExportClause, node.ModuleSpecifier, node.Attributes), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ExportDeclaration) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.ExportClause) | + propagateSubtreeFacts(node.ModuleSpecifier) | + propagateSubtreeFacts(node.Attributes) | + core.IfElse(node.IsTypeOnly, SubtreeContainsTypeScript, SubtreeFactsNone) } func IsExportDeclaration(node *Node) bool { @@ -3881,7 +4534,7 @@ type NamespaceExport struct { func (f *NodeFactory) NewNamespaceExport(name *ModuleExportName) *Node { data := &NamespaceExport{} data.name = name - return newNode(KindNamespaceExport, data, f.hooks) + return f.newNode(KindNamespaceExport, data) } func (f *NodeFactory) UpdateNamespaceExport(node *NamespaceExport, name *ModuleExportName) *Node { @@ -3899,14 +4552,18 @@ func (node *NamespaceExport) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamespaceExport(node, v.visitNode(node.name)) } -func (node *NamespaceExport) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamespaceExport(node.Name()), node.AsNode(), f.hooks) +func (node *NamespaceExport) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamespaceExport(node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *NamespaceExport) Name() *DeclarationName { return node.name } +func (node *NamespaceExport) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) +} + func IsNamespaceExport(node *Node) bool { return node.Kind == KindNamespaceExport } @@ -3915,13 +4572,14 @@ func IsNamespaceExport(node *Node) bool { type NamedExports struct { NodeBase - Elements *NodeList // NodeList[*ExportSpecifierNode] + compositeNodeBase + Elements *ExportSpecifierList // NodeList[*ExportSpecifierNode] } func (f *NodeFactory) NewNamedExports(elements *NodeList) *Node { data := &NamedExports{} data.Elements = elements - return newNode(KindNamedExports, data, f.hooks) + return f.newNode(KindNamedExports, data) } func (f *NodeFactory) UpdateNamedExports(node *NamedExports, elements *ExportSpecifierList) *Node { @@ -3939,8 +4597,12 @@ func (node *NamedExports) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamedExports(node, v.visitNodes(node.Elements)) } -func (node *NamedExports) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamedExports(node.Elements), node.AsNode(), f.hooks) +func (node *NamedExports) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamedExports(node.Elements), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *NamedExports) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Elements, propagateSubtreeFacts) } func IsNamedExports(node *Node) bool { @@ -3953,6 +4615,7 @@ type ExportSpecifier struct { NodeBase DeclarationBase ExportableBase + compositeNodeBase IsTypeOnly bool PropertyName *ModuleExportName // ModuleExportName. Optional, name preceding 'as' keyword name *ModuleExportName // ModuleExportName @@ -3963,7 +4626,7 @@ func (f *NodeFactory) NewExportSpecifier(isTypeOnly bool, propertyName *ModuleEx data.IsTypeOnly = isTypeOnly data.PropertyName = propertyName data.name = name - return newNode(KindExportSpecifier, data, f.hooks) + return f.newNode(KindExportSpecifier, data) } func (f *NodeFactory) UpdateExportSpecifier(node *ExportSpecifier, isTypeOnly bool, propertyName *ModuleExportName, name *ModuleExportName) *Node { @@ -3981,14 +4644,23 @@ func (node *ExportSpecifier) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateExportSpecifier(node, node.IsTypeOnly, v.visitNode(node.PropertyName), v.visitNode(node.name)) } -func (node *ExportSpecifier) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExportSpecifier(node.IsTypeOnly, node.PropertyName, node.Name()), node.AsNode(), f.hooks) +func (node *ExportSpecifier) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewExportSpecifier(node.IsTypeOnly, node.PropertyName, node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ExportSpecifier) Name() *DeclarationName { return node.name } +func (node *ExportSpecifier) computeSubtreeFacts() SubtreeFacts { + if node.IsTypeOnly { + return SubtreeContainsTypeScript + } else { + return propagateSubtreeFacts(node.PropertyName) | + propagateSubtreeFacts(node.name) + } +} + func IsExportSpecifier(node *Node) bool { return node.Kind == KindExportSpecifier } @@ -4021,6 +4693,7 @@ type CallSignatureDeclaration struct { DeclarationBase FunctionLikeBase TypeElementBase + typeSyntaxBase } func (f *NodeFactory) NewCallSignatureDeclaration(typeParameters *NodeList, parameters *NodeList, returnType *TypeNode) *Node { @@ -4028,7 +4701,7 @@ func (f *NodeFactory) NewCallSignatureDeclaration(typeParameters *NodeList, para data.TypeParameters = typeParameters data.Parameters = parameters data.Type = returnType - return newNode(KindCallSignature, data, f.hooks) + return f.newNode(KindCallSignature, data) } func (f *NodeFactory) UpdateCallSignatureDeclaration(node *CallSignatureDeclaration, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -4046,8 +4719,8 @@ func (node *CallSignatureDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateCallSignatureDeclaration(node, v.visitNodes(node.TypeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *CallSignatureDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewCallSignatureDeclaration(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *CallSignatureDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCallSignatureDeclaration(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsCallSignatureDeclaration(node *Node) bool { @@ -4061,6 +4734,7 @@ type ConstructSignatureDeclaration struct { DeclarationBase FunctionLikeBase TypeElementBase + typeSyntaxBase } func (f *NodeFactory) NewConstructSignatureDeclaration(typeParameters *NodeList, parameters *NodeList, returnType *TypeNode) *Node { @@ -4068,7 +4742,7 @@ func (f *NodeFactory) NewConstructSignatureDeclaration(typeParameters *NodeList, data.TypeParameters = typeParameters data.Parameters = parameters data.Type = returnType - return newNode(KindConstructSignature, data, f.hooks) + return f.newNode(KindConstructSignature, data) } func (f *NodeFactory) UpdateConstructSignatureDeclaration(node *ConstructSignatureDeclaration, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -4086,8 +4760,8 @@ func (node *ConstructSignatureDeclaration) VisitEachChild(v *NodeVisitor) *Node return v.Factory.UpdateConstructSignatureDeclaration(node, v.visitNodes(node.TypeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *ConstructSignatureDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewConstructSignatureDeclaration(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *ConstructSignatureDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewConstructSignatureDeclaration(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsConstructSignatureDeclaration(node *Node) bool { @@ -4102,6 +4776,7 @@ type ConstructorDeclaration struct { ModifiersBase FunctionLikeWithBodyBase ClassElementBase + compositeNodeBase ReturnFlowNode *FlowNode } @@ -4112,7 +4787,7 @@ func (f *NodeFactory) NewConstructorDeclaration(modifiers *ModifierList, typePar data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindConstructor, data, f.hooks) + return f.newNode(KindConstructor, data) } func (f *NodeFactory) UpdateConstructorDeclaration(node *ConstructorDeclaration, modifiers *ModifierList, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { @@ -4130,8 +4805,24 @@ func (node *ConstructorDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateConstructorDeclaration(node, v.visitModifiers(node.modifiers), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *ConstructorDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewConstructorDeclaration(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *ConstructorDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewConstructorDeclaration(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ConstructorDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.Body == nil { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Body) + } +} + +func (node *ConstructorDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsConstructor } func IsConstructorDeclaration(node *Node) bool { @@ -4148,6 +4839,7 @@ type AccessorDeclarationBase struct { TypeElementBase ClassElementBase ObjectLiteralElementBase + compositeNodeBase } func (node *AccessorDeclarationBase) ForEachChild(v Visitor) bool { @@ -4157,19 +4849,30 @@ func (node *AccessorDeclarationBase) ForEachChild(v Visitor) bool { func (node *AccessorDeclarationBase) IsAccessorDeclaration() {} +func (node *AccessorDeclarationBase) computeSubtreeFacts() SubtreeFacts { + if node.Body == nil { + return SubtreeContainsTypeScript + } else { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Body) + } +} + +func (node *AccessorDeclarationBase) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsAccessor | + propagateSubtreeFacts(node.name) +} + // GetAccessorDeclaration type GetAccessorDeclaration struct { AccessorDeclarationBase } -func (f *NodeFactory) UpdateGetAccessorDeclaration(node *GetAccessorDeclaration, modifiers *ModifierList, name *PropertyName, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { - if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || parameters != node.Parameters || returnType != node.Type || body != node.Body { - return updateNode(f.NewGetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body), node.AsNode(), f.hooks) - } - return node.AsNode() -} - func (f *NodeFactory) NewGetAccessorDeclaration(modifiers *ModifierList, name *PropertyName, typeParameters *NodeList, parameters *NodeList, returnType *TypeNode, body *BlockNode) *Node { data := &GetAccessorDeclaration{} data.modifiers = modifiers @@ -4178,15 +4881,22 @@ func (f *NodeFactory) NewGetAccessorDeclaration(modifiers *ModifierList, name *P data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindGetAccessor, data, f.hooks) + return f.newNode(KindGetAccessor, data) +} + +func (f *NodeFactory) UpdateGetAccessorDeclaration(node *GetAccessorDeclaration, modifiers *ModifierList, name *PropertyName, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { + if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || parameters != node.Parameters || returnType != node.Type || body != node.Body { + return updateNode(f.NewGetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body), node.AsNode(), f.hooks) + } + return node.AsNode() } func (node *GetAccessorDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateGetAccessorDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *GetAccessorDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewGetAccessorDeclaration(node.modifiers, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *GetAccessorDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewGetAccessorDeclaration(node.modifiers, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func IsGetAccessorDeclaration(node *Node) bool { @@ -4199,13 +4909,6 @@ type SetAccessorDeclaration struct { AccessorDeclarationBase } -func (f *NodeFactory) UpdateSetAccessorDeclaration(node *SetAccessorDeclaration, modifiers *ModifierList, name *PropertyName, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { - if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || parameters != node.Parameters || returnType != node.Type || body != node.Body { - return updateNode(f.NewSetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body), node.AsNode(), f.hooks) - } - return node.AsNode() -} - func (f *NodeFactory) NewSetAccessorDeclaration(modifiers *ModifierList, name *PropertyName, typeParameters *NodeList, parameters *NodeList, returnType *TypeNode, body *BlockNode) *Node { data := &SetAccessorDeclaration{} data.modifiers = modifiers @@ -4214,15 +4917,22 @@ func (f *NodeFactory) NewSetAccessorDeclaration(modifiers *ModifierList, name *P data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindSetAccessor, data, f.hooks) + return f.newNode(KindSetAccessor, data) +} + +func (f *NodeFactory) UpdateSetAccessorDeclaration(node *SetAccessorDeclaration, modifiers *ModifierList, name *PropertyName, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { + if modifiers != node.modifiers || name != node.name || typeParameters != node.TypeParameters || parameters != node.Parameters || returnType != node.Type || body != node.Body { + return updateNode(f.NewSetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body), node.AsNode(), f.hooks) + } + return node.AsNode() } func (node *SetAccessorDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateSetAccessorDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *SetAccessorDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSetAccessorDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *SetAccessorDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSetAccessorDeclaration(node.Modifiers(), node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func IsSetAccessorDeclaration(node *Node) bool { @@ -4238,6 +4948,7 @@ type IndexSignatureDeclaration struct { FunctionLikeBase TypeElementBase ClassElementBase + typeSyntaxBase } func (f *NodeFactory) NewIndexSignatureDeclaration(modifiers *ModifierList, parameters *NodeList, returnType *TypeNode) *Node { @@ -4245,7 +4956,7 @@ func (f *NodeFactory) NewIndexSignatureDeclaration(modifiers *ModifierList, para data.modifiers = modifiers data.Parameters = parameters data.Type = returnType - return newNode(KindIndexSignature, data, f.hooks) + return f.newNode(KindIndexSignature, data) } func (f *NodeFactory) UpdateIndexSignatureDeclaration(node *IndexSignatureDeclaration, modifiers *ModifierList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -4263,8 +4974,8 @@ func (node *IndexSignatureDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateIndexSignatureDeclaration(node, v.visitModifiers(node.modifiers), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *IndexSignatureDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewIndexSignatureDeclaration(node.Modifiers(), node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *IndexSignatureDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewIndexSignatureDeclaration(node.Modifiers(), node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsIndexSignatureDeclaration(node *Node) bool { @@ -4278,6 +4989,7 @@ type MethodSignatureDeclaration struct { NamedMemberBase FunctionLikeBase TypeElementBase + typeSyntaxBase } func (f *NodeFactory) NewMethodSignatureDeclaration(modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, typeParameters *NodeList, parameters *NodeList, returnType *TypeNode) *Node { @@ -4288,7 +5000,7 @@ func (f *NodeFactory) NewMethodSignatureDeclaration(modifiers *ModifierList, nam data.TypeParameters = typeParameters data.Parameters = parameters data.Type = returnType - return newNode(KindMethodSignature, data, f.hooks) + return f.newNode(KindMethodSignature, data) } func (f *NodeFactory) UpdateMethodSignatureDeclaration(node *MethodSignatureDeclaration, modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -4307,8 +5019,8 @@ func (node *MethodSignatureDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateMethodSignatureDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitNodes(node.TypeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *MethodSignatureDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewMethodSignatureDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *MethodSignatureDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewMethodSignatureDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsMethodSignatureDeclaration(node *Node) bool { @@ -4324,6 +5036,7 @@ type MethodDeclaration struct { FlowNodeBase ClassElementBase ObjectLiteralElementBase + compositeNodeBase } func (f *NodeFactory) NewMethodDeclaration(modifiers *ModifierList, asteriskToken *TokenNode, name *PropertyName, postfixToken *TokenNode, typeParameters *NodeList, parameters *NodeList, returnType *TypeNode, body *BlockNode) *Node { @@ -4336,7 +5049,7 @@ func (f *NodeFactory) NewMethodDeclaration(modifiers *ModifierList, asteriskToke data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindMethodDeclaration, data, f.hooks) + return f.newNode(KindMethodDeclaration, data) } func (f *NodeFactory) UpdateMethodDeclaration(node *MethodDeclaration, modifiers *ModifierList, asteriskToken *TokenNode, name *PropertyName, postfixToken *TokenNode, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { @@ -4355,8 +5068,32 @@ func (node *MethodDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateMethodDeclaration(node, v.visitModifiers(node.modifiers), v.visitToken(node.AsteriskToken), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *MethodDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewMethodDeclaration(node.Modifiers(), node.AsteriskToken, node.Name(), node.PostfixToken, node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *MethodDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewMethodDeclaration(node.Modifiers(), node.AsteriskToken, node.Name(), node.PostfixToken, node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *MethodDeclaration) computeSubtreeFacts() SubtreeFacts { + if node.Body == nil { + return SubtreeContainsTypeScript + } else { + isAsync := node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAsync != 0 + isGenerator := node.AsteriskToken != nil + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.AsteriskToken) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxSubtreeFacts(node.PostfixToken) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateSubtreeFacts(node.Body) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + core.IfElse(isAsync && isGenerator, SubtreeContainsES2018, SubtreeFactsNone) | + core.IfElse(isAsync && !isGenerator, SubtreeContainsES2017, SubtreeFactsNone) + } +} + +func (node *MethodDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsMethod | + propagateSubtreeFacts(node.name) } func IsMethodDeclaration(node *Node) bool { @@ -4369,6 +5106,7 @@ type PropertySignatureDeclaration struct { NodeBase NamedMemberBase TypeElementBase + typeSyntaxBase Type *TypeNode // TypeNode Initializer *Expression // Expression. For error reporting purposes } @@ -4380,7 +5118,7 @@ func (f *NodeFactory) NewPropertySignatureDeclaration(modifiers *ModifierList, n data.PostfixToken = postfixToken data.Type = typeNode data.Initializer = initializer - return newNode(KindPropertySignature, data, f.hooks) + return f.newNode(KindPropertySignature, data) } func (f *NodeFactory) UpdatePropertySignatureDeclaration(node *PropertySignatureDeclaration, modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, typeNode *TypeNode, initializer *Expression) *Node { @@ -4398,8 +5136,8 @@ func (node *PropertySignatureDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePropertySignatureDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitNode(node.Type), v.visitNode(node.Initializer)) } -func (node *PropertySignatureDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPropertySignatureDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.Type, node.Initializer), node.AsNode(), f.hooks) +func (node *PropertySignatureDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPropertySignatureDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.Type, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) } func IsPropertySignatureDeclaration(node *Node) bool { @@ -4412,6 +5150,7 @@ type PropertyDeclaration struct { NodeBase NamedMemberBase ClassElementBase + compositeNodeBase Type *TypeNode // TypeNode. Optional Initializer *Expression // Expression. Optional } @@ -4423,7 +5162,7 @@ func (f *NodeFactory) NewPropertyDeclaration(modifiers *ModifierList, name *Prop data.PostfixToken = postfixToken data.Type = typeNode data.Initializer = initializer - return newNode(KindPropertyDeclaration, data, f.hooks) + return f.newNode(KindPropertyDeclaration, data) } func (f *NodeFactory) UpdatePropertyDeclaration(node *PropertyDeclaration, modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, typeNode *TypeNode, initializer *Expression) *Node { @@ -4441,8 +5180,22 @@ func (node *PropertyDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePropertyDeclaration(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitNode(node.Type), v.visitNode(node.Initializer)) } -func (node *PropertyDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPropertyDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.Type, node.Initializer), node.AsNode(), f.hooks) +func (node *PropertyDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPropertyDeclaration(node.Modifiers(), node.Name(), node.PostfixToken, node.Type, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *PropertyDeclaration) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxSubtreeFacts(node.PostfixToken) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Initializer) | + SubtreeContainsClassFields +} + +func (node *PropertyDeclaration) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsProperty | + propagateSubtreeFacts(node.name) } func IsPropertyDeclaration(node *Node) bool { @@ -4458,11 +5211,11 @@ type SemicolonClassElement struct { } func (f *NodeFactory) NewSemicolonClassElement() *Node { - return newNode(KindSemicolonClassElement, &SemicolonClassElement{}, f.hooks) + return f.newNode(KindSemicolonClassElement, &SemicolonClassElement{}) } -func (node *SemicolonClassElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSemicolonClassElement(), node.AsNode(), f.hooks) +func (node *SemicolonClassElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSemicolonClassElement(), node.AsNode(), f.AsNodeFactory().hooks) } // ClassStaticBlockDeclaration @@ -4473,6 +5226,7 @@ type ClassStaticBlockDeclaration struct { ModifiersBase LocalsContainerBase ClassElementBase + compositeNodeBase Body *BlockNode // BlockNode ReturnFlowNode *FlowNode } @@ -4481,7 +5235,7 @@ func (f *NodeFactory) NewClassStaticBlockDeclaration(modifiers *ModifierList, bo data := &ClassStaticBlockDeclaration{} data.modifiers = modifiers data.Body = body - return newNode(KindClassStaticBlockDeclaration, data, f.hooks) + return f.newNode(KindClassStaticBlockDeclaration, data) } func (f *NodeFactory) UpdateClassStaticBlockDeclaration(node *ClassStaticBlockDeclaration, modifiers *ModifierList, body *BlockNode) *Node { @@ -4502,8 +5256,14 @@ func (node *ClassStaticBlockDeclaration) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateClassStaticBlockDeclaration(node, modifiers, body) } -func (node *ClassStaticBlockDeclaration) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewClassStaticBlockDeclaration(node.Modifiers(), node.Body), node.AsNode(), f.hooks) +func (node *ClassStaticBlockDeclaration) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewClassStaticBlockDeclaration(node.Modifiers(), node.Body), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ClassStaticBlockDeclaration) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.Body) | + SubtreeContainsClassFields } func IsClassStaticBlockDeclaration(node *Node) bool { @@ -4523,11 +5283,11 @@ type OmittedExpression struct { } func (f *NodeFactory) NewOmittedExpression() *Node { - return newNode(KindOmittedExpression, &OmittedExpression{}, f.hooks) + return f.newNode(KindOmittedExpression, &OmittedExpression{}) } -func (node *OmittedExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewOmittedExpression(), node.AsNode(), f.hooks) +func (node *OmittedExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewOmittedExpression(), node.AsNode(), f.AsNodeFactory().hooks) } func IsOmittedExpression(node *Node) bool { @@ -4542,11 +5302,21 @@ type KeywordExpression struct { } func (f *NodeFactory) NewKeywordExpression(kind Kind) *Node { - return newNode(kind, &KeywordExpression{}, f.hooks) + return f.newNode(kind, &KeywordExpression{}) } -func (node *KeywordExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewKeywordExpression(node.Kind), node.AsNode(), f.hooks) +func (node *KeywordExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewKeywordExpression(node.Kind), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *KeywordExpression) computeSubtreeFacts() SubtreeFacts { + switch node.Kind { + case KindThisKeyword: + return SubtreeContainsLexicalThis + case KindSuperKeyword: + return SubtreeContainsLexicalSuper + } + return SubtreeFactsNone } // LiteralLikeBase @@ -4568,11 +5338,12 @@ type StringLiteral struct { func (f *NodeFactory) NewStringLiteral(text string) *Node { data := f.stringLiteralPool.New() data.Text = text - return newNode(KindStringLiteral, data, f.hooks) + f.textCount++ + return f.newNode(KindStringLiteral, data) } -func (node *StringLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewStringLiteral(node.Text), node.AsNode(), f.hooks) +func (node *StringLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewStringLiteral(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } func IsStringLiteral(node *Node) bool { @@ -4589,11 +5360,12 @@ type NumericLiteral struct { func (f *NodeFactory) NewNumericLiteral(text string) *Node { data := &NumericLiteral{} data.Text = text - return newNode(KindNumericLiteral, data, f.hooks) + f.textCount++ + return f.newNode(KindNumericLiteral, data) } -func (node *NumericLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNumericLiteral(node.Text), node.AsNode(), f.hooks) +func (node *NumericLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNumericLiteral(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } func IsNumericLiteral(node *Node) bool { @@ -4610,11 +5382,16 @@ type BigIntLiteral struct { func (f *NodeFactory) NewBigIntLiteral(text string) *Node { data := &BigIntLiteral{} data.Text = text - return newNode(KindBigIntLiteral, data, f.hooks) + f.textCount++ + return f.newNode(KindBigIntLiteral, data) +} + +func (node *BigIntLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBigIntLiteral(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *BigIntLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBigIntLiteral(node.Text), node.AsNode(), f.hooks) +func (node *BigIntLiteral) computeSubtreeFacts() SubtreeFacts { + return SubtreeContainsES2020 } func IsBigIntLiteral(node *Node) bool { @@ -4631,11 +5408,12 @@ type RegularExpressionLiteral struct { func (f *NodeFactory) NewRegularExpressionLiteral(text string) *Node { data := &RegularExpressionLiteral{} data.Text = text - return newNode(KindRegularExpressionLiteral, data, f.hooks) + f.textCount++ + return f.newNode(KindRegularExpressionLiteral, data) } -func (node *RegularExpressionLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewRegularExpressionLiteral(node.Text), node.AsNode(), f.hooks) +func (node *RegularExpressionLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewRegularExpressionLiteral(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } // NoSubstitutionTemplateLiteral @@ -4648,11 +5426,12 @@ type NoSubstitutionTemplateLiteral struct { func (f *NodeFactory) NewNoSubstitutionTemplateLiteral(text string) *Node { data := &NoSubstitutionTemplateLiteral{} data.Text = text - return newNode(KindNoSubstitutionTemplateLiteral, data, f.hooks) + f.textCount++ + return f.newNode(KindNoSubstitutionTemplateLiteral, data) } -func (node *NoSubstitutionTemplateLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNoSubstitutionTemplateLiteral(node.Text), node.AsNode(), f.hooks) +func (node *NoSubstitutionTemplateLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNoSubstitutionTemplateLiteral(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } // BinaryExpression @@ -4660,6 +5439,7 @@ func (node *NoSubstitutionTemplateLiteral) Clone(f *NodeFactory) *Node { type BinaryExpression struct { ExpressionBase DeclarationBase + compositeNodeBase Left *Expression // Expression OperatorToken *TokenNode // TokenNode Right *Expression // Expression @@ -4673,7 +5453,7 @@ func (f *NodeFactory) NewBinaryExpression(left *Expression, operatorToken *Token data.Left = left data.OperatorToken = operatorToken data.Right = right - return newNode(KindBinaryExpression, data, f.hooks) + return f.newNode(KindBinaryExpression, data) } func (f *NodeFactory) UpdateBinaryExpression(node *BinaryExpression, left *Expression, operatorToken *TokenNode, right *Expression) *Node { @@ -4691,8 +5471,15 @@ func (node *BinaryExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateBinaryExpression(node, v.visitNode(node.Left), v.visitToken(node.OperatorToken), v.visitNode(node.Right)) } -func (node *BinaryExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewBinaryExpression(node.Left, node.OperatorToken, node.Right), node.AsNode(), f.hooks) +func (node *BinaryExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewBinaryExpression(node.Left, node.OperatorToken, node.Right), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *BinaryExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Left) | + propagateSubtreeFacts(node.OperatorToken) | + propagateSubtreeFacts(node.Right) | + core.IfElse(node.OperatorToken.Kind == KindInKeyword && IsPrivateIdentifier(node.Left), SubtreeContainsClassFields, SubtreeFactsNone) } func IsBinaryExpression(node *Node) bool { @@ -4711,7 +5498,7 @@ func (f *NodeFactory) NewPrefixUnaryExpression(operator Kind, operand *Expressio data := &PrefixUnaryExpression{} data.Operator = operator data.Operand = operand - return newNode(KindPrefixUnaryExpression, data, f.hooks) + return f.newNode(KindPrefixUnaryExpression, data) } func (f *NodeFactory) UpdatePrefixUnaryExpression(node *PrefixUnaryExpression, operand *Expression) *Node { @@ -4729,8 +5516,12 @@ func (node *PrefixUnaryExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePrefixUnaryExpression(node, v.visitNode(node.Operand)) } -func (node *PrefixUnaryExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPrefixUnaryExpression(node.Operator, node.Operand), node.AsNode(), f.hooks) +func (node *PrefixUnaryExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPrefixUnaryExpression(node.Operator, node.Operand), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *PrefixUnaryExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Operand) } func IsPrefixUnaryExpression(node *Node) bool { @@ -4749,7 +5540,7 @@ func (f *NodeFactory) NewPostfixUnaryExpression(operand *Expression, operator Ki data := &PostfixUnaryExpression{} data.Operand = operand data.Operator = operator - return newNode(KindPostfixUnaryExpression, data, f.hooks) + return f.newNode(KindPostfixUnaryExpression, data) } func (f *NodeFactory) UpdatePostfixUnaryExpression(node *PostfixUnaryExpression, operand *Expression) *Node { @@ -4767,8 +5558,12 @@ func (node *PostfixUnaryExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePostfixUnaryExpression(node, v.visitNode(node.Operand)) } -func (node *PostfixUnaryExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPostfixUnaryExpression(node.Operand, node.Operator), node.AsNode(), f.hooks) +func (node *PostfixUnaryExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPostfixUnaryExpression(node.Operand, node.Operator), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *PostfixUnaryExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Operand) } // YieldExpression @@ -4783,7 +5578,7 @@ func (f *NodeFactory) NewYieldExpression(asteriskToken *TokenNode, expression *E data := &YieldExpression{} data.AsteriskToken = asteriskToken data.Expression = expression - return newNode(KindYieldExpression, data, f.hooks) + return f.newNode(KindYieldExpression, data) } func (f *NodeFactory) UpdateYieldExpression(node *YieldExpression, asteriskToken *TokenNode, expression *Expression) *Node { @@ -4801,8 +5596,12 @@ func (node *YieldExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateYieldExpression(node, v.visitToken(node.AsteriskToken), v.visitNode(node.Expression)) } -func (node *YieldExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewYieldExpression(node.AsteriskToken, node.Expression), node.AsNode(), f.hooks) +func (node *YieldExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewYieldExpression(node.AsteriskToken, node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *YieldExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsES2018 } // ArrowFunction @@ -4813,6 +5612,7 @@ type ArrowFunction struct { ModifiersBase FunctionLikeWithBodyBase FlowNodeBase + compositeNodeBase EqualsGreaterThanToken *TokenNode // TokenNode } @@ -4824,7 +5624,7 @@ func (f *NodeFactory) NewArrowFunction(modifiers *ModifierList, typeParameters * data.Type = returnType data.EqualsGreaterThanToken = equalsGreaterThanToken data.Body = body - return newNode(KindArrowFunction, data, f.hooks) + return f.newNode(KindArrowFunction, data) } func (f *NodeFactory) UpdateArrowFunction(node *ArrowFunction, modifiers *ModifierList, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, equalsGreaterThanToken *TokenNode, body *BlockOrExpression) *Node { @@ -4843,14 +5643,27 @@ func (node *ArrowFunction) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateArrowFunction(node, v.visitModifiers(node.modifiers), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitToken(node.EqualsGreaterThanToken), v.visitFunctionBody(node.Body)) } -func (node *ArrowFunction) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewArrowFunction(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type, node.EqualsGreaterThanToken, node.Body), node.AsNode(), f.hooks) +func (node *ArrowFunction) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewArrowFunction(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type, node.EqualsGreaterThanToken, node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func (node *ArrowFunction) Name() *DeclarationName { return nil } +func (node *ArrowFunction) computeSubtreeFacts() SubtreeFacts { + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Body) | + core.IfElse(node.ModifierFlags()&ModifierFlagsAsync != 0, SubtreeContainsES2017, SubtreeFactsNone) +} + +func (node *ArrowFunction) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsArrowFunction +} + func IsArrowFunction(node *Node) bool { return node.Kind == KindArrowFunction } @@ -4863,6 +5676,7 @@ type FunctionExpression struct { ModifiersBase FunctionLikeWithBodyBase FlowNodeBase + compositeNodeBase name *IdentifierNode // IdentifierNode. Optional ReturnFlowNode *FlowNode } @@ -4876,7 +5690,7 @@ func (f *NodeFactory) NewFunctionExpression(modifiers *ModifierList, asteriskTok data.Parameters = parameters data.Type = returnType data.Body = body - return newNode(KindFunctionExpression, data, f.hooks) + return f.newNode(KindFunctionExpression, data) } func (f *NodeFactory) UpdateFunctionExpression(node *FunctionExpression, modifiers *ModifierList, asteriskToken *TokenNode, name *IdentifierNode, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode, body *BlockNode) *Node { @@ -4895,14 +5709,32 @@ func (node *FunctionExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateFunctionExpression(node, v.visitModifiers(node.modifiers), v.visitToken(node.AsteriskToken), v.visitNode(node.name), v.visitNodes(node.TypeParameters), v.visitParameters(node.Parameters), v.visitNode(node.Type), v.visitFunctionBody(node.Body)) } -func (node *FunctionExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewFunctionExpression(node.Modifiers(), node.AsteriskToken, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.hooks) +func (node *FunctionExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewFunctionExpression(node.Modifiers(), node.AsteriskToken, node.Name(), node.TypeParameters, node.Parameters, node.Type, node.Body), node.AsNode(), f.AsNodeFactory().hooks) } func (node *FunctionExpression) Name() *DeclarationName { return node.name } +func (node *FunctionExpression) computeSubtreeFacts() SubtreeFacts { + isAsync := node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAsync != 0 + isGenerator := node.AsteriskToken != nil + return propagateModifierListSubtreeFacts(node.modifiers) | + propagateSubtreeFacts(node.AsteriskToken) | + propagateSubtreeFacts(node.name) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) | + propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) | + propagateEraseableSyntaxSubtreeFacts(node.Type) | + propagateSubtreeFacts(node.Body) | + core.IfElse(isAsync && isGenerator, SubtreeContainsES2018, SubtreeFactsNone) | + core.IfElse(isAsync && !isGenerator, SubtreeContainsES2017, SubtreeFactsNone) +} + +func (node *FunctionExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsFunction +} + func IsFunctionExpression(node *Node) bool { return node.Kind == KindFunctionExpression } @@ -4919,7 +5751,7 @@ func (f *NodeFactory) NewAsExpression(expression *Expression, typeNode *TypeNode data := &AsExpression{} data.Expression = expression data.Type = typeNode - return newNode(KindAsExpression, data, f.hooks) + return f.newNode(KindAsExpression, data) } func (f *NodeFactory) UpdateAsExpression(node *AsExpression, expression *Expression, typeNode *TypeNode) *Node { @@ -4937,8 +5769,16 @@ func (node *AsExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateAsExpression(node, v.visitNode(node.Expression), v.visitNode(node.Type)) } -func (node *AsExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewAsExpression(node.Expression, node.Type), node.AsNode(), f.hooks) +func (node *AsExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewAsExpression(node.Expression, node.Type), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *AsExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript +} + +func (node *AsExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression } // SatisfiesExpression @@ -4953,7 +5793,7 @@ func (f *NodeFactory) NewSatisfiesExpression(expression *Expression, typeNode *T data := &SatisfiesExpression{} data.Expression = expression data.Type = typeNode - return newNode(KindSatisfiesExpression, data, f.hooks) + return f.newNode(KindSatisfiesExpression, data) } func (f *NodeFactory) UpdateSatisfiesExpression(node *SatisfiesExpression, expression *Expression, typeNode *TypeNode) *Node { @@ -4971,8 +5811,16 @@ func (node *SatisfiesExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateSatisfiesExpression(node, v.visitNode(node.Expression), v.visitNode(node.Type)) } -func (node *SatisfiesExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSatisfiesExpression(node.Expression, node.Type), node.AsNode(), f.hooks) +func (node *SatisfiesExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSatisfiesExpression(node.Expression, node.Type), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *SatisfiesExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript +} + +func (node *SatisfiesExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression } func IsSatisfiesExpression(node *Node) bool { @@ -4983,6 +5831,7 @@ func IsSatisfiesExpression(node *Node) bool { type ConditionalExpression struct { ExpressionBase + compositeNodeBase Condition *Expression QuestionToken *TokenNode WhenTrue *Expression @@ -4997,7 +5846,7 @@ func (f *NodeFactory) NewConditionalExpression(condition *Expression, questionTo data.WhenTrue = whenTrue data.ColonToken = colonToken data.WhenFalse = whenFalse - return newNode(KindConditionalExpression, data, f.hooks) + return f.newNode(KindConditionalExpression, data) } func (f *NodeFactory) UpdateConditionalExpression(node *ConditionalExpression, condition *Expression, questionToken *TokenNode, whenTrue *Expression, colonToken *TokenNode, whenFalse *Expression) *Node { @@ -5016,8 +5865,14 @@ func (node *ConditionalExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateConditionalExpression(node, v.visitNode(node.Condition), v.visitToken(node.QuestionToken), v.visitNode(node.WhenTrue), v.visitToken(node.ColonToken), v.visitNode(node.WhenFalse)) } -func (node *ConditionalExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewConditionalExpression(node.Condition, node.QuestionToken, node.WhenTrue, node.ColonToken, node.WhenFalse), node.AsNode(), f.hooks) +func (node *ConditionalExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewConditionalExpression(node.Condition, node.QuestionToken, node.WhenTrue, node.ColonToken, node.WhenFalse), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ConditionalExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Condition) | + propagateSubtreeFacts(node.WhenTrue) | + propagateSubtreeFacts(node.WhenFalse) } // PropertyAccessExpression @@ -5025,6 +5880,7 @@ func (node *ConditionalExpression) Clone(f *NodeFactory) *Node { type PropertyAccessExpression struct { ExpressionBase FlowNodeBase + compositeNodeBase Expression *Expression // Expression QuestionDotToken *TokenNode // TokenNode name *MemberName // MemberName @@ -5035,7 +5891,7 @@ func (f *NodeFactory) NewPropertyAccessExpression(expression *Expression, questi data.Expression = expression data.QuestionDotToken = questionDotToken data.name = name - node := newNode(KindPropertyAccessExpression, data, f.hooks) + node := f.newNode(KindPropertyAccessExpression, data) node.Flags |= flags & NodeFlagsOptionalChain return node } @@ -5055,12 +5911,22 @@ func (node *PropertyAccessExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePropertyAccessExpression(node, v.visitNode(node.Expression), v.visitToken(node.QuestionDotToken), v.visitNode(node.name)) } -func (node *PropertyAccessExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPropertyAccessExpression(node.Expression, node.QuestionDotToken, node.Name(), node.Flags), node.AsNode(), f.hooks) +func (node *PropertyAccessExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPropertyAccessExpression(node.Expression, node.QuestionDotToken, node.Name(), node.Flags), node.AsNode(), f.AsNodeFactory().hooks) } func (node *PropertyAccessExpression) Name() *DeclarationName { return node.name } +func (node *PropertyAccessExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.QuestionDotToken) | + propagateSubtreeFacts(node.name) +} + +func (node *PropertyAccessExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsPropertyAccess +} + func IsPropertyAccessExpression(node *Node) bool { return node.Kind == KindPropertyAccessExpression } @@ -5070,6 +5936,7 @@ func IsPropertyAccessExpression(node *Node) bool { type ElementAccessExpression struct { ExpressionBase FlowNodeBase + compositeNodeBase Expression *Expression // Expression QuestionDotToken *TokenNode // TokenNode ArgumentExpression *Expression // Expression @@ -5080,7 +5947,7 @@ func (f *NodeFactory) NewElementAccessExpression(expression *Expression, questio data.Expression = expression data.QuestionDotToken = questionDotToken data.ArgumentExpression = argumentExpression - node := newNode(KindElementAccessExpression, data, f.hooks) + node := f.newNode(KindElementAccessExpression, data) node.Flags |= flags & NodeFlagsOptionalChain return node } @@ -5100,8 +5967,18 @@ func (node *ElementAccessExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateElementAccessExpression(node, v.visitNode(node.Expression), v.visitToken(node.QuestionDotToken), v.visitNode(node.ArgumentExpression)) } -func (node *ElementAccessExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewElementAccessExpression(node.Expression, node.QuestionDotToken, node.ArgumentExpression, node.Flags), node.AsNode(), f.hooks) +func (node *ElementAccessExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewElementAccessExpression(node.Expression, node.QuestionDotToken, node.ArgumentExpression, node.Flags), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ElementAccessExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.QuestionDotToken) | + propagateSubtreeFacts(node.ArgumentExpression) +} + +func (node *ElementAccessExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsElementAccess } func IsElementAccessExpression(node *Node) bool { @@ -5112,6 +5989,7 @@ func IsElementAccessExpression(node *Node) bool { type CallExpression struct { ExpressionBase + compositeNodeBase Expression *Expression // Expression QuestionDotToken *TokenNode // TokenNode TypeArguments *NodeList // NodeList[*TypeNode]. Optional @@ -5124,7 +6002,7 @@ func (f *NodeFactory) NewCallExpression(expression *Expression, questionDotToken data.QuestionDotToken = questionDotToken data.TypeArguments = typeArguments data.Arguments = arguments - node := newNode(KindCallExpression, data, f.hooks) + node := f.newNode(KindCallExpression, data) node.Flags |= flags & NodeFlagsOptionalChain return node } @@ -5144,8 +6022,20 @@ func (node *CallExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateCallExpression(node, v.visitNode(node.Expression), v.visitToken(node.QuestionDotToken), v.visitNodes(node.TypeArguments), v.visitNodes(node.Arguments)) } -func (node *CallExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewCallExpression(node.Expression, node.QuestionDotToken, node.TypeArguments, node.Arguments, node.Flags), node.AsNode(), f.hooks) +func (node *CallExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewCallExpression(node.Expression, node.QuestionDotToken, node.TypeArguments, node.Arguments, node.Flags), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *CallExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateSubtreeFacts(node.QuestionDotToken) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) | + propagateNodeListSubtreeFacts(node.Arguments, propagateSubtreeFacts) | + core.IfElse(node.Expression.Kind == KindImportKeyword, SubtreeContainsDynamicImport, SubtreeFactsNone) +} + +func (node *CallExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsCall } func IsCallExpression(node *Node) bool { @@ -5156,24 +6046,25 @@ func IsCallExpression(node *Node) bool { type NewExpression struct { ExpressionBase + compositeNodeBase Expression *Expression // Expression TypeArguments *NodeList // NodeList[*TypeNode]. Optional Arguments *NodeList // NodeList[*Expression]. Optional } -func (f *NodeFactory) UpdateNewExpression(node *NewExpression, expression *Expression, typeArguments *TypeArgumentList, arguments *ArgumentList) *Node { - if expression != node.Expression || typeArguments != node.TypeArguments || arguments != node.Arguments { - return updateNode(f.NewNewExpression(expression, typeArguments, arguments), node.AsNode(), f.hooks) - } - return node.AsNode() -} - func (f *NodeFactory) NewNewExpression(expression *Expression, typeArguments *NodeList, arguments *NodeList) *Node { data := &NewExpression{} data.Expression = expression data.TypeArguments = typeArguments data.Arguments = arguments - return newNode(KindNewExpression, data, f.hooks) + return f.newNode(KindNewExpression, data) +} + +func (f *NodeFactory) UpdateNewExpression(node *NewExpression, expression *Expression, typeArguments *TypeArgumentList, arguments *ArgumentList) *Node { + if expression != node.Expression || typeArguments != node.TypeArguments || arguments != node.Arguments { + return updateNode(f.NewNewExpression(expression, typeArguments, arguments), node.AsNode(), f.hooks) + } + return node.AsNode() } func (node *NewExpression) ForEachChild(v Visitor) bool { @@ -5184,8 +6075,18 @@ func (node *NewExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNewExpression(node, v.visitNode(node.Expression), v.visitNodes(node.TypeArguments), v.visitNodes(node.Arguments)) } -func (node *NewExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNewExpression(node.Expression, node.TypeArguments, node.Arguments), node.AsNode(), f.hooks) +func (node *NewExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNewExpression(node.Expression, node.TypeArguments, node.Arguments), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *NewExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) | + propagateNodeListSubtreeFacts(node.Arguments, propagateSubtreeFacts) +} + +func (node *NewExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsNew } func IsNewExpression(node *Node) bool { @@ -5197,6 +6098,7 @@ func IsNewExpression(node *Node) bool { type MetaProperty struct { ExpressionBase FlowNodeBase + compositeNodeBase KeywordToken Kind // NewKeyword | ImportKeyword name *IdentifierNode // IdentifierNode } @@ -5205,7 +6107,7 @@ func (f *NodeFactory) NewMetaProperty(keywordToken Kind, name *IdentifierNode) * data := &MetaProperty{} data.KeywordToken = keywordToken data.name = name - return newNode(KindMetaProperty, data, f.hooks) + return f.newNode(KindMetaProperty, data) } func (f *NodeFactory) UpdateMetaProperty(node *MetaProperty, name *IdentifierNode) *Node { @@ -5223,14 +6125,19 @@ func (node *MetaProperty) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateMetaProperty(node, v.visitNode(node.name)) } -func (node *MetaProperty) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewMetaProperty(node.Kind, node.Name()), node.AsNode(), f.hooks) +func (node *MetaProperty) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewMetaProperty(node.Kind, node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *MetaProperty) Name() *DeclarationName { return node.name } +func (node *MetaProperty) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + core.IfElse(node.KeywordToken == KindImportKeyword, SubtreeContainsES2020, SubtreeFactsNone) +} + func IsMetaProperty(node *Node) bool { return node.Kind == KindMetaProperty } @@ -5246,7 +6153,7 @@ func (f *NodeFactory) NewNonNullExpression(expression *Expression, flags NodeFla data := &NonNullExpression{} data.Expression = expression data.Flags |= flags & NodeFlagsOptionalChain - return newNode(KindNonNullExpression, data, f.hooks) + return f.newNode(KindNonNullExpression, data) } func (f *NodeFactory) UpdateNonNullExpression(node *NonNullExpression, expression *Expression) *Node { @@ -5264,8 +6171,12 @@ func (node *NonNullExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNonNullExpression(node, v.visitNode(node.Expression)) } -func (node *NonNullExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNonNullExpression(node.Expression, node.Flags), node.AsNode(), f.hooks) +func (node *NonNullExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNonNullExpression(node.Expression, node.Flags), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *NonNullExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript } func IsNonNullExpression(node *Node) bool { @@ -5282,7 +6193,7 @@ type SpreadElement struct { func (f *NodeFactory) NewSpreadElement(expression *Expression) *Node { data := &SpreadElement{} data.Expression = expression - return newNode(KindSpreadElement, data, f.hooks) + return f.newNode(KindSpreadElement, data) } func (f *NodeFactory) UpdateSpreadElement(node *SpreadElement, expression *Expression) *Node { @@ -5300,8 +6211,12 @@ func (node *SpreadElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateSpreadElement(node, v.visitNode(node.Expression)) } -func (node *SpreadElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSpreadElement(node.Expression), node.AsNode(), f.hooks) +func (node *SpreadElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSpreadElement(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *SpreadElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsSpreadElement(node *Node) bool { @@ -5312,6 +6227,7 @@ func IsSpreadElement(node *Node) bool { type TemplateExpression struct { ExpressionBase + compositeNodeBase Head *TemplateHeadNode // TemplateHeadNode TemplateSpans *NodeList // NodeList[*TemplateSpanNode] } @@ -5320,7 +6236,7 @@ func (f *NodeFactory) NewTemplateExpression(head *TemplateHeadNode, templateSpan data := &TemplateExpression{} data.Head = head data.TemplateSpans = templateSpans - return newNode(KindTemplateExpression, data, f.hooks) + return f.newNode(KindTemplateExpression, data) } func (f *NodeFactory) UpdateTemplateExpression(node *TemplateExpression, head *TemplateHeadNode, templateSpans *TemplateSpanList) *Node { @@ -5338,8 +6254,13 @@ func (node *TemplateExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTemplateExpression(node, v.visitNode(node.Head), v.visitNodes(node.TemplateSpans)) } -func (node *TemplateExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateExpression(node.Head, node.TemplateSpans), node.AsNode(), f.hooks) +func (node *TemplateExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateExpression(node.Head, node.TemplateSpans), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TemplateExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Head) | + propagateNodeListSubtreeFacts(node.TemplateSpans, propagateSubtreeFacts) } func IsTemplateExpression(node *Node) bool { @@ -5358,7 +6279,7 @@ func (f *NodeFactory) NewTemplateSpan(expression *Expression, literal *TemplateM data := &TemplateSpan{} data.Expression = expression data.Literal = literal - return newNode(KindTemplateSpan, data, f.hooks) + return f.newNode(KindTemplateSpan, data) } func (f *NodeFactory) UpdateTemplateSpan(node *TemplateSpan, expression *Expression, literal *TemplateMiddleOrTail) *Node { @@ -5376,8 +6297,12 @@ func (node *TemplateSpan) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTemplateSpan(node, v.visitNode(node.Expression), v.visitNode(node.Literal)) } -func (node *TemplateSpan) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateSpan(node.Expression, node.Literal), node.AsNode(), f.hooks) +func (node *TemplateSpan) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateSpan(node.Expression, node.Literal), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TemplateSpan) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsTemplateSpan(node *Node) bool { @@ -5388,6 +6313,7 @@ func IsTemplateSpan(node *Node) bool { type TaggedTemplateExpression struct { ExpressionBase + compositeNodeBase Tag *Expression // Expression QuestionDotToken *TokenNode // TokenNode. For error reporting purposes only TypeArguments *NodeList // NodeList[*TypeNode]. Optional @@ -5400,7 +6326,7 @@ func (f *NodeFactory) NewTaggedTemplateExpression(tag *Expression, questionDotTo data.QuestionDotToken = questionDotToken data.TypeArguments = typeArguments data.Template = template - node := newNode(KindTaggedTemplateExpression, data, f.hooks) + node := f.newNode(KindTaggedTemplateExpression, data) node.Flags |= flags & NodeFlagsOptionalChain return node } @@ -5420,8 +6346,15 @@ func (node *TaggedTemplateExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTaggedTemplateExpression(node, v.visitNode(node.Tag), v.visitToken(node.QuestionDotToken), v.visitNodes(node.TypeArguments), v.visitNode(node.Template)) } -func (node *TaggedTemplateExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTaggedTemplateExpression(node.Tag, node.QuestionDotToken, node.TypeArguments, node.Template, node.Flags), node.AsNode(), f.hooks) +func (node *TaggedTemplateExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTaggedTemplateExpression(node.Tag, node.QuestionDotToken, node.TypeArguments, node.Template, node.Flags), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TaggedTemplateExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Tag) | + propagateSubtreeFacts(node.QuestionDotToken) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) | + propagateSubtreeFacts(node.Template) } func IsTaggedTemplateExpression(node *Node) bool { @@ -5438,7 +6371,7 @@ type ParenthesizedExpression struct { func (f *NodeFactory) NewParenthesizedExpression(expression *Expression) *Node { data := f.parenthesizedExpressionPool.New() data.Expression = expression - return newNode(KindParenthesizedExpression, data, f.hooks) + return f.newNode(KindParenthesizedExpression, data) } func (f *NodeFactory) UpdateParenthesizedExpression(node *ParenthesizedExpression, expression *Expression) *Node { @@ -5456,8 +6389,16 @@ func (node *ParenthesizedExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateParenthesizedExpression(node, v.visitNode(node.Expression)) } -func (node *ParenthesizedExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewParenthesizedExpression(node.Expression), node.AsNode(), f.hooks) +func (node *ParenthesizedExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewParenthesizedExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ParenthesizedExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) +} + +func (node *ParenthesizedExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression } func IsParenthesizedExpression(node *Node) bool { @@ -5468,6 +6409,7 @@ func IsParenthesizedExpression(node *Node) bool { type ArrayLiteralExpression struct { ExpressionBase + compositeNodeBase Elements *NodeList // NodeList[*Expression] MultiLine bool } @@ -5476,7 +6418,7 @@ func (f *NodeFactory) NewArrayLiteralExpression(elements *NodeList, multiLine bo data := &ArrayLiteralExpression{} data.Elements = elements data.MultiLine = multiLine - return newNode(KindArrayLiteralExpression, data, f.hooks) + return f.newNode(KindArrayLiteralExpression, data) } func (f *NodeFactory) UpdateArrayLiteralExpression(node *ArrayLiteralExpression, elements *ElementList) *Node { @@ -5494,8 +6436,16 @@ func (node *ArrayLiteralExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateArrayLiteralExpression(node, v.visitNodes(node.Elements)) } -func (node *ArrayLiteralExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewArrayLiteralExpression(node.Elements, node.MultiLine), node.AsNode(), f.hooks) +func (node *ArrayLiteralExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewArrayLiteralExpression(node.Elements, node.MultiLine), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ArrayLiteralExpression) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Elements, propagateSubtreeFacts) +} + +func (node *ArrayLiteralExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsArrayLiteral } func IsArrayLiteralExpression(node *Node) bool { @@ -5507,6 +6457,7 @@ func IsArrayLiteralExpression(node *Node) bool { type ObjectLiteralExpression struct { ExpressionBase DeclarationBase + compositeNodeBase Properties *NodeList // NodeList[*ObjectLiteralElement] MultiLine bool } @@ -5515,7 +6466,7 @@ func (f *NodeFactory) NewObjectLiteralExpression(properties *NodeList, multiLine data := &ObjectLiteralExpression{} data.Properties = properties data.MultiLine = multiLine - return newNode(KindObjectLiteralExpression, data, f.hooks) + return f.newNode(KindObjectLiteralExpression, data) } func (f *NodeFactory) UpdateObjectLiteralExpression(node *ObjectLiteralExpression, properties *PropertyDefinitionList) *Node { @@ -5533,8 +6484,16 @@ func (node *ObjectLiteralExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateObjectLiteralExpression(node, v.visitNodes(node.Properties)) } -func (node *ObjectLiteralExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewObjectLiteralExpression(node.Properties, node.MultiLine), node.AsNode(), f.hooks) +func (node *ObjectLiteralExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewObjectLiteralExpression(node.Properties, node.MultiLine), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ObjectLiteralExpression) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Properties, propagateSubtreeFacts) +} + +func (node *ObjectLiteralExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsObjectLiteral } func IsObjectLiteralExpression(node *Node) bool { @@ -5557,7 +6516,7 @@ type SpreadAssignment struct { func (f *NodeFactory) NewSpreadAssignment(expression *Expression) *Node { data := &SpreadAssignment{} data.Expression = expression - return newNode(KindSpreadAssignment, data, f.hooks) + return f.newNode(KindSpreadAssignment, data) } func (f *NodeFactory) UpdateSpreadAssignment(node *SpreadAssignment, expression *Expression) *Node { @@ -5575,8 +6534,12 @@ func (node *SpreadAssignment) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateSpreadAssignment(node, v.visitNode(node.Expression)) } -func (node *SpreadAssignment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSpreadAssignment(node.Expression), node.AsNode(), f.hooks) +func (node *SpreadAssignment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSpreadAssignment(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *SpreadAssignment) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsES2018 | SubtreeContainsObjectRestOrSpread } func IsSpreadAssignment(node *Node) bool { @@ -5589,6 +6552,7 @@ type PropertyAssignment struct { NodeBase NamedMemberBase ObjectLiteralElementBase + compositeNodeBase Initializer *Expression // Expression } @@ -5598,7 +6562,7 @@ func (f *NodeFactory) NewPropertyAssignment(modifiers *ModifierList, name *Prope data.name = name data.PostfixToken = postfixToken data.Initializer = initializer - return newNode(KindPropertyAssignment, data, f.hooks) + return f.newNode(KindPropertyAssignment, data) } func (f *NodeFactory) UpdatePropertyAssignment(node *PropertyAssignment, modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, initializer *Expression) *Node { @@ -5616,8 +6580,13 @@ func (node *PropertyAssignment) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePropertyAssignment(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitNode(node.Initializer)) } -func (node *PropertyAssignment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPropertyAssignment(node.Modifiers(), node.Name(), node.PostfixToken, node.Initializer), node.AsNode(), f.hooks) +func (node *PropertyAssignment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPropertyAssignment(node.Modifiers(), node.Name(), node.PostfixToken, node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *PropertyAssignment) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Initializer) } func IsPropertyAssignment(node *Node) bool { @@ -5630,6 +6599,7 @@ type ShorthandPropertyAssignment struct { NodeBase NamedMemberBase ObjectLiteralElementBase + compositeNodeBase EqualsToken *TokenNode ObjectAssignmentInitializer *Expression // Optional } @@ -5641,7 +6611,7 @@ func (f *NodeFactory) NewShorthandPropertyAssignment(modifiers *ModifierList, na data.PostfixToken = postfixToken data.EqualsToken = equalsToken data.ObjectAssignmentInitializer = objectAssignmentInitializer - return newNode(KindShorthandPropertyAssignment, data, f.hooks) + return f.newNode(KindShorthandPropertyAssignment, data) } func (f *NodeFactory) UpdateShorthandPropertyAssignment(node *ShorthandPropertyAssignment, modifiers *ModifierList, name *PropertyName, postfixToken *TokenNode, equalsToken *TokenNode, objectAssignmentInitializer *Expression) *Node { @@ -5659,8 +6629,14 @@ func (node *ShorthandPropertyAssignment) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateShorthandPropertyAssignment(node, v.visitModifiers(node.modifiers), v.visitNode(node.name), v.visitToken(node.PostfixToken), v.visitToken(node.EqualsToken), v.visitNode(node.ObjectAssignmentInitializer)) } -func (node *ShorthandPropertyAssignment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewShorthandPropertyAssignment(node.Modifiers(), node.Name(), node.PostfixToken, node.EqualsToken, node.ObjectAssignmentInitializer), node.AsNode(), f.hooks) +func (node *ShorthandPropertyAssignment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewShorthandPropertyAssignment(node.Modifiers(), node.Name(), node.PostfixToken, node.EqualsToken, node.ObjectAssignmentInitializer), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ShorthandPropertyAssignment) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | // we do not use propagateSubtreeFacts here because this is an IdentifierReference + propagateSubtreeFacts(node.ObjectAssignmentInitializer) | + SubtreeContainsTypeScript // may require rewriting in a TypeScript namespace } func IsShorthandPropertyAssignment(node *Node) bool { @@ -5677,7 +6653,7 @@ type DeleteExpression struct { func (f *NodeFactory) NewDeleteExpression(expression *Expression) *Node { data := &DeleteExpression{} data.Expression = expression - return newNode(KindDeleteExpression, data, f.hooks) + return f.newNode(KindDeleteExpression, data) } func (f *NodeFactory) UpdateDeleteExpression(node *DeleteExpression, expression *Expression) *Node { @@ -5695,8 +6671,12 @@ func (node *DeleteExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateDeleteExpression(node, v.visitNode(node.Expression)) } -func (node *DeleteExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewDeleteExpression(node.Expression), node.AsNode(), f.hooks) +func (node *DeleteExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewDeleteExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *DeleteExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } // TypeOfExpression @@ -5709,7 +6689,7 @@ type TypeOfExpression struct { func (f *NodeFactory) NewTypeOfExpression(expression *Expression) *Node { data := &TypeOfExpression{} data.Expression = expression - return newNode(KindTypeOfExpression, data, f.hooks) + return f.newNode(KindTypeOfExpression, data) } func (f *NodeFactory) UpdateTypeOfExpression(node *TypeOfExpression, expression *Expression) *Node { @@ -5727,8 +6707,12 @@ func (node *TypeOfExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeOfExpression(node, v.visitNode(node.Expression)) } -func (node *TypeOfExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeOfExpression(node.Expression), node.AsNode(), f.hooks) +func (node *TypeOfExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeOfExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TypeOfExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } func IsTypeOfExpression(node *Node) bool { @@ -5745,7 +6729,7 @@ type VoidExpression struct { func (f *NodeFactory) NewVoidExpression(expression *Expression) *Node { data := &VoidExpression{} data.Expression = expression - return newNode(KindVoidExpression, data, f.hooks) + return f.newNode(KindVoidExpression, data) } func (f *NodeFactory) UpdateVoidExpression(node *VoidExpression, expression *Expression) *Node { @@ -5763,8 +6747,12 @@ func (node *VoidExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateVoidExpression(node, v.visitNode(node.Expression)) } -func (node *VoidExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewVoidExpression(node.Expression), node.AsNode(), f.hooks) +func (node *VoidExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewVoidExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *VoidExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) } // AwaitExpression @@ -5777,7 +6765,7 @@ type AwaitExpression struct { func (f *NodeFactory) NewAwaitExpression(expression *Expression) *Node { data := &AwaitExpression{} data.Expression = expression - return newNode(KindAwaitExpression, data, f.hooks) + return f.newNode(KindAwaitExpression, data) } func (f *NodeFactory) UpdateAwaitExpression(node *AwaitExpression, expression *Expression) *Node { @@ -5795,8 +6783,12 @@ func (node *AwaitExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateAwaitExpression(node, v.visitNode(node.Expression)) } -func (node *AwaitExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewAwaitExpression(node.Expression), node.AsNode(), f.hooks) +func (node *AwaitExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewAwaitExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *AwaitExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsES2017 | SubtreeContainsES2018 | SubtreeContainsAwait } func IsAwaitExpression(node *Node) bool { @@ -5815,7 +6807,7 @@ func (f *NodeFactory) NewTypeAssertion(typeNode *TypeNode, expression *Expressio data := &TypeAssertion{} data.Type = typeNode data.Expression = expression - return newNode(KindTypeAssertionExpression, data, f.hooks) + return f.newNode(KindTypeAssertionExpression, data) } func (f *NodeFactory) UpdateTypeAssertion(node *TypeAssertion, typeNode *TypeNode, expression *Expression) *Node { @@ -5833,14 +6825,23 @@ func (node *TypeAssertion) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeAssertion(node, v.visitNode(node.Type), v.visitNode(node.Expression)) } -func (node *TypeAssertion) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeAssertion(node.Type, node.Expression), node.AsNode(), f.hooks) +func (node *TypeAssertion) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeAssertion(node.Type, node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *TypeAssertion) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript +} + +func (node *TypeAssertion) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression } // TypeNodeBase type TypeNodeBase struct { NodeBase + typeSyntaxBase } // KeywordTypeNode @@ -5850,11 +6851,11 @@ type KeywordTypeNode struct { } func (f *NodeFactory) NewKeywordTypeNode(kind Kind) *Node { - return newNode(kind, f.keywordTypeNodePool.New(), f.hooks) + return f.newNode(kind, f.keywordTypeNodePool.New()) } -func (node *KeywordTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewKeywordTypeNode(node.Kind), node.AsNode(), f.hooks) +func (node *KeywordTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewKeywordTypeNode(node.Kind), node.AsNode(), f.AsNodeFactory().hooks) } // UnionOrIntersectionTypeBase @@ -5884,15 +6885,15 @@ func (f *NodeFactory) UpdateUnionTypeNode(node *UnionTypeNode, types *TypeList) func (f *NodeFactory) NewUnionTypeNode(types *NodeList) *Node { data := &UnionTypeNode{} data.Types = types - return newNode(KindUnionType, data, f.hooks) + return f.newNode(KindUnionType, data) } func (node *UnionTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateUnionTypeNode(node, v.visitNodes(node.Types)) } -func (node *UnionTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewUnionTypeNode(node.Types), node.AsNode(), f.hooks) +func (node *UnionTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewUnionTypeNode(node.Types), node.AsNode(), f.AsNodeFactory().hooks) } // IntersectionTypeNode @@ -5911,15 +6912,15 @@ func (f *NodeFactory) UpdateIntersectionTypeNode(node *IntersectionTypeNode, typ func (f *NodeFactory) NewIntersectionTypeNode(types *NodeList) *Node { data := &IntersectionTypeNode{} data.Types = types - return newNode(KindIntersectionType, data, f.hooks) + return f.newNode(KindIntersectionType, data) } func (node *IntersectionTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateIntersectionTypeNode(node, v.visitNodes(node.Types)) } -func (node *IntersectionTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewIntersectionTypeNode(node.Types), node.AsNode(), f.hooks) +func (node *IntersectionTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewIntersectionTypeNode(node.Types), node.AsNode(), f.AsNodeFactory().hooks) } // ConditionalTypeNode @@ -5939,7 +6940,7 @@ func (f *NodeFactory) NewConditionalTypeNode(checkType *TypeNode, extendsType *T data.ExtendsType = extendsType data.TrueType = trueType data.FalseType = falseType - return newNode(KindConditionalType, data, f.hooks) + return f.newNode(KindConditionalType, data) } func (f *NodeFactory) UpdateConditionalTypeNode(node *ConditionalTypeNode, checkType *TypeNode, extendsType *TypeNode, trueType *TypeNode, falseType *TypeNode) *Node { @@ -5957,8 +6958,8 @@ func (node *ConditionalTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateConditionalTypeNode(node, v.visitNode(node.CheckType), v.visitNode(node.ExtendsType), v.visitNode(node.TrueType), v.visitNode(node.FalseType)) } -func (node *ConditionalTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewConditionalTypeNode(node.CheckType, node.ExtendsType, node.TrueType, node.FalseType), node.AsNode(), f.hooks) +func (node *ConditionalTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewConditionalTypeNode(node.CheckType, node.ExtendsType, node.TrueType, node.FalseType), node.AsNode(), f.AsNodeFactory().hooks) } func IsConditionalTypeNode(node *Node) bool { @@ -5977,7 +6978,7 @@ func (f *NodeFactory) NewTypeOperatorNode(operator Kind, typeNode *TypeNode) *No data := &TypeOperatorNode{} data.Operator = operator data.Type = typeNode - return newNode(KindTypeOperator, data, f.hooks) + return f.newNode(KindTypeOperator, data) } func (f *NodeFactory) UpdateTypeOperatorNode(node *TypeOperatorNode, typeNode *TypeNode) *Node { @@ -5995,8 +6996,8 @@ func (node *TypeOperatorNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeOperatorNode(node, v.visitNode(node.Type)) } -func (node *TypeOperatorNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeOperatorNode(node.Operator, node.Type), node.AsNode(), f.hooks) +func (node *TypeOperatorNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeOperatorNode(node.Operator, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsTypeOperatorNode(node *Node) bool { @@ -6013,7 +7014,7 @@ type InferTypeNode struct { func (f *NodeFactory) NewInferTypeNode(typeParameter *TypeParameterDeclarationNode) *Node { data := &InferTypeNode{} data.TypeParameter = typeParameter - return newNode(KindInferType, data, f.hooks) + return f.newNode(KindInferType, data) } func (f *NodeFactory) UpdateInferTypeNode(node *InferTypeNode, typeParameter *TypeNode) *Node { @@ -6031,8 +7032,8 @@ func (node *InferTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateInferTypeNode(node, v.visitNode(node.TypeParameter)) } -func (node *InferTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewInferTypeNode(node.TypeParameter), node.AsNode(), f.hooks) +func (node *InferTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewInferTypeNode(node.TypeParameter), node.AsNode(), f.AsNodeFactory().hooks) } func IsInferTypeNode(node *Node) bool { @@ -6049,7 +7050,7 @@ type ArrayTypeNode struct { func (f *NodeFactory) NewArrayTypeNode(elementType *TypeNode) *Node { data := &ArrayTypeNode{} data.ElementType = elementType - return newNode(KindArrayType, data, f.hooks) + return f.newNode(KindArrayType, data) } func (f *NodeFactory) UpdateArrayTypeNode(node *ArrayTypeNode, elementType *TypeNode) *Node { @@ -6067,8 +7068,8 @@ func (node *ArrayTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateArrayTypeNode(node, v.visitNode(node.ElementType)) } -func (node *ArrayTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewArrayTypeNode(node.ElementType), node.AsNode(), f.hooks) +func (node *ArrayTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewArrayTypeNode(node.ElementType), node.AsNode(), f.AsNodeFactory().hooks) } // IndexedAccessTypeNode @@ -6083,7 +7084,7 @@ func (f *NodeFactory) NewIndexedAccessTypeNode(objectType *TypeNode, indexType * data := &IndexedAccessTypeNode{} data.ObjectType = objectType data.IndexType = indexType - return newNode(KindIndexedAccessType, data, f.hooks) + return f.newNode(KindIndexedAccessType, data) } func (f *NodeFactory) UpdateIndexedAccessTypeNode(node *IndexedAccessTypeNode, objectType *TypeNode, indexType *TypeNode) *Node { @@ -6101,8 +7102,8 @@ func (node *IndexedAccessTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateIndexedAccessTypeNode(node, v.visitNode(node.ObjectType), v.visitNode(node.IndexType)) } -func (node *IndexedAccessTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewIndexedAccessTypeNode(node.ObjectType, node.IndexType), node.AsNode(), f.hooks) +func (node *IndexedAccessTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewIndexedAccessTypeNode(node.ObjectType, node.IndexType), node.AsNode(), f.AsNodeFactory().hooks) } func IsIndexedAccessTypeNode(node *Node) bool { @@ -6121,7 +7122,7 @@ func (f *NodeFactory) NewTypeReferenceNode(typeName *EntityName, typeArguments * data := f.typeReferenceNodePool.New() data.TypeName = typeName data.TypeArguments = typeArguments - return newNode(KindTypeReference, data, f.hooks) + return f.newNode(KindTypeReference, data) } func (f *NodeFactory) UpdateTypeReferenceNode(node *TypeReferenceNode, typeName *EntityName, typeArguments *TypeArgumentList) *Node { @@ -6139,8 +7140,8 @@ func (node *TypeReferenceNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeReferenceNode(node, v.visitNode(node.TypeName), v.visitNodes(node.TypeArguments)) } -func (node *TypeReferenceNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeReferenceNode(node.TypeName, node.TypeArguments), node.AsNode(), f.hooks) +func (node *TypeReferenceNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeReferenceNode(node.TypeName, node.TypeArguments), node.AsNode(), f.AsNodeFactory().hooks) } func IsTypeReferenceNode(node *Node) bool { @@ -6151,6 +7152,7 @@ func IsTypeReferenceNode(node *Node) bool { type ExpressionWithTypeArguments struct { ExpressionBase + compositeNodeBase Expression *Expression // Expression TypeArguments *NodeList // NodeList[*TypeNode]. Optional } @@ -6159,7 +7161,7 @@ func (f *NodeFactory) NewExpressionWithTypeArguments(expression *Expression, typ data := &ExpressionWithTypeArguments{} data.Expression = expression data.TypeArguments = typeArguments - return newNode(KindExpressionWithTypeArguments, data, f.hooks) + return f.newNode(KindExpressionWithTypeArguments, data) } func (f *NodeFactory) UpdateExpressionWithTypeArguments(node *ExpressionWithTypeArguments, expression *Expression, typeArguments *TypeArgumentList) *Node { @@ -6177,8 +7179,13 @@ func (node *ExpressionWithTypeArguments) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateExpressionWithTypeArguments(node, v.visitNode(node.Expression), v.visitNodes(node.TypeArguments)) } -func (node *ExpressionWithTypeArguments) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewExpressionWithTypeArguments(node.Expression, node.TypeArguments), node.AsNode(), f.hooks) +func (node *ExpressionWithTypeArguments) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewExpressionWithTypeArguments(node.Expression, node.TypeArguments), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ExpressionWithTypeArguments) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) } func IsExpressionWithTypeArguments(node *Node) bool { @@ -6195,7 +7202,7 @@ type LiteralTypeNode struct { func (f *NodeFactory) NewLiteralTypeNode(literal *Node) *Node { data := f.literalTypeNodePool.New() data.Literal = literal - return newNode(KindLiteralType, data, f.hooks) + return f.newNode(KindLiteralType, data) } func (f *NodeFactory) UpdateLiteralTypeNode(node *LiteralTypeNode, literal *Node) *Node { @@ -6213,8 +7220,8 @@ func (node *LiteralTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateLiteralTypeNode(node, v.visitNode(node.Literal)) } -func (node *LiteralTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewLiteralTypeNode(node.Literal), node.AsNode(), f.hooks) +func (node *LiteralTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewLiteralTypeNode(node.Literal), node.AsNode(), f.AsNodeFactory().hooks) } func IsLiteralTypeNode(node *Node) bool { @@ -6228,11 +7235,11 @@ type ThisTypeNode struct { } func (f *NodeFactory) NewThisTypeNode() *Node { - return newNode(KindThisType, &ThisTypeNode{}, f.hooks) + return f.newNode(KindThisType, &ThisTypeNode{}) } -func (node *ThisTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewThisTypeNode(), node.AsNode(), f.hooks) +func (node *ThisTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewThisTypeNode(), node.AsNode(), f.AsNodeFactory().hooks) } func IsThisTypeNode(node *Node) bool { @@ -6253,7 +7260,7 @@ func (f *NodeFactory) NewTypePredicateNode(assertsModifier *TokenNode, parameter data.AssertsModifier = assertsModifier data.ParameterName = parameterName data.Type = typeNode - return newNode(KindTypePredicate, data, f.hooks) + return f.newNode(KindTypePredicate, data) } func (f *NodeFactory) UpdateTypePredicateNode(node *TypePredicateNode, assertsModifier *TokenNode, parameterName *TypePredicateParameterName, typeNode *TypeNode) *Node { @@ -6271,8 +7278,8 @@ func (node *TypePredicateNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypePredicateNode(node, v.visitNode(node.AssertsModifier), v.visitNode(node.ParameterName), v.visitNode(node.Type)) } -func (node *TypePredicateNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypePredicateNode(node.AssertsModifier, node.ParameterName, node.Type), node.AsNode(), f.hooks) +func (node *TypePredicateNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypePredicateNode(node.AssertsModifier, node.ParameterName, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsTypePredicateNode(node *Node) bool { @@ -6297,7 +7304,7 @@ func (f *NodeFactory) NewImportTypeNode(isTypeOf bool, argument *TypeNode, attri data.Attributes = attributes data.Qualifier = qualifier data.TypeArguments = typeArguments - return newNode(KindImportType, data, f.hooks) + return f.newNode(KindImportType, data) } func (f *NodeFactory) UpdateImportTypeNode(node *ImportTypeNode, isTypeOf bool, argument *TypeNode, attributes *ImportAttributesNode, qualifier *EntityName, typeArguments *TypeArgumentList) *Node { @@ -6315,8 +7322,8 @@ func (node *ImportTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportTypeNode(node, node.IsTypeOf, v.visitNode(node.Argument), v.visitNode(node.Attributes), v.visitNode(node.Qualifier), v.visitNodes(node.TypeArguments)) } -func (node *ImportTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportTypeNode(node.IsTypeOf, node.Argument, node.Attributes, node.Qualifier, node.TypeArguments), node.AsNode(), f.hooks) +func (node *ImportTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportTypeNode(node.IsTypeOf, node.Argument, node.Attributes, node.Qualifier, node.TypeArguments), node.AsNode(), f.AsNodeFactory().hooks) } func IsImportTypeNode(node *Node) bool { @@ -6327,6 +7334,7 @@ func IsImportTypeNode(node *Node) bool { type ImportAttribute struct { NodeBase + compositeNodeBase name *ImportAttributeName // ImportAttributeName Value *Expression // Expression } @@ -6335,7 +7343,7 @@ func (f *NodeFactory) NewImportAttribute(name *ImportAttributeName, value *Expre data := &ImportAttribute{} data.name = name data.Value = value - return newNode(KindImportAttribute, data, f.hooks) + return f.newNode(KindImportAttribute, data) } func (f *NodeFactory) UpdateImportAttribute(node *ImportAttribute, name *ImportAttributeName, value *Expression) *Node { @@ -6353,8 +7361,13 @@ func (node *ImportAttribute) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportAttribute(node, v.visitNode(node.name), v.visitNode(node.Value)) } -func (node *ImportAttribute) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportAttribute(node.Name(), node.Value), node.AsNode(), f.hooks) +func (node *ImportAttribute) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportAttribute(node.Name(), node.Value), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ImportAttribute) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Value) } func (node *ImportAttribute) Name() *ImportAttributeName { @@ -6365,6 +7378,7 @@ func (node *ImportAttribute) Name() *ImportAttributeName { type ImportAttributes struct { NodeBase + compositeNodeBase Token Kind Attributes *NodeList // NodeList[*ImportAttributeNode] MultiLine bool @@ -6375,7 +7389,7 @@ func (f *NodeFactory) NewImportAttributes(token Kind, attributes *NodeList, mult data.Token = token data.Attributes = attributes data.MultiLine = multiLine - return newNode(KindImportAttributes, data, f.hooks) + return f.newNode(KindImportAttributes, data) } func (f *NodeFactory) UpdateImportAttributes(node *ImportAttributes, attributes *ImportAttributeList) *Node { @@ -6393,8 +7407,12 @@ func (node *ImportAttributes) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateImportAttributes(node, v.visitNodes(node.Attributes)) } -func (node *ImportAttributes) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewImportAttributes(node.Token, node.Attributes, node.MultiLine), node.AsNode(), f.hooks) +func (node *ImportAttributes) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewImportAttributes(node.Token, node.Attributes, node.MultiLine), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *ImportAttributes) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Attributes, propagateSubtreeFacts) } func IsImportAttributes(node *Node) bool { @@ -6413,7 +7431,7 @@ func (f *NodeFactory) NewTypeQueryNode(exprName *EntityName, typeArguments *Node data := &TypeQueryNode{} data.ExprName = exprName data.TypeArguments = typeArguments - return newNode(KindTypeQuery, data, f.hooks) + return f.newNode(KindTypeQuery, data) } func (f *NodeFactory) UpdateTypeQueryNode(node *TypeQueryNode, exprName *EntityName, typeArguments *TypeArgumentList) *Node { @@ -6431,8 +7449,8 @@ func (node *TypeQueryNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeQueryNode(node, v.visitNode(node.ExprName), v.visitNodes(node.TypeArguments)) } -func (node *TypeQueryNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeQueryNode(node.ExprName, node.TypeArguments), node.AsNode(), f.hooks) +func (node *TypeQueryNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeQueryNode(node.ExprName, node.TypeArguments), node.AsNode(), f.AsNodeFactory().hooks) } func IsTypeQueryNode(node *Node) bool { @@ -6461,7 +7479,7 @@ func (f *NodeFactory) NewMappedTypeNode(readonlyToken *TokenNode, typeParameter data.QuestionToken = questionToken data.Type = typeNode data.Members = members - return newNode(KindMappedType, data, f.hooks) + return f.newNode(KindMappedType, data) } func (f *NodeFactory) UpdateMappedTypeNode(node *MappedTypeNode, readonlyToken *TokenNode, typeParameter *TypeParameterDeclarationNode, nameType *TypeNode, questionToken *TokenNode, typeNode *TypeNode, members *TypeElementList) *Node { @@ -6480,8 +7498,8 @@ func (node *MappedTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateMappedTypeNode(node, v.visitToken(node.ReadonlyToken), v.visitNode(node.TypeParameter), v.visitNode(node.NameType), v.visitToken(node.QuestionToken), v.visitNode(node.Type), v.visitNodes(node.Members)) } -func (node *MappedTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewMappedTypeNode(node.ReadonlyToken, node.TypeParameter, node.NameType, node.QuestionToken, node.Type, node.Members), node.AsNode(), f.hooks) +func (node *MappedTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewMappedTypeNode(node.ReadonlyToken, node.TypeParameter, node.NameType, node.QuestionToken, node.Type, node.Members), node.AsNode(), f.AsNodeFactory().hooks) } func IsMappedTypeNode(node *Node) bool { @@ -6499,7 +7517,7 @@ type TypeLiteralNode struct { func (f *NodeFactory) NewTypeLiteralNode(members *NodeList) *Node { data := &TypeLiteralNode{} data.Members = members - return newNode(KindTypeLiteral, data, f.hooks) + return f.newNode(KindTypeLiteral, data) } func (f *NodeFactory) UpdateTypeLiteralNode(node *TypeLiteralNode, members *TypeElementList) *Node { @@ -6517,8 +7535,8 @@ func (node *TypeLiteralNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTypeLiteralNode(node, v.visitNodes(node.Members)) } -func (node *TypeLiteralNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTypeLiteralNode(node.Members), node.AsNode(), f.hooks) +func (node *TypeLiteralNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTypeLiteralNode(node.Members), node.AsNode(), f.AsNodeFactory().hooks) } func IsTypeLiteralNode(node *Node) bool { @@ -6535,7 +7553,7 @@ type TupleTypeNode struct { func (f *NodeFactory) NewTupleTypeNode(elements *NodeList) *Node { data := &TupleTypeNode{} data.Elements = elements - return newNode(KindTupleType, data, f.hooks) + return f.newNode(KindTupleType, data) } func (f *NodeFactory) UpdateTupleTypeNode(node *TupleTypeNode, elements *TypeList) *Node { @@ -6553,8 +7571,8 @@ func (node *TupleTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTupleTypeNode(node, v.visitNodes(node.Elements)) } -func (node *TupleTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTupleTypeNode(node.Elements), node.AsNode(), f.hooks) +func (node *TupleTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTupleTypeNode(node.Elements), node.AsNode(), f.AsNodeFactory().hooks) } func IsTupleTypeNode(node *Node) bool { @@ -6578,7 +7596,7 @@ func (f *NodeFactory) NewNamedTupleMember(dotDotDotToken *TokenNode, name *Ident data.name = name data.QuestionToken = questionToken data.Type = typeNode - return newNode(KindNamedTupleMember, data, f.hooks) + return f.newNode(KindNamedTupleMember, data) } func (f *NodeFactory) UpdateNamedTupleMember(node *NamedTupleMember, dotDotDotToken *TokenNode, name *IdentifierNode, questionToken *TokenNode, typeNode *TypeNode) *Node { @@ -6596,8 +7614,8 @@ func (node *NamedTupleMember) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateNamedTupleMember(node, v.visitToken(node.DotDotDotToken), v.visitNode(node.name), v.visitToken(node.QuestionToken), v.visitNode(node.Type)) } -func (node *NamedTupleMember) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewNamedTupleMember(node.DotDotDotToken, node.Name(), node.QuestionToken, node.Type), node.AsNode(), f.hooks) +func (node *NamedTupleMember) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewNamedTupleMember(node.DotDotDotToken, node.Name(), node.QuestionToken, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func (node *NamedTupleMember) Name() *DeclarationName { @@ -6618,7 +7636,7 @@ type OptionalTypeNode struct { func (f *NodeFactory) NewOptionalTypeNode(typeNode *TypeNode) *Node { data := &OptionalTypeNode{} data.Type = typeNode - return newNode(KindOptionalType, data, f.hooks) + return f.newNode(KindOptionalType, data) } func (f *NodeFactory) UpdateOptionalTypeNode(node *OptionalTypeNode, typeNode *TypeNode) *Node { @@ -6636,8 +7654,8 @@ func (node *OptionalTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateOptionalTypeNode(node, v.visitNode(node.Type)) } -func (node *OptionalTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewOptionalTypeNode(node.Type), node.AsNode(), f.hooks) +func (node *OptionalTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewOptionalTypeNode(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsOptionalTypeNode(node *Node) bool { @@ -6654,7 +7672,7 @@ type RestTypeNode struct { func (f *NodeFactory) NewRestTypeNode(typeNode *TypeNode) *Node { data := &RestTypeNode{} data.Type = typeNode - return newNode(KindRestType, data, f.hooks) + return f.newNode(KindRestType, data) } func (f *NodeFactory) UpdateRestTypeNode(node *RestTypeNode, typeNode *TypeNode) *Node { @@ -6672,8 +7690,8 @@ func (node *RestTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateRestTypeNode(node, v.visitNode(node.Type)) } -func (node *RestTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewRestTypeNode(node.Type), node.AsNode(), f.hooks) +func (node *RestTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewRestTypeNode(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsRestTypeNode(node *Node) bool { @@ -6690,7 +7708,7 @@ type ParenthesizedTypeNode struct { func (f *NodeFactory) NewParenthesizedTypeNode(typeNode *TypeNode) *Node { data := &ParenthesizedTypeNode{} data.Type = typeNode - return newNode(KindParenthesizedType, data, f.hooks) + return f.newNode(KindParenthesizedType, data) } func (f *NodeFactory) UpdateParenthesizedTypeNode(node *ParenthesizedTypeNode, typeNode *TypeNode) *Node { @@ -6708,8 +7726,8 @@ func (node *ParenthesizedTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateParenthesizedTypeNode(node, v.visitNode(node.Type)) } -func (node *ParenthesizedTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewParenthesizedTypeNode(node.Type), node.AsNode(), f.hooks) +func (node *ParenthesizedTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewParenthesizedTypeNode(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsParenthesizedTypeNode(node *Node) bool { @@ -6740,7 +7758,7 @@ func (f *NodeFactory) NewFunctionTypeNode(typeParameters *NodeList, parameters * data.TypeParameters = typeParameters data.Parameters = parameters data.Type = returnType - return newNode(KindFunctionType, data, f.hooks) + return f.newNode(KindFunctionType, data) } func (f *NodeFactory) UpdateFunctionTypeNode(node *FunctionTypeNode, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -6754,8 +7772,8 @@ func (node *FunctionTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateFunctionTypeNode(node, v.visitNodes(node.TypeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *FunctionTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewFunctionTypeNode(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *FunctionTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewFunctionTypeNode(node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsFunctionTypeNode(node *Node) bool { @@ -6774,7 +7792,7 @@ func (f *NodeFactory) NewConstructorTypeNode(modifiers *ModifierList, typeParame data.TypeParameters = typeParameters data.Parameters = parameters data.Type = returnType - return newNode(KindConstructorType, data, f.hooks) + return f.newNode(KindConstructorType, data) } func (f *NodeFactory) UpdateConstructorTypeNode(node *ConstructorTypeNode, modifiers *ModifierList, typeParameters *TypeParameterList, parameters *ParameterList, returnType *TypeNode) *Node { @@ -6788,8 +7806,8 @@ func (node *ConstructorTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateConstructorTypeNode(node, v.visitModifiers(node.modifiers), v.visitNodes(node.TypeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *ConstructorTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewConstructorTypeNode(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *ConstructorTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewConstructorTypeNode(node.Modifiers(), node.TypeParameters, node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func IsConstructorTypeNode(node *Node) bool { @@ -6819,11 +7837,12 @@ func (f *NodeFactory) NewTemplateHead(text string, rawText string, templateFlags data.Text = text data.RawText = rawText data.TemplateFlags = templateFlags - return newNode(KindTemplateHead, data, f.hooks) + f.textCount++ + return f.newNode(KindTemplateHead, data) } -func (node *TemplateHead) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateHead(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.hooks) +func (node *TemplateHead) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateHead(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.AsNodeFactory().hooks) } // TemplateMiddle @@ -6838,11 +7857,12 @@ func (f *NodeFactory) NewTemplateMiddle(text string, rawText string, templateFla data.Text = text data.RawText = rawText data.TemplateFlags = templateFlags - return newNode(KindTemplateMiddle, data, f.hooks) + f.textCount++ + return f.newNode(KindTemplateMiddle, data) } -func (node *TemplateMiddle) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateMiddle(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.hooks) +func (node *TemplateMiddle) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateMiddle(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.AsNodeFactory().hooks) } // TemplateTail @@ -6857,11 +7877,12 @@ func (f *NodeFactory) NewTemplateTail(text string, rawText string, templateFlags data.Text = text data.RawText = rawText data.TemplateFlags = templateFlags - return newNode(KindTemplateTail, data, f.hooks) + f.textCount++ + return f.newNode(KindTemplateTail, data) } -func (node *TemplateTail) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateTail(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.hooks) +func (node *TemplateTail) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateTail(node.Text, node.RawText, node.TemplateFlags), node.AsNode(), f.AsNodeFactory().hooks) } // TemplateLiteralTypeNode @@ -6876,7 +7897,7 @@ func (f *NodeFactory) NewTemplateLiteralTypeNode(head *TemplateHeadNode, templat data := &TemplateLiteralTypeNode{} data.Head = head data.TemplateSpans = templateSpans - return newNode(KindTemplateLiteralType, data, f.hooks) + return f.newNode(KindTemplateLiteralType, data) } func (f *NodeFactory) UpdateTemplateLiteralTypeNode(node *TemplateLiteralTypeNode, head *TemplateHeadNode, templateSpans *TemplateLiteralTypeSpanList) *Node { @@ -6894,14 +7915,15 @@ func (node *TemplateLiteralTypeNode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTemplateLiteralTypeNode(node, v.visitNode(node.Head), v.visitNodes(node.TemplateSpans)) } -func (node *TemplateLiteralTypeNode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateLiteralTypeNode(node.Head, node.TemplateSpans), node.AsNode(), f.hooks) +func (node *TemplateLiteralTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateLiteralTypeNode(node.Head, node.TemplateSpans), node.AsNode(), f.AsNodeFactory().hooks) } // TemplateLiteralTypeSpan type TemplateLiteralTypeSpan struct { NodeBase + typeSyntaxBase Type *TypeNode // TypeNode Literal *TemplateMiddleOrTail // TemplateMiddleOrTail } @@ -6910,7 +7932,7 @@ func (f *NodeFactory) NewTemplateLiteralTypeSpan(typeNode *TypeNode, literal *Te data := &TemplateLiteralTypeSpan{} data.Type = typeNode data.Literal = literal - return newNode(KindTemplateLiteralTypeSpan, data, f.hooks) + return f.newNode(KindTemplateLiteralTypeSpan, data) } func (f *NodeFactory) UpdateTemplateLiteralTypeSpan(node *TemplateLiteralTypeSpan, typeNode *TypeNode, literal *TemplateMiddleOrTail) *Node { @@ -6928,8 +7950,8 @@ func (node *TemplateLiteralTypeSpan) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateTemplateLiteralTypeSpan(node, v.visitNode(node.Type), v.visitNode(node.Literal)) } -func (node *TemplateLiteralTypeSpan) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewTemplateLiteralTypeSpan(node.Type, node.Literal), node.AsNode(), f.hooks) +func (node *TemplateLiteralTypeSpan) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewTemplateLiteralTypeSpan(node.Type, node.Literal), node.AsNode(), f.AsNodeFactory().hooks) } func IsTemplateLiteralTypeSpan(node *Node) bool { @@ -6950,11 +7972,11 @@ func (f *NodeFactory) NewSyntheticExpression(t any, isSpread bool, tupleNameSour data.Type = t data.IsSpread = isSpread data.TupleNameSource = tupleNameSource - return newNode(KindSyntheticExpression, data, f.hooks) + return f.newNode(KindSyntheticExpression, data) } -func (node *SyntheticExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSyntheticExpression(node.Type, node.IsSpread, node.TupleNameSource), node.AsNode(), f.hooks) +func (node *SyntheticExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSyntheticExpression(node.Type, node.IsSpread, node.TupleNameSource), node.AsNode(), f.AsNodeFactory().hooks) } func IsSyntheticExpression(node *Node) bool { @@ -6989,8 +8011,16 @@ func (node *PartiallyEmittedExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdatePartiallyEmittedExpression(node, v.visitNode(node.Expression)) } -func (node *PartiallyEmittedExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewPartiallyEmittedExpression(node.Expression), node.AsNode(), f.hooks) +func (node *PartiallyEmittedExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewPartiallyEmittedExpression(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *PartiallyEmittedExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) +} + +func (node *PartiallyEmittedExpression) propagateSubtreeFacts() SubtreeFacts { + return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression } func IsPartiallyEmittedExpression(node *Node) bool { @@ -7001,6 +8031,7 @@ func IsPartiallyEmittedExpression(node *Node) bool { type JsxElement struct { ExpressionBase + compositeNodeBase OpeningElement *JsxOpeningElementNode // JsxOpeningElementNode Children *NodeList // NodeList[*JsxChild] ClosingElement *JsxClosingElementNode // JsxClosingElementNode @@ -7011,7 +8042,7 @@ func (f *NodeFactory) NewJsxElement(openingElement *JsxOpeningElementNode, child data.OpeningElement = openingElement data.Children = children data.ClosingElement = closingElement - return newNode(KindJsxElement, data, f.hooks) + return f.newNode(KindJsxElement, data) } func (f *NodeFactory) UpdateJsxElement(node *JsxElement, openingElement *JsxOpeningElementNode, children *JsxChildList, closingElement *JsxClosingElementNode) *Node { @@ -7029,21 +8060,33 @@ func (node *JsxElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxElement(node, v.visitNode(node.OpeningElement), v.visitNodes(node.Children), v.visitNode(node.ClosingElement)) } -func (node *JsxElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxElement(node.OpeningElement, node.Children, node.ClosingElement), node.AsNode(), f.hooks) +func (node *JsxElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxElement(node.OpeningElement, node.Children, node.ClosingElement), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.OpeningElement) | + propagateNodeListSubtreeFacts(node.Children, propagateSubtreeFacts) | + propagateSubtreeFacts(node.ClosingElement) | + SubtreeContainsJsx +} + +func IsJsxElement(node *Node) bool { + return node.Kind == KindJsxElement } // JsxAttributes type JsxAttributes struct { ExpressionBase DeclarationBase + compositeNodeBase Properties *NodeList // NodeList[*JsxAttributeLike] } func (f *NodeFactory) NewJsxAttributes(properties *NodeList) *Node { data := &JsxAttributes{} data.Properties = properties - return newNode(KindJsxAttributes, data, f.hooks) + return f.newNode(KindJsxAttributes, data) } func (f *NodeFactory) UpdateJsxAttributes(node *JsxAttributes, properties *JsxAttributeList) *Node { @@ -7061,8 +8104,13 @@ func (node *JsxAttributes) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxAttributes(node, v.visitNodes(node.Properties)) } -func (node *JsxAttributes) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxAttributes(node.Properties), node.AsNode(), f.hooks) +func (node *JsxAttributes) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxAttributes(node.Properties), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxAttributes) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Properties, propagateSubtreeFacts) | + SubtreeContainsJsx } func IsJsxAttributes(node *Node) bool { @@ -7073,6 +8121,7 @@ func IsJsxAttributes(node *Node) bool { type JsxNamespacedName struct { ExpressionBase + compositeNodeBase name *IdentifierNode // IdentifierNode Namespace *IdentifierNode // IdentifierNode } @@ -7081,7 +8130,7 @@ func (f *NodeFactory) NewJsxNamespacedName(namespace *IdentifierNode, name *Iden data := &JsxNamespacedName{} data.Namespace = namespace data.name = name - return newNode(KindJsxNamespacedName, data, f.hooks) + return f.newNode(KindJsxNamespacedName, data) } func (f *NodeFactory) UpdateJsxNamespacedName(node *JsxNamespacedName, name *IdentifierNode, namespace *IdentifierNode) *Node { @@ -7099,14 +8148,20 @@ func (node *JsxNamespacedName) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxNamespacedName(node, v.visitNode(node.name), v.visitNode(node.Namespace)) } -func (node *JsxNamespacedName) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxNamespacedName(node.Name(), node.Namespace), node.AsNode(), f.hooks) +func (node *JsxNamespacedName) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxNamespacedName(node.Name(), node.Namespace), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JsxNamespacedName) Name() *DeclarationName { return node.name } +func (node *JsxNamespacedName) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Namespace) | + propagateSubtreeFacts(node.name) | + SubtreeContainsJsx +} + func IsJsxNamespacedName(node *Node) bool { return node.Kind == KindJsxNamespacedName } @@ -7115,6 +8170,7 @@ func IsJsxNamespacedName(node *Node) bool { type JsxOpeningElement struct { ExpressionBase + compositeNodeBase TagName *JsxTagNameExpression // JsxTagNameExpression (Identifier | KeywordExpression | JsxTagNamePropertyAccess | JsxNamespacedName) TypeArguments *NodeList // NodeList[*TypeNode]. Optional Attributes *JsxAttributesNode // JsxAttributesNode @@ -7125,7 +8181,7 @@ func (f *NodeFactory) NewJsxOpeningElement(tagName *JsxTagNameExpression, typeAr data.TagName = tagName data.TypeArguments = typeArguments data.Attributes = attributes - return newNode(KindJsxOpeningElement, data, f.hooks) + return f.newNode(KindJsxOpeningElement, data) } func (f *NodeFactory) UpdateJsxOpeningElement(node *JsxOpeningElement, tagName *JsxTagNameExpression, typeArguments *TypeArgumentList, attributes *JsxAttributesNode) *Node { @@ -7143,8 +8199,15 @@ func (node *JsxOpeningElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxOpeningElement(node, v.visitNode(node.TagName), v.visitNodes(node.TypeArguments), v.visitNode(node.Attributes)) } -func (node *JsxOpeningElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxOpeningElement(node.TagName, node.TypeArguments, node.Attributes), node.AsNode(), f.hooks) +func (node *JsxOpeningElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxOpeningElement(node.TagName, node.TypeArguments, node.Attributes), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxOpeningElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.TagName) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) | + propagateSubtreeFacts(node.Attributes) | + SubtreeContainsJsx } func IsJsxOpeningElement(node *Node) bool { @@ -7155,6 +8218,7 @@ func IsJsxOpeningElement(node *Node) bool { type JsxSelfClosingElement struct { ExpressionBase + compositeNodeBase TagName *JsxTagNameExpression // JsxTagNameExpression (IdentifierReference | KeywordExpression | JsxTagNamePropertyAccess | JsxNamespacedName) TypeArguments *NodeList // NodeList[*TypeNode]. Optional Attributes *JsxAttributesNode // JsxAttributesNode @@ -7165,7 +8229,7 @@ func (f *NodeFactory) NewJsxSelfClosingElement(tagName *JsxTagNameExpression, ty data.TagName = tagName data.TypeArguments = typeArguments data.Attributes = attributes - return newNode(KindJsxSelfClosingElement, data, f.hooks) + return f.newNode(KindJsxSelfClosingElement, data) } func (f *NodeFactory) UpdateJsxSelfClosingElement(node *JsxSelfClosingElement, tagName *JsxTagNameExpression, typeArguments *TypeArgumentList, attributes *JsxAttributesNode) *Node { @@ -7183,8 +8247,15 @@ func (node *JsxSelfClosingElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxSelfClosingElement(node, v.visitNode(node.TagName), v.visitNodes(node.TypeArguments), v.visitNode(node.Attributes)) } -func (node *JsxSelfClosingElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxSelfClosingElement(node.TagName, node.TypeArguments, node.Attributes), node.AsNode(), f.hooks) +func (node *JsxSelfClosingElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxSelfClosingElement(node.TagName, node.TypeArguments, node.Attributes), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxSelfClosingElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.TagName) | + propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) | + propagateSubtreeFacts(node.Attributes) | + SubtreeContainsJsx } func IsJsxSelfClosingElement(node *Node) bool { @@ -7195,6 +8266,7 @@ func IsJsxSelfClosingElement(node *Node) bool { type JsxFragment struct { ExpressionBase + compositeNodeBase OpeningFragment *JsxOpeningFragmentNode // JsxOpeningFragmentNode Children *NodeList // NodeList[*JsxChild] ClosingFragment *JsxClosingFragmentNode // JsxClosingFragmentNode @@ -7205,7 +8277,7 @@ func (f *NodeFactory) NewJsxFragment(openingFragment *JsxOpeningFragmentNode, ch data.OpeningFragment = openingFragment data.Children = children data.ClosingFragment = closingFragment - return newNode(KindJsxFragment, data, f.hooks) + return f.newNode(KindJsxFragment, data) } func (f *NodeFactory) UpdateJsxFragment(node *JsxFragment, openingFragment *JsxOpeningFragmentNode, children *JsxChildList, closingFragment *JsxClosingFragmentNode) *Node { @@ -7223,8 +8295,17 @@ func (node *JsxFragment) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxFragment(node, v.visitNode(node.OpeningFragment), v.visitNodes(node.Children), v.visitNode(node.ClosingFragment)) } -func (node *JsxFragment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxFragment(node.OpeningFragment, node.Children, node.ClosingFragment), node.AsNode(), f.hooks) +func (node *JsxFragment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxFragment(node.OpeningFragment, node.Children, node.ClosingFragment), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxFragment) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Children, propagateSubtreeFacts) | + SubtreeContainsJsx +} + +func IsJsxFragment(node *Node) bool { + return node.Kind == KindJsxFragment } /// The opening element of a <>...</> JsxFragment @@ -7234,11 +8315,15 @@ type JsxOpeningFragment struct { } func (f *NodeFactory) NewJsxOpeningFragment() *Node { - return newNode(KindJsxOpeningFragment, &JsxOpeningFragment{}, f.hooks) + return f.newNode(KindJsxOpeningFragment, &JsxOpeningFragment{}) +} + +func (node *JsxOpeningFragment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxOpeningFragment(), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *JsxOpeningFragment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxOpeningFragment(), node.AsNode(), f.hooks) +func (node *JsxOpeningFragment) computeSubtreeFacts() SubtreeFacts { + return SubtreeContainsJsx } func IsJsxOpeningFragment(node *Node) bool { @@ -7252,11 +8337,15 @@ type JsxClosingFragment struct { } func (f *NodeFactory) NewJsxClosingFragment() *Node { - return newNode(KindJsxClosingFragment, &JsxClosingFragment{}, f.hooks) + return f.newNode(KindJsxClosingFragment, &JsxClosingFragment{}) +} + +func (node *JsxClosingFragment) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxClosingFragment(), node.AsNode(), f.AsNodeFactory().hooks) } -func (node *JsxClosingFragment) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxClosingFragment(), node.AsNode(), f.hooks) +func (node *JsxClosingFragment) computeSubtreeFacts() SubtreeFacts { + return SubtreeContainsJsx } // JsxAttribute @@ -7264,6 +8353,7 @@ func (node *JsxClosingFragment) Clone(f *NodeFactory) *Node { type JsxAttribute struct { NodeBase DeclarationBase + compositeNodeBase name *JsxAttributeName // JsxAttributeName Initializer *JsxAttributeValue // JsxAttributeValue. Optional, <X y /> is sugar for <X y={true} /> } @@ -7272,11 +8362,7 @@ func (f *NodeFactory) NewJsxAttribute(name *JsxAttributeName, initializer *JsxAt data := &JsxAttribute{} data.name = name data.Initializer = initializer - return newNode(KindJsxAttribute, data, f.hooks) -} - -func (node *JsxAttribute) Name() *JsxAttributeName { - return node.name + return f.newNode(KindJsxAttribute, data) } func (f *NodeFactory) UpdateJsxAttribute(node *JsxAttribute, name *JsxAttributeName, initializer *JsxAttributeValue) *Node { @@ -7294,8 +8380,18 @@ func (node *JsxAttribute) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxAttribute(node, v.visitNode(node.name), v.visitNode(node.Initializer)) } -func (node *JsxAttribute) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxAttribute(node.Name(), node.Initializer), node.AsNode(), f.hooks) +func (node *JsxAttribute) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxAttribute(node.Name(), node.Initializer), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxAttribute) Name() *JsxAttributeName { + return node.name +} + +func (node *JsxAttribute) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.name) | + propagateSubtreeFacts(node.Initializer) | + SubtreeContainsJsx } func IsJsxAttribute(node *Node) bool { @@ -7312,7 +8408,7 @@ type JsxSpreadAttribute struct { func (f *NodeFactory) NewJsxSpreadAttribute(expression *Expression) *Node { data := &JsxSpreadAttribute{} data.Expression = expression - return newNode(KindJsxSpreadAttribute, data, f.hooks) + return f.newNode(KindJsxSpreadAttribute, data) } func (f *NodeFactory) UpdateJsxSpreadAttribute(node *JsxSpreadAttribute, expression *Expression) *Node { @@ -7330,8 +8426,16 @@ func (node *JsxSpreadAttribute) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxSpreadAttribute(node, v.visitNode(node.Expression)) } -func (node *JsxSpreadAttribute) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxSpreadAttribute(node.Expression), node.AsNode(), f.hooks) +func (node *JsxSpreadAttribute) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxSpreadAttribute(node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxSpreadAttribute) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsJsx +} + +func IsJsxSpreadAttribute(node *Node) bool { + return node.Kind == KindJsxSpreadAttribute } // JsxClosingElement @@ -7344,7 +8448,7 @@ type JsxClosingElement struct { func (f *NodeFactory) NewJsxClosingElement(tagName *JsxTagNameExpression) *Node { data := &JsxClosingElement{} data.TagName = tagName - return newNode(KindJsxClosingElement, data, f.hooks) + return f.newNode(KindJsxClosingElement, data) } func (f *NodeFactory) UpdateJsxClosingElement(node *JsxClosingElement, tagName *JsxTagNameExpression) *Node { @@ -7362,8 +8466,12 @@ func (node *JsxClosingElement) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxClosingElement(node, v.visitNode(node.TagName)) } -func (node *JsxClosingElement) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxClosingElement(node.TagName), node.AsNode(), f.hooks) +func (node *JsxClosingElement) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxClosingElement(node.TagName), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxClosingElement) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.TagName) | SubtreeContainsJsx } func IsJsxClosingElement(node *Node) bool { @@ -7382,7 +8490,7 @@ func (f *NodeFactory) NewJsxExpression(dotDotDotToken *TokenNode, expression *Ex data := &JsxExpression{} data.DotDotDotToken = dotDotDotToken data.Expression = expression - return newNode(KindJsxExpression, data, f.hooks) + return f.newNode(KindJsxExpression, data) } func (f *NodeFactory) UpdateJsxExpression(node *JsxExpression, dotDotDotToken *TokenNode, expression *Expression) *Node { @@ -7400,8 +8508,16 @@ func (node *JsxExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJsxExpression(node, v.visitToken(node.DotDotDotToken), v.visitNode(node.Expression)) } -func (node *JsxExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxExpression(node.DotDotDotToken, node.Expression), node.AsNode(), f.hooks) +func (node *JsxExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxExpression(node.DotDotDotToken, node.Expression), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxExpression) computeSubtreeFacts() SubtreeFacts { + return propagateSubtreeFacts(node.Expression) | SubtreeContainsJsx +} + +func IsJsxExpression(node *Node) bool { + return node.Kind == KindJsxExpression } // JsxText @@ -7416,11 +8532,20 @@ func (f *NodeFactory) NewJsxText(text string, containsOnlyTriviaWhiteSpace bool) data := &JsxText{} data.Text = text data.ContainsOnlyTriviaWhiteSpaces = containsOnlyTriviaWhiteSpace - return newNode(KindJsxText, data, f.hooks) + f.textCount++ + return f.newNode(KindJsxText, data) +} + +func (node *JsxText) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJsxText(node.Text, node.ContainsOnlyTriviaWhiteSpaces), node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *JsxText) computeSubtreeFacts() SubtreeFacts { + return SubtreeContainsJsx } -func (node *JsxText) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJsxText(node.Text, node.ContainsOnlyTriviaWhiteSpaces), node.AsNode(), f.hooks) +func IsJsxText(node *Node) bool { + return node.Kind == KindJsxText } // SyntaxList @@ -7433,15 +8558,15 @@ type SyntaxList struct { func (f *NodeFactory) NewSyntaxList(children []*Node) *Node { data := &SyntaxList{} data.Children = children - return newNode(KindSyntaxList, data, f.hooks) + return f.newNode(KindSyntaxList, data) } func (node *SyntaxList) ForEachChild(v Visitor) bool { return visitNodes(v, node.Children) } -func (node *SyntaxList) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewSyntaxList(node.Children), node.AsNode(), f.hooks) +func (node *SyntaxList) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewSyntaxList(node.Children), node.AsNode(), f.AsNodeFactory().hooks) } /// JSDoc /// @@ -7456,7 +8581,7 @@ func (f *NodeFactory) NewJSDoc(comment *NodeList, tags *NodeList) *Node { data := f.jsdocPool.New() data.Comment = comment data.Tags = tags - return newNode(KindJSDoc, data, f.hooks) + return f.newNode(KindJSDoc, data) } func (f *NodeFactory) UpdateJSDoc(node *JSDoc, comment *NodeList, tags *NodeList) *Node { @@ -7474,8 +8599,8 @@ func (node *JSDoc) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDoc(node, v.visitNodes(node.Comment), v.visitNodes(node.Tags)) } -func (node *JSDoc) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDoc(node.Comment, node.Tags), node.AsNode(), f.hooks) +func (node *JSDoc) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDoc(node.Comment, node.Tags), node.AsNode(), f.AsNodeFactory().hooks) } type JSDocTagBase struct { @@ -7497,11 +8622,12 @@ type JSDocText struct { func (f *NodeFactory) NewJSDocText(text string) *Node { data := f.jsdocTextPool.New() data.Text = text - return newNode(KindJSDocText, data, f.hooks) + f.textCount++ + return f.newNode(KindJSDocText, data) } -func (node *JSDocText) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocText(node.Text), node.AsNode(), f.hooks) +func (node *JSDocText) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocText(node.Text), node.AsNode(), f.AsNodeFactory().hooks) } type JSDocLink struct { @@ -7513,7 +8639,8 @@ func (f *NodeFactory) NewJSDocLink(name *Node, text string) *Node { data := &JSDocLink{} data.name = name data.Text = text - return newNode(KindJSDocLink, data, f.hooks) + f.textCount++ + return f.newNode(KindJSDocLink, data) } func (f *NodeFactory) UpdateJSDocLink(node *JSDocLink, name *Node, text string) *Node { @@ -7531,8 +8658,8 @@ func (node *JSDocLink) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocLink(node, v.visitNode(node.name), node.Text) } -func (node *JSDocLink) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocLink(node.Name(), node.Text), node.AsNode(), f.hooks) +func (node *JSDocLink) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocLink(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocLink) Name() *DeclarationName { @@ -7548,7 +8675,8 @@ func (f *NodeFactory) NewJSDocLinkPlain(name *Node, text string) *Node { data := &JSDocLinkPlain{} data.name = name data.Text = text - return newNode(KindJSDocLinkPlain, data, f.hooks) + f.textCount++ + return f.newNode(KindJSDocLinkPlain, data) } func (f *NodeFactory) UpdateJSDocLinkPlain(node *JSDocLinkPlain, name *Node, text string) *Node { @@ -7566,8 +8694,8 @@ func (node *JSDocLinkPlain) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocLinkPlain(node, v.visitNode(node.name), node.Text) } -func (node *JSDocLinkPlain) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocLinkPlain(node.Name(), node.Text), node.AsNode(), f.hooks) +func (node *JSDocLinkPlain) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocLinkPlain(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocLinkPlain) Name() *DeclarationName { @@ -7583,7 +8711,8 @@ func (f *NodeFactory) NewJSDocLinkCode(name *Node, text string) *Node { data := &JSDocLinkCode{} data.name = name data.Text = text - return newNode(KindJSDocLinkCode, data, f.hooks) + f.textCount++ + return f.newNode(KindJSDocLinkCode, data) } func (f *NodeFactory) UpdateJSDocLinkCode(node *JSDocLinkCode, name *Node, text string) *Node { @@ -7601,8 +8730,8 @@ func (node *JSDocLinkCode) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocLinkCode(node, v.visitNode(node.name), node.Text) } -func (node *JSDocLinkCode) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocLinkCode(node.Name(), node.Text), node.AsNode(), f.hooks) +func (node *JSDocLinkCode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocLinkCode(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocLinkCode) Name() *DeclarationName { @@ -7613,13 +8742,14 @@ func (node *JSDocLinkCode) Name() *DeclarationName { type JSDocTypeExpression struct { TypeNodeBase + Host *Node Type *TypeNode } func (f *NodeFactory) NewJSDocTypeExpression(typeNode *TypeNode) *Node { data := &JSDocTypeExpression{} data.Type = typeNode - return newNode(KindJSDocTypeExpression, data, f.hooks) + return f.newNode(KindJSDocTypeExpression, data) } func (f *NodeFactory) UpdateJSDocTypeExpression(node *JSDocTypeExpression, typeNode *TypeNode) *Node { @@ -7637,8 +8767,8 @@ func (node *JSDocTypeExpression) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocTypeExpression(node, v.visitNode(node.Type)) } -func (node *JSDocTypeExpression) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocTypeExpression(node.Type), node.AsNode(), f.hooks) +func (node *JSDocTypeExpression) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocTypeExpression(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocNonNullableType @@ -7651,7 +8781,7 @@ type JSDocNonNullableType struct { func (f *NodeFactory) NewJSDocNonNullableType(typeNode *TypeNode) *Node { data := &JSDocNonNullableType{} data.Type = typeNode - return newNode(KindJSDocNonNullableType, data, f.hooks) + return f.newNode(KindJSDocNonNullableType, data) } func (f *NodeFactory) UpdateJSDocNonNullableType(node *JSDocNonNullableType, typeNode *TypeNode) *Node { @@ -7669,8 +8799,12 @@ func (node *JSDocNonNullableType) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocNonNullableType(node, v.visitNode(node.Type)) } -func (node *JSDocNonNullableType) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocNonNullableType(node.Type), node.AsNode(), f.hooks) +func (node *JSDocNonNullableType) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocNonNullableType(node.Type), node.AsNode(), f.AsNodeFactory().hooks) +} + +func IsJSDocNonNullableType(node *Node) bool { + return node.Kind == KindJSDocNonNullableType } // JSDocNullableType @@ -7683,7 +8817,7 @@ type JSDocNullableType struct { func (f *NodeFactory) NewJSDocNullableType(typeNode *TypeNode) *Node { data := &JSDocNullableType{} data.Type = typeNode - return newNode(KindJSDocNullableType, data, f.hooks) + return f.newNode(KindJSDocNullableType, data) } func (f *NodeFactory) UpdateJSDocNullableType(node *JSDocNullableType, typeNode *TypeNode) *Node { @@ -7701,8 +8835,12 @@ func (node *JSDocNullableType) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocNullableType(node, v.visitNode(node.Type)) } -func (node *JSDocNullableType) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocNullableType(node.Type), node.AsNode(), f.hooks) +func (node *JSDocNullableType) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocNullableType(node.Type), node.AsNode(), f.AsNodeFactory().hooks) +} + +func IsJSDocNullableType(node *Node) bool { + return node.Kind == KindJSDocNullableType } // JSDocAllType @@ -7713,11 +8851,11 @@ type JSDocAllType struct { func (f *NodeFactory) NewJSDocAllType() *Node { data := &JSDocAllType{} - return newNode(KindJSDocAllType, data, f.hooks) + return f.newNode(KindJSDocAllType, data) } -func (node *JSDocAllType) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocAllType(), node.AsNode(), f.hooks) +func (node *JSDocAllType) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocAllType(), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocVariadicType @@ -7730,7 +8868,7 @@ type JSDocVariadicType struct { func (f *NodeFactory) NewJSDocVariadicType(typeNode *TypeNode) *Node { data := &JSDocVariadicType{} data.Type = typeNode - return newNode(KindJSDocVariadicType, data, f.hooks) + return f.newNode(KindJSDocVariadicType, data) } func (f *NodeFactory) UpdateJSDocVariadicType(node *JSDocVariadicType, typeNode *TypeNode) *Node { @@ -7748,8 +8886,8 @@ func (node *JSDocVariadicType) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocVariadicType(node, v.visitNode(node.Type)) } -func (node *JSDocVariadicType) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocVariadicType(node.Type), node.AsNode(), f.hooks) +func (node *JSDocVariadicType) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocVariadicType(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocOptionalType @@ -7762,7 +8900,7 @@ type JSDocOptionalType struct { func (f *NodeFactory) NewJSDocOptionalType(typeNode *TypeNode) *Node { data := &JSDocOptionalType{} data.Type = typeNode - return newNode(KindJSDocOptionalType, data, f.hooks) + return f.newNode(KindJSDocOptionalType, data) } func (f *NodeFactory) UpdateJSDocOptionalType(node *JSDocOptionalType, typeNode *TypeNode) *Node { @@ -7780,8 +8918,8 @@ func (node *JSDocOptionalType) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocOptionalType(node, v.visitNode(node.Type)) } -func (node *JSDocOptionalType) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocOptionalType(node.Type), node.AsNode(), f.hooks) +func (node *JSDocOptionalType) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocOptionalType(node.Type), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocTypeTag @@ -7796,7 +8934,7 @@ func (f *NodeFactory) NewJSDocTypeTag(tagName *IdentifierNode, typeExpression *N data.TagName = tagName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocTypeTag, data, f.hooks) + return f.newNode(KindJSDocTypeTag, data) } func (f *NodeFactory) UpdateJSDocTypeTag(node *JSDocTypeTag, tagName *IdentifierNode, typeExpression *TypeNode, comment *NodeList) *Node { @@ -7814,8 +8952,8 @@ func (node *JSDocTypeTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocTypeTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNodes(node.Comment)) } -func (node *JSDocTypeTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocTypeTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocTypeTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocTypeTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func IsJSDocTypeTag(node *Node) bool { @@ -7831,7 +8969,7 @@ func (f *NodeFactory) NewJSDocUnknownTag(tagName *IdentifierNode, comment *NodeL data := &JSDocUnknownTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocTag, data, f.hooks) + return f.newNode(KindJSDocTag, data) } func (f *NodeFactory) UpdateJSDocUnknownTag(node *JSDocUnknownTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -7849,8 +8987,8 @@ func (node *JSDocUnknownTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocUnknownTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocUnknownTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocUnknownTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocUnknownTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocUnknownTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func IsJSDocUnknownTag(node *Node) bool { @@ -7870,7 +9008,7 @@ func (f *NodeFactory) NewJSDocTemplateTag(tagName *IdentifierNode, constraint *N data.Constraint = constraint data.typeParameters = typeParameters data.Comment = comment - return newNode(KindJSDocTemplateTag, data, f.hooks) + return f.newNode(KindJSDocTemplateTag, data) } func (f *NodeFactory) UpdateJSDocTemplateTag(node *JSDocTemplateTag, tagName *IdentifierNode, constraint *Node, typeParameters *TypeParameterList, comment *NodeList) *Node { @@ -7888,14 +9026,13 @@ func (node *JSDocTemplateTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocTemplateTag(node, v.visitNode(node.TagName), v.visitNode(node.Constraint), v.visitNodes(node.typeParameters), v.visitNodes(node.Comment)) } -func (node *JSDocTemplateTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocTemplateTag(node.TagName, node.Constraint, node.TypeParameters(), node.Comment), node.AsNode(), f.hooks) +func (node *JSDocTemplateTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocTemplateTag(node.TagName, node.Constraint, node.TypeParameters(), node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocTemplateTag) TypeParameters() *TypeParameterList { return node.typeParameters } -// JSDocParameterTag - +// JSDocPropertyTag type JSDocPropertyTag struct { JSDocTagBase name *EntityName @@ -7912,7 +9049,7 @@ func (f *NodeFactory) NewJSDocPropertyTag(tagName *IdentifierNode, name *EntityN data.TypeExpression = typeExpression data.IsNameFirst = isNameFirst data.Comment = comment - return newNode(KindJSDocPropertyTag, data, f.hooks) + return f.newNode(KindJSDocPropertyTag, data) } func (f *NodeFactory) UpdateJSDocPropertyTag(node *JSDocPropertyTag, tagName *IdentifierNode, name *EntityName, isBracketed bool, typeExpression *TypeNode, isNameFirst bool, comment *NodeList) *Node { @@ -7941,12 +9078,13 @@ func (node *JSDocPropertyTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocPropertyTag(node, tagName, name, node.IsBracketed, typeExpression, node.IsNameFirst, v.visitNodes(node.Comment)) } -func (node *JSDocPropertyTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocPropertyTag(node.TagName, node.Name(), node.IsBracketed, node.TypeExpression, node.IsNameFirst, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocPropertyTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocPropertyTag(node.TagName, node.Name(), node.IsBracketed, node.TypeExpression, node.IsNameFirst, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocPropertyTag) Name() *EntityName { return node.name } +// JSDocParameterTag type JSDocParameterTag struct { JSDocTagBase name *EntityName @@ -7963,7 +9101,7 @@ func (f *NodeFactory) NewJSDocParameterTag(tagName *IdentifierNode, name *Entity data.TypeExpression = typeExpression data.IsNameFirst = isNameFirst data.Comment = comment - return newNode(KindJSDocParameterTag, data, f.hooks) + return f.newNode(KindJSDocParameterTag, data) } func (f *NodeFactory) UpdateJSDocParameterTag(node *JSDocParameterTag, tagName *IdentifierNode, name *EntityName, isBracketed bool, typeExpression *TypeNode, isNameFirst bool, comment *NodeList) *Node { @@ -7995,8 +9133,8 @@ func (node *JSDocParameterTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocParameterTag(node, tagName, name, node.IsBracketed, typeExpression, node.IsNameFirst, v.visitNodes(node.Comment)) } -func (node *JSDocParameterTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocParameterTag(node.TagName, node.Name(), node.IsBracketed, node.TypeExpression, node.IsNameFirst, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocParameterTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocParameterTag(node.TagName, node.Name(), node.IsBracketed, node.TypeExpression, node.IsNameFirst, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocParameterTag) Name() *EntityName { return node.name } @@ -8012,7 +9150,7 @@ func (f *NodeFactory) NewJSDocReturnTag(tagName *IdentifierNode, typeExpression data.TagName = tagName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocReturnTag, data, f.hooks) + return f.newNode(KindJSDocReturnTag, data) } func (f *NodeFactory) UpdateJSDocReturnTag(node *JSDocReturnTag, tagName *IdentifierNode, typeExpression *TypeNode, comment *NodeList) *Node { @@ -8030,8 +9168,8 @@ func (node *JSDocReturnTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocReturnTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNodes(node.Comment)) } -func (node *JSDocReturnTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocReturnTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocReturnTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocReturnTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func IsJSDocReturnTag(node *Node) bool { @@ -8047,7 +9185,7 @@ func (f *NodeFactory) NewJSDocPublicTag(tagName *IdentifierNode, comment *NodeLi data := &JSDocPublicTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocPublicTag, data, f.hooks) + return f.newNode(KindJSDocPublicTag, data) } func (f *NodeFactory) UpdateJSDocPublicTag(node *JSDocPublicTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8065,8 +9203,8 @@ func (node *JSDocPublicTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocPublicTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocPublicTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocPublicTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocPublicTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocPublicTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocPrivateTag @@ -8078,7 +9216,7 @@ func (f *NodeFactory) NewJSDocPrivateTag(tagName *IdentifierNode, comment *NodeL data := &JSDocPrivateTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocPrivateTag, data, f.hooks) + return f.newNode(KindJSDocPrivateTag, data) } func (f *NodeFactory) UpdateJSDocPrivateTag(node *JSDocPrivateTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8096,8 +9234,8 @@ func (node *JSDocPrivateTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocPrivateTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocPrivateTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocPrivateTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocPrivateTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocPrivateTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocProtectedTag @@ -8109,7 +9247,7 @@ func (f *NodeFactory) NewJSDocProtectedTag(tagName *IdentifierNode, comment *Nod data := &JSDocProtectedTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocProtectedTag, data, f.hooks) + return f.newNode(KindJSDocProtectedTag, data) } func (f *NodeFactory) UpdateJSDocProtectedTag(node *JSDocProtectedTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8127,8 +9265,8 @@ func (node *JSDocProtectedTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocProtectedTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocProtectedTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocProtectedTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocProtectedTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocProtectedTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocReadonlyTag @@ -8140,7 +9278,7 @@ func (f *NodeFactory) NewJSDocReadonlyTag(tagName *IdentifierNode, comment *Node data := &JSDocReadonlyTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocReadonlyTag, data, f.hooks) + return f.newNode(KindJSDocReadonlyTag, data) } func (f *NodeFactory) UpdateJSDocReadonlyTag(node *JSDocReadonlyTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8158,8 +9296,8 @@ func (node *JSDocReadonlyTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocReadonlyTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocReadonlyTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocReadonlyTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocReadonlyTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocReadonlyTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocOverrideTag @@ -8171,7 +9309,7 @@ func (f *NodeFactory) NewJSDocOverrideTag(tagName *IdentifierNode, comment *Node data := &JSDocOverrideTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocOverrideTag, data, f.hooks) + return f.newNode(KindJSDocOverrideTag, data) } func (f *NodeFactory) UpdateJSDocOverrideTag(node *JSDocOverrideTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8189,8 +9327,8 @@ func (node *JSDocOverrideTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocOverrideTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocOverrideTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocOverrideTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocOverrideTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocOverrideTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocDeprecatedTag @@ -8202,7 +9340,7 @@ func (f *NodeFactory) NewJSDocDeprecatedTag(tagName *IdentifierNode, comment *No data := &JSDocDeprecatedTag{} data.TagName = tagName data.Comment = comment - return newNode(KindJSDocDeprecatedTag, data, f.hooks) + return f.newNode(KindJSDocDeprecatedTag, data) } func (f *NodeFactory) UpdateJSDocDeprecatedTag(node *JSDocDeprecatedTag, tagName *IdentifierNode, comment *NodeList) *Node { @@ -8220,8 +9358,8 @@ func (node *JSDocDeprecatedTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocDeprecatedTag(node, v.visitNode(node.TagName), v.visitNodes(node.Comment)) } -func (node *JSDocDeprecatedTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocDeprecatedTag(node.TagName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocDeprecatedTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocDeprecatedTag(node.TagName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } func IsJSDocDeprecatedTag(node *Node) bool { @@ -8239,7 +9377,7 @@ func (f *NodeFactory) NewJSDocSeeTag(tagName *IdentifierNode, nameExpression *Ty data.TagName = tagName data.NameExpression = nameExpression data.Comment = comment - return newNode(KindJSDocSeeTag, data, f.hooks) + return f.newNode(KindJSDocSeeTag, data) } func (f *NodeFactory) UpdateJSDocSeeTag(node *JSDocSeeTag, tagName *IdentifierNode, nameExpression *TypeNode, comment *NodeList) *Node { @@ -8257,8 +9395,8 @@ func (node *JSDocSeeTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocSeeTag(node, v.visitNode(node.TagName), v.visitNode(node.NameExpression), v.visitNodes(node.Comment)) } -func (node *JSDocSeeTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocSeeTag(node.TagName, node.NameExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocSeeTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocSeeTag(node.TagName, node.NameExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocImplementsTag @@ -8272,7 +9410,7 @@ func (f *NodeFactory) NewJSDocImplementsTag(tagName *IdentifierNode, className * data.TagName = tagName data.ClassName = className data.Comment = comment - return newNode(KindJSDocImplementsTag, data, f.hooks) + return f.newNode(KindJSDocImplementsTag, data) } func (f *NodeFactory) UpdateJSDocImplementsTag(node *JSDocImplementsTag, tagName *IdentifierNode, className *Expression, comment *NodeList) *Node { @@ -8290,8 +9428,8 @@ func (node *JSDocImplementsTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocImplementsTag(node, v.visitNode(node.TagName), v.visitNode(node.ClassName), v.visitNodes(node.Comment)) } -func (node *JSDocImplementsTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocImplementsTag(node.TagName, node.ClassName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocImplementsTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocImplementsTag(node.TagName, node.ClassName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocAugmentsTag @@ -8305,7 +9443,7 @@ func (f *NodeFactory) NewJSDocAugmentsTag(tagName *IdentifierNode, className *Ex data.TagName = tagName data.ClassName = className data.Comment = comment - return newNode(KindJSDocAugmentsTag, data, f.hooks) + return f.newNode(KindJSDocAugmentsTag, data) } func (f *NodeFactory) UpdateJSDocAugmentsTag(node *JSDocAugmentsTag, tagName *IdentifierNode, className *Expression, comment *NodeList) *Node { @@ -8323,8 +9461,8 @@ func (node *JSDocAugmentsTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocAugmentsTag(node, v.visitNode(node.TagName), v.visitNode(node.ClassName), v.visitNodes(node.Comment)) } -func (node *JSDocAugmentsTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocAugmentsTag(node.TagName, node.ClassName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocAugmentsTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocAugmentsTag(node.TagName, node.ClassName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocSatisfiesTag @@ -8338,7 +9476,7 @@ func (f *NodeFactory) NewJSDocSatisfiesTag(tagName *IdentifierNode, typeExpressi data.TagName = tagName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocSatisfiesTag, data, f.hooks) + return f.newNode(KindJSDocSatisfiesTag, data) } func (f *NodeFactory) UpdateJSDocSatisfiesTag(node *JSDocSatisfiesTag, tagName *IdentifierNode, typeExpression *TypeNode, comment *NodeList) *Node { @@ -8356,8 +9494,8 @@ func (node *JSDocSatisfiesTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocSatisfiesTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNodes(node.Comment)) } -func (node *JSDocSatisfiesTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocSatisfiesTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocSatisfiesTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocSatisfiesTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocThisTag @@ -8371,7 +9509,7 @@ func (f *NodeFactory) NewJSDocThisTag(tagName *IdentifierNode, typeExpression *T data.TagName = tagName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocThisTag, data, f.hooks) + return f.newNode(KindJSDocThisTag, data) } func (f *NodeFactory) UpdateJSDocThisTag(node *JSDocThisTag, tagName *IdentifierNode, typeExpression *TypeNode, comment *NodeList) *Node { @@ -8389,15 +9527,15 @@ func (node *JSDocThisTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocThisTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNodes(node.Comment)) } -func (node *JSDocThisTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocThisTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocThisTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocThisTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocImportTag type JSDocImportTag struct { JSDocTagBase ImportClause *Declaration - ModuleSpecifier *Node + ModuleSpecifier *Expression Attributes *Node } @@ -8408,7 +9546,7 @@ func (f *NodeFactory) NewJSDocImportTag(tagName *IdentifierNode, importClause *D data.ModuleSpecifier = moduleSpecifier data.Attributes = attributes data.Comment = comment - return newNode(KindJSDocImportTag, data, f.hooks) + return f.newNode(KindJSDocImportTag, data) } func (f *NodeFactory) UpdateJSDocImportTag(node *JSDocImportTag, tagName *IdentifierNode, importClause *Declaration, moduleSpecifier *Node, attributes *Node, comment *NodeList) *Node { @@ -8426,8 +9564,12 @@ func (node *JSDocImportTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocImportTag(node, v.visitNode(node.TagName), v.visitNode(node.ImportClause), v.visitNode(node.ModuleSpecifier), v.visitNode(node.Attributes), v.visitNodes(node.Comment)) } -func (node *JSDocImportTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocImportTag(node.TagName, node.ImportClause, node.ModuleSpecifier, node.Attributes, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocImportTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocImportTag(node.TagName, node.ImportClause, node.ModuleSpecifier, node.Attributes, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) +} + +func IsJSDocImportTag(node *Node) bool { + return node.Kind == KindJSDocImportTag } // JSDocCallbackTag @@ -8443,7 +9585,7 @@ func (f *NodeFactory) NewJSDocCallbackTag(tagName *IdentifierNode, typeExpressio data.FullName = fullName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocCallbackTag, data, f.hooks) + return f.newNode(KindJSDocCallbackTag, data) } func (f *NodeFactory) UpdateJSDocCallbackTag(node *JSDocCallbackTag, tagName *IdentifierNode, typeExpression *TypeNode, fullName *Node, comment *NodeList) *Node { @@ -8461,8 +9603,8 @@ func (node *JSDocCallbackTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocCallbackTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNode(node.FullName), v.visitNodes(node.Comment)) } -func (node *JSDocCallbackTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocCallbackTag(node.TagName, node.TypeExpression, node.FullName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocCallbackTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocCallbackTag(node.TagName, node.TypeExpression, node.FullName, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocOverloadTag @@ -8476,7 +9618,7 @@ func (f *NodeFactory) NewJSDocOverloadTag(tagName *IdentifierNode, typeExpressio data.TagName = tagName data.TypeExpression = typeExpression data.Comment = comment - return newNode(KindJSDocOverloadTag, data, f.hooks) + return f.newNode(KindJSDocOverloadTag, data) } func (f *NodeFactory) UpdateJSDocOverloadTag(node *JSDocOverloadTag, tagName *IdentifierNode, typeExpression *TypeNode, comment *NodeList) *Node { @@ -8494,28 +9636,28 @@ func (node *JSDocOverloadTag) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocOverloadTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNodes(node.Comment)) } -func (node *JSDocOverloadTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocOverloadTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocOverloadTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocOverloadTag(node.TagName, node.TypeExpression, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocTypedefTag type JSDocTypedefTag struct { JSDocTagBase TypeExpression *Node - FullName *Node + name *IdentifierNode } -func (f *NodeFactory) NewJSDocTypedefTag(tagName *IdentifierNode, typeExpression *Node, fullName *Node, comment *NodeList) *Node { +func (f *NodeFactory) NewJSDocTypedefTag(tagName *IdentifierNode, typeExpression *Node, name *IdentifierNode, comment *NodeList) *Node { data := &JSDocTypedefTag{} data.TagName = tagName data.TypeExpression = typeExpression - data.FullName = fullName + data.name = name data.Comment = comment - return newNode(KindJSDocTypedefTag, data, f.hooks) + return f.newNode(KindJSDocTypedefTag, data) } -func (f *NodeFactory) UpdateJSDocTypedefTag(node *JSDocTypedefTag, tagName *IdentifierNode, typeExpression *Node, fullName *Node, comment *NodeList) *Node { - if tagName != node.TagName || typeExpression != node.TypeExpression || fullName != node.FullName || comment != node.Comment { +func (f *NodeFactory) UpdateJSDocTypedefTag(node *JSDocTypedefTag, tagName *IdentifierNode, typeExpression *Node, fullName *IdentifierNode, comment *NodeList) *Node { + if tagName != node.TagName || typeExpression != node.TypeExpression || fullName != node.name || comment != node.Comment { return updateNode(f.NewJSDocTypedefTag(tagName, typeExpression, fullName, comment), node.AsNode(), f.hooks) } return node.AsNode() @@ -8523,52 +9665,54 @@ func (f *NodeFactory) UpdateJSDocTypedefTag(node *JSDocTypedefTag, tagName *Iden func (node *JSDocTypedefTag) ForEachChild(v Visitor) bool { if node.TypeExpression != nil && node.TypeExpression.Kind == KindJSDocTypeLiteral { - return visit(v, node.TagName) || visit(v, node.FullName) || visit(v, node.TypeExpression) || visitNodeList(v, node.Comment) + return visit(v, node.TagName) || visit(v, node.name) || visit(v, node.TypeExpression) || visitNodeList(v, node.Comment) } - return visit(v, node.TagName) || visit(v, node.TypeExpression) || visit(v, node.FullName) || visitNodeList(v, node.Comment) + return visit(v, node.TagName) || visit(v, node.TypeExpression) || visit(v, node.name) || visitNodeList(v, node.Comment) } func (node *JSDocTypedefTag) VisitEachChild(v *NodeVisitor) *Node { - return v.Factory.UpdateJSDocTypedefTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNode(node.FullName), v.visitNodes(node.Comment)) + return v.Factory.UpdateJSDocTypedefTag(node, v.visitNode(node.TagName), v.visitNode(node.TypeExpression), v.visitNode(node.name), v.visitNodes(node.Comment)) } -func (node *JSDocTypedefTag) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocTypedefTag(node.TagName, node.TypeExpression, node.FullName, node.Comment), node.AsNode(), f.hooks) +func (node *JSDocTypedefTag) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocTypedefTag(node.TagName, node.TypeExpression, node.name, node.Comment), node.AsNode(), f.AsNodeFactory().hooks) } +func (node *JSDocTypedefTag) Name() *DeclarationName { return node.name } + // JSDocTypeLiteral type JSDocTypeLiteral struct { TypeNodeBase DeclarationBase - JsDocPropertyTags []*Node + JSDocPropertyTags []*Node IsArrayType bool } -func (f *NodeFactory) NewJSDocTypeLiteral(jsDocPropertyTags []*Node, isArrayType bool) *Node { +func (f *NodeFactory) NewJSDocTypeLiteral(jsdocPropertyTags []*Node, isArrayType bool) *Node { data := &JSDocTypeLiteral{} - data.JsDocPropertyTags = jsDocPropertyTags + data.JSDocPropertyTags = jsdocPropertyTags data.IsArrayType = isArrayType - return newNode(KindJSDocTypeLiteral, data, f.hooks) + return f.newNode(KindJSDocTypeLiteral, data) } -func (f *NodeFactory) UpdateJSDocTypeLiteral(node *JSDocTypeLiteral, jsDocPropertyTags []*Node, isArrayType bool) *Node { - if !core.Same(jsDocPropertyTags, node.JsDocPropertyTags) || isArrayType != node.IsArrayType { - return updateNode(f.NewJSDocTypeLiteral(jsDocPropertyTags, isArrayType), node.AsNode(), f.hooks) +func (f *NodeFactory) UpdateJSDocTypeLiteral(node *JSDocTypeLiteral, jsdocPropertyTags []*Node, isArrayType bool) *Node { + if !core.Same(jsdocPropertyTags, node.JSDocPropertyTags) || isArrayType != node.IsArrayType { + return updateNode(f.NewJSDocTypeLiteral(jsdocPropertyTags, isArrayType), node.AsNode(), f.hooks) } return node.AsNode() } func (node *JSDocTypeLiteral) ForEachChild(v Visitor) bool { - return visitNodes(v, node.JsDocPropertyTags) + return visitNodes(v, node.JSDocPropertyTags) } func (node *JSDocTypeLiteral) VisitEachChild(v *NodeVisitor) *Node { - jsdocPropertyTags := core.SameMap(node.JsDocPropertyTags, func(n *Node) *Node { return v.visitNode(n) }) + jsdocPropertyTags := core.SameMap(node.JSDocPropertyTags, func(n *Node) *Node { return v.visitNode(n) }) return v.Factory.UpdateJSDocTypeLiteral(node, jsdocPropertyTags, node.IsArrayType) } -func (node *JSDocTypeLiteral) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocTypeLiteral(node.JsDocPropertyTags, node.IsArrayType), node.AsNode(), f.hooks) +func (node *JSDocTypeLiteral) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocTypeLiteral(node.JSDocPropertyTags, node.IsArrayType), node.AsNode(), f.AsNodeFactory().hooks) } // JSDocSignature @@ -8584,7 +9728,7 @@ func (f *NodeFactory) NewJSDocSignature(typeParameters *TypeParameterList, param data.typeParameters = typeParameters data.Parameters = parameters data.Type = typeNode - return newNode(KindJSDocSignature, data, f.hooks) + return f.newNode(KindJSDocSignature, data) } func (f *NodeFactory) UpdateJSDocSignature(node *JSDocSignature, typeParameters *TypeParameterList, parameters *NodeList, typeNode *JSDocTag) *Node { @@ -8602,8 +9746,8 @@ func (node *JSDocSignature) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocSignature(node, v.visitNodes(node.typeParameters), v.visitNodes(node.Parameters), v.visitNode(node.Type)) } -func (node *JSDocSignature) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocSignature(node.TypeParameters(), node.Parameters, node.Type), node.AsNode(), f.hooks) +func (node *JSDocSignature) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocSignature(node.TypeParameters(), node.Parameters, node.Type), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocSignature) TypeParameters() *TypeParameterList { return node.typeParameters } @@ -8617,7 +9761,7 @@ type JSDocNameReference struct { func (f *NodeFactory) NewJSDocNameReference(name *EntityName) *Node { data := &JSDocNameReference{} data.name = name - return newNode(KindJSDocNameReference, data, f.hooks) + return f.newNode(KindJSDocNameReference, data) } func (f *NodeFactory) UpdateJSDocNameReference(node *JSDocNameReference, name *EntityName) *Node { @@ -8635,8 +9779,8 @@ func (node *JSDocNameReference) VisitEachChild(v *NodeVisitor) *Node { return v.Factory.UpdateJSDocNameReference(node, v.visitNode(node.name)) } -func (node *JSDocNameReference) Clone(f *NodeFactory) *Node { - return cloneNode(f.NewJSDocNameReference(node.Name()), node.AsNode(), f.hooks) +func (node *JSDocNameReference) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewJSDocNameReference(node.Name()), node.AsNode(), f.AsNodeFactory().hooks) } func (node *JSDocNameReference) Name() *EntityName { return node.name } @@ -8663,14 +9807,25 @@ type CommentDirective struct { // SourceFile +type SourceFileMetaData struct { + PackageJsonType string + ImpliedNodeFormat core.ResolutionMode +} + +type CheckJsDirective struct { + Enabled bool + Range CommentRange +} + type SourceFile struct { NodeBase DeclarationBase LocalsContainerBase + compositeNodeBase // Fields set by NewSourceFile - Text string + text string fileName string path tspath.Path Statements *NodeList // NodeList[*Statement] @@ -8686,6 +9841,7 @@ type SourceFile struct { HasNoDefaultLib bool UsesUriStyleNodeCoreModules core.Tristate Identifiers map[string]string + IdentifierCount int Imports []*LiteralLikeNode // []LiteralLikeNode ModuleAugmentations []*ModuleName // []ModuleName AmbientModuleNames []string @@ -8695,6 +9851,9 @@ type SourceFile struct { ReferencedFiles []*FileReference TypeReferenceDirectives []*FileReference LibReferenceDirectives []*FileReference + CheckJsDirective *CheckJsDirective + NodeCount int + TextCount int // Fields set by binder @@ -8705,7 +9864,7 @@ type SourceFile struct { EndFlowNode *FlowNode SymbolCount int ClassifiableNames core.Set[string] - PatternAmbientModules []PatternAmbientModule + PatternAmbientModules []*PatternAmbientModule // Fields set by LineMap @@ -8723,10 +9882,9 @@ type SourceFile struct { // !!! - ImpliedNodeFormat core.ModuleKind - CommonJsModuleIndicator *Node + CommonJSModuleIndicator *Node ExternalModuleIndicator *Node - JsGlobalAugmentations SymbolTable + JSGlobalAugmentations SymbolTable } func (f *NodeFactory) NewSourceFile(text string, fileName string, path tspath.Path, statements *NodeList) *Node { @@ -8735,12 +9893,16 @@ func (f *NodeFactory) NewSourceFile(text string, fileName string, path tspath.Pa } data := &SourceFile{} - data.Text = text + data.text = text data.fileName = fileName data.path = path data.Statements = statements data.LanguageVersion = core.ScriptTargetLatest - return newNode(KindSourceFile, data, f.hooks) + return f.newNode(KindSourceFile, data) +} + +func (node *SourceFile) Text() string { + return node.text } func (node *SourceFile) FileName() string { @@ -8808,23 +9970,26 @@ func (node *SourceFile) copyFrom(other *SourceFile) { node.ReferencedFiles = other.ReferencedFiles node.TypeReferenceDirectives = other.TypeReferenceDirectives node.LibReferenceDirectives = other.LibReferenceDirectives - node.ImpliedNodeFormat = other.ImpliedNodeFormat - node.CommonJsModuleIndicator = other.CommonJsModuleIndicator + node.CommonJSModuleIndicator = other.CommonJSModuleIndicator node.ExternalModuleIndicator = other.ExternalModuleIndicator - node.JsGlobalAugmentations = other.JsGlobalAugmentations + node.JSGlobalAugmentations = other.JSGlobalAugmentations node.Flags |= other.Flags } -func (node *SourceFile) Clone(f *NodeFactory) *Node { - updated := f.NewSourceFile(node.Text, node.FileName(), node.Path(), node.Statements) +func (node *SourceFile) Clone(f NodeFactoryCoercible) *Node { + updated := f.AsNodeFactory().NewSourceFile(node.Text(), node.FileName(), node.Path(), node.Statements) newFile := updated.AsSourceFile() newFile.copyFrom(node) - return cloneNode(updated, node.AsNode(), f.hooks) + return cloneNode(updated, node.AsNode(), f.AsNodeFactory().hooks) +} + +func (node *SourceFile) computeSubtreeFacts() SubtreeFacts { + return propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts) } func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList) *Node { if statements != node.Statements { - updated := f.NewSourceFile(node.Text, node.fileName, node.path, statements).AsSourceFile() + updated := f.NewSourceFile(node.Text(), node.fileName, node.path, statements).AsSourceFile() updated.copyFrom(node) return updateNode(updated.AsNode(), node.AsNode(), f.hooks) } @@ -8840,7 +10005,7 @@ func (node *SourceFile) LineMap() []core.TextPos { defer node.lineMapMu.Unlock() lineMap = node.lineMap if lineMap == nil { - lineMap = core.ComputeLineStarts(node.Text) + lineMap = core.ComputeLineStarts(node.Text()) node.lineMap = lineMap } } @@ -8875,7 +10040,7 @@ func (node *SourceFile) GetOrCreateToken( panic(fmt.Sprintf("Token cache mismatch: %v != %v", token.Kind, kind)) } if token.Parent != parent { - panic("Token cache mismatch: parent") + panic(fmt.Sprintf("Token cache mismatch: parent. Expected parent of kind %v, got %v", token.Parent.Kind, parent.Kind)) } return token } @@ -8891,17 +10056,22 @@ func IsSourceFile(node *Node) bool { return node.Kind == KindSourceFile } +type SourceFileLike interface { + Text() string + LineMap() []core.TextPos +} + type CommentRange struct { core.TextRange - HasTrailingNewLine bool Kind Kind + HasTrailingNewLine bool } func (f *NodeFactory) NewCommentRange(kind Kind, pos int, end int, hasTrailingNewLine bool) CommentRange { return CommentRange{ TextRange: core.NewTextRange(pos, end), - HasTrailingNewLine: hasTrailingNewLine, Kind: kind, + HasTrailingNewLine: hasTrailingNewLine, } } @@ -8919,9 +10089,9 @@ type PragmaArgument struct { } type Pragma struct { - Name string - Args map[string]PragmaArgument - ArgsRange CommentRange + CommentRange + Name string + Args map[string]PragmaArgument } type PragmaKindFlags = uint8 diff --git a/internal/ast/diagnostic.go b/internal/ast/diagnostic.go index d83c9aabca..5ab4be4b02 100644 --- a/internal/ast/diagnostic.go +++ b/internal/ast/diagnostic.go @@ -5,8 +5,8 @@ import ( "slices" "strings" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" ) // Diagnostic @@ -60,6 +60,11 @@ func (d *Diagnostic) AddRelatedInfo(relatedInformation *Diagnostic) *Diagnostic return d } +func (d *Diagnostic) Clone() *Diagnostic { + result := *d + return &result +} + func NewDiagnostic(file *SourceFile, loc core.TextRange, message *diagnostics.Message, args ...any) *Diagnostic { return &Diagnostic{ file: file, @@ -137,12 +142,16 @@ func getDiagnosticPath(d *Diagnostic) string { } func EqualDiagnostics(d1, d2 *Diagnostic) bool { + return EqualDiagnosticsNoRelatedInfo(d1, d2) && + slices.EqualFunc(d1.RelatedInformation(), d2.RelatedInformation(), EqualDiagnostics) +} + +func EqualDiagnosticsNoRelatedInfo(d1, d2 *Diagnostic) bool { return getDiagnosticPath(d1) == getDiagnosticPath(d2) && d1.Loc() == d2.Loc() && d1.Code() == d2.Code() && d1.Message() == d2.Message() && - slices.EqualFunc(d1.MessageChain(), d2.MessageChain(), equalMessageChain) && - slices.EqualFunc(d1.RelatedInformation(), d2.RelatedInformation(), EqualDiagnostics) + slices.EqualFunc(d1.MessageChain(), d2.MessageChain(), equalMessageChain) } func equalMessageChain(c1, c2 *Diagnostic) bool { diff --git a/internal/ast/kind.go b/internal/ast/kind.go index cfcb41d291..3107c895bd 100644 --- a/internal/ast/kind.go +++ b/internal/ast/kind.go @@ -377,6 +377,10 @@ const ( KindJSDocImportTag // Synthesized list KindSyntaxList + // Reparsed JS nodes + KindJSTypeAliasDeclaration + KindJSExportAssignment + KindCommonJSExport // Transformation nodes KindNotEmittedStatement KindPartiallyEmittedExpression diff --git a/internal/ast/kind_stringer_generated.go b/internal/ast/kind_stringer_generated.go index b067e7f341..329adfa55d 100644 --- a/internal/ast/kind_stringer_generated.go +++ b/internal/ast/kind_stringer_generated.go @@ -353,16 +353,19 @@ func _() { _ = x[KindJSDocSatisfiesTag-342] _ = x[KindJSDocImportTag-343] _ = x[KindSyntaxList-344] - _ = x[KindNotEmittedStatement-345] - _ = x[KindPartiallyEmittedExpression-346] - _ = x[KindCommaListExpression-347] - _ = x[KindSyntheticReferenceExpression-348] - _ = x[KindCount-349] + _ = x[KindJSTypeAliasDeclaration-345] + _ = x[KindJSExportAssignment-346] + _ = x[KindCommonJSExport-347] + _ = x[KindNotEmittedStatement-348] + _ = x[KindPartiallyEmittedExpression-349] + _ = x[KindCommaListExpression-350] + _ = x[KindSyntheticReferenceExpression-351] + _ = x[KindCount-352] } -const _Kind_name = "KindUnknownKindEndOfFileKindSingleLineCommentTriviaKindMultiLineCommentTriviaKindNewLineTriviaKindWhitespaceTriviaKindConflictMarkerTriviaKindNonTextFileMarkerTriviaKindNumericLiteralKindBigIntLiteralKindStringLiteralKindJsxTextKindJsxTextAllWhiteSpacesKindRegularExpressionLiteralKindNoSubstitutionTemplateLiteralKindTemplateHeadKindTemplateMiddleKindTemplateTailKindOpenBraceTokenKindCloseBraceTokenKindOpenParenTokenKindCloseParenTokenKindOpenBracketTokenKindCloseBracketTokenKindDotTokenKindDotDotDotTokenKindSemicolonTokenKindCommaTokenKindQuestionDotTokenKindLessThanTokenKindLessThanSlashTokenKindGreaterThanTokenKindLessThanEqualsTokenKindGreaterThanEqualsTokenKindEqualsEqualsTokenKindExclamationEqualsTokenKindEqualsEqualsEqualsTokenKindExclamationEqualsEqualsTokenKindEqualsGreaterThanTokenKindPlusTokenKindMinusTokenKindAsteriskTokenKindAsteriskAsteriskTokenKindSlashTokenKindPercentTokenKindPlusPlusTokenKindMinusMinusTokenKindLessThanLessThanTokenKindGreaterThanGreaterThanTokenKindGreaterThanGreaterThanGreaterThanTokenKindAmpersandTokenKindBarTokenKindCaretTokenKindExclamationTokenKindTildeTokenKindAmpersandAmpersandTokenKindBarBarTokenKindQuestionTokenKindColonTokenKindAtTokenKindQuestionQuestionTokenKindBacktickTokenKindHashTokenKindEqualsTokenKindPlusEqualsTokenKindMinusEqualsTokenKindAsteriskEqualsTokenKindAsteriskAsteriskEqualsTokenKindSlashEqualsTokenKindPercentEqualsTokenKindLessThanLessThanEqualsTokenKindGreaterThanGreaterThanEqualsTokenKindGreaterThanGreaterThanGreaterThanEqualsTokenKindAmpersandEqualsTokenKindBarEqualsTokenKindBarBarEqualsTokenKindAmpersandAmpersandEqualsTokenKindQuestionQuestionEqualsTokenKindCaretEqualsTokenKindIdentifierKindPrivateIdentifierKindJSDocCommentTextTokenKindBreakKeywordKindCaseKeywordKindCatchKeywordKindClassKeywordKindConstKeywordKindContinueKeywordKindDebuggerKeywordKindDefaultKeywordKindDeleteKeywordKindDoKeywordKindElseKeywordKindEnumKeywordKindExportKeywordKindExtendsKeywordKindFalseKeywordKindFinallyKeywordKindForKeywordKindFunctionKeywordKindIfKeywordKindImportKeywordKindInKeywordKindInstanceOfKeywordKindNewKeywordKindNullKeywordKindReturnKeywordKindSuperKeywordKindSwitchKeywordKindThisKeywordKindThrowKeywordKindTrueKeywordKindTryKeywordKindTypeOfKeywordKindVarKeywordKindVoidKeywordKindWhileKeywordKindWithKeywordKindImplementsKeywordKindInterfaceKeywordKindLetKeywordKindPackageKeywordKindPrivateKeywordKindProtectedKeywordKindPublicKeywordKindStaticKeywordKindYieldKeywordKindAbstractKeywordKindAccessorKeywordKindAsKeywordKindAssertsKeywordKindAssertKeywordKindAnyKeywordKindAsyncKeywordKindAwaitKeywordKindBooleanKeywordKindConstructorKeywordKindDeclareKeywordKindGetKeywordKindImmediateKeywordKindInferKeywordKindIntrinsicKeywordKindIsKeywordKindKeyOfKeywordKindModuleKeywordKindNamespaceKeywordKindNeverKeywordKindOutKeywordKindReadonlyKeywordKindRequireKeywordKindNumberKeywordKindObjectKeywordKindSatisfiesKeywordKindSetKeywordKindStringKeywordKindSymbolKeywordKindTypeKeywordKindUndefinedKeywordKindUniqueKeywordKindUnknownKeywordKindUsingKeywordKindFromKeywordKindGlobalKeywordKindBigIntKeywordKindOverrideKeywordKindOfKeywordKindQualifiedNameKindComputedPropertyNameKindTypeParameterKindParameterKindDecoratorKindPropertySignatureKindPropertyDeclarationKindMethodSignatureKindMethodDeclarationKindClassStaticBlockDeclarationKindConstructorKindGetAccessorKindSetAccessorKindCallSignatureKindConstructSignatureKindIndexSignatureKindTypePredicateKindTypeReferenceKindFunctionTypeKindConstructorTypeKindTypeQueryKindTypeLiteralKindArrayTypeKindTupleTypeKindOptionalTypeKindRestTypeKindUnionTypeKindIntersectionTypeKindConditionalTypeKindInferTypeKindParenthesizedTypeKindThisTypeKindTypeOperatorKindIndexedAccessTypeKindMappedTypeKindLiteralTypeKindNamedTupleMemberKindTemplateLiteralTypeKindTemplateLiteralTypeSpanKindImportTypeKindObjectBindingPatternKindArrayBindingPatternKindBindingElementKindArrayLiteralExpressionKindObjectLiteralExpressionKindPropertyAccessExpressionKindElementAccessExpressionKindCallExpressionKindNewExpressionKindTaggedTemplateExpressionKindTypeAssertionExpressionKindParenthesizedExpressionKindFunctionExpressionKindArrowFunctionKindDeleteExpressionKindTypeOfExpressionKindVoidExpressionKindAwaitExpressionKindPrefixUnaryExpressionKindPostfixUnaryExpressionKindBinaryExpressionKindConditionalExpressionKindTemplateExpressionKindYieldExpressionKindSpreadElementKindClassExpressionKindOmittedExpressionKindExpressionWithTypeArgumentsKindAsExpressionKindNonNullExpressionKindMetaPropertyKindSyntheticExpressionKindSatisfiesExpressionKindTemplateSpanKindSemicolonClassElementKindBlockKindEmptyStatementKindVariableStatementKindExpressionStatementKindIfStatementKindDoStatementKindWhileStatementKindForStatementKindForInStatementKindForOfStatementKindContinueStatementKindBreakStatementKindReturnStatementKindWithStatementKindSwitchStatementKindLabeledStatementKindThrowStatementKindTryStatementKindDebuggerStatementKindVariableDeclarationKindVariableDeclarationListKindFunctionDeclarationKindClassDeclarationKindInterfaceDeclarationKindTypeAliasDeclarationKindEnumDeclarationKindModuleDeclarationKindModuleBlockKindCaseBlockKindNamespaceExportDeclarationKindImportEqualsDeclarationKindImportDeclarationKindImportClauseKindNamespaceImportKindNamedImportsKindImportSpecifierKindExportAssignmentKindExportDeclarationKindNamedExportsKindNamespaceExportKindExportSpecifierKindMissingDeclarationKindExternalModuleReferenceKindJsxElementKindJsxSelfClosingElementKindJsxOpeningElementKindJsxClosingElementKindJsxFragmentKindJsxOpeningFragmentKindJsxClosingFragmentKindJsxAttributeKindJsxAttributesKindJsxSpreadAttributeKindJsxExpressionKindJsxNamespacedNameKindCaseClauseKindDefaultClauseKindHeritageClauseKindCatchClauseKindImportAttributesKindImportAttributeKindPropertyAssignmentKindShorthandPropertyAssignmentKindSpreadAssignmentKindEnumMemberKindSourceFileKindBundleKindJSDocTypeExpressionKindJSDocNameReferenceKindJSDocMemberNameKindJSDocAllTypeKindJSDocNullableTypeKindJSDocNonNullableTypeKindJSDocOptionalTypeKindJSDocVariadicTypeKindJSDocKindJSDocTextKindJSDocTypeLiteralKindJSDocSignatureKindJSDocLinkKindJSDocLinkCodeKindJSDocLinkPlainKindJSDocTagKindJSDocAugmentsTagKindJSDocImplementsTagKindJSDocDeprecatedTagKindJSDocPublicTagKindJSDocPrivateTagKindJSDocProtectedTagKindJSDocReadonlyTagKindJSDocOverrideTagKindJSDocCallbackTagKindJSDocOverloadTagKindJSDocParameterTagKindJSDocReturnTagKindJSDocThisTagKindJSDocTypeTagKindJSDocTemplateTagKindJSDocTypedefTagKindJSDocSeeTagKindJSDocPropertyTagKindJSDocSatisfiesTagKindJSDocImportTagKindSyntaxListKindNotEmittedStatementKindPartiallyEmittedExpressionKindCommaListExpressionKindSyntheticReferenceExpressionKindCount" +const _Kind_name = "KindUnknownKindEndOfFileKindSingleLineCommentTriviaKindMultiLineCommentTriviaKindNewLineTriviaKindWhitespaceTriviaKindConflictMarkerTriviaKindNonTextFileMarkerTriviaKindNumericLiteralKindBigIntLiteralKindStringLiteralKindJsxTextKindJsxTextAllWhiteSpacesKindRegularExpressionLiteralKindNoSubstitutionTemplateLiteralKindTemplateHeadKindTemplateMiddleKindTemplateTailKindOpenBraceTokenKindCloseBraceTokenKindOpenParenTokenKindCloseParenTokenKindOpenBracketTokenKindCloseBracketTokenKindDotTokenKindDotDotDotTokenKindSemicolonTokenKindCommaTokenKindQuestionDotTokenKindLessThanTokenKindLessThanSlashTokenKindGreaterThanTokenKindLessThanEqualsTokenKindGreaterThanEqualsTokenKindEqualsEqualsTokenKindExclamationEqualsTokenKindEqualsEqualsEqualsTokenKindExclamationEqualsEqualsTokenKindEqualsGreaterThanTokenKindPlusTokenKindMinusTokenKindAsteriskTokenKindAsteriskAsteriskTokenKindSlashTokenKindPercentTokenKindPlusPlusTokenKindMinusMinusTokenKindLessThanLessThanTokenKindGreaterThanGreaterThanTokenKindGreaterThanGreaterThanGreaterThanTokenKindAmpersandTokenKindBarTokenKindCaretTokenKindExclamationTokenKindTildeTokenKindAmpersandAmpersandTokenKindBarBarTokenKindQuestionTokenKindColonTokenKindAtTokenKindQuestionQuestionTokenKindBacktickTokenKindHashTokenKindEqualsTokenKindPlusEqualsTokenKindMinusEqualsTokenKindAsteriskEqualsTokenKindAsteriskAsteriskEqualsTokenKindSlashEqualsTokenKindPercentEqualsTokenKindLessThanLessThanEqualsTokenKindGreaterThanGreaterThanEqualsTokenKindGreaterThanGreaterThanGreaterThanEqualsTokenKindAmpersandEqualsTokenKindBarEqualsTokenKindBarBarEqualsTokenKindAmpersandAmpersandEqualsTokenKindQuestionQuestionEqualsTokenKindCaretEqualsTokenKindIdentifierKindPrivateIdentifierKindJSDocCommentTextTokenKindBreakKeywordKindCaseKeywordKindCatchKeywordKindClassKeywordKindConstKeywordKindContinueKeywordKindDebuggerKeywordKindDefaultKeywordKindDeleteKeywordKindDoKeywordKindElseKeywordKindEnumKeywordKindExportKeywordKindExtendsKeywordKindFalseKeywordKindFinallyKeywordKindForKeywordKindFunctionKeywordKindIfKeywordKindImportKeywordKindInKeywordKindInstanceOfKeywordKindNewKeywordKindNullKeywordKindReturnKeywordKindSuperKeywordKindSwitchKeywordKindThisKeywordKindThrowKeywordKindTrueKeywordKindTryKeywordKindTypeOfKeywordKindVarKeywordKindVoidKeywordKindWhileKeywordKindWithKeywordKindImplementsKeywordKindInterfaceKeywordKindLetKeywordKindPackageKeywordKindPrivateKeywordKindProtectedKeywordKindPublicKeywordKindStaticKeywordKindYieldKeywordKindAbstractKeywordKindAccessorKeywordKindAsKeywordKindAssertsKeywordKindAssertKeywordKindAnyKeywordKindAsyncKeywordKindAwaitKeywordKindBooleanKeywordKindConstructorKeywordKindDeclareKeywordKindGetKeywordKindImmediateKeywordKindInferKeywordKindIntrinsicKeywordKindIsKeywordKindKeyOfKeywordKindModuleKeywordKindNamespaceKeywordKindNeverKeywordKindOutKeywordKindReadonlyKeywordKindRequireKeywordKindNumberKeywordKindObjectKeywordKindSatisfiesKeywordKindSetKeywordKindStringKeywordKindSymbolKeywordKindTypeKeywordKindUndefinedKeywordKindUniqueKeywordKindUnknownKeywordKindUsingKeywordKindFromKeywordKindGlobalKeywordKindBigIntKeywordKindOverrideKeywordKindOfKeywordKindQualifiedNameKindComputedPropertyNameKindTypeParameterKindParameterKindDecoratorKindPropertySignatureKindPropertyDeclarationKindMethodSignatureKindMethodDeclarationKindClassStaticBlockDeclarationKindConstructorKindGetAccessorKindSetAccessorKindCallSignatureKindConstructSignatureKindIndexSignatureKindTypePredicateKindTypeReferenceKindFunctionTypeKindConstructorTypeKindTypeQueryKindTypeLiteralKindArrayTypeKindTupleTypeKindOptionalTypeKindRestTypeKindUnionTypeKindIntersectionTypeKindConditionalTypeKindInferTypeKindParenthesizedTypeKindThisTypeKindTypeOperatorKindIndexedAccessTypeKindMappedTypeKindLiteralTypeKindNamedTupleMemberKindTemplateLiteralTypeKindTemplateLiteralTypeSpanKindImportTypeKindObjectBindingPatternKindArrayBindingPatternKindBindingElementKindArrayLiteralExpressionKindObjectLiteralExpressionKindPropertyAccessExpressionKindElementAccessExpressionKindCallExpressionKindNewExpressionKindTaggedTemplateExpressionKindTypeAssertionExpressionKindParenthesizedExpressionKindFunctionExpressionKindArrowFunctionKindDeleteExpressionKindTypeOfExpressionKindVoidExpressionKindAwaitExpressionKindPrefixUnaryExpressionKindPostfixUnaryExpressionKindBinaryExpressionKindConditionalExpressionKindTemplateExpressionKindYieldExpressionKindSpreadElementKindClassExpressionKindOmittedExpressionKindExpressionWithTypeArgumentsKindAsExpressionKindNonNullExpressionKindMetaPropertyKindSyntheticExpressionKindSatisfiesExpressionKindTemplateSpanKindSemicolonClassElementKindBlockKindEmptyStatementKindVariableStatementKindExpressionStatementKindIfStatementKindDoStatementKindWhileStatementKindForStatementKindForInStatementKindForOfStatementKindContinueStatementKindBreakStatementKindReturnStatementKindWithStatementKindSwitchStatementKindLabeledStatementKindThrowStatementKindTryStatementKindDebuggerStatementKindVariableDeclarationKindVariableDeclarationListKindFunctionDeclarationKindClassDeclarationKindInterfaceDeclarationKindTypeAliasDeclarationKindEnumDeclarationKindModuleDeclarationKindModuleBlockKindCaseBlockKindNamespaceExportDeclarationKindImportEqualsDeclarationKindImportDeclarationKindImportClauseKindNamespaceImportKindNamedImportsKindImportSpecifierKindExportAssignmentKindExportDeclarationKindNamedExportsKindNamespaceExportKindExportSpecifierKindMissingDeclarationKindExternalModuleReferenceKindJsxElementKindJsxSelfClosingElementKindJsxOpeningElementKindJsxClosingElementKindJsxFragmentKindJsxOpeningFragmentKindJsxClosingFragmentKindJsxAttributeKindJsxAttributesKindJsxSpreadAttributeKindJsxExpressionKindJsxNamespacedNameKindCaseClauseKindDefaultClauseKindHeritageClauseKindCatchClauseKindImportAttributesKindImportAttributeKindPropertyAssignmentKindShorthandPropertyAssignmentKindSpreadAssignmentKindEnumMemberKindSourceFileKindBundleKindJSDocTypeExpressionKindJSDocNameReferenceKindJSDocMemberNameKindJSDocAllTypeKindJSDocNullableTypeKindJSDocNonNullableTypeKindJSDocOptionalTypeKindJSDocVariadicTypeKindJSDocKindJSDocTextKindJSDocTypeLiteralKindJSDocSignatureKindJSDocLinkKindJSDocLinkCodeKindJSDocLinkPlainKindJSDocTagKindJSDocAugmentsTagKindJSDocImplementsTagKindJSDocDeprecatedTagKindJSDocPublicTagKindJSDocPrivateTagKindJSDocProtectedTagKindJSDocReadonlyTagKindJSDocOverrideTagKindJSDocCallbackTagKindJSDocOverloadTagKindJSDocParameterTagKindJSDocReturnTagKindJSDocThisTagKindJSDocTypeTagKindJSDocTemplateTagKindJSDocTypedefTagKindJSDocSeeTagKindJSDocPropertyTagKindJSDocSatisfiesTagKindJSDocImportTagKindSyntaxListKindJSTypeAliasDeclarationKindJSExportAssignmentKindCommonJSExportKindNotEmittedStatementKindPartiallyEmittedExpressionKindCommaListExpressionKindSyntheticReferenceExpressionKindCount" -var _Kind_index = [...]uint16{0, 11, 24, 51, 77, 94, 114, 138, 165, 183, 200, 217, 228, 253, 281, 314, 330, 348, 364, 382, 401, 419, 438, 458, 479, 491, 509, 527, 541, 561, 578, 600, 620, 643, 669, 690, 716, 743, 775, 801, 814, 828, 845, 870, 884, 900, 917, 936, 961, 992, 1034, 1052, 1064, 1078, 1098, 1112, 1139, 1154, 1171, 1185, 1196, 1221, 1238, 1251, 1266, 1285, 1305, 1328, 1359, 1379, 1401, 1432, 1469, 1517, 1541, 1559, 1580, 1613, 1644, 1664, 1678, 1699, 1724, 1740, 1755, 1771, 1787, 1803, 1822, 1841, 1859, 1876, 1889, 1904, 1919, 1936, 1954, 1970, 1988, 2002, 2021, 2034, 2051, 2064, 2085, 2099, 2114, 2131, 2147, 2164, 2179, 2195, 2210, 2224, 2241, 2255, 2270, 2286, 2301, 2322, 2342, 2356, 2374, 2392, 2412, 2429, 2446, 2462, 2481, 2500, 2513, 2531, 2548, 2562, 2578, 2594, 2612, 2634, 2652, 2666, 2686, 2702, 2722, 2735, 2751, 2768, 2788, 2804, 2818, 2837, 2855, 2872, 2889, 2909, 2923, 2940, 2957, 2972, 2992, 3009, 3027, 3043, 3058, 3075, 3092, 3111, 3124, 3141, 3165, 3182, 3195, 3208, 3229, 3252, 3271, 3292, 3323, 3338, 3353, 3368, 3385, 3407, 3425, 3442, 3459, 3475, 3494, 3507, 3522, 3535, 3548, 3564, 3576, 3589, 3609, 3628, 3641, 3662, 3674, 3690, 3711, 3725, 3740, 3760, 3783, 3810, 3824, 3848, 3871, 3889, 3915, 3942, 3970, 3997, 4015, 4032, 4060, 4087, 4114, 4136, 4153, 4173, 4193, 4211, 4230, 4255, 4281, 4301, 4326, 4348, 4367, 4384, 4403, 4424, 4455, 4471, 4492, 4508, 4531, 4554, 4570, 4595, 4604, 4622, 4643, 4666, 4681, 4696, 4714, 4730, 4748, 4766, 4787, 4805, 4824, 4841, 4860, 4880, 4898, 4914, 4935, 4958, 4985, 5008, 5028, 5052, 5076, 5095, 5116, 5131, 5144, 5174, 5201, 5222, 5238, 5257, 5273, 5292, 5312, 5333, 5349, 5368, 5387, 5409, 5436, 5450, 5475, 5496, 5517, 5532, 5554, 5576, 5592, 5609, 5631, 5648, 5669, 5683, 5700, 5718, 5733, 5753, 5772, 5794, 5825, 5845, 5859, 5873, 5883, 5906, 5928, 5947, 5963, 5984, 6008, 6029, 6050, 6059, 6072, 6092, 6110, 6123, 6140, 6158, 6170, 6190, 6212, 6234, 6252, 6271, 6292, 6312, 6332, 6352, 6372, 6393, 6411, 6427, 6443, 6463, 6482, 6497, 6517, 6538, 6556, 6570, 6593, 6623, 6646, 6678, 6687} +var _Kind_index = [...]uint16{0, 11, 24, 51, 77, 94, 114, 138, 165, 183, 200, 217, 228, 253, 281, 314, 330, 348, 364, 382, 401, 419, 438, 458, 479, 491, 509, 527, 541, 561, 578, 600, 620, 643, 669, 690, 716, 743, 775, 801, 814, 828, 845, 870, 884, 900, 917, 936, 961, 992, 1034, 1052, 1064, 1078, 1098, 1112, 1139, 1154, 1171, 1185, 1196, 1221, 1238, 1251, 1266, 1285, 1305, 1328, 1359, 1379, 1401, 1432, 1469, 1517, 1541, 1559, 1580, 1613, 1644, 1664, 1678, 1699, 1724, 1740, 1755, 1771, 1787, 1803, 1822, 1841, 1859, 1876, 1889, 1904, 1919, 1936, 1954, 1970, 1988, 2002, 2021, 2034, 2051, 2064, 2085, 2099, 2114, 2131, 2147, 2164, 2179, 2195, 2210, 2224, 2241, 2255, 2270, 2286, 2301, 2322, 2342, 2356, 2374, 2392, 2412, 2429, 2446, 2462, 2481, 2500, 2513, 2531, 2548, 2562, 2578, 2594, 2612, 2634, 2652, 2666, 2686, 2702, 2722, 2735, 2751, 2768, 2788, 2804, 2818, 2837, 2855, 2872, 2889, 2909, 2923, 2940, 2957, 2972, 2992, 3009, 3027, 3043, 3058, 3075, 3092, 3111, 3124, 3141, 3165, 3182, 3195, 3208, 3229, 3252, 3271, 3292, 3323, 3338, 3353, 3368, 3385, 3407, 3425, 3442, 3459, 3475, 3494, 3507, 3522, 3535, 3548, 3564, 3576, 3589, 3609, 3628, 3641, 3662, 3674, 3690, 3711, 3725, 3740, 3760, 3783, 3810, 3824, 3848, 3871, 3889, 3915, 3942, 3970, 3997, 4015, 4032, 4060, 4087, 4114, 4136, 4153, 4173, 4193, 4211, 4230, 4255, 4281, 4301, 4326, 4348, 4367, 4384, 4403, 4424, 4455, 4471, 4492, 4508, 4531, 4554, 4570, 4595, 4604, 4622, 4643, 4666, 4681, 4696, 4714, 4730, 4748, 4766, 4787, 4805, 4824, 4841, 4860, 4880, 4898, 4914, 4935, 4958, 4985, 5008, 5028, 5052, 5076, 5095, 5116, 5131, 5144, 5174, 5201, 5222, 5238, 5257, 5273, 5292, 5312, 5333, 5349, 5368, 5387, 5409, 5436, 5450, 5475, 5496, 5517, 5532, 5554, 5576, 5592, 5609, 5631, 5648, 5669, 5683, 5700, 5718, 5733, 5753, 5772, 5794, 5825, 5845, 5859, 5873, 5883, 5906, 5928, 5947, 5963, 5984, 6008, 6029, 6050, 6059, 6072, 6092, 6110, 6123, 6140, 6158, 6170, 6190, 6212, 6234, 6252, 6271, 6292, 6312, 6332, 6352, 6372, 6393, 6411, 6427, 6443, 6463, 6482, 6497, 6517, 6538, 6556, 6570, 6596, 6618, 6636, 6659, 6689, 6712, 6744, 6753} func (i Kind) String() string { if i < 0 || i >= Kind(len(_Kind_index)-1) { diff --git a/internal/ast/nodeflags.go b/internal/ast/nodeflags.go index 62e7891042..5b6441ed58 100644 --- a/internal/ast/nodeflags.go +++ b/internal/ast/nodeflags.go @@ -7,25 +7,22 @@ const ( NodeFlagsLet NodeFlags = 1 << 0 // Variable declaration NodeFlagsConst NodeFlags = 1 << 1 // Variable declaration NodeFlagsUsing NodeFlags = 1 << 2 // Variable declaration - NodeFlagsNestedNamespace NodeFlags = 1 << 3 // Namespace declaration + NodeFlagsReparsed NodeFlags = 1 << 3 // Node was synthesized during parsing NodeFlagsSynthesized NodeFlags = 1 << 4 // Node was synthesized during transformation - NodeFlagsNamespace NodeFlags = 1 << 5 // Namespace declaration - NodeFlagsOptionalChain NodeFlags = 1 << 6 // Chained MemberExpression rooted to a pseudo-OptionalExpression - NodeFlagsExportContext NodeFlags = 1 << 7 // Export context (initialized by binding) - NodeFlagsContainsThis NodeFlags = 1 << 8 // Interface contains references to "this" - NodeFlagsHasImplicitReturn NodeFlags = 1 << 9 // If function implicitly returns on one of codepaths (initialized by binding) - NodeFlagsHasExplicitReturn NodeFlags = 1 << 10 // If function has explicit reachable return on one of codepaths (initialized by binding) - NodeFlagsGlobalAugmentation NodeFlags = 1 << 11 // Set if module declaration is an augmentation for the global scope - NodeFlagsHasAsyncFunctions NodeFlags = 1 << 12 // If the file has async functions (initialized by binding) - NodeFlagsDisallowInContext NodeFlags = 1 << 13 // If node was parsed in a context where 'in-expressions' are not allowed - NodeFlagsYieldContext NodeFlags = 1 << 14 // If node was parsed in the 'yield' context created when parsing a generator - NodeFlagsDecoratorContext NodeFlags = 1 << 15 // If node was parsed as part of a decorator - NodeFlagsAwaitContext NodeFlags = 1 << 16 // If node was parsed in the 'await' context created when parsing an async function - NodeFlagsDisallowConditionalTypesContext NodeFlags = 1 << 17 // If node was parsed in a context where conditional types are not allowed - NodeFlagsThisNodeHasError NodeFlags = 1 << 18 // If the parser encountered an error when parsing the code that created this node - NodeFlagsJavaScriptFile NodeFlags = 1 << 19 // If node was parsed in a JavaScript - NodeFlagsThisNodeOrAnySubNodesHasError NodeFlags = 1 << 20 // If this node or any of its children had an error - NodeFlagsHasAggregatedChildData NodeFlags = 1 << 21 // If we've computed data from children and cached it in this node + NodeFlagsOptionalChain NodeFlags = 1 << 5 // Chained MemberExpression rooted to a pseudo-OptionalExpression + NodeFlagsExportContext NodeFlags = 1 << 6 // Export context (initialized by binding) + NodeFlagsContainsThis NodeFlags = 1 << 7 // Interface contains references to "this" + NodeFlagsHasImplicitReturn NodeFlags = 1 << 8 // If function implicitly returns on one of codepaths (initialized by binding) + NodeFlagsHasExplicitReturn NodeFlags = 1 << 9 // If function has explicit reachable return on one of codepaths (initialized by binding) + NodeFlagsDisallowInContext NodeFlags = 1 << 10 // If node was parsed in a context where 'in-expressions' are not allowed + NodeFlagsYieldContext NodeFlags = 1 << 11 // If node was parsed in the 'yield' context created when parsing a generator + NodeFlagsDecoratorContext NodeFlags = 1 << 12 // If node was parsed as part of a decorator + NodeFlagsAwaitContext NodeFlags = 1 << 13 // If node was parsed in the 'await' context created when parsing an async function + NodeFlagsDisallowConditionalTypesContext NodeFlags = 1 << 14 // If node was parsed in a context where conditional types are not allowed + NodeFlagsThisNodeHasError NodeFlags = 1 << 15 // If the parser encountered an error when parsing the code that created this node + NodeFlagsJavaScriptFile NodeFlags = 1 << 16 // If node was parsed in a JavaScript + NodeFlagsThisNodeOrAnySubNodesHasError NodeFlags = 1 << 17 // If this node or any of its children had an error + NodeFlagsHasAggregatedChildData NodeFlags = 1 << 18 // If we've computed data from children and cached it in this node // These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid // walking the tree if the flags are not set. However, these flags are just a approximation @@ -36,22 +33,23 @@ const ( // removal, it is likely that users will add the import anyway. // The advantage of this approach is its simplicity. For the case of batch compilation, // we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used. - NodeFlagsPossiblyContainsDynamicImport NodeFlags = 1 << 22 - NodeFlagsPossiblyContainsImportMeta NodeFlags = 1 << 23 + NodeFlagsPossiblyContainsDynamicImport NodeFlags = 1 << 19 + NodeFlagsPossiblyContainsImportMeta NodeFlags = 1 << 20 - NodeFlagsHasJSDoc NodeFlags = 1 << 24 // If node has preceding JSDoc comment(s) - NodeFlagsJSDoc NodeFlags = 1 << 25 // If node was parsed inside jsdoc - NodeFlagsAmbient NodeFlags = 1 << 26 // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. - NodeFlagsInWithStatement NodeFlags = 1 << 27 // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) - NodeFlagsJsonFile NodeFlags = 1 << 28 // If node was parsed in a Json - NodeFlagsDeprecated NodeFlags = 1 << 30 // If has '@deprecated' JSDoc tag + NodeFlagsHasJSDoc NodeFlags = 1 << 21 // If node has preceding JSDoc comment(s) + NodeFlagsJSDoc NodeFlags = 1 << 22 // If node was parsed inside jsdoc + NodeFlagsAmbient NodeFlags = 1 << 23 // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. + NodeFlagsInWithStatement NodeFlags = 1 << 24 // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) + NodeFlagsJsonFile NodeFlags = 1 << 25 // If node was parsed in a Json + NodeFlagsDeprecated NodeFlags = 1 << 26 // If has '@deprecated' JSDoc tag + + NodeFlagsSkipDirectInference NodeFlags = 1 << 27 // If the node should skip direct type inference. NodeFlagsBlockScoped = NodeFlagsLet | NodeFlagsConst | NodeFlagsUsing NodeFlagsConstant = NodeFlagsConst | NodeFlagsUsing NodeFlagsAwaitUsing = NodeFlagsConst | NodeFlagsUsing // Variable declaration (NOTE: on a single node these flags would otherwise be mutually exclusive) - NodeFlagsReachabilityCheckFlags = NodeFlagsHasImplicitReturn | NodeFlagsHasExplicitReturn - NodeFlagsReachabilityAndEmitFlags = NodeFlagsReachabilityCheckFlags | NodeFlagsHasAsyncFunctions + NodeFlagsReachabilityCheckFlags = NodeFlagsHasImplicitReturn | NodeFlagsHasExplicitReturn // Parsing context flags NodeFlagsContextFlags NodeFlags = NodeFlagsDisallowInContext | NodeFlagsDisallowConditionalTypesContext | NodeFlagsYieldContext | NodeFlagsDecoratorContext | NodeFlagsAwaitContext | NodeFlagsJavaScriptFile | NodeFlagsInWithStatement | NodeFlagsAmbient @@ -65,6 +63,5 @@ const ( NodeFlagsPermanentlySetIncrementalFlags NodeFlags = NodeFlagsPossiblyContainsDynamicImport | NodeFlagsPossiblyContainsImportMeta // The following flags repurpose other NodeFlags as different meanings for Identifier nodes - NodeFlagsIdentifierHasExtendedUnicodeEscape NodeFlags = NodeFlagsContainsThis // Indicates whether the identifier contains an extended unicode escape sequence - NodeFlagsIdentifierIsInJSDocNamespace NodeFlags = NodeFlagsHasAsyncFunctions // Indicates whether the identifier is part of a JSDoc namespace + NodeFlagsIdentifierHasExtendedUnicodeEscape NodeFlags = NodeFlagsContainsThis // Indicates whether the identifier contains an extended unicode escape sequence ) diff --git a/internal/ast/precedence.go b/internal/ast/precedence.go index abeb9a57e2..26b001d362 100644 --- a/internal/ast/precedence.go +++ b/internal/ast/precedence.go @@ -414,6 +414,12 @@ const ( // TypePrecedenceConditional TypePrecedence = iota + // JSDoc precedence (optional and variadic types) + // + // JSDocType: + // `...`? Type `=`? + TypePrecedenceJSDoc + // Function precedence // // Type[Extends]: @@ -651,6 +657,8 @@ func GetTypeNodePrecedence(n *TypeNode) TypePrecedence { switch n.Kind { case KindConditionalType: return TypePrecedenceConditional + case KindJSDocOptionalType, KindJSDocVariadicType: + return TypePrecedenceJSDoc case KindFunctionType, KindConstructorType: return TypePrecedenceFunction case KindUnionType: @@ -684,6 +692,9 @@ func GetTypeNodePrecedence(n *TypeNode) TypePrecedence { KindObjectKeyword, KindIntrinsicKeyword, KindVoidKeyword, + KindJSDocAllType, + KindJSDocNullableType, + KindJSDocNonNullableType, KindLiteralType, KindTypePredicate, KindTypeReference, diff --git a/internal/ast/subtreefacts.go b/internal/ast/subtreefacts.go new file mode 100644 index 0000000000..66f65f8fd1 --- /dev/null +++ b/internal/ast/subtreefacts.go @@ -0,0 +1,116 @@ +package ast + +import ( + "github.com/microsoft/typescript-go/internal/core" +) + +type SubtreeFacts int32 + +const ( + // Facts + // - Flags used to indicate that a node or subtree contains syntax specific to a particular ECMAScript variant. + + SubtreeContainsTypeScript SubtreeFacts = 1 << iota + SubtreeContainsJsx + SubtreeContainsESNext + SubtreeContainsES2022 + SubtreeContainsES2021 + SubtreeContainsES2020 + SubtreeContainsES2019 + SubtreeContainsES2018 + SubtreeContainsES2017 + SubtreeContainsES2016 + + // Markers + // - Flags used to indicate that a node or subtree contains a particular kind of syntax. + + SubtreeContainsLexicalThis + SubtreeContainsLexicalSuper + SubtreeContainsRest + SubtreeContainsObjectRestOrSpread + SubtreeContainsAwait + SubtreeContainsDynamicImport + SubtreeContainsClassFields + SubtreeContainsDecorators + SubtreeContainsIdentifier + + SubtreeFactsComputed // NOTE: This should always be last + SubtreeFactsNone SubtreeFacts = 0 + + // Scope Exclusions + // - Bitmasks that exclude flags from propagating out of a specific context + // into the subtree flags of their container. + + SubtreeExclusionsNode = SubtreeFactsComputed + SubtreeExclusionsEraseable = ^SubtreeContainsTypeScript + SubtreeExclusionsOuterExpression = SubtreeExclusionsNode + SubtreeExclusionsPropertyAccess = SubtreeExclusionsNode + SubtreeExclusionsElementAccess = SubtreeExclusionsNode + SubtreeExclusionsArrowFunction = SubtreeExclusionsNode | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsFunction = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsConstructor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsMethod = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsAccessor = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper | SubtreeContainsAwait | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsProperty = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper + SubtreeExclusionsClass = SubtreeExclusionsNode + SubtreeExclusionsModule = SubtreeExclusionsNode | SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper + SubtreeExclusionsObjectLiteral = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsArrayLiteral = SubtreeExclusionsNode + SubtreeExclusionsCall = SubtreeExclusionsNode + SubtreeExclusionsNew = SubtreeExclusionsNode + SubtreeExclusionsVariableDeclarationList = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsParameter = SubtreeExclusionsNode + SubtreeExclusionsCatchClause = SubtreeExclusionsNode | SubtreeContainsObjectRestOrSpread + SubtreeExclusionsBindingPattern = SubtreeExclusionsNode | SubtreeContainsRest + + // Masks + // - Additional bitmasks + + SubtreeContainsLexicalThisOrSuper = SubtreeContainsLexicalThis | SubtreeContainsLexicalSuper +) + +func propagateEraseableSyntaxListSubtreeFacts(children *TypeArgumentList) SubtreeFacts { + return core.IfElse(children != nil, SubtreeContainsTypeScript, SubtreeFactsNone) +} + +func propagateEraseableSyntaxSubtreeFacts(child *TypeNode) SubtreeFacts { + return core.IfElse(child != nil, SubtreeContainsTypeScript, SubtreeFactsNone) +} + +func propagateObjectBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts { + facts := propagateSubtreeFacts(child) + if facts&SubtreeContainsRest != 0 { + facts &= ^SubtreeContainsRest + facts |= SubtreeContainsObjectRestOrSpread + } + return facts +} + +func propagateBindingElementSubtreeFacts(child *BindingElementNode) SubtreeFacts { + return propagateSubtreeFacts(child) & ^SubtreeContainsRest +} + +func propagateSubtreeFacts(child *Node) SubtreeFacts { + if child == nil { + return SubtreeFactsNone + } + return child.propagateSubtreeFacts() +} + +func propagateNodeListSubtreeFacts(children *NodeList, propagate func(*Node) SubtreeFacts) SubtreeFacts { + if children == nil { + return SubtreeFactsNone + } + facts := SubtreeFactsNone + for _, child := range children.Nodes { + facts |= propagate(child) + } + return facts +} + +func propagateModifierListSubtreeFacts(children *ModifierList) SubtreeFacts { + if children == nil { + return SubtreeFactsNone + } + return propagateNodeListSubtreeFacts(&children.NodeList, propagateSubtreeFacts) +} diff --git a/internal/ast/symbol.go b/internal/ast/symbol.go index 92e9412cd9..ea5d73a7eb 100644 --- a/internal/ast/symbol.go +++ b/internal/ast/symbol.go @@ -49,6 +49,7 @@ const ( InternalSymbolNameExportEquals = "export=" // Export assignment symbol InternalSymbolNameDefault = "default" // Default export symbol (technically not wholly internal, but included here for usability) InternalSymbolNameThis = "this" + InternalSymbolNameModuleExports = "module.exports" ) func SymbolName(symbol *Symbol) string { diff --git a/internal/ast/symbolflags.go b/internal/ast/symbolflags.go index bee3687981..9f65726d1e 100644 --- a/internal/ast/symbolflags.go +++ b/internal/ast/symbolflags.go @@ -68,7 +68,7 @@ const ( SymbolFlagsMethodExcludes = SymbolFlagsValue & ^SymbolFlagsMethod SymbolFlagsGetAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsSetAccessor SymbolFlagsSetAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsGetAccessor - SymbolFlagsAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsAccessor + SymbolFlagsAccessorExcludes = SymbolFlagsValue SymbolFlagsTypeParameterExcludes = SymbolFlagsType & ^SymbolFlagsTypeParameter SymbolFlagsTypeAliasExcludes = SymbolFlagsType SymbolFlagsAliasExcludes = SymbolFlagsAlias diff --git a/internal/ast/tokenflags.go b/internal/ast/tokenflags.go index 36e9a8528e..d30cf49f49 100644 --- a/internal/ast/tokenflags.go +++ b/internal/ast/tokenflags.go @@ -23,8 +23,9 @@ const ( TokenFlagsSingleQuote TokenFlags = 1 << 16 // e.g. `'abc'` TokenFlagsBinaryOrOctalSpecifier TokenFlags = TokenFlagsBinarySpecifier | TokenFlagsOctalSpecifier TokenFlagsWithSpecifier TokenFlags = TokenFlagsHexSpecifier | TokenFlagsBinaryOrOctalSpecifier - TokenFlagsStringLiteralFlags TokenFlags = TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape | TokenFlagsSingleQuote + TokenFlagsStringLiteralFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape | TokenFlagsSingleQuote TokenFlagsNumericLiteralFlags TokenFlags = TokenFlagsScientific | TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsWithSpecifier | TokenFlagsContainsSeparator | TokenFlagsContainsInvalidSeparator - TokenFlagsTemplateLiteralLikeFlags TokenFlags = TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape + TokenFlagsTemplateLiteralLikeFlags TokenFlags = TokenFlagsUnterminated | TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape + TokenFlagsRegularExpressionLiteralFlags TokenFlags = TokenFlagsUnterminated TokenFlagsIsInvalid TokenFlags = TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsContainsInvalidSeparator | TokenFlagsContainsInvalidEscape ) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 4b7c524423..ffe9baee60 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -75,11 +75,26 @@ func NodeIsSynthesized(node *Node) bool { return PositionIsSynthesized(node.Loc.Pos()) || PositionIsSynthesized(node.Loc.End()) } +func RangeIsSynthesized(loc core.TextRange) bool { + return PositionIsSynthesized(loc.Pos()) || PositionIsSynthesized(loc.End()) +} + // Determines whether a position is synthetic func PositionIsSynthesized(pos int) bool { return pos < 0 } +func FindLastVisibleNode(nodes []*Node) *Node { + fromEnd := 1 + for fromEnd <= len(nodes) && nodes[len(nodes)-fromEnd].Flags&NodeFlagsReparsed != 0 { + fromEnd++ + } + if fromEnd <= len(nodes) { + return nodes[len(nodes)-fromEnd] + } + return nil +} + func NodeKindIs(node *Node, kinds ...Kind) bool { return slices.Contains(kinds, node.Kind) } @@ -499,7 +514,7 @@ func IsFunctionLikeDeclaration(node *Node) bool { return node != nil && isFunctionLikeDeclarationKind(node.Kind) } -func isFunctionLikeKind(kind Kind) bool { +func IsFunctionLikeKind(kind Kind) bool { switch kind { case KindMethodSignature, KindCallSignature, @@ -516,7 +531,7 @@ func isFunctionLikeKind(kind Kind) bool { // Determines if a node is function- or signature-like. func IsFunctionLike(node *Node) bool { // TODO(rbuckton): Move `node != nil` test to call sites - return node != nil && isFunctionLikeKind(node.Kind) + return node != nil && IsFunctionLikeKind(node.Kind) } func IsFunctionLikeOrClassStaticBlockDeclaration(node *Node) bool { @@ -616,6 +631,10 @@ func IsJsxChild(node *Node) bool { return false } +func IsJsxAttributeLike(node *Node) bool { + return IsJsxAttribute(node) || IsJsxSpreadAttribute(node) +} + func isDeclarationStatementKind(kind Kind) bool { switch kind { case KindFunctionDeclaration, @@ -623,12 +642,14 @@ func isDeclarationStatementKind(kind Kind) bool { KindClassDeclaration, KindInterfaceDeclaration, KindTypeAliasDeclaration, + KindJSTypeAliasDeclaration, KindEnumDeclaration, KindModuleDeclaration, KindImportDeclaration, KindImportEqualsDeclaration, KindExportDeclaration, KindExportAssignment, + KindJSExportAssignment, KindNamespaceExportDeclaration: return true } @@ -892,6 +913,17 @@ func FindAncestor(node *Node, callback func(*Node) bool) *Node { return nil } +// Walks up the parents of a node to find the ancestor that matches the kind +func FindAncestorKind(node *Node, kind Kind) *Node { + for node != nil { + if node.Kind == kind { + return node + } + node = node.Parent + } + return nil +} + type FindAncestorResult int32 const ( @@ -900,6 +932,13 @@ const ( FindAncestorQuit ) +func ToFindAncestorResult(b bool) FindAncestorResult { + if b { + return FindAncestorTrue + } + return FindAncestorFalse +} + // Walks up the parents of a node to find the ancestor that matches the callback func FindAncestorOrQuit(node *Node, callback func(*Node) FindAncestorResult) *Node { for node != nil { @@ -1168,6 +1207,10 @@ func WalkUpBindingElementsAndPatterns(binding *Node) *Node { return node.Parent } +func IsSourceFileJS(file *SourceFile) bool { + return file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX +} + func IsInJSFile(node *Node) bool { return node != nil && node.Flags&NodeFlagsJavaScriptFile != 0 } @@ -1262,7 +1305,7 @@ func GetElementOrPropertyAccessArgumentExpressionOrName(node *Node) *Node { } func GetElementOrPropertyAccessName(node *Node) string { - name := getElementOrPropertyAccessArgumentExpressionOrName(node) + name := GetElementOrPropertyAccessArgumentExpressionOrName(node) if name == nil { return "" } @@ -1309,10 +1352,10 @@ func GetNonAssignedNameOfDeclaration(declaration *Node) *Node { switch declaration.Kind { case KindBinaryExpression: if IsFunctionPropertyAssignment(declaration) { - return getElementOrPropertyAccessArgumentExpressionOrName(declaration.AsBinaryExpression().Left) + return GetElementOrPropertyAccessArgumentExpressionOrName(declaration.AsBinaryExpression().Left) } return nil - case KindExportAssignment: + case KindExportAssignment, KindJSExportAssignment: expr := declaration.AsExportAssignment().Expression if IsIdentifier(expr) { return expr @@ -1372,22 +1415,6 @@ func IsFunctionPropertyAssignment(node *Node) bool { return false } -// Does not handle signed numeric names like `a[+0]` - handling those would require handling prefix unary expressions -// throughout late binding handling as well, which is awkward (but ultimately probably doable if there is demand) -func getElementOrPropertyAccessArgumentExpressionOrName(node *Node) *Node { - switch node.Kind { - case KindPropertyAccessExpression: - return node.Name() - case KindElementAccessExpression: - arg := SkipParentheses(node.AsElementAccessExpression().ArgumentExpression) - if IsStringOrNumericLiteralLike(arg) { - return arg - } - return node - } - panic("Unhandled case in getElementOrPropertyAccessArgumentExpressionOrName") -} - /** * A declaration has a dynamic name if all of the following are true: * 1. The declaration has a computed property name. @@ -1444,17 +1471,13 @@ func IsExternalModule(file *SourceFile) bool { return file.ExternalModuleIndicator != nil } -func IsExternalOrCommonJsModule(file *SourceFile) bool { - return file.ExternalModuleIndicator != nil || file.CommonJsModuleIndicator != nil +func IsExternalOrCommonJSModule(file *SourceFile) bool { + return file.ExternalModuleIndicator != nil || file.CommonJSModuleIndicator != nil } -// TODO: Should we deprecate `IsExternalOrCommonJsModule` in favor of this function? +// TODO: Should we deprecate `IsExternalOrCommonJSModule` in favor of this function? func IsEffectiveExternalModule(node *SourceFile, compilerOptions *core.CompilerOptions) bool { - return IsExternalModule(node) || (isCommonJSContainingModuleKind(compilerOptions.GetEmitModuleKind()) && node.CommonJsModuleIndicator != nil) -} - -func IsEffectiveExternalModuleWorker(node *SourceFile, moduleKind core.ModuleKind) bool { - return IsExternalModule(node) || (isCommonJSContainingModuleKind(moduleKind) && node.CommonJsModuleIndicator != nil) + return IsExternalModule(node) || (isCommonJSContainingModuleKind(compilerOptions.GetEmitModuleKind()) && node.CommonJSModuleIndicator != nil) } func isCommonJSContainingModuleKind(kind core.ModuleKind) bool { @@ -1476,7 +1499,7 @@ func IsExportNamespaceAsDefaultDeclaration(node *Node) bool { } func IsGlobalScopeAugmentation(node *Node) bool { - return node.Flags&NodeFlagsGlobalAugmentation != 0 + return IsModuleDeclaration(node) && node.AsModuleDeclaration().Keyword == KindGlobalKeyword } func IsModuleAugmentationExternal(node *Node) bool { @@ -1626,20 +1649,7 @@ func IsEnumConst(node *Node) bool { } func ExportAssignmentIsAlias(node *Node) bool { - return isAliasableExpression(getExportAssignmentExpression(node)) -} - -func getExportAssignmentExpression(node *Node) *Node { - switch node.Kind { - case KindExportAssignment: - return node.AsExportAssignment().Expression - case KindBinaryExpression: - return node.AsBinaryExpression().Right - } - panic("Unhandled case in getExportAssignmentExpression") -} - -func isAliasableExpression(e *Node) bool { + e := node.AsExportAssignment().Expression return IsEntityNameExpression(e) || IsClassExpression(e) } @@ -1659,6 +1669,10 @@ func IsJsonSourceFile(file *SourceFile) bool { return file.ScriptKind == core.ScriptKindJSON } +func IsInJsonFile(node *Node) bool { + return node.Flags&NodeFlagsJsonFile != 0 +} + func GetExternalModuleName(node *Node) *Expression { switch node.Kind { case KindImportDeclaration: @@ -1675,7 +1689,7 @@ func GetExternalModuleName(node *Node) *Expression { case KindImportType: return getImportTypeNodeLiteral(node) case KindCallExpression: - return node.AsCallExpression().Arguments.Nodes[0] + return core.FirstOrNil(node.AsCallExpression().Arguments.Nodes) case KindModuleDeclaration: if IsStringLiteral(node.AsModuleDeclaration().Name()) { return node.AsModuleDeclaration().Name() @@ -1814,6 +1828,8 @@ func IsPartOfTypeNode(node *Node) bool { KindBooleanKeyword, KindSymbolKeyword, KindObjectKeyword, KindUndefinedKeyword, KindNullKeyword, KindNeverKeyword: return true + case KindVoidKeyword: + return node.Parent.Kind != KindVoidExpression case KindExpressionWithTypeArguments: return isPartOfTypeExpressionWithTypeArguments(node) case KindTypeParameter: @@ -1835,6 +1851,13 @@ func IsPartOfTypeNode(node *Node) bool { func isPartOfTypeNodeInParent(node *Node) bool { parent := node.Parent + if parent.Kind == KindTypeQuery { + return false + } + if parent.Kind == KindImportType { + return !parent.AsImportTypeNode().IsTypeOf + } + // Do not recursively call isPartOfTypeNode on the parent. In the example: // // let a: A.B.C; @@ -1845,10 +1868,6 @@ func isPartOfTypeNodeInParent(node *Node) bool { return true } switch parent.Kind { - case KindTypeQuery: - return false - case KindImportType: - return !parent.AsImportTypeNode().IsTypeOf case KindExpressionWithTypeArguments: return isPartOfTypeExpressionWithTypeArguments(parent) case KindTypeParameter: @@ -1926,6 +1945,7 @@ func TryGetTextOfPropertyName(name *Node) (string, bool) { return "", false } +// True if node is of a JSDoc kind that may contain comment text. func IsJSDocCommentContainingNode(node *Node) bool { return node.Kind == KindJSDoc || node.Kind == KindJSDocText || @@ -2013,6 +2033,7 @@ func GetMeaningFromDeclaration(node *Node) SemanticMeaning { case KindTypeParameter, KindInterfaceDeclaration, KindTypeAliasDeclaration, + KindJSTypeAliasDeclaration, KindTypeLiteral: return SemanticMeaningType case KindEnumMember, KindClassDeclaration: @@ -2033,6 +2054,7 @@ func GetMeaningFromDeclaration(node *Node) SemanticMeaning { KindImportEqualsDeclaration, KindImportDeclaration, KindExportAssignment, + KindJSExportAssignment, KindExportDeclaration: return SemanticMeaningAll @@ -2081,7 +2103,7 @@ func IsBreakOrContinueStatement(node *Node) bool { // virtual `Parent` pointers that can be used to walk up the tree. Since `getModuleInstanceStateForAliasTarget` may // potentially walk up out of the provided `Node`, merely setting the parent pointers for a given `ModuleDeclaration` // prior to invoking `GetModuleInstanceState` is not sufficient. It is, however, necessary that the `Parent` pointers -// for all ancestors of the `Node` provided to `GetModuleInstanceState` have ben set. +// for all ancestors of the `Node` provided to `GetModuleInstanceState` have been set. // Push a virtual parent pointer onto `ancestors` and return it. func pushAncestor(ancestors []*Node, parent *Node) []*Node { @@ -2140,7 +2162,7 @@ func getModuleInstanceStateCached(node *Node, ancestors []*Node, visited map[Nod func getModuleInstanceStateWorker(node *Node, ancestors []*Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState { // A module is uninstantiated if it contains only switch node.Kind { - case KindInterfaceDeclaration, KindTypeAliasDeclaration: + case KindInterfaceDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration: return ModuleInstanceStateNonInstantiated case KindEnumDeclaration: if IsEnumConst(node) { @@ -2187,10 +2209,6 @@ func getModuleInstanceStateWorker(node *Node, ancestors []*Node, visited map[Nod return state case KindModuleDeclaration: return getModuleInstanceState(node, ancestors, visited) - case KindIdentifier: - if node.Flags&NodeFlagsIdentifierIsInJSDocNamespace != 0 { - return ModuleInstanceStateNonInstantiated - } } return ModuleInstanceStateInstantiated } @@ -2278,12 +2296,12 @@ func IsConstTypeReference(node *Node) bool { } func IsGlobalSourceFile(node *Node) bool { - return node.Kind == KindSourceFile && !IsExternalOrCommonJsModule(node.AsSourceFile()) + return node.Kind == KindSourceFile && !IsExternalOrCommonJSModule(node.AsSourceFile()) } -func IsParameterLikeOrReturnTag(node *Node) bool { +func IsParameterLike(node *Node) bool { switch node.Kind { - case KindParameter, KindTypeParameter, KindJSDocParameterTag, KindJSDocReturnTag: + case KindParameter, KindTypeParameter: return true } return false @@ -2354,27 +2372,43 @@ func IsDefaultImport(node *Node /*ImportDeclaration | ImportEqualsDeclaration | return importClause != nil && importClause.AsImportClause().name != nil } -func GetEmitModuleFormatOfFileWorker(sourceFile *SourceFile, options *core.CompilerOptions) core.ModuleKind { - result := GetImpliedNodeFormatForEmitWorker(sourceFile, options) +func GetImpliedNodeFormatForFile(path string, packageJsonType string) core.ModuleKind { + impliedNodeFormat := core.ResolutionModeNone + if tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDmts, tspath.ExtensionMts, tspath.ExtensionMjs}) { + impliedNodeFormat = core.ResolutionModeESM + } else if tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDcts, tspath.ExtensionCts, tspath.ExtensionCjs}) { + impliedNodeFormat = core.ResolutionModeCommonJS + } else if packageJsonType != "" && tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDts, tspath.ExtensionTs, tspath.ExtensionTsx, tspath.ExtensionJs, tspath.ExtensionJsx}) { + impliedNodeFormat = core.IfElse(packageJsonType == "module", core.ResolutionModeESM, core.ResolutionModeCommonJS) + } + + return impliedNodeFormat +} + +func GetEmitModuleFormatOfFileWorker(sourceFile *SourceFile, options *core.CompilerOptions, sourceFileMetaData *SourceFileMetaData) core.ModuleKind { + result := GetImpliedNodeFormatForEmitWorker(sourceFile.FileName(), options, sourceFileMetaData) if result != core.ModuleKindNone { return result } return options.GetEmitModuleKind() } -func GetImpliedNodeFormatForEmitWorker(sourceFile *SourceFile, options *core.CompilerOptions) core.ResolutionMode { +func GetImpliedNodeFormatForEmitWorker(fileName string, options *core.CompilerOptions, sourceFileMetaData *SourceFileMetaData) core.ModuleKind { moduleKind := options.GetEmitModuleKind() if core.ModuleKindNode16 <= moduleKind && moduleKind <= core.ModuleKindNodeNext { - return sourceFile.ImpliedNodeFormat + if sourceFileMetaData == nil { + return core.ModuleKindNone + } + return sourceFileMetaData.ImpliedNodeFormat } - if sourceFile.ImpliedNodeFormat == core.ModuleKindCommonJS && - ( /*sourceFile.packageJsonScope.contents.packageJsonContent.type == "commonjs" ||*/ // !!! - tspath.FileExtensionIsOneOf(sourceFile.FileName(), []string{tspath.ExtensionCjs, tspath.ExtensionCts})) { + if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS && + (sourceFileMetaData.PackageJsonType == "commonjs" || + tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionCjs, tspath.ExtensionCts})) { return core.ModuleKindCommonJS } - if sourceFile.ImpliedNodeFormat == core.ModuleKindESNext && - ( /*sourceFile.packageJsonScope?.contents.packageJsonContent.type === "module" ||*/ // !!! - tspath.FileExtensionIsOneOf(sourceFile.fileName, []string{tspath.ExtensionMjs, tspath.ExtensionMts})) { + if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindESNext && + (sourceFileMetaData.PackageJsonType == "module" || + tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionMjs, tspath.ExtensionMts})) { return core.ModuleKindESNext } return core.ModuleKindNone @@ -2409,6 +2443,8 @@ func IsNonLocalAlias(symbol *Symbol, excludes SymbolFlags) bool { // An alias symbol is created by one of the following declarations: // // import <symbol> = ... +// const <symbol> = ... (JS only) +// const { <symbol>, ... } = ... (JS only) // import <symbol> from ... // import * as <symbol> from ... // import { x as <symbol> } from ... @@ -2416,6 +2452,7 @@ func IsNonLocalAlias(symbol *Symbol, excludes SymbolFlags) bool { // export * as ns <symbol> from ... // export = <EntityNameExpression> // export default <EntityNameExpression> +// module.exports = <EntityNameExpression> (JS only) func IsAliasSymbolDeclaration(node *Node) bool { switch node.Kind { case KindImportEqualsDeclaration, KindNamespaceExportDeclaration, KindNamespaceImport, KindNamespaceExport, @@ -2423,8 +2460,10 @@ func IsAliasSymbolDeclaration(node *Node) bool { return true case KindImportClause: return node.AsImportClause().Name() != nil - case KindExportAssignment: + case KindExportAssignment, KindJSExportAssignment: return ExportAssignmentIsAlias(node) + case KindVariableDeclaration, KindBindingElement: + return IsVariableDeclarationInitializedToRequire(node) } return false } @@ -2439,9 +2478,9 @@ func GetNodeAtPosition(file *SourceFile, position int, isJavaScriptFile bool) *N for { var child *Node if isJavaScriptFile { - for _, jsDoc := range current.JSDoc(file) { - if nodeContainsPosition(jsDoc, position) { - child = jsDoc + for _, jsdoc := range current.JSDoc(file) { + if nodeContainsPosition(jsdoc, position) { + child = jsdoc break } } @@ -2500,10 +2539,10 @@ func ForEachDynamicImportOrRequireCall( cb func(node *Node, argument *Expression) bool, ) bool { isJavaScriptFile := IsInJSFile(file.AsNode()) - lastIndex, size := findImportOrRequire(file.Text, 0) + lastIndex, size := findImportOrRequire(file.Text(), 0) for lastIndex >= 0 { node := GetNodeAtPosition(file, lastIndex, isJavaScriptFile && includeTypeSpaceImports) - if isJavaScriptFile && IsRequireCall(node, requireStringLiteralLikeArgument) { + if isJavaScriptFile && IsRequireCall(node) { if cb(node, node.Arguments()[0]) { return true } @@ -2525,12 +2564,13 @@ func ForEachDynamicImportOrRequireCall( } // skip past import/require lastIndex += size - lastIndex, size = findImportOrRequire(file.Text, lastIndex) + lastIndex, size = findImportOrRequire(file.Text(), lastIndex) } return false } -func IsRequireCall(node *Node, requireStringLiteralLikeArgument bool) bool { +// IsVariableDeclarationInitializedToRequire should be used wherever parent pointers are set +func IsRequireCall(node *Node) bool { if !IsCallExpression(node) { return false } @@ -2541,5 +2581,223 @@ func IsRequireCall(node *Node, requireStringLiteralLikeArgument bool) bool { if len(call.Arguments.Nodes) != 1 { return false } - return !requireStringLiteralLikeArgument || IsStringLiteralLike(call.Arguments.Nodes[0]) + return IsStringLiteralLike(call.Arguments.Nodes[0]) +} + +func IsUnterminatedLiteral(node *Node) bool { + return node.LiteralLikeData().TokenFlags&TokenFlagsUnterminated != 0 +} + +func GetJSXImplicitImportBase(compilerOptions *core.CompilerOptions, file *SourceFile) string { + jsxImportSourcePragma := GetPragmaFromSourceFile(file, "jsximportsource") + jsxRuntimePragma := GetPragmaFromSourceFile(file, "jsxruntime") + if GetPragmaArgument(jsxRuntimePragma, "factory") == "classic" { + return "" + } + if compilerOptions.Jsx == core.JsxEmitReactJSX || + compilerOptions.Jsx == core.JsxEmitReactJSXDev || + compilerOptions.JsxImportSource != "" || + jsxImportSourcePragma != nil || + GetPragmaArgument(jsxRuntimePragma, "factory") == "automatic" { + result := GetPragmaArgument(jsxImportSourcePragma, "factory") + if result == "" { + result = compilerOptions.JsxImportSource + } + if result == "" { + result = "react" + } + return result + } + return "" +} + +func GetJSXRuntimeImport(base string, options *core.CompilerOptions) string { + if base == "" { + return base + } + return base + "/" + core.IfElse(options.Jsx == core.JsxEmitReactJSXDev, "jsx-dev-runtime", "jsx-runtime") +} + +func GetPragmaFromSourceFile(file *SourceFile, name string) *Pragma { + var result *Pragma + if file != nil { + for i := range file.Pragmas { + if file.Pragmas[i].Name == name { + result = &file.Pragmas[i] // Last one wins + } + } + } + return result +} + +func GetPragmaArgument(pragma *Pragma, name string) string { + if pragma != nil { + if arg, ok := pragma.Args[name]; ok { + return arg.Value + } + } + return "" +} + +// Of the form: `const x = require("x")` or `const { x } = require("x")` or with `var` or `let` +// The variable must not be exported and must not have a type annotation, even a jsdoc one. +// The initializer must be a call to `require` with a string literal or a string literal-like argument. +func IsVariableDeclarationInitializedToRequire(node *Node) bool { + if !IsInJSFile(node) { + return false + } + if node.Kind == KindBindingElement { + node = node.Parent.Parent + } + if node.Kind != KindVariableDeclaration { + return false + } + + return node.Parent.Parent.ModifierFlags()&ModifierFlagsExport == 0 && + node.AsVariableDeclaration().Initializer != nil && + node.Type() == nil && + IsRequireCall(node.AsVariableDeclaration().Initializer) +} + +func IsModuleExportsAccessExpression(node *Node) bool { + return (IsPropertyAccessExpression(node) || isLiteralLikeElementAccess(node)) && + IsModuleIdentifier(node.Expression()) && + GetElementOrPropertyAccessName(node) == "exports" +} + +func isLiteralLikeElementAccess(node *Node) bool { + return node.Kind == KindElementAccessExpression && IsStringOrNumericLiteralLike(node.AsElementAccessExpression().ArgumentExpression) +} + +func IsCheckJSEnabledForFile(sourceFile *SourceFile, compilerOptions *core.CompilerOptions) bool { + if sourceFile.CheckJsDirective != nil { + return sourceFile.CheckJsDirective.Enabled + } + return compilerOptions.CheckJs == core.TSTrue +} + +func GetLeftmostAccessExpression(expr *Node) *Node { + for IsAccessExpression(expr) { + expr = expr.Expression() + } + return expr +} + +func IsTypeOnlyImportDeclaration(node *Node) bool { + switch node.Kind { + case KindImportSpecifier: + return node.AsImportSpecifier().IsTypeOnly || node.Parent.Parent.AsImportClause().IsTypeOnly + case KindNamespaceImport: + return node.Parent.AsImportClause().IsTypeOnly + case KindImportClause: + return node.AsImportClause().IsTypeOnly + case KindImportEqualsDeclaration: + return node.AsImportEqualsDeclaration().IsTypeOnly + } + return false +} + +func isTypeOnlyExportDeclaration(node *Node) bool { + switch node.Kind { + case KindExportSpecifier: + return node.AsExportSpecifier().IsTypeOnly || node.Parent.Parent.AsExportDeclaration().IsTypeOnly + case KindExportDeclaration: + d := node.AsExportDeclaration() + return d.IsTypeOnly && d.ModuleSpecifier != nil && d.ExportClause == nil + case KindNamespaceExport: + return node.Parent.AsExportDeclaration().IsTypeOnly + } + return false +} + +func IsTypeOnlyImportOrExportDeclaration(node *Node) bool { + return IsTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node) +} + +func GetSourceFileOfModule(module *Symbol) *SourceFile { + declaration := module.ValueDeclaration + if declaration == nil { + declaration = getNonAugmentationDeclaration(module) + } + return GetSourceFileOfNode(declaration) +} + +func getNonAugmentationDeclaration(symbol *Symbol) *Node { + return core.Find(symbol.Declarations, func(d *Node) bool { + return !IsExternalModuleAugmentation(d) && !IsGlobalScopeAugmentation(d) + }) +} + +func IsExternalModuleAugmentation(node *Node) bool { + return IsAmbientModule(node) && IsModuleAugmentationExternal(node) +} + +func GetClassLikeDeclarationOfSymbol(symbol *Symbol) *Node { + return core.Find(symbol.Declarations, IsClassLike) +} + +func GetLanguageVariant(scriptKind core.ScriptKind) core.LanguageVariant { + switch scriptKind { + case core.ScriptKindTSX, core.ScriptKindJSX, core.ScriptKindJS, core.ScriptKindJSON: + // .tsx and .jsx files are treated as jsx language variant. + return core.LanguageVariantJSX + } + return core.LanguageVariantStandard +} + +func IsCallLikeExpression(node *Node) bool { + switch node.Kind { + case KindJsxOpeningElement, KindJsxSelfClosingElement, KindCallExpression, KindNewExpression, + KindTaggedTemplateExpression, KindDecorator: + return true + } + return false +} + +func IsCallLikeOrFunctionLikeExpression(node *Node) bool { + return IsCallLikeExpression(node) || IsFunctionExpressionOrArrowFunction(node) +} + +func NodeHasKind(node *Node, kind Kind) bool { + if node == nil { + return false + } + return node.Kind == kind +} + +func IsContextualKeyword(token Kind) bool { + return KindFirstContextualKeyword <= token && token <= KindLastContextualKeyword +} + +func IsThisInTypeQuery(node *Node) bool { + if !IsThisIdentifier(node) { + return false + } + for IsQualifiedName(node.Parent) && node.Parent.AsQualifiedName().Left == node { + node = node.Parent + } + return node.Parent.Kind == KindTypeQuery +} + +// Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `let` declaration. +func IsLet(node *Node) bool { + return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsLet +} + +func IsClassMemberModifier(token Kind) bool { + return IsParameterPropertyModifier(token) || token == KindStaticKeyword || + token == KindOverrideKeyword || token == KindAccessorKeyword +} + +func IsParameterPropertyModifier(kind Kind) bool { + return ModifierToFlag(kind)&ModifierFlagsParameterPropertyModifier != 0 +} + +func ForEachChildAndJSDoc(node *Node, sourceFile *SourceFile, v Visitor) bool { + if node.Flags&NodeFlagsHasJSDoc != 0 { + if visitNodes(v, node.JSDoc(sourceFile)) { + return true + } + } + return node.ForEachChild(v) } diff --git a/internal/ast/visitor.go b/internal/ast/visitor.go index 2c807873b7..cc3fd76f20 100644 --- a/internal/ast/visitor.go +++ b/internal/ast/visitor.go @@ -258,18 +258,21 @@ func (v *NodeVisitor) visitTopLevelStatements(nodes *StatementList) *StatementLi } func (v *NodeVisitor) liftToBlock(node *Statement) *Statement { - if node != nil && node.Kind == KindSyntaxList { - nodes := node.AsSyntaxList().Children - if len(nodes) == 0 { - node = nil - } else if len(nodes) == 1 { - node = nodes[0] + var nodes []*Node + if node != nil { + if node.Kind == KindSyntaxList { + nodes = node.AsSyntaxList().Children } else { - node = v.Factory.NewBlock(v.Factory.NewNodeList(nodes), true /*multiLine*/) - } - if node != nil && node.Kind == KindSyntaxList { - panic("The result of visiting and lifting a Node may not be SyntaxList") + nodes = []*Node{node} } } + if len(nodes) == 1 { + node = nodes[0] + } else { + node = v.Factory.NewBlock(v.Factory.NewNodeList(nodes), true /*multiLine*/) + } + if node.Kind == KindSyntaxList { + panic("The result of visiting and lifting a Node may not be SyntaxList") + } return node } diff --git a/internal/astnav/tokens.go b/internal/astnav/tokens.go index feac94654d..b70f2de7f9 100644 --- a/internal/astnav/tokens.go +++ b/internal/astnav/tokens.go @@ -64,7 +64,7 @@ func getTokenAtPosition( visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node { // We can't abort visiting children, so once a match is found, we set `next` // and do nothing on subsequent visits. - if node != nil && next == nil { + if node != nil && node.Flags&ast.NodeFlagsReparsed == 0 && next == nil { switch testNode(node) { case -1: if !ast.IsJSDocKind(node.Kind) { @@ -81,20 +81,6 @@ func getTokenAtPosition( return node } - visitNodes := func(nodes []*ast.Node) { - index, match := core.BinarySearchUniqueFunc(nodes, position, func(middle int, node *ast.Node) int { - cmp := testNode(node) - if cmp < 0 { - left = node.End() - } - return cmp - }) - - if match { - next = nodes[index] - } - } - visitNodeList := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList { if nodeList != nil && len(nodeList.Nodes) > 0 && next == nil { if nodeList.End() == position && includePrecedingTokenAtEndPosition != nil { @@ -103,7 +89,33 @@ func getTokenAtPosition( } else if nodeList.End() <= position { left = nodeList.End() } else if nodeList.Pos() <= position { - visitNodes(nodeList.Nodes) + nodes := nodeList.Nodes + index, match := core.BinarySearchUniqueFunc(nodes, func(middle int, node *ast.Node) int { + if node.Flags&ast.NodeFlagsReparsed != 0 { + return 0 + } + cmp := testNode(node) + if cmp < 0 { + left = node.End() + } + return cmp + }) + if match && nodes[index].Flags&ast.NodeFlagsReparsed != 0 { + // filter and search again + nodes = core.Filter(nodes, func(node *ast.Node) bool { + return node.Flags&ast.NodeFlagsReparsed == 0 + }) + index, match = core.BinarySearchUniqueFunc(nodes, func(middle int, node *ast.Node) int { + cmp := testNode(node) + if cmp < 0 { + left = node.End() + } + return cmp + }) + } + if match { + next = nodes[index] + } } } return nodeList @@ -179,7 +191,7 @@ func getPosition(node *ast.Node, sourceFile *ast.SourceFile, allowPositionInLead if allowPositionInLeadingTrivia { return node.Pos() } - return scanner.GetTokenPosOfNode(node, sourceFile, true /*includeJsDoc*/) + return scanner.GetTokenPosOfNode(node, sourceFile, true /*includeJSDoc*/) } func findRightmostNode(node *ast.Node) *ast.Node { @@ -195,14 +207,18 @@ func findRightmostNode(node *ast.Node) *ast.Node { VisitNode: visitNode, VisitToken: visitNode, VisitNodes: func(nodeList *ast.NodeList, visitor *ast.NodeVisitor) *ast.NodeList { - if nodeList != nil && len(nodeList.Nodes) > 0 { - next = nodeList.Nodes[len(nodeList.Nodes)-1] + if nodeList != nil { + if rightmost := ast.FindLastVisibleNode(nodeList.Nodes); rightmost != nil { + next = rightmost + } } return nodeList }, VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList { - if modifiers != nil && len(modifiers.Nodes) > 0 { - next = modifiers.Nodes[len(modifiers.Nodes)-1] + if modifiers != nil { + if rightmost := ast.FindLastVisibleNode(modifiers.Nodes); rightmost != nil { + next = rightmost + } } return modifiers }, @@ -220,13 +236,335 @@ func findRightmostNode(node *ast.Node) *ast.Node { func visitEachChildAndJSDoc(node *ast.Node, sourceFile *ast.SourceFile, visitor *ast.NodeVisitor) { if node.Flags&ast.NodeFlagsHasJSDoc != 0 { - for _, jsDoc := range node.JSDoc(sourceFile) { + for _, jsdoc := range node.JSDoc(sourceFile) { if visitor.Hooks.VisitNode != nil { - visitor.Hooks.VisitNode(jsDoc, visitor) + visitor.Hooks.VisitNode(jsdoc, visitor) } else { - visitor.VisitNode(jsDoc) + visitor.VisitNode(jsdoc) } } } node.VisitEachChild(visitor) } + +const ( + comparisonLessThan = -1 + comparisonEqualTo = 0 + comparisonGreaterThan = 1 +) + +// Finds the leftmost token satisfying `position < token.End()`. +// If the leftmost token satisfying `position < token.End()` is invalid, or if position +// is in the trivia of that leftmost token, +// we will find the rightmost valid token with `token.End() <= position`. +func FindPrecedingToken(sourceFile *ast.SourceFile, position int) *ast.Node { + return FindPrecedingTokenEx(sourceFile, position, nil, false) +} + +func FindPrecedingTokenEx(sourceFile *ast.SourceFile, position int, startNode *ast.Node, excludeJSDoc bool) *ast.Node { + var find func(node *ast.Node) *ast.Node + find = func(n *ast.Node) *ast.Node { + if ast.IsNonWhitespaceToken(n) { + return n + } + + // `foundChild` is the leftmost node that contains the target position. + // `prevChild` is the last visited child of the current node. + var foundChild, prevChild *ast.Node + visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node { + // skip synthesized nodes (that will exist now because of jsdoc handling) + if node == nil || node.Flags&ast.NodeFlagsReparsed != 0 { + return node + } + if foundChild != nil { // We cannot abort visiting children, so once the desired child is found, we do nothing. + return node + } + if position < node.End() && (prevChild == nil || prevChild.End() <= position) { + foundChild = node + } else { + prevChild = node + } + return node + } + visitNodes := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList { + if foundChild != nil { + return nodeList + } + if nodeList != nil && len(nodeList.Nodes) > 0 { + nodes := nodeList.Nodes + if isJSDocSingleCommentNodeList(n, nodeList) { + return nodeList + } + index, match := core.BinarySearchUniqueFunc(nodes, func(middle int, _ *ast.Node) int { + // synthetic jsdoc nodes should have jsdocNode.End() <= n.Pos() + if nodes[middle].Flags&ast.NodeFlagsReparsed != 0 { + return comparisonLessThan + } + if position < nodes[middle].End() { + if middle == 0 || position >= nodes[middle-1].End() { + return comparisonEqualTo + } + return comparisonGreaterThan + } + return comparisonLessThan + }) + + if match { + foundChild = nodes[index] + } + + validLookupIndex := core.IfElse(match, index-1, len(nodes)-1) + for i := validLookupIndex; i >= 0; i-- { + if nodes[i].Flags&ast.NodeFlagsReparsed != 0 { + continue + } + if prevChild == nil { + prevChild = nodes[i] + } + } + } + return nodeList + } + nodeVisitor := ast.NewNodeVisitor(core.Identity, nil, ast.NodeVisitorHooks{ + VisitNode: visitNode, + VisitToken: visitNode, + VisitNodes: visitNodes, + VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList { + if modifiers != nil { + visitNodes(&modifiers.NodeList, visitor) + } + return modifiers + }, + }) + visitEachChildAndJSDoc(n, sourceFile, nodeVisitor) + + if foundChild != nil { + // Note that the span of a node's tokens is [getStartOfNode(node, ...), node.end). + // Given that `position < child.end` and child has constituent tokens, we distinguish these cases: + // 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`): + // we need to find the last token in a previous child node or child tokens. + // 2) `position` is within the same span: we recurse on `child`. + start := GetStartOfNode(foundChild, sourceFile, !excludeJSDoc /*includeJSDoc*/) + lookInPreviousChild := start >= position || // cursor in the leading trivia or preceding tokens + !isValidPrecedingNode(foundChild, sourceFile) + if lookInPreviousChild { + if position >= foundChild.Pos() { + // Find jsdoc preceding the foundChild. + var jsDoc *ast.Node + nodeJSDoc := n.JSDoc(sourceFile) + for i := len(nodeJSDoc) - 1; i >= 0; i-- { + if nodeJSDoc[i].Pos() >= foundChild.Pos() { + jsDoc = nodeJSDoc[i] + break + } + } + if jsDoc != nil { + if !excludeJSDoc { + return find(jsDoc) + } else { + return findRightmostValidToken(jsDoc.End(), sourceFile, n, position, excludeJSDoc) + } + } + return findRightmostValidToken(foundChild.Pos(), sourceFile, n, -1 /*position*/, excludeJSDoc) + } else { // Answer is in tokens between two visited children. + return findRightmostValidToken(foundChild.Pos(), sourceFile, n, position, excludeJSDoc) + } + } else { + // position is in [foundChild.getStart(), foundChild.End): recur. + return find(foundChild) + } + } + + // We have two cases here: either the position is at the end of the file, + // or the desired token is in the unvisited trailing tokens of the current node. + if position >= n.End() { + return findRightmostValidToken(n.End(), sourceFile, n, -1 /*position*/, excludeJSDoc) + } else { + return findRightmostValidToken(n.End(), sourceFile, n, position, excludeJSDoc) + } + } + + var node *ast.Node + if startNode != nil { + node = startNode + } else { + node = sourceFile.AsNode() + } + result := find(node) + if result != nil && ast.IsWhitespaceOnlyJsxText(result) { + panic("Expected result to be a non-whitespace token.") + } + return result +} + +func isValidPrecedingNode(node *ast.Node, sourceFile *ast.SourceFile) bool { + start := GetStartOfNode(node, sourceFile, false /*includeJSDoc*/) + width := node.End() - start + return !(ast.IsWhitespaceOnlyJsxText(node) || width == 0) +} + +func GetStartOfNode(node *ast.Node, file *ast.SourceFile, includeJSDoc bool) int { + return scanner.GetTokenPosOfNode(node, file, includeJSDoc) +} + +// If this is a single comment JSDoc, we do not visit the comment node. +func isJSDocSingleCommentNodeList(parent *ast.Node, nodeList *ast.NodeList) bool { + return parent.Kind == ast.KindJSDoc && nodeList == parent.AsJSDoc().Comment && nodeList != nil && len(nodeList.Nodes) == 1 +} + +// Looks for rightmost valid token in the range [startPos, endPos). +// If position is >= 0, looks for rightmost valid token that precedes or touches that position. +func findRightmostValidToken(endPos int, sourceFile *ast.SourceFile, containingNode *ast.Node, position int, excludeJSDoc bool) *ast.Node { + if position == -1 { + position = containingNode.End() + } + var find func(n *ast.Node, endPos int) *ast.Node + find = func(n *ast.Node, endPos int) *ast.Node { + if n == nil { + return nil + } + if ast.IsNonWhitespaceToken(n) { + return n + } + + var rightmostValidNode *ast.Node + rightmostVisitedNodes := make([]*ast.Node, 0, 1) // Nodes after the last valid node. + hasChildren := false + shouldVisitNode := func(node *ast.Node) bool { + // Node is synthetic or out of the desired range: don't visit it. + return !(node.Flags&ast.NodeFlagsReparsed != 0 || + node.End() > endPos || GetStartOfNode(node, sourceFile, !excludeJSDoc /*includeJSDoc*/) >= position) + } + visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node { + if node == nil { + return node + } + hasChildren = true + if !shouldVisitNode(node) { + return node + } + rightmostVisitedNodes = append(rightmostVisitedNodes, node) + if isValidPrecedingNode(node, sourceFile) { + rightmostValidNode = node + rightmostVisitedNodes = rightmostVisitedNodes[:0] + } + return node + } + visitNodes := func(nodeList *ast.NodeList, _ *ast.NodeVisitor) *ast.NodeList { + if nodeList != nil && len(nodeList.Nodes) > 0 { + if isJSDocSingleCommentNodeList(n, nodeList) { + return nodeList + } + hasChildren = true + index, _ := core.BinarySearchUniqueFunc(nodeList.Nodes, func(middle int, node *ast.Node) int { + if node.End() > endPos { + return comparisonGreaterThan + } + return comparisonLessThan + }) + validIndex := -1 + for i := index - 1; i >= 0; i-- { + if !shouldVisitNode(nodeList.Nodes[i]) { + continue + } + if isValidPrecedingNode(nodeList.Nodes[i], sourceFile) { + validIndex = i + rightmostValidNode = nodeList.Nodes[i] + break + } + } + for i := validIndex + 1; i < index; i++ { + if !shouldVisitNode(nodeList.Nodes[i]) { + continue + } + rightmostVisitedNodes = append(rightmostVisitedNodes, nodeList.Nodes[i]) + } + } + return nodeList + } + nodeVisitor := ast.NewNodeVisitor(core.Identity, nil, ast.NodeVisitorHooks{ + VisitNode: visitNode, + VisitToken: visitNode, + VisitNodes: visitNodes, + VisitModifiers: func(modifiers *ast.ModifierList, visitor *ast.NodeVisitor) *ast.ModifierList { + if modifiers != nil { + visitNodes(&modifiers.NodeList, visitor) + } + return modifiers + }, + }) + visitEachChildAndJSDoc(n, sourceFile, nodeVisitor) + + // Three cases: + // 1. The answer is a token of `rightmostValidNode`. + // 2. The answer is one of the unvisited tokens that occur after the rightmost valid node. + // 3. The current node is a childless, token-less node. The answer is the current node. + + // Case 2: Look at unvisited trailing tokens that occur in between the rightmost visited nodes. + if !ast.IsJSDocCommentContainingNode(n) { // JSDoc nodes don't include trivia tokens as children. + var startPos int + if rightmostValidNode != nil { + startPos = rightmostValidNode.End() + } else { + startPos = n.Pos() + } + scanner := scanner.GetScannerForSourceFile(sourceFile, startPos) + var tokens []*ast.Node + for _, visitedNode := range rightmostVisitedNodes { + // Trailing tokens that occur before this node. + for startPos < min(visitedNode.Pos(), position) { + tokenStart := scanner.TokenStart() + if tokenStart >= position { + break + } + token := scanner.Token() + tokenFullStart := scanner.TokenFullStart() + tokenEnd := scanner.TokenEnd() + startPos = tokenEnd + tokens = append(tokens, sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, n)) + scanner.Scan() + } + startPos = visitedNode.End() + scanner.ResetPos(startPos) + } + // Trailing tokens after last visited node. + for startPos < min(endPos, position) { + tokenStart := scanner.TokenStart() + if tokenStart >= position { + break + } + token := scanner.Token() + tokenFullStart := scanner.TokenFullStart() + tokenEnd := scanner.TokenEnd() + startPos = tokenEnd + tokens = append(tokens, sourceFile.GetOrCreateToken(token, tokenFullStart, tokenEnd, n)) + scanner.Scan() + } + + lastToken := len(tokens) - 1 + // Find preceding valid token. + for i := lastToken; i >= 0; i-- { + if !ast.IsWhitespaceOnlyJsxText(tokens[i]) { + return tokens[i] + } + } + } + + // Case 3: childless node. + if !hasChildren { + return n + } + // Case 1: recur on rightmostValidNode. + if rightmostValidNode != nil { + endPos = rightmostValidNode.End() + } + return find(rightmostValidNode, endPos) + } + + return find(containingNode, endPos) +} + +// !!! +func FindNextToken(previousToken *ast.Node, parent *ast.Node, file *ast.SourceFile) *ast.Node { + return nil +} diff --git a/internal/astnav/tokens_test.go b/internal/astnav/tokens_test.go index 76e1474ddb..7ccd674924 100644 --- a/internal/astnav/tokens_test.go +++ b/internal/astnav/tokens_test.go @@ -36,10 +36,11 @@ func TestGetTokenAtPosition(t *testing.T) { baselineTokens( t, "GetTokenAtPosition", - func(fileText string, positions []int) []tokenInfo { + false, /*includeEOF*/ + func(fileText string, positions []int) []*tokenInfo { return tsGetTokensAtPositions(t, fileText, positions) }, - func(file *ast.SourceFile, pos int) tokenInfo { + func(file *ast.SourceFile, pos int) *tokenInfo { return toTokenInfo(astnav.GetTokenAtPosition(file, pos)) }, ) @@ -65,23 +66,24 @@ func TestGetTouchingPropertyName(t *testing.T) { baselineTokens( t, "GetTouchingPropertyName", - func(fileText string, positions []int) []tokenInfo { + false, /*includeEOF*/ + func(fileText string, positions []int) []*tokenInfo { return tsGetTouchingPropertyName(t, fileText, positions) }, - func(file *ast.SourceFile, pos int) tokenInfo { + func(file *ast.SourceFile, pos int) *tokenInfo { return toTokenInfo(astnav.GetTouchingPropertyName(file, pos)) }, ) } -func baselineTokens(t *testing.T, testName string, getTSTokens func(fileText string, positions []int) []tokenInfo, getGoToken func(file *ast.SourceFile, pos int) tokenInfo) { +func baselineTokens(t *testing.T, testName string, includeEOF bool, getTSTokens func(fileText string, positions []int) []*tokenInfo, getGoToken func(file *ast.SourceFile, pos int) *tokenInfo) { for _, fileName := range testFiles { t.Run(filepath.Base(fileName), func(t *testing.T) { t.Parallel() fileText, err := os.ReadFile(fileName) assert.NilError(t, err) - positions := make([]int, len(fileText)) + positions := make([]int, len(fileText)+core.IfElse(includeEOF, 1, 0)) for i := range positions { positions[i] = i } @@ -96,9 +98,9 @@ func baselineTokens(t *testing.T, testName string, getTSTokens func(fileText str goToken := getGoToken(file, pos) diff := tokenDiff{goToken: goToken, tsToken: tsToken} - if currentDiff != diff { - if currentDiff.goToken != currentDiff.tsToken { - writeRangeDiff(&output, file, currentDiff, currentRange) + if !diffEqual(currentDiff, diff) { + if !tokensEqual(currentDiff.goToken, currentDiff.tsToken) { + writeRangeDiff(&output, file, currentDiff, currentRange, pos) } currentDiff = diff currentRange = core.NewTextRange(pos, pos) @@ -106,8 +108,8 @@ func baselineTokens(t *testing.T, testName string, getTSTokens func(fileText str currentRange = currentRange.WithEnd(pos) } - if currentDiff.goToken != currentDiff.tsToken { - writeRangeDiff(&output, file, currentDiff, currentRange) + if !tokensEqual(currentDiff.goToken, currentDiff.tsToken) { + writeRangeDiff(&output, file, currentDiff, currentRange, len(tsTokens)-1) } baseline.Run( @@ -123,8 +125,8 @@ func baselineTokens(t *testing.T, testName string, getTSTokens func(fileText str } type tokenDiff struct { - goToken tokenInfo - tsToken tokenInfo + goToken *tokenInfo + tsToken *tokenInfo } type tokenInfo struct { @@ -133,20 +135,34 @@ type tokenInfo struct { End int `json:"end"` } -func toTokenInfo(node *ast.Node) tokenInfo { +func toTokenInfo(node *ast.Node) *tokenInfo { + if node == nil { + return nil + } kind := strings.Replace(node.Kind.String(), "Kind", "", 1) switch kind { case "EndOfFile": kind = "EndOfFileToken" } - return tokenInfo{ + return &tokenInfo{ Kind: kind, Pos: node.Pos(), End: node.End(), } } -func tsGetTokensAtPositions(t testing.TB, fileText string, positions []int) []tokenInfo { +func diffEqual(a, b tokenDiff) bool { + return tokensEqual(a.goToken, b.goToken) && tokensEqual(a.tsToken, b.tsToken) +} + +func tokensEqual(t1, t2 *tokenInfo) bool { + if t1 == nil || t2 == nil { + return t1 == t2 + } + return *t1 == *t2 +} + +func tsGetTokensAtPositions(t testing.TB, fileText string, positions []int) []*tokenInfo { dir := t.TempDir() err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644) assert.NilError(t, err) @@ -178,12 +194,12 @@ func tsGetTokensAtPositions(t testing.TB, fileText string, positions []int) []to }); };` - info, err := jstest.EvalNodeScriptWithTS[[]tokenInfo](t, script, dir, "") + info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "") assert.NilError(t, err) return info } -func tsGetTouchingPropertyName(t testing.TB, fileText string, positions []int) []tokenInfo { +func tsGetTouchingPropertyName(t testing.TB, fileText string, positions []int) []*tokenInfo { dir := t.TempDir() err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644) assert.NilError(t, err) @@ -215,17 +231,31 @@ func tsGetTouchingPropertyName(t testing.TB, fileText string, positions []int) [ }); };` - info, err := jstest.EvalNodeScriptWithTS[[]tokenInfo](t, script, dir, "") + info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "") assert.NilError(t, err) return info } -func writeRangeDiff(output *strings.Builder, file *ast.SourceFile, diff tokenDiff, rng core.TextRange) { +func writeRangeDiff(output *strings.Builder, file *ast.SourceFile, diff tokenDiff, rng core.TextRange, position int) { lines := file.LineMap() - tsStartLine, _ := core.PositionToLineAndCharacter(diff.tsToken.Pos, lines) - tsEndLine, _ := core.PositionToLineAndCharacter(diff.tsToken.End, lines) - goStartLine, _ := core.PositionToLineAndCharacter(diff.goToken.Pos, lines) - goEndLine, _ := core.PositionToLineAndCharacter(diff.goToken.End, lines) + + tsTokenPos := position + goTokenPos := position + tsTokenEnd := position + goTokenEnd := position + if diff.tsToken != nil { + tsTokenPos = diff.tsToken.Pos + tsTokenEnd = diff.tsToken.End + } + if diff.goToken != nil { + goTokenPos = diff.goToken.Pos + goTokenEnd = diff.goToken.End + } + tsStartLine, _ := core.PositionToLineAndCharacter(tsTokenPos, lines) + tsEndLine, _ := core.PositionToLineAndCharacter(tsTokenEnd, lines) + goStartLine, _ := core.PositionToLineAndCharacter(goTokenPos, lines) + goEndLine, _ := core.PositionToLineAndCharacter(goTokenEnd, lines) + contextLines := 2 startLine := min(tsStartLine, goStartLine) endLine := max(tsEndLine, goEndLine) @@ -253,15 +283,23 @@ func writeRangeDiff(output *strings.Builder, file *ast.SourceFile, diff tokenDif } output.WriteString(fmt.Sprintf("ãPositions: [%d, %d]ã\n", rng.Pos(), rng.End())) - output.WriteString(fmt.Sprintf("ãTS: %s [%d, %d)ã\n", diff.tsToken.Kind, diff.tsToken.Pos, diff.tsToken.End)) - output.WriteString(fmt.Sprintf("ãGo: %s [%d, %d)ã\n", diff.goToken.Kind, diff.goToken.Pos, diff.goToken.End)) + if diff.tsToken != nil { + output.WriteString(fmt.Sprintf("ãTS: %s [%d, %d)ã\n", diff.tsToken.Kind, tsTokenPos, tsTokenEnd)) + } else { + output.WriteString("ãTS: nilã\n") + } + if diff.goToken != nil { + output.WriteString(fmt.Sprintf("ãGo: %s [%d, %d)ã\n", diff.goToken.Kind, goTokenPos, goTokenEnd)) + } else { + output.WriteString("ãGo: nilã\n") + } for line := contextStart; line <= contextEnd; line++ { if truncate, skipTo := shouldTruncate(line); truncate { output.WriteString(fmt.Sprintf("%s â........ %d lines omitted ........\n", strings.Repeat(" ", digits), skipTo-line+1)) line = skipTo } output.WriteString(fmt.Sprintf("%*d â", digits, line+1)) - end := len(file.Text) + 1 + end := len(file.Text()) + 1 if line < len(lines)-1 { end = int(lines[line+1]) } @@ -269,26 +307,162 @@ func writeRangeDiff(output *strings.Builder, file *ast.SourceFile, diff tokenDif if pos == rng.End()+1 { output.WriteString("ã") } - if pos == diff.tsToken.End { + if diff.tsToken != nil && pos == tsTokenEnd { output.WriteString("ã") } - if pos == diff.goToken.End { + if diff.goToken != nil && pos == goTokenEnd { output.WriteString("ã") } - if pos == diff.goToken.Pos { + if diff.goToken != nil && pos == goTokenPos { output.WriteString("ã") } - if pos == diff.tsToken.Pos { + if diff.tsToken != nil && pos == tsTokenPos { output.WriteString("ã") } if pos == rng.Pos() { output.WriteString("ã") } - if pos < len(file.Text) { - output.WriteByte(file.Text[pos]) + if pos < len(file.Text()) { + output.WriteByte(file.Text()[pos]) } } } } + +func TestFindPrecedingToken(t *testing.T) { + t.Parallel() + repo.SkipIfNoTypeScriptSubmodule(t) + jstest.SkipIfNoNodeJS(t) + + t.Run("baseline", func(t *testing.T) { + t.Parallel() + baselineTokens( + t, + "FindPrecedingToken", + true, /*includeEOF*/ + func(fileText string, positions []int) []*tokenInfo { + return tsFindPrecedingTokens(t, fileText, positions) + }, + func(file *ast.SourceFile, pos int) *tokenInfo { + return toTokenInfo(astnav.FindPrecedingToken(file, pos)) + }, + ) + }) +} + +func TestUnitFindPrecedingToken(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + fileContent string + position int + expectedKind ast.Kind + }{ + { + name: "after dot in jsdoc", + fileContent: `import { + CharacterCodes, + compareStringsCaseInsensitive, + compareStringsCaseSensitive, + compareValues, + Comparison, + Debug, + endsWith, + equateStringsCaseInsensitive, + equateStringsCaseSensitive, + GetCanonicalFileName, + getDeclarationFileExtension, + getStringComparer, + identity, + lastOrUndefined, + Path, + some, + startsWith, +} from "./_namespaces/ts.js"; + +/** + * Internally, we represent paths as strings with '/' as the directory separator. + * When we make system calls (eg: LanguageServiceHost.getDirectory()), + * we expect the host to correctly handle paths in our specified format. + * + * @internal + */ +export const directorySeparator = "/"; +/** @internal */ +export const altDirectorySeparator = "\\"; +const urlSchemeSeparator = "://"; +const backslashRegExp = /\\/g; + + +backslashRegExp. + +//Path Tests + +/** + * Determines whether a charCode corresponds to '/' or '\'. + * + * @internal + */ +export function isAnyDirectorySeparator(charCode: number): boolean { + return charCode === CharacterCodes.slash || charCode === CharacterCodes.backslash; +}`, + position: 839, + expectedKind: ast.KindDotToken, + }, + { + name: "after comma in parameter list", + fileContent: `takesCb((n, s, ))`, + position: 15, + expectedKind: ast.KindCommaToken, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile("/file.ts", "/file.ts", testCase.fileContent, core.ScriptTargetLatest, scanner.JSDocParsingModeParseAll) + token := astnav.FindPrecedingToken(file, testCase.position) + assert.Equal(t, token.Kind, testCase.expectedKind) + }) + } +} + +func tsFindPrecedingTokens(t *testing.T, fileText string, positions []int) []*tokenInfo { + dir := t.TempDir() + err := os.WriteFile(filepath.Join(dir, "file.ts"), []byte(fileText), 0o644) + assert.NilError(t, err) + + err = os.WriteFile(filepath.Join(dir, "positions.json"), []byte(core.Must(core.StringifyJson(positions, "", ""))), 0o644) + assert.NilError(t, err) + + script := ` + import fs from "fs"; + export default (ts) => { + const positions = JSON.parse(fs.readFileSync("positions.json", "utf8")); + const fileText = fs.readFileSync("file.ts", "utf8"); + const file = ts.createSourceFile( + "file.ts", + fileText, + { languageVersion: ts.ScriptTarget.Latest, jsDocParsingMode: ts.JSDocParsingMode.ParseAll }, + /*setParentNodes*/ true + ); + return positions.map(position => { + let token = ts.findPrecedingToken(position, file); + if (token === undefined) { + return undefined; + } + if (token.kind === ts.SyntaxKind.SyntaxList) { + token = token.parent; + } + return { + kind: ts.Debug.formatSyntaxKind(token.kind), + pos: token.pos, + end: token.end, + }; + }); + };` + info, err := jstest.EvalNodeScriptWithTS[[]*tokenInfo](t, script, dir, "") + assert.NilError(t, err) + return info +} diff --git a/internal/binder/binder.go b/internal/binder/binder.go index 57133eb2a2..ca96bc4c37 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -6,9 +6,10 @@ import ( "sync" "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/scanner" + "github.com/microsoft/typescript-go/internal/tspath" ) type ContainerFlags int32 @@ -39,7 +40,7 @@ const ( type Binder struct { file *ast.SourceFile - options *core.CompilerOptions + options *core.SourceFileAffectingCompilerOptions languageVersion core.ScriptTarget bindFunc func(*ast.Node) bool unreachableFlow *ast.FlowNode @@ -65,6 +66,7 @@ type Binder struct { hasFlowEffects bool inStrictMode bool inAssignmentPattern bool + seenParseError bool symbolCount int classifiableNames core.Set[string] symbolPool core.Pool[ast.Symbol] @@ -84,7 +86,7 @@ type ActiveLabel struct { func (label *ActiveLabel) BreakTarget() *ast.FlowNode { return label.breakTarget } func (label *ActiveLabel) ContinueTarget() *ast.FlowNode { return label.continueTarget } -func BindSourceFile(file *ast.SourceFile, options *core.CompilerOptions) { +func BindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) { // This is constructed this way to make the compiler "out-line" the function, // avoiding most work in the common case where the file has already been bound. if !file.IsBound() { @@ -109,13 +111,14 @@ func putBinder(b *Binder) { binderPool.Put(b) } -func bindSourceFile(file *ast.SourceFile, options *core.CompilerOptions) { +func bindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) { file.BindOnce(func() { b := getBinder() defer putBinder(b) b.file = file b.options = options - b.languageVersion = options.GetEmitScriptTarget() + b.languageVersion = options.EmitScriptTarget + b.inStrictMode = options.BindInStrictMode && !file.IsDeclarationFile || ast.IsExternalModule(file) b.unreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable) b.reportedUnreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable) b.bind(file.AsNode()) @@ -277,6 +280,13 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol } } b.addDiagnostic(diag) + // When get or set accessor conflicts with a non-accessor or an accessor of a different kind, we mark + // the symbol as a full accessor such that all subsequent declarations are considered conflicting. This + // for example ensures that a get accessor followed by a non-accessor followed by a set accessor with the + // same name are all marked as duplicates. + if symbol.Flags&ast.SymbolFlagsAccessor != 0 && symbol.Flags&ast.SymbolFlagsAccessor != includes&ast.SymbolFlagsAccessor { + symbol.Flags |= ast.SymbolFlagsAccessor + } symbol = b.newSymbol(ast.SymbolFlagsNone, name) } } @@ -295,6 +305,8 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol func (b *Binder) getDeclarationName(node *ast.Node) string { if ast.IsExportAssignment(node) { return core.IfElse(node.AsExportAssignment().IsExportEquals, ast.InternalSymbolNameExportEquals, ast.InternalSymbolNameDefault) + } else if ast.IsJSExportAssignment(node) { + return ast.InternalSymbolNameExportEquals } name := ast.GetNameOfDeclaration(node) if name != nil { @@ -314,7 +326,7 @@ func (b *Binder) getDeclarationName(node *ast.Node) string { } return GetSymbolNameForPrivateIdentifier(containingClass.Symbol(), name.Text()) } - if ast.IsPropertyNameLiteral(name) { + if ast.IsPropertyNameLiteral(name) || ast.IsJsxNamespacedName(name) { return name.Text() } if ast.IsComputedPropertyName(name) { @@ -329,9 +341,6 @@ func (b *Binder) getDeclarationName(node *ast.Node) string { } panic("Only computed properties with literal names have declaration names") } - // if isJsxNamespacedName(name) { - // return getEscapedTextOfJsxNamespacedName(name) - // } return ast.InternalSymbolNameMissing } switch node.Kind { @@ -368,12 +377,16 @@ func GetSymbolNameForPrivateIdentifier(containingClassSymbol *ast.Symbol, descri } func (b *Binder) declareModuleMember(node *ast.Node, symbolFlags ast.SymbolFlags, symbolExcludes ast.SymbolFlags) *ast.Symbol { + container := b.container + if node.Kind == ast.KindCommonJSExport { + container = b.file.AsNode() + } hasExportModifier := ast.GetCombinedModifierFlags(node)&ast.ModifierFlagsExport != 0 if symbolFlags&ast.SymbolFlagsAlias != 0 { if node.Kind == ast.KindExportSpecifier || (node.Kind == ast.KindImportEqualsDeclaration && hasExportModifier) { - return b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes) + return b.declareSymbol(ast.GetExports(container.Symbol()), container.Symbol(), node, symbolFlags, symbolExcludes) } - return b.declareSymbol(ast.GetLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes) + return b.declareSymbol(ast.GetLocals(container), nil /*parent*/, node, symbolFlags, symbolExcludes) } // Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag, // and an associated export symbol with all the correct flags set on it. There are 2 main reasons: @@ -390,21 +403,21 @@ func (b *Binder) declareModuleMember(node *ast.Node, symbolFlags ast.SymbolFlags // during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation // and this case is specially handled. Module augmentations should only be merged with original module definition // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed. - if !ast.IsAmbientModule(node) && (hasExportModifier || b.container.Flags&ast.NodeFlagsExportContext != 0) { - if !ast.IsLocalsContainer(b.container) || (ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault) && b.getDeclarationName(node) == ast.InternalSymbolNameMissing) { - return b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes) + if !ast.IsAmbientModule(node) && (hasExportModifier || container.Flags&ast.NodeFlagsExportContext != 0) { + if !ast.IsLocalsContainer(container) || (ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault) && b.getDeclarationName(node) == ast.InternalSymbolNameMissing) || ast.IsCommonJSExport(node) { + return b.declareSymbol(ast.GetExports(container.Symbol()), container.Symbol(), node, symbolFlags, symbolExcludes) // No local symbol for an unnamed default! } exportKind := ast.SymbolFlagsNone if symbolFlags&ast.SymbolFlagsValue != 0 { exportKind = ast.SymbolFlagsExportValue } - local := b.declareSymbol(ast.GetLocals(b.container), nil /*parent*/, node, exportKind, symbolExcludes) - local.ExportSymbol = b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes) + local := b.declareSymbol(ast.GetLocals(container), nil /*parent*/, node, exportKind, symbolExcludes) + local.ExportSymbol = b.declareSymbol(ast.GetExports(container.Symbol()), container.Symbol(), node, symbolFlags, symbolExcludes) node.ExportableData().LocalSymbol = local return local } - return b.declareSymbol(ast.GetLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes) + return b.declareSymbol(ast.GetLocals(container), nil /*parent*/, node, symbolFlags, symbolExcludes) } func (b *Binder) declareClassMember(node *ast.Node, symbolFlags ast.SymbolFlags, symbolExcludes ast.SymbolFlags) *ast.Symbol { @@ -415,7 +428,7 @@ func (b *Binder) declareClassMember(node *ast.Node, symbolFlags ast.SymbolFlags, } func (b *Binder) declareSourceFileMember(node *ast.Node, symbolFlags ast.SymbolFlags, symbolExcludes ast.SymbolFlags) *ast.Symbol { - if ast.IsExternalModule(b.file) { + if ast.IsExternalOrCommonJSModule(b.file) { return b.declareModuleMember(node, symbolFlags, symbolExcludes) } return b.declareSymbol(ast.GetLocals(b.file.AsNode()), nil /*parent*/, node, symbolFlags, symbolExcludes) @@ -436,7 +449,7 @@ func (b *Binder) declareSymbolAndAddToSymbolTable(node *ast.Node, symbolFlags as case ast.KindFunctionType, ast.KindConstructorType, ast.KindCallSignature, ast.KindConstructSignature, ast.KindJSDocSignature, ast.KindIndexSignature, ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindConstructor, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, - ast.KindClassStaticBlockDeclaration, ast.KindTypeAliasDeclaration, ast.KindMappedType: + ast.KindClassStaticBlockDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType: return b.declareSymbol(ast.GetLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes) } panic("Unhandled case in declareSymbolAndAddToSymbolTable") @@ -636,6 +649,8 @@ func (b *Binder) bind(node *ast.Node) bool { case ast.KindBindingElement: node.AsBindingElement().FlowNode = b.currentFlow b.bindVariableDeclarationOrBindingElement(node) + case ast.KindCommonJSExport: + b.declareModuleMember(node, ast.SymbolFlagsFunctionScopedVariable, ast.SymbolFlagsFunctionScopedVariableExcludes) case ast.KindPropertyDeclaration, ast.KindPropertySignature: b.bindPropertyWorker(node) case ast.KindPropertyAssignment, ast.KindShorthandPropertyAssignment: @@ -669,7 +684,9 @@ func (b *Binder) bind(node *ast.Node) bool { b.bindClassLikeDeclaration(node) case ast.KindInterfaceDeclaration: b.bindBlockScopedDeclaration(node, ast.SymbolFlagsInterface, ast.SymbolFlagsInterfaceExcludes) - case ast.KindTypeAliasDeclaration: + case ast.KindCallExpression: + b.bindCallExpression(node) + case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration: b.bindBlockScopedDeclaration(node, ast.SymbolFlagsTypeAlias, ast.SymbolFlagsTypeAliasExcludes) case ast.KindEnumDeclaration: b.bindEnumDeclaration(node) @@ -683,7 +700,7 @@ func (b *Binder) bind(node *ast.Node) bool { b.bindImportClause(node) case ast.KindExportDeclaration: b.bindExportDeclaration(node) - case ast.KindExportAssignment: + case ast.KindExportAssignment, ast.KindJSExportAssignment: b.bindExportAssignment(node) case ast.KindSourceFile: b.updateStrictModeStatementList(node.AsSourceFile().Statements) @@ -704,31 +721,40 @@ func (b *Binder) bind(node *ast.Node) bool { // the current 'container' node when it changes. This helps us know which symbol table // a local should go into for example. Since terminal nodes are known not to have // children, as an optimization we don't process those. + thisNodeOrAnySubnodesHasError := node.Flags&ast.NodeFlagsThisNodeHasError != 0 if node.Kind > ast.KindLastToken { saveParent := b.parent + saveSeenParseError := b.seenParseError b.parent = node + b.seenParseError = false containerFlags := GetContainerFlags(node) if containerFlags == ContainerFlagsNone { b.bindChildren(node) } else { b.bindContainer(node, containerFlags) } + if b.seenParseError { + thisNodeOrAnySubnodesHasError = true + } b.parent = saveParent + b.seenParseError = saveSeenParseError } else { saveParent := b.parent if node.Kind == ast.KindEndOfFile { b.parent = node } - b.bindJSDoc(node) + b.setJSDocParents(node) b.parent = saveParent } + if thisNodeOrAnySubnodesHasError { + node.Flags |= ast.NodeFlagsThisNodeOrAnySubNodesHasError + b.seenParseError = true + } b.inStrictMode = saveInStrictMode return false } -func (b *Binder) bindJSDoc(node *ast.Node) { - // !!! if isInJSFile(node) { - // !!! else { +func (b *Binder) setJSDocParents(node *ast.Node) { for _, jsdoc := range node.JSDoc(b.file) { setParent(jsdoc, node) ast.SetParentInChildren(jsdoc) @@ -744,7 +770,7 @@ func (b *Binder) bindPropertyWorker(node *ast.Node) { func (b *Binder) bindSourceFileIfExternalModule() { b.setExportContextFlag(b.file.AsNode()) - if ast.IsExternalModule(b.file) { + if ast.IsExternalOrCommonJSModule(b.file) { b.bindSourceFileAsExternalModule() } else if ast.IsJsonSourceFile(b.file) { b.bindSourceFileAsExternalModule() @@ -756,8 +782,7 @@ func (b *Binder) bindSourceFileIfExternalModule() { } func (b *Binder) bindSourceFileAsExternalModule() { - // !!! Remove file extension from module name - b.bindAnonymousDeclaration(b.file.AsNode(), ast.SymbolFlagsValueModule, "\""+b.file.FileName()+"\"") + b.bindAnonymousDeclaration(b.file.AsNode(), ast.SymbolFlagsValueModule, "\""+tspath.RemoveFileExtension(b.file.FileName())+"\"") } func (b *Binder) bindModuleDeclaration(node *ast.Node) { @@ -778,7 +803,9 @@ func (b *Binder) bindModuleDeclaration(node *ast.Node) { } } symbol := b.declareSymbolAndAddToSymbolTable(node, ast.SymbolFlagsValueModule, ast.SymbolFlagsValueModuleExcludes) - b.file.PatternAmbientModules = append(b.file.PatternAmbientModules, ast.PatternAmbientModule{Pattern: pattern, Symbol: symbol}) + if pattern.StarIndex >= 0 { + b.file.PatternAmbientModules = append(b.file.PatternAmbientModules, &ast.PatternAmbientModule{Pattern: pattern, Symbol: symbol}) + } } } else { state := b.declareModuleSymbol(node) @@ -838,7 +865,11 @@ func (b *Binder) bindExportDeclaration(node *ast.Node) { } func (b *Binder) bindExportAssignment(node *ast.Node) { - if b.container.Symbol() == nil { + container := b.container + if ast.IsJSExportAssignment(node) { + container = b.file.AsNode() + } + if container.Symbol() == nil && ast.IsExportAssignment(node) { // Incorrect export assignment in some sort of block construct b.bindAnonymousDeclaration(node, ast.SymbolFlagsValue, b.getDeclarationName(node)) } else { @@ -848,8 +879,8 @@ func (b *Binder) bindExportAssignment(node *ast.Node) { } // If there is an `export default x;` alias declaration, can't `export default` anything else. // (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.) - symbol := b.declareSymbol(ast.GetExports(b.container.Symbol()), b.container.Symbol(), node, flags, ast.SymbolFlagsAll) - if node.AsExportAssignment().IsExportEquals { + symbol := b.declareSymbol(ast.GetExports(container.Symbol()), container.Symbol(), node, flags, ast.SymbolFlagsAll) + if ast.IsJSExportAssignment(node) || node.AsExportAssignment().IsExportEquals { // Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set. SetValueDeclaration(symbol, node) } @@ -886,14 +917,11 @@ func (b *Binder) hasExportDeclarations(node *ast.Node) bool { } } return core.Some(statements, func(s *ast.Node) bool { - return ast.IsExportDeclaration(s) || ast.IsExportAssignment(s) + return ast.IsExportDeclaration(s) || ast.IsExportAssignment(s) || ast.IsJSExportAssignment(s) }) } func (b *Binder) bindFunctionExpression(node *ast.Node) { - if !b.file.IsDeclarationFile && node.Flags&ast.NodeFlagsAmbient == 0 && isAsyncFunction(node) { - b.emitFlags |= ast.NodeFlagsHasAsyncFunctions - } setFlowNode(node, b.currentFlow) bindingName := ast.InternalSymbolNameFunction if ast.IsFunctionExpression(node) && node.AsFunctionExpression().Name() != nil { @@ -903,6 +931,19 @@ func (b *Binder) bindFunctionExpression(node *ast.Node) { b.bindAnonymousDeclaration(node, ast.SymbolFlagsFunction, bindingName) } +func (b *Binder) bindCallExpression(node *ast.Node) { + // !!! for ModuleDetectionKind.Force, external module indicator is forced to `true` in Strada for source files, in which case + // we should set the commonjs module indicator but not call b.bindSourceFileAsExternalModule + // !!! && file.externalModuleIndicator !== true (used for ModuleDetectionKind.Force) + if ast.IsInJSFile(node) && + b.file.ExternalModuleIndicator == nil && + b.file.CommonJSModuleIndicator == nil && + ast.IsVariableDeclarationInitializedToRequire(node.Parent) { + b.file.CommonJSModuleIndicator = node + b.bindSourceFileAsExternalModule() + } +} + func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { name := node.Name() switch node.Kind { @@ -937,9 +978,6 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { } func (b *Binder) bindPropertyOrMethodOrAccessor(node *ast.Node, symbolFlags ast.SymbolFlags, symbolExcludes ast.SymbolFlags) { - if !b.file.IsDeclarationFile && node.Flags&ast.NodeFlagsAmbient == 0 && isAsyncFunction(node) { - b.emitFlags |= ast.NodeFlagsHasAsyncFunctions - } if b.currentFlow != nil && ast.IsObjectLiteralOrClassExpressionMethodOrAccessor(node) { setFlowNode(node, b.currentFlow) } @@ -1018,6 +1056,8 @@ func (b *Binder) bindVariableDeclarationOrBindingElement(node *ast.Node) { } if name := node.Name(); name != nil && !ast.IsBindingPattern(name) { switch { + case ast.IsVariableDeclarationInitializedToRequire(node): + b.declareSymbolAndAddToSymbolTable(node, ast.SymbolFlagsAlias, ast.SymbolFlagsAliasExcludes) case ast.IsBlockOrCatchScoped(node): b.bindBlockScopedDeclaration(node, ast.SymbolFlagsBlockScopedVariable, ast.SymbolFlagsBlockScopedVariableExcludes) case ast.IsPartOfParameterDeclaration(node): @@ -1043,7 +1083,7 @@ func (b *Binder) bindParameter(node *ast.Node) { // return // } decl := node.AsParameterDeclaration() - if b.inStrictMode && node.Flags&ast.NodeFlagsAmbient == 9 { + if b.inStrictMode && node.Flags&ast.NodeFlagsAmbient == 0 { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) b.checkStrictModeEvalOrArguments(node, decl.Name()) @@ -1064,9 +1104,6 @@ func (b *Binder) bindParameter(node *ast.Node) { } func (b *Binder) bindFunctionDeclaration(node *ast.Node) { - if !b.file.IsDeclarationFile && node.Flags&ast.NodeFlagsAmbient == 0 && isAsyncFunction(node) { - b.emitFlags |= ast.NodeFlagsHasAsyncFunctions - } b.checkStrictModeFunctionName(node) if b.inStrictMode { b.checkStrictModeFunctionDeclaration(node) @@ -1100,7 +1137,7 @@ func (b *Binder) bindBlockScopedDeclaration(node *ast.Node, symbolFlags ast.Symb case ast.KindModuleDeclaration: b.declareModuleMember(node, symbolFlags, symbolExcludes) case ast.KindSourceFile: - if ast.IsExternalOrCommonJsModule(b.container.AsSourceFile()) { + if ast.IsExternalOrCommonJSModule(b.container.AsSourceFile()) { b.declareModuleMember(node, symbolFlags, symbolExcludes) break } @@ -1143,7 +1180,7 @@ func (b *Binder) lookupName(name string, container *ast.Node) *ast.Symbol { } } if ast.IsSourceFile(container) { - local := container.AsSourceFile().JsGlobalAugmentations[name] + local := container.AsSourceFile().JSGlobalAugmentations[name] if local != nil { return local } @@ -1318,7 +1355,7 @@ func (b *Binder) checkStrictModeWithStatement(node *ast.Node) { func (b *Binder) checkStrictModeLabeledStatement(node *ast.Node) { // Grammar checking for labeledStatement - if b.inStrictMode && b.options.Target >= core.ScriptTargetES2015 { + if b.inStrictMode && b.options.EmitScriptTarget >= core.ScriptTargetES2015 { data := node.AsLabeledStatement() if ast.IsDeclarationStatement(data.Statement) || ast.IsVariableStatement(data.Statement) { b.errorOnFirstToken(data.Label, diagnostics.A_label_is_not_allowed_here) @@ -1430,7 +1467,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { b.hasExplicitReturn = false b.bindChildren(node) // Reset all reachability check related flags on node (for incremental scenarios) - node.Flags &= ^ast.NodeFlagsReachabilityAndEmitFlags + node.Flags &= ^ast.NodeFlagsReachabilityCheckFlags if b.currentFlow.Flags&ast.FlowFlagsUnreachable == 0 && containerFlags&ContainerFlagsIsFunctionLike != 0 { bodyData := node.BodyData() if bodyData != nil && ast.NodeIsPresent(bodyData.Body) { @@ -1486,7 +1523,7 @@ func (b *Binder) bindChildren(node *ast.Node) { b.inAssignmentPattern = false if b.checkUnreachable(node) { b.bindEachChild(node) - b.bindJSDoc(node) + b.setJSDocParents(node) b.inAssignmentPattern = saveInAssignmentPattern return } @@ -1571,10 +1608,12 @@ func (b *Binder) bindChildren(node *ast.Node) { case ast.KindObjectLiteralExpression, ast.KindArrayLiteralExpression, ast.KindPropertyAssignment, ast.KindSpreadElement: b.inAssignmentPattern = saveInAssignmentPattern b.bindEachChild(node) + case ast.KindJSExportAssignment, ast.KindCommonJSExport: + return // Reparsed nodes do not double-bind children, which are not reparsed default: b.bindEachChild(node) } - b.bindJSDoc(node) + b.setJSDocParents(node) b.inAssignmentPattern = saveInAssignmentPattern } @@ -1652,7 +1691,7 @@ func (b *Binder) checkUnreachable(node *ast.Node) bool { func (b *Binder) shouldReportErrorOnModuleDeclaration(node *ast.Node) bool { instanceState := ast.GetModuleInstanceState(node) - return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options.ShouldPreserveConstEnums()) + return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options.ShouldPreserveConstEnums) } func (b *Binder) errorOnEachUnreachableRange(node *ast.Node, isError bool) { @@ -1690,7 +1729,7 @@ func (b *Binder) isExecutableStatement(s *ast.Node) bool { func (b *Binder) isPurelyTypeDeclaration(s *ast.Node) bool { switch s.Kind { - case ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration: + case ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration: return true case ast.KindModuleDeclaration: return ast.GetModuleInstanceState(s) != ast.ModuleInstanceStateInstantiated @@ -1979,7 +2018,7 @@ func (b *Binder) bindTryStatement(node *ast.Node) { b.addAntecedent(b.currentReturnTarget, b.createReduceLabel(finallyLabel, returnLabel.Antecedents, b.currentFlow)) } // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a - // control flow that goes back through the finally blok and back through each possible exception source. + // control flow that goes back through the finally block and back through each possible exception source. if b.currentExceptionTarget != nil && exceptionLabel.Antecedents != nil { b.addAntecedent(b.currentExceptionTarget, b.createReduceLabel(finallyLabel, exceptionLabel.Antecedents, b.currentFlow)) } @@ -2408,8 +2447,8 @@ func (b *Binder) bindInitializer(node *ast.Node) { b.currentFlow = b.finishFlowLabel(exitFlow) } -func isEnumDeclarationWithPreservedEmit(node *ast.Node, options *core.CompilerOptions) bool { - return node.Kind == ast.KindEnumDeclaration && (!ast.IsEnumConst(node) || options.ShouldPreserveConstEnums()) +func isEnumDeclarationWithPreservedEmit(node *ast.Node, options *core.SourceFileAffectingCompilerOptions) bool { + return node.Kind == ast.KindEnumDeclaration && (!ast.IsEnumConst(node) || options.ShouldPreserveConstEnums) } func setFlowNode(node *ast.Node, flowNode *ast.FlowNode) { @@ -2487,7 +2526,7 @@ func GetContainerFlags(node *ast.Node) ContainerFlags { return ContainerFlagsIsContainer case ast.KindInterfaceDeclaration: return ContainerFlagsIsContainer | ContainerFlagsIsInterface - case ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration, ast.KindMappedType, ast.KindIndexSignature: + case ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, ast.KindIndexSignature: return ContainerFlagsIsContainer | ContainerFlagsHasLocals case ast.KindSourceFile: return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals @@ -2733,11 +2772,11 @@ func isFunctionSymbol(symbol *ast.Symbol) bool { return false } -func unreachableCodeIsError(options *core.CompilerOptions) bool { +func unreachableCodeIsError(options *core.SourceFileAffectingCompilerOptions) bool { return options.AllowUnreachableCode == core.TSFalse } -func unusedLabelIsError(options *core.CompilerOptions) bool { +func unusedLabelIsError(options *core.SourceFileAffectingCompilerOptions) bool { return options.AllowUnusedLabels == core.TSFalse } @@ -2773,7 +2812,7 @@ func isEffectiveModuleDeclaration(node *ast.Node) bool { } func getErrorRangeForArrowFunction(sourceFile *ast.SourceFile, node *ast.Node) core.TextRange { - pos := scanner.SkipTrivia(sourceFile.Text, node.Pos()) + pos := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) body := node.AsArrowFunction().Body if body != nil && body.Kind == ast.KindBlock { startLine, _ := scanner.GetLineAndCharacterOfPosition(sourceFile, body.Pos()) @@ -2791,21 +2830,21 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR errorNode := node switch node.Kind { case ast.KindSourceFile: - pos := scanner.SkipTrivia(sourceFile.Text, 0) - if pos == len(sourceFile.Text) { + pos := scanner.SkipTrivia(sourceFile.Text(), 0) + if pos == len(sourceFile.Text()) { return core.NewTextRange(0, 0) } return scanner.GetRangeOfTokenAtPosition(sourceFile, pos) // This list is a work in progress. Add missing node kinds to improve their error spans case ast.KindVariableDeclaration, ast.KindBindingElement, ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration, ast.KindModuleDeclaration, ast.KindEnumDeclaration, ast.KindEnumMember, ast.KindFunctionDeclaration, ast.KindFunctionExpression, - ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindTypeAliasDeclaration, ast.KindPropertyDeclaration, + ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindNamespaceImport: errorNode = ast.GetNameOfDeclaration(node) case ast.KindArrowFunction: return getErrorRangeForArrowFunction(sourceFile, node) case ast.KindCaseClause, ast.KindDefaultClause: - start := scanner.SkipTrivia(sourceFile.Text, node.Pos()) + start := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) end := node.End() statements := node.AsCaseOrDefaultClause().Statements.Nodes if len(statements) != 0 { @@ -2813,10 +2852,10 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR } return core.NewTextRange(start, end) case ast.KindReturnStatement, ast.KindYieldExpression: - pos := scanner.SkipTrivia(sourceFile.Text, node.Pos()) + pos := scanner.SkipTrivia(sourceFile.Text(), node.Pos()) return scanner.GetRangeOfTokenAtPosition(sourceFile, pos) case ast.KindSatisfiesExpression: - pos := scanner.SkipTrivia(sourceFile.Text, node.AsSatisfiesExpression().Expression.End()) + pos := scanner.SkipTrivia(sourceFile.Text(), node.AsSatisfiesExpression().Expression.End()) return scanner.GetRangeOfTokenAtPosition(sourceFile, pos) case ast.KindConstructor: scanner := scanner.GetScannerForSourceFile(sourceFile, node.Pos()) @@ -2827,7 +2866,7 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR return core.NewTextRange(start, scanner.TokenEnd()) // !!! // case KindJSDocSatisfiesTag: - // pos := scanner.SkipTrivia(sourceFile.text, node.tagName.pos) + // pos := scanner.SkipTrivia(sourceFile.Text(), node.tagName.pos) // return scanner.GetRangeOfTokenAtPosition(sourceFile, pos) } if errorNode == nil { @@ -2836,8 +2875,8 @@ func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextR return scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) } pos := errorNode.Pos() - if !ast.NodeIsMissing(errorNode) { - pos = scanner.SkipTrivia(sourceFile.Text, pos) + if !ast.NodeIsMissing(errorNode) && !ast.IsJsxText(errorNode) { + pos = scanner.SkipTrivia(sourceFile.Text(), pos) } return core.NewTextRange(pos, errorNode.End()) } diff --git a/internal/binder/binder_test.go b/internal/binder/binder_test.go index c78be8e1dd..4dea2edfeb 100644 --- a/internal/binder/binder_test.go +++ b/internal/binder/binder_test.go @@ -28,15 +28,16 @@ func BenchmarkBind(b *testing.B) { } compilerOptions := &core.CompilerOptions{Target: core.ScriptTargetESNext, ModuleKind: core.ModuleKindNodeNext} + sourceAffecting := compilerOptions.SourceFileAffecting() - // The above parses do a lot of work; ensure GC is finished before we start collecting pefrormance data. + // The above parses do a lot of work; ensure GC is finished before we start collecting performance data. // GC must be called twice to allow things to settle. runtime.GC() runtime.GC() b.ResetTimer() for i := range b.N { - BindSourceFile(sourceFiles[i], compilerOptions) + BindSourceFile(sourceFiles[i], sourceAffecting) } }) } diff --git a/internal/binder/nameresolver.go b/internal/binder/nameresolver.go index 6a04053de7..ca8b26f28d 100644 --- a/internal/binder/nameresolver.go +++ b/internal/binder/nameresolver.go @@ -2,8 +2,8 @@ package binder import ( "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" ) type NameResolver struct { @@ -12,6 +12,8 @@ type NameResolver struct { Error func(location *ast.Node, message *diagnostics.Message, args ...any) *ast.Diagnostic Globals ast.SymbolTable ArgumentsSymbol *ast.Symbol + RequireSymbol *ast.Symbol + GetModuleSymbol func(sourceFile *ast.Node) *ast.Symbol Lookup func(symbols ast.SymbolTable, name string, meaning ast.SymbolFlags) *ast.Symbol SymbolReferenced func(symbol *ast.Symbol, meaning ast.SymbolFlags) SetRequiresScopeChangeCache func(node *ast.Node, value core.Tristate) @@ -55,12 +57,8 @@ loop: // - 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&ast.SymbolFlagsType != 0 && lastLocation.Kind != ast.KindJSDoc { - useResult = result.Flags&ast.SymbolFlagsTypeParameter != 0 && (lastLocation.Flags&ast.NodeFlagsSynthesized != 0 || - lastLocation == location.Type() || - ast.IsParameterLikeOrReturnTag(lastLocation)) + if meaning&result.Flags&ast.SymbolFlagsType != 0 { + useResult = result.Flags&ast.SymbolFlagsTypeParameter != 0 && (lastLocation == location.Type() || ast.IsParameterLike(lastLocation)) } if meaning&result.Flags&ast.SymbolFlagsVariable != 0 { // expression inside parameter will lookup as normal variable scope when targeting es2015+ @@ -90,7 +88,7 @@ loop: withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation) switch location.Kind { case ast.KindSourceFile: - if !ast.IsExternalOrCommonJsModule(location.AsSourceFile()) { + if !ast.IsExternalOrCommonJSModule(location.AsSourceFile()) { break } fallthrough @@ -290,19 +288,11 @@ loop: if isSelfReferenceLocation(location, lastLocation) { lastSelfReferenceLocation = location } - lastLocation = location - switch { - // case isJSDocTemplateTag(location): - // location = getEffectiveContainerForJSDocTemplateTag(location.(*JSDocTemplateTag)) - // if location == nil { - // location = location.parent - // } - // case isJSDocParameterTag(location) || isJSDocReturnTag(location): - // location = getHostSignatureFromJSDoc(location) - // if location == nil { - // location = location.parent - // } - default: + if location.Kind == ast.KindJSDocTypeExpression && location.AsJSDocTypeExpression().Host != nil { + lastLocation = location.AsJSDocTypeExpression().Host.Type() + location = location.AsJSDocTypeExpression().Host + } else { + lastLocation = location location = location.Parent } } @@ -315,10 +305,33 @@ loop: } } if result == nil { + if lastLocation != nil && + lastLocation.Kind == ast.KindSourceFile && + lastLocation.AsSourceFile().CommonJSModuleIndicator != nil && + name == "exports" && + meaning&lastLocation.Symbol().Flags != 0 { + return lastLocation.Symbol() + } + if lastLocation != nil && + r.GetModuleSymbol != nil && + lastLocation.Kind == ast.KindSourceFile && + lastLocation.AsSourceFile().CommonJSModuleIndicator != nil && + name == "module" && + originalLocation.Parent != nil && + ast.IsModuleExportsAccessExpression(originalLocation.Parent) && + meaning&lastLocation.Symbol().Flags != 0 { + return r.GetModuleSymbol(lastLocation) + } if !excludeGlobals { result = r.lookup(r.Globals, name, meaning|ast.SymbolFlagsGlobalLookup) } } + if result == nil { + if originalLocation != nil && originalLocation.Parent != nil && originalLocation.Parent.Parent != nil && + ast.IsVariableDeclarationInitializedToRequire(originalLocation.Parent.Parent) { + return r.RequireSymbol + } + } if nameNotFoundMessage != nil { if propertyWithInvalidInitializer != nil && r.OnPropertyWithInvalidInitializer != nil && r.OnPropertyWithInvalidInitializer(originalLocation, name, propertyWithInvalidInitializer, result) { return nil @@ -358,7 +371,7 @@ func (r *NameResolver) useOuterVariableScopeInParameter(result *ast.Symbol, loca r.SetRequiresScopeChangeCache(functionLocation, declarationRequiresScopeChange) } } - return declarationRequiresScopeChange == core.TSTrue + return declarationRequiresScopeChange != core.TSTrue } } } @@ -489,9 +502,9 @@ func isTypeParameterSymbolDeclaredInContainer(symbol *ast.Symbol, container *ast func isSelfReferenceLocation(node *ast.Node, lastLocation *ast.Node) bool { switch node.Kind { case ast.KindParameter: - return lastLocation != nil && lastLocation == node.AsParameterDeclaration().Name() + return lastLocation != nil && lastLocation == node.Name() case ast.KindFunctionDeclaration, ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindEnumDeclaration, - ast.KindTypeAliasDeclaration, ast.KindModuleDeclaration: // For `namespace N { N; }` + ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindModuleDeclaration: // For `namespace N { N; }` return true } return false diff --git a/internal/binder/referenceresolver.go b/internal/binder/referenceresolver.go index 1bdca780fd..8fbe5297e3 100644 --- a/internal/binder/referenceresolver.go +++ b/internal/binder/referenceresolver.go @@ -2,8 +2,8 @@ package binder import ( "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" ) type ReferenceResolver interface { @@ -27,12 +27,14 @@ var _ ReferenceResolver = &referenceResolver{} type referenceResolver struct { resolver *NameResolver + options *core.CompilerOptions hooks ReferenceResolverHooks } -func NewReferenceResolver(hooks ReferenceResolverHooks) ReferenceResolver { +func NewReferenceResolver(options *core.CompilerOptions, hooks ReferenceResolverHooks) ReferenceResolver { return &referenceResolver{ - hooks: hooks, + options: options, + hooks: hooks, } } @@ -91,7 +93,9 @@ func (r *referenceResolver) getReferencedValueSymbol(reference *ast.IdentifierNo } if r.resolver == nil { - r.resolver = &NameResolver{} + r.resolver = &NameResolver{ + CompilerOptions: r.options, + } } return r.resolver.Resolve(location, reference.Text(), ast.SymbolFlagsExportValue|ast.SymbolFlagsValue|ast.SymbolFlagsAlias, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/) diff --git a/internal/bundled/embed.go b/internal/bundled/embed.go index 7d28f5ceeb..82ba6f9634 100644 --- a/internal/bundled/embed.go +++ b/internal/bundled/embed.go @@ -154,6 +154,13 @@ func (vfs *wrappedFS) WriteFile(path string, data string, writeByteOrderMark boo return vfs.fs.WriteFile(path, data, writeByteOrderMark) } +func (vfs *wrappedFS) Remove(path string) error { + if _, ok := splitPath(path); ok { + panic("cannot remove from embedded file system") + } + return vfs.fs.Remove(path) +} + type fileInfo struct { mode fs.FileMode name string diff --git a/internal/bundled/embed_generated.go b/internal/bundled/embed_generated.go index 9c7fb11262..a39bcf2c87 100644 --- a/internal/bundled/embed_generated.go +++ b/internal/bundled/embed_generated.go @@ -51,6 +51,8 @@ var ( libs_lib_es2016_full_d_ts string //go:embed libs/lib.es2016.intl.d.ts libs_lib_es2016_intl_d_ts string + //go:embed libs/lib.es2017.arraybuffer.d.ts + libs_lib_es2017_arraybuffer_d_ts string //go:embed libs/lib.es2017.d.ts libs_lib_es2017_d_ts string //go:embed libs/lib.es2017.date.d.ts @@ -141,8 +143,6 @@ var ( libs_lib_es2022_object_d_ts string //go:embed libs/lib.es2022.regexp.d.ts libs_lib_es2022_regexp_d_ts string - //go:embed libs/lib.es2022.sharedmemory.d.ts - libs_lib_es2022_sharedmemory_d_ts string //go:embed libs/lib.es2022.string.d.ts libs_lib_es2022_string_d_ts string //go:embed libs/lib.es2023.array.d.ts @@ -155,6 +155,24 @@ var ( libs_lib_es2023_full_d_ts string //go:embed libs/lib.es2023.intl.d.ts libs_lib_es2023_intl_d_ts string + //go:embed libs/lib.es2024.arraybuffer.d.ts + libs_lib_es2024_arraybuffer_d_ts string + //go:embed libs/lib.es2024.collection.d.ts + libs_lib_es2024_collection_d_ts string + //go:embed libs/lib.es2024.d.ts + libs_lib_es2024_d_ts string + //go:embed libs/lib.es2024.full.d.ts + libs_lib_es2024_full_d_ts string + //go:embed libs/lib.es2024.object.d.ts + libs_lib_es2024_object_d_ts string + //go:embed libs/lib.es2024.promise.d.ts + libs_lib_es2024_promise_d_ts string + //go:embed libs/lib.es2024.regexp.d.ts + libs_lib_es2024_regexp_d_ts string + //go:embed libs/lib.es2024.sharedmemory.d.ts + libs_lib_es2024_sharedmemory_d_ts string + //go:embed libs/lib.es2024.string.d.ts + libs_lib_es2024_string_d_ts string //go:embed libs/lib.es5.d.ts libs_lib_es5_d_ts string //go:embed libs/lib.es6.d.ts @@ -175,14 +193,6 @@ var ( libs_lib_esnext_intl_d_ts string //go:embed libs/lib.esnext.iterator.d.ts libs_lib_esnext_iterator_d_ts string - //go:embed libs/lib.esnext.object.d.ts - libs_lib_esnext_object_d_ts string - //go:embed libs/lib.esnext.promise.d.ts - libs_lib_esnext_promise_d_ts string - //go:embed libs/lib.esnext.regexp.d.ts - libs_lib_esnext_regexp_d_ts string - //go:embed libs/lib.esnext.string.d.ts - libs_lib_esnext_string_d_ts string //go:embed libs/lib.scripthost.d.ts libs_lib_scripthost_d_ts string //go:embed libs/lib.webworker.asynciterable.d.ts @@ -216,6 +226,7 @@ var embeddedContents = map[string]string{ "libs/lib.es2016.d.ts": libs_lib_es2016_d_ts, "libs/lib.es2016.full.d.ts": libs_lib_es2016_full_d_ts, "libs/lib.es2016.intl.d.ts": libs_lib_es2016_intl_d_ts, + "libs/lib.es2017.arraybuffer.d.ts": libs_lib_es2017_arraybuffer_d_ts, "libs/lib.es2017.d.ts": libs_lib_es2017_d_ts, "libs/lib.es2017.date.d.ts": libs_lib_es2017_date_d_ts, "libs/lib.es2017.full.d.ts": libs_lib_es2017_full_d_ts, @@ -261,13 +272,21 @@ var embeddedContents = map[string]string{ "libs/lib.es2022.intl.d.ts": libs_lib_es2022_intl_d_ts, "libs/lib.es2022.object.d.ts": libs_lib_es2022_object_d_ts, "libs/lib.es2022.regexp.d.ts": libs_lib_es2022_regexp_d_ts, - "libs/lib.es2022.sharedmemory.d.ts": libs_lib_es2022_sharedmemory_d_ts, "libs/lib.es2022.string.d.ts": libs_lib_es2022_string_d_ts, "libs/lib.es2023.array.d.ts": libs_lib_es2023_array_d_ts, "libs/lib.es2023.collection.d.ts": libs_lib_es2023_collection_d_ts, "libs/lib.es2023.d.ts": libs_lib_es2023_d_ts, "libs/lib.es2023.full.d.ts": libs_lib_es2023_full_d_ts, "libs/lib.es2023.intl.d.ts": libs_lib_es2023_intl_d_ts, + "libs/lib.es2024.arraybuffer.d.ts": libs_lib_es2024_arraybuffer_d_ts, + "libs/lib.es2024.collection.d.ts": libs_lib_es2024_collection_d_ts, + "libs/lib.es2024.d.ts": libs_lib_es2024_d_ts, + "libs/lib.es2024.full.d.ts": libs_lib_es2024_full_d_ts, + "libs/lib.es2024.object.d.ts": libs_lib_es2024_object_d_ts, + "libs/lib.es2024.promise.d.ts": libs_lib_es2024_promise_d_ts, + "libs/lib.es2024.regexp.d.ts": libs_lib_es2024_regexp_d_ts, + "libs/lib.es2024.sharedmemory.d.ts": libs_lib_es2024_sharedmemory_d_ts, + "libs/lib.es2024.string.d.ts": libs_lib_es2024_string_d_ts, "libs/lib.es5.d.ts": libs_lib_es5_d_ts, "libs/lib.es6.d.ts": libs_lib_es6_d_ts, "libs/lib.esnext.array.d.ts": libs_lib_esnext_array_d_ts, @@ -278,10 +297,6 @@ var embeddedContents = map[string]string{ "libs/lib.esnext.full.d.ts": libs_lib_esnext_full_d_ts, "libs/lib.esnext.intl.d.ts": libs_lib_esnext_intl_d_ts, "libs/lib.esnext.iterator.d.ts": libs_lib_esnext_iterator_d_ts, - "libs/lib.esnext.object.d.ts": libs_lib_esnext_object_d_ts, - "libs/lib.esnext.promise.d.ts": libs_lib_esnext_promise_d_ts, - "libs/lib.esnext.regexp.d.ts": libs_lib_esnext_regexp_d_ts, - "libs/lib.esnext.string.d.ts": libs_lib_esnext_string_d_ts, "libs/lib.scripthost.d.ts": libs_lib_scripthost_d_ts, "libs/lib.webworker.asynciterable.d.ts": libs_lib_webworker_asynciterable_d_ts, "libs/lib.webworker.d.ts": libs_lib_webworker_d_ts, @@ -310,6 +325,7 @@ var libsEntries = []fs.DirEntry{ &fileInfo{name: "lib.es2016.d.ts", size: int64(len(libs_lib_es2016_d_ts))}, &fileInfo{name: "lib.es2016.full.d.ts", size: int64(len(libs_lib_es2016_full_d_ts))}, &fileInfo{name: "lib.es2016.intl.d.ts", size: int64(len(libs_lib_es2016_intl_d_ts))}, + &fileInfo{name: "lib.es2017.arraybuffer.d.ts", size: int64(len(libs_lib_es2017_arraybuffer_d_ts))}, &fileInfo{name: "lib.es2017.d.ts", size: int64(len(libs_lib_es2017_d_ts))}, &fileInfo{name: "lib.es2017.date.d.ts", size: int64(len(libs_lib_es2017_date_d_ts))}, &fileInfo{name: "lib.es2017.full.d.ts", size: int64(len(libs_lib_es2017_full_d_ts))}, @@ -355,13 +371,21 @@ var libsEntries = []fs.DirEntry{ &fileInfo{name: "lib.es2022.intl.d.ts", size: int64(len(libs_lib_es2022_intl_d_ts))}, &fileInfo{name: "lib.es2022.object.d.ts", size: int64(len(libs_lib_es2022_object_d_ts))}, &fileInfo{name: "lib.es2022.regexp.d.ts", size: int64(len(libs_lib_es2022_regexp_d_ts))}, - &fileInfo{name: "lib.es2022.sharedmemory.d.ts", size: int64(len(libs_lib_es2022_sharedmemory_d_ts))}, &fileInfo{name: "lib.es2022.string.d.ts", size: int64(len(libs_lib_es2022_string_d_ts))}, &fileInfo{name: "lib.es2023.array.d.ts", size: int64(len(libs_lib_es2023_array_d_ts))}, &fileInfo{name: "lib.es2023.collection.d.ts", size: int64(len(libs_lib_es2023_collection_d_ts))}, &fileInfo{name: "lib.es2023.d.ts", size: int64(len(libs_lib_es2023_d_ts))}, &fileInfo{name: "lib.es2023.full.d.ts", size: int64(len(libs_lib_es2023_full_d_ts))}, &fileInfo{name: "lib.es2023.intl.d.ts", size: int64(len(libs_lib_es2023_intl_d_ts))}, + &fileInfo{name: "lib.es2024.arraybuffer.d.ts", size: int64(len(libs_lib_es2024_arraybuffer_d_ts))}, + &fileInfo{name: "lib.es2024.collection.d.ts", size: int64(len(libs_lib_es2024_collection_d_ts))}, + &fileInfo{name: "lib.es2024.d.ts", size: int64(len(libs_lib_es2024_d_ts))}, + &fileInfo{name: "lib.es2024.full.d.ts", size: int64(len(libs_lib_es2024_full_d_ts))}, + &fileInfo{name: "lib.es2024.object.d.ts", size: int64(len(libs_lib_es2024_object_d_ts))}, + &fileInfo{name: "lib.es2024.promise.d.ts", size: int64(len(libs_lib_es2024_promise_d_ts))}, + &fileInfo{name: "lib.es2024.regexp.d.ts", size: int64(len(libs_lib_es2024_regexp_d_ts))}, + &fileInfo{name: "lib.es2024.sharedmemory.d.ts", size: int64(len(libs_lib_es2024_sharedmemory_d_ts))}, + &fileInfo{name: "lib.es2024.string.d.ts", size: int64(len(libs_lib_es2024_string_d_ts))}, &fileInfo{name: "lib.es5.d.ts", size: int64(len(libs_lib_es5_d_ts))}, &fileInfo{name: "lib.es6.d.ts", size: int64(len(libs_lib_es6_d_ts))}, &fileInfo{name: "lib.esnext.array.d.ts", size: int64(len(libs_lib_esnext_array_d_ts))}, @@ -372,10 +396,6 @@ var libsEntries = []fs.DirEntry{ &fileInfo{name: "lib.esnext.full.d.ts", size: int64(len(libs_lib_esnext_full_d_ts))}, &fileInfo{name: "lib.esnext.intl.d.ts", size: int64(len(libs_lib_esnext_intl_d_ts))}, &fileInfo{name: "lib.esnext.iterator.d.ts", size: int64(len(libs_lib_esnext_iterator_d_ts))}, - &fileInfo{name: "lib.esnext.object.d.ts", size: int64(len(libs_lib_esnext_object_d_ts))}, - &fileInfo{name: "lib.esnext.promise.d.ts", size: int64(len(libs_lib_esnext_promise_d_ts))}, - &fileInfo{name: "lib.esnext.regexp.d.ts", size: int64(len(libs_lib_esnext_regexp_d_ts))}, - &fileInfo{name: "lib.esnext.string.d.ts", size: int64(len(libs_lib_esnext_string_d_ts))}, &fileInfo{name: "lib.scripthost.d.ts", size: int64(len(libs_lib_scripthost_d_ts))}, &fileInfo{name: "lib.webworker.asynciterable.d.ts", size: int64(len(libs_lib_webworker_asynciterable_d_ts))}, &fileInfo{name: "lib.webworker.d.ts", size: int64(len(libs_lib_webworker_d_ts))}, diff --git a/internal/bundled/libs/lib.es2016.intl.d.ts b/internal/bundled/libs/lib.es2016.intl.d.ts index 7af6efc2b0..83ca380f0b 100644 --- a/internal/bundled/libs/lib.es2016.intl.d.ts +++ b/internal/bundled/libs/lib.es2016.intl.d.ts @@ -22,7 +22,7 @@ declare namespace Intl { * the canonical locale names. Duplicates will be omitted and elements * will be validated as structurally valid language tags. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/getCanonicalLocales) + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/getCanonicalLocales) * * @param locale A list of String values for which to get the canonical locale names * @returns An array containing the canonical and validated locale names. diff --git a/internal/bundled/libs/lib.es2017.arraybuffer.d.ts b/internal/bundled/libs/lib.es2017.arraybuffer.d.ts new file mode 100644 index 0000000000..e2f00b8340 --- /dev/null +++ b/internal/bundled/libs/lib.es2017.arraybuffer.d.ts @@ -0,0 +1,21 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +interface ArrayBufferConstructor { + new (): ArrayBuffer; +} diff --git a/internal/bundled/libs/lib.es2017.d.ts b/internal/bundled/libs/lib.es2017.d.ts index e0bd4eeb72..234a01f956 100644 --- a/internal/bundled/libs/lib.es2017.d.ts +++ b/internal/bundled/libs/lib.es2017.d.ts @@ -17,9 +17,10 @@ and limitations under the License. /// <reference no-default-lib="true"/> /// <reference lib="es2016" /> +/// <reference lib="es2017.arraybuffer" /> +/// <reference lib="es2017.date" /> +/// <reference lib="es2017.intl" /> /// <reference lib="es2017.object" /> /// <reference lib="es2017.sharedmemory" /> /// <reference lib="es2017.string" /> -/// <reference lib="es2017.intl" /> /// <reference lib="es2017.typedarrays" /> -/// <reference lib="es2017.date" /> diff --git a/internal/bundled/libs/lib.es2017.sharedmemory.d.ts b/internal/bundled/libs/lib.es2017.sharedmemory.d.ts index 5c7d784ebf..89b703982b 100644 --- a/internal/bundled/libs/lib.es2017.sharedmemory.d.ts +++ b/internal/bundled/libs/lib.es2017.sharedmemory.d.ts @@ -28,14 +28,14 @@ interface SharedArrayBuffer { /** * Returns a section of an SharedArrayBuffer. */ - slice(begin: number, end?: number): SharedArrayBuffer; + slice(begin?: number, end?: number): SharedArrayBuffer; readonly [Symbol.species]: SharedArrayBuffer; readonly [Symbol.toStringTag]: "SharedArrayBuffer"; } interface SharedArrayBufferConstructor { readonly prototype: SharedArrayBuffer; - new (byteLength: number): SharedArrayBuffer; + new (byteLength?: number): SharedArrayBuffer; } declare var SharedArrayBuffer: SharedArrayBufferConstructor; diff --git a/internal/bundled/libs/lib.es2020.bigint.d.ts b/internal/bundled/libs/lib.es2020.bigint.d.ts index 0cb1630289..187772ec62 100644 --- a/internal/bundled/libs/lib.es2020.bigint.d.ts +++ b/internal/bundled/libs/lib.es2020.bigint.d.ts @@ -20,7 +20,7 @@ and limitations under the License. interface BigIntToLocaleStringOptions { /** - * The locale matching algorithm to use.The default is "best fit". For information about this option, see the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation Intl page}. + * The locale matching algorithm to use.The default is "best fit". For information about this option, see the {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation Intl page}. */ localeMatcher?: string; /** diff --git a/internal/bundled/libs/lib.es2020.intl.d.ts b/internal/bundled/libs/lib.es2020.intl.d.ts index 53cdacb69f..d78b640887 100644 --- a/internal/bundled/libs/lib.es2020.intl.d.ts +++ b/internal/bundled/libs/lib.es2020.intl.d.ts @@ -23,14 +23,14 @@ declare namespace Intl { * * For example: "fa", "es-MX", "zh-Hant-TW". * - * See [MDN - Intl - locales argument](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). + * See [MDN - Intl - locales argument](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). */ type UnicodeBCP47LocaleIdentifier = string; /** * Unit to use in the relative time internationalized message. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/format#Parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/format#Parameters). */ type RelativeTimeFormatUnit = | "year" @@ -57,7 +57,7 @@ declare namespace Intl { * but `formatToParts` only outputs singular (e.g. "day") not plural (e.g. * "days"). * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts#Using_formatToParts). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts#Using_formatToParts). */ type RelativeTimeFormatUnitSingular = | "year" @@ -79,21 +79,21 @@ declare namespace Intl { /** * The format of output message. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). */ type RelativeTimeFormatNumeric = "always" | "auto"; /** * The length of the internationalized message. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). */ type RelativeTimeFormatStyle = "long" | "short" | "narrow"; /** * The locale or locales to use * - * See [MDN - Intl - locales argument](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). + * See [MDN - Intl - locales argument](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). */ type LocalesArgument = UnicodeBCP47LocaleIdentifier | Locale | readonly (UnicodeBCP47LocaleIdentifier | Locale)[] | undefined; @@ -101,7 +101,7 @@ declare namespace Intl { * An object with some or all of properties of `options` parameter * of `Intl.RelativeTimeFormat` constructor. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters). */ interface RelativeTimeFormatOptions { /** The locale matching algorithm to use. For information about this option, see [Intl page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation). */ @@ -117,7 +117,7 @@ declare namespace Intl { * and formatting options computed during initialization * of the `Intl.RelativeTimeFormat` object * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/resolvedOptions#Description). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/resolvedOptions#Description). */ interface ResolvedRelativeTimeFormatOptions { locale: UnicodeBCP47LocaleIdentifier; @@ -130,7 +130,7 @@ declare namespace Intl { * An object representing the relative time format in parts * that can be used for custom locale-aware formatting. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts#Using_formatToParts). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts#Using_formatToParts). */ type RelativeTimeFormatPart = | { @@ -166,7 +166,7 @@ declare namespace Intl { * * @returns {string} Internationalized relative time message as string * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/format). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/format). */ format(value: number, unit: RelativeTimeFormatUnit): string; @@ -179,14 +179,14 @@ declare namespace Intl { * * @throws `RangeError` if `unit` was given something other than `unit` possible values * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts). */ formatToParts(value: number, unit: RelativeTimeFormatUnit): RelativeTimeFormatPart[]; /** * Provides access to the locale and options computed during initialization of this `Intl.RelativeTimeFormat` object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/resolvedOptions). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/resolvedOptions). */ resolvedOptions(): ResolvedRelativeTimeFormatOptions; } @@ -195,22 +195,22 @@ declare namespace Intl { * The [`Intl.RelativeTimeFormat`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) * object is a constructor for objects that enable language-sensitive relative time formatting. * - * [Compatibility](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat#Browser_compatibility). + * [Compatibility](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat#Browser_compatibility). */ const RelativeTimeFormat: { /** - * Creates [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) objects + * Creates [Intl.RelativeTimeFormat](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) objects * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the locales argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters) + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters) * with some or all of options of `RelativeTimeFormatOptions`. * - * @returns [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) object. + * @returns [Intl.RelativeTimeFormat](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat) object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat). */ new ( locales?: LocalesArgument, @@ -224,16 +224,16 @@ declare namespace Intl { * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the locales argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters) + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#Parameters) * with some or all of options of the formatting. * * @returns An array containing those of the provided locales * that are supported in date and time formatting * without having to fall back to the runtime's default locale. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/supportedLocalesOf). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/supportedLocalesOf). */ supportedLocalesOf( locales?: LocalesArgument, @@ -336,18 +336,18 @@ declare namespace Intl { } /** - * Constructor creates [Intl.Locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) + * Constructor creates [Intl.Locale](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) * objects * * @param tag - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646). * For the general form and interpretation of the locales argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/Locale#Parameters) with some or all of options of the locale. + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/Locale#Parameters) with some or all of options of the locale. * - * @returns [Intl.Locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) object. + * @returns [Intl.Locale](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale). */ const Locale: { new (tag: UnicodeBCP47LocaleIdentifier | Locale, options?: LocaleOptions): Locale; @@ -388,7 +388,7 @@ declare namespace Intl { interface DisplayNames { /** * Receives a code and returns a string based on the locale and options provided when instantiating - * [`Intl.DisplayNames()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) + * [`Intl.DisplayNames()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) * * @param code The `code` to provide depends on the `type` passed to display name during creation: * - If the type is `"region"`, code should be either an [ISO-3166 two letters region code](https://www.iso.org/iso-3166-country-codes.html), @@ -399,35 +399,35 @@ declare namespace Intl { * `languageCode` is either a two letters ISO 639-1 language code or a three letters ISO 639-2 language code. * - If the type is `"currency"`, code should be a [3-letter ISO 4217 currency code](https://www.iso.org/iso-4217-currency-codes.html). * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/of). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/of). */ of(code: string): string | undefined; /** * Returns a new object with properties reflecting the locale and style formatting options computed during the construction of the current - * [`Intl/DisplayNames`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) object. + * [`Intl/DisplayNames`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/resolvedOptions). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/resolvedOptions). */ resolvedOptions(): ResolvedDisplayNamesOptions; } /** - * The [`Intl.DisplayNames()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) + * The [`Intl.DisplayNames()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) * object enables the consistent translation of language, region and script display names. * - * [Compatibility](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames#browser_compatibility). + * [Compatibility](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames#browser_compatibility). */ const DisplayNames: { prototype: DisplayNames; /** * @param locales A string with a BCP 47 language tag, or an array of such strings. - * For the general form and interpretation of the `locales` argument, see the [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation) + * For the general form and interpretation of the `locales` argument, see the [Intl](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation) * page. * * @param options An object for setting up a display name. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/DisplayNames). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/DisplayNames). */ new (locales: LocalesArgument, options: DisplayNamesOptions): DisplayNames; @@ -435,14 +435,14 @@ declare namespace Intl { * Returns an array containing those of the provided locales that are supported in display names without having to fall back to the runtime's default locale. * * @param locales A string with a BCP 47 language tag, or an array of such strings. - * For the general form and interpretation of the `locales` argument, see the [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation) + * For the general form and interpretation of the `locales` argument, see the [Intl](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation) * page. * * @param options An object with a locale matcher. * * @returns An array of strings representing a subset of the given locale tags that are supported in display names without having to fall back to the runtime's default locale. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/supportedLocalesOf). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/supportedLocalesOf). */ supportedLocalesOf(locales?: LocalesArgument, options?: { localeMatcher?: RelativeTimeFormatLocaleMatcher; }): UnicodeBCP47LocaleIdentifier[]; }; diff --git a/internal/bundled/libs/lib.es2020.sharedmemory.d.ts b/internal/bundled/libs/lib.es2020.sharedmemory.d.ts index c563ab8c5a..35641a6426 100644 --- a/internal/bundled/libs/lib.es2020.sharedmemory.d.ts +++ b/internal/bundled/libs/lib.es2020.sharedmemory.d.ts @@ -16,6 +16,8 @@ and limitations under the License. /// <reference no-default-lib="true"/> +/// <reference lib="es2020.bigint" /> + interface Atomics { /** * Adds a value to the value at the given position in the array, returning the original value. diff --git a/internal/bundled/libs/lib.es2020.string.d.ts b/internal/bundled/libs/lib.es2020.string.d.ts index cdb38e0d86..4c2a4ded06 100644 --- a/internal/bundled/libs/lib.es2020.string.d.ts +++ b/internal/bundled/libs/lib.es2020.string.d.ts @@ -16,6 +16,8 @@ and limitations under the License. /// <reference no-default-lib="true"/> +/// <reference lib="es2015.iterable" /> +/// <reference lib="es2020.intl" /> /// <reference lib="es2020.symbol.wellknown" /> interface String { diff --git a/internal/bundled/libs/lib.es2021.intl.d.ts b/internal/bundled/libs/lib.es2021.intl.d.ts index ec90ad1b2c..a0fe4825e7 100644 --- a/internal/bundled/libs/lib.es2021.intl.d.ts +++ b/internal/bundled/libs/lib.es2021.intl.d.ts @@ -50,28 +50,28 @@ declare namespace Intl { /** * The locale matching algorithm to use. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). */ type ListFormatLocaleMatcher = "lookup" | "best fit"; /** * The format of output message. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). */ type ListFormatType = "conjunction" | "disjunction" | "unit"; /** * The length of the formatted message. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). */ type ListFormatStyle = "long" | "short" | "narrow"; /** * An object with some or all properties of the `Intl.ListFormat` constructor `options` parameter. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters). */ interface ListFormatOptions { /** The locale matching algorithm to use. For information about this option, see [Intl page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation). */ @@ -92,26 +92,26 @@ declare namespace Intl { /** * Returns a string with a language-specific representation of the list. * - * @param list - An iterable object, such as an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). + * @param list - An iterable object, such as an [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array). * * @throws `TypeError` if `list` includes something other than the possible values. * * @returns {string} A language-specific formatted string representing the elements of the list. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/format). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/format). */ format(list: Iterable<string>): string; /** * Returns an Array of objects representing the different components that can be used to format a list of values in a locale-aware fashion. * - * @param list - An iterable object, such as an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), to be formatted according to a locale. + * @param list - An iterable object, such as an [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array), to be formatted according to a locale. * * @throws `TypeError` if `list` includes something other than the possible values. * * @returns {{ type: "element" | "literal", value: string; }[]} An Array of components which contains the formatted parts from the list. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/formatToParts). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/formatToParts). */ formatToParts(list: Iterable<string>): { type: "element" | "literal"; value: string; }[]; @@ -120,7 +120,7 @@ declare namespace Intl { * formatting options computed during the construction of the current * `Intl.ListFormat` object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/resolvedOptions). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/resolvedOptions). */ resolvedOptions(): ResolvedListFormatOptions; } @@ -129,19 +129,19 @@ declare namespace Intl { prototype: ListFormat; /** - * Creates [Intl.ListFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) objects that + * Creates [Intl.ListFormat](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) objects that * enable language-sensitive list formatting. * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the `locales` argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters) + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat#parameters) * with some or all options of `ListFormatOptions`. * - * @returns [Intl.ListFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) object. + * @returns [Intl.ListFormatOptions](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat). */ new (locales?: LocalesArgument, options?: ListFormatOptions): ListFormat; @@ -151,15 +151,15 @@ declare namespace Intl { * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the `locales` argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf#parameters). + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf#parameters). * with some or all possible options. * * @returns An array of strings representing a subset of the given locale tags that are supported in list * formatting without having to fall back to the runtime's default locale. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf). */ supportedLocalesOf(locales: LocalesArgument, options?: Pick<ListFormatOptions, "localeMatcher">): UnicodeBCP47LocaleIdentifier[]; }; diff --git a/internal/bundled/libs/lib.es2021.weakref.d.ts b/internal/bundled/libs/lib.es2021.weakref.d.ts index 48e76265a2..9e03365a20 100644 --- a/internal/bundled/libs/lib.es2021.weakref.d.ts +++ b/internal/bundled/libs/lib.es2021.weakref.d.ts @@ -16,6 +16,8 @@ and limitations under the License. /// <reference no-default-lib="true"/> +/// <reference lib="es2015.symbol.wellknown" /> + interface WeakRef<T extends WeakKey> { readonly [Symbol.toStringTag]: "WeakRef"; diff --git a/internal/bundled/libs/lib.es2022.d.ts b/internal/bundled/libs/lib.es2022.d.ts index 2ae78aba3f..ca7cc91ac9 100644 --- a/internal/bundled/libs/lib.es2022.d.ts +++ b/internal/bundled/libs/lib.es2022.d.ts @@ -21,6 +21,5 @@ and limitations under the License. /// <reference lib="es2022.error" /> /// <reference lib="es2022.intl" /> /// <reference lib="es2022.object" /> -/// <reference lib="es2022.sharedmemory" /> -/// <reference lib="es2022.string" /> /// <reference lib="es2022.regexp" /> +/// <reference lib="es2022.string" /> diff --git a/internal/bundled/libs/lib.es2022.error.d.ts b/internal/bundled/libs/lib.es2022.error.d.ts index 782c485e7c..5e02521b42 100644 --- a/internal/bundled/libs/lib.es2022.error.d.ts +++ b/internal/bundled/libs/lib.es2022.error.d.ts @@ -16,6 +16,8 @@ and limitations under the License. /// <reference no-default-lib="true"/> +/// <reference lib="es2021.promise" /> + interface ErrorOptions { cause?: unknown; } diff --git a/internal/bundled/libs/lib.es2022.intl.d.ts b/internal/bundled/libs/lib.es2022.intl.d.ts index cd8eb11408..3f4a2ca1e4 100644 --- a/internal/bundled/libs/lib.es2022.intl.d.ts +++ b/internal/bundled/libs/lib.es2022.intl.d.ts @@ -20,7 +20,7 @@ declare namespace Intl { /** * An object with some or all properties of the `Intl.Segmenter` constructor `options` parameter. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/Segmenter#parameters) + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/Segmenter#parameters) */ interface SegmenterOptions { /** The locale matching algorithm to use. For information about this option, see [Intl page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation). */ @@ -84,14 +84,14 @@ declare namespace Intl { * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the `locales` argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options - An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/Segmenter#parameters) + * @param options - An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/Segmenter#parameters) * with some or all options of `SegmenterOptions`. * - * @returns [Intl.Segmenter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segments) object. + * @returns [Intl.Segmenter](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segments) object. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter). + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter). */ new (locales?: LocalesArgument, options?: SegmenterOptions): Segmenter; @@ -100,19 +100,19 @@ declare namespace Intl { * * @param locales - A string with a [BCP 47 language tag](http://tools.ietf.org/html/rfc5646), or an array of such strings. * For the general form and interpretation of the `locales` argument, - * see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). + * see the [`Intl` page](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation). * - * @param options An [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf#parameters). + * @param options An [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf#parameters). * with some or all possible options. * - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf) + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf) */ supportedLocalesOf(locales: LocalesArgument, options?: Pick<SegmenterOptions, "localeMatcher">): UnicodeBCP47LocaleIdentifier[]; }; /** * Returns a sorted array of the supported collation, calendar, currency, numbering system, timezones, and units by the implementation. - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/supportedValuesOf) + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/supportedValuesOf) * * @param key A string indicating the category of values to return. * @returns A sorted array of the supported values. diff --git a/internal/bundled/libs/lib.es2022.sharedmemory.d.ts b/internal/bundled/libs/lib.es2022.sharedmemory.d.ts deleted file mode 100644 index ea67b0081b..0000000000 --- a/internal/bundled/libs/lib.es2022.sharedmemory.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ - - -/// <reference no-default-lib="true"/> - -interface Atomics { - /** - * A non-blocking, asynchronous version of wait which is usable on the main thread. - * Waits asynchronously on a shared memory location and returns a Promise - * @param typedArray A shared Int32Array or BigInt64Array. - * @param index The position in the typedArray to wait on. - * @param value The expected value to test. - * @param [timeout] The expected value to test. - */ - waitAsync(typedArray: Int32Array, index: number, value: number, timeout?: number): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; - - /** - * A non-blocking, asynchronous version of wait which is usable on the main thread. - * Waits asynchronously on a shared memory location and returns a Promise - * @param typedArray A shared Int32Array or BigInt64Array. - * @param index The position in the typedArray to wait on. - * @param value The expected value to test. - * @param [timeout] The expected value to test. - */ - waitAsync(typedArray: BigInt64Array, index: number, value: bigint, timeout?: number): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; -} diff --git a/internal/bundled/libs/lib.es2024.arraybuffer.d.ts b/internal/bundled/libs/lib.es2024.arraybuffer.d.ts new file mode 100644 index 0000000000..2a5623d90c --- /dev/null +++ b/internal/bundled/libs/lib.es2024.arraybuffer.d.ts @@ -0,0 +1,65 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +interface ArrayBuffer { + /** + * If this ArrayBuffer is resizable, returns the maximum byte length given during construction; returns the byte length if not. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/maxByteLength) + */ + get maxByteLength(): number; + + /** + * Returns true if this ArrayBuffer can be resized. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/resizable) + */ + get resizable(): boolean; + + /** + * Resizes the ArrayBuffer to the specified size (in bytes). + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/resize) + */ + resize(newByteLength?: number): void; + + /** + * Returns a boolean indicating whether or not this buffer has been detached (transferred). + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/detached) + */ + get detached(): boolean; + + /** + * Creates a new ArrayBuffer with the same byte content as this buffer, then detaches this buffer. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/transfer) + */ + transfer(newByteLength?: number): ArrayBuffer; + + /** + * Creates a new non-resizable ArrayBuffer with the same byte content as this buffer, then detaches this buffer. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/transferToFixedLength) + */ + transferToFixedLength(newByteLength?: number): ArrayBuffer; +} + +interface ArrayBufferConstructor { + new (byteLength: number, options?: { maxByteLength?: number; }): ArrayBuffer; +} diff --git a/internal/bundled/libs/lib.es2024.collection.d.ts b/internal/bundled/libs/lib.es2024.collection.d.ts new file mode 100644 index 0000000000..a48fd93d5f --- /dev/null +++ b/internal/bundled/libs/lib.es2024.collection.d.ts @@ -0,0 +1,29 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +interface MapConstructor { + /** + * Groups members of an iterable according to the return value of the passed callback. + * @param items An iterable. + * @param keySelector A callback which will be invoked for each item in items. + */ + groupBy<K, T>( + items: Iterable<T>, + keySelector: (item: T, index: number) => K, + ): Map<K, T[]>; +} diff --git a/internal/bundled/libs/lib.es2024.d.ts b/internal/bundled/libs/lib.es2024.d.ts new file mode 100644 index 0000000000..44311afb00 --- /dev/null +++ b/internal/bundled/libs/lib.es2024.d.ts @@ -0,0 +1,26 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +/// <reference lib="es2023" /> +/// <reference lib="es2024.arraybuffer" /> +/// <reference lib="es2024.collection" /> +/// <reference lib="es2024.object" /> +/// <reference lib="es2024.promise" /> +/// <reference lib="es2024.regexp" /> +/// <reference lib="es2024.sharedmemory" /> +/// <reference lib="es2024.string" /> diff --git a/internal/bundled/libs/lib.es2024.full.d.ts b/internal/bundled/libs/lib.es2024.full.d.ts new file mode 100644 index 0000000000..b8c6e74867 --- /dev/null +++ b/internal/bundled/libs/lib.es2024.full.d.ts @@ -0,0 +1,24 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +/// <reference lib="es2024" /> +/// <reference lib="dom" /> +/// <reference lib="webworker.importscripts" /> +/// <reference lib="scripthost" /> +/// <reference lib="dom.iterable" /> +/// <reference lib="dom.asynciterable" /> diff --git a/internal/bundled/libs/lib.esnext.object.d.ts b/internal/bundled/libs/lib.es2024.object.d.ts similarity index 100% rename from internal/bundled/libs/lib.esnext.object.d.ts rename to internal/bundled/libs/lib.es2024.object.d.ts diff --git a/internal/bundled/libs/lib.esnext.promise.d.ts b/internal/bundled/libs/lib.es2024.promise.d.ts similarity index 100% rename from internal/bundled/libs/lib.esnext.promise.d.ts rename to internal/bundled/libs/lib.es2024.promise.d.ts diff --git a/internal/bundled/libs/lib.esnext.regexp.d.ts b/internal/bundled/libs/lib.es2024.regexp.d.ts similarity index 100% rename from internal/bundled/libs/lib.esnext.regexp.d.ts rename to internal/bundled/libs/lib.es2024.regexp.d.ts diff --git a/internal/bundled/libs/lib.es2024.sharedmemory.d.ts b/internal/bundled/libs/lib.es2024.sharedmemory.d.ts new file mode 100644 index 0000000000..1d6bb455a9 --- /dev/null +++ b/internal/bundled/libs/lib.es2024.sharedmemory.d.ts @@ -0,0 +1,68 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/// <reference no-default-lib="true"/> + +/// <reference lib="es2020.bigint" /> + +interface Atomics { + /** + * A non-blocking, asynchronous version of wait which is usable on the main thread. + * Waits asynchronously on a shared memory location and returns a Promise + * @param typedArray A shared Int32Array or BigInt64Array. + * @param index The position in the typedArray to wait on. + * @param value The expected value to test. + * @param [timeout] The expected value to test. + */ + waitAsync(typedArray: Int32Array, index: number, value: number, timeout?: number): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; + + /** + * A non-blocking, asynchronous version of wait which is usable on the main thread. + * Waits asynchronously on a shared memory location and returns a Promise + * @param typedArray A shared Int32Array or BigInt64Array. + * @param index The position in the typedArray to wait on. + * @param value The expected value to test. + * @param [timeout] The expected value to test. + */ + waitAsync(typedArray: BigInt64Array, index: number, value: bigint, timeout?: number): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; +} + +interface SharedArrayBuffer { + /** + * Returns true if this SharedArrayBuffer can be grown. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/growable) + */ + get growable(): number; + + /** + * If this SharedArrayBuffer is growable, returns the maximum byte length given during construction; returns the byte length if not. + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/maxByteLength) + */ + get maxByteLength(): number; + + /** + * Grows the SharedArrayBuffer to the specified size (in bytes). + * + * [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/grow) + */ + grow(newByteLength?: number): void; +} + +interface SharedArrayBufferConstructor { + new (byteLength: number, options?: { maxByteLength?: number; }): SharedArrayBuffer; +} diff --git a/internal/bundled/libs/lib.esnext.string.d.ts b/internal/bundled/libs/lib.es2024.string.d.ts similarity index 100% rename from internal/bundled/libs/lib.esnext.string.d.ts rename to internal/bundled/libs/lib.es2024.string.d.ts diff --git a/internal/bundled/libs/lib.es5.d.ts b/internal/bundled/libs/lib.es5.d.ts index c29d5acc7b..f0ff2f8656 100644 --- a/internal/bundled/libs/lib.es5.d.ts +++ b/internal/bundled/libs/lib.es5.d.ts @@ -1701,7 +1701,7 @@ interface ArrayBuffer { /** * Returns a section of an ArrayBuffer. */ - slice(begin: number, end?: number): ArrayBuffer; + slice(begin?: number, end?: number): ArrayBuffer; } /** diff --git a/internal/bundled/libs/lib.esnext.collection.d.ts b/internal/bundled/libs/lib.esnext.collection.d.ts index 1278a38f67..46b0b08951 100644 --- a/internal/bundled/libs/lib.esnext.collection.d.ts +++ b/internal/bundled/libs/lib.esnext.collection.d.ts @@ -16,17 +16,7 @@ and limitations under the License. /// <reference no-default-lib="true"/> -interface MapConstructor { - /** - * Groups members of an iterable according to the return value of the passed callback. - * @param items An iterable. - * @param keySelector A callback which will be invoked for each item in items. - */ - groupBy<K, T>( - items: Iterable<T>, - keySelector: (item: T, index: number) => K, - ): Map<K, T[]>; -} +/// <reference lib="es2024.collection" /> interface ReadonlySetLike<T> { /** diff --git a/internal/bundled/libs/lib.esnext.d.ts b/internal/bundled/libs/lib.esnext.d.ts index e0217b6c60..37b5ea5ed6 100644 --- a/internal/bundled/libs/lib.esnext.d.ts +++ b/internal/bundled/libs/lib.esnext.d.ts @@ -16,14 +16,10 @@ and limitations under the License. /// <reference no-default-lib="true"/> -/// <reference lib="es2023" /> +/// <reference lib="es2024" /> /// <reference lib="esnext.intl" /> /// <reference lib="esnext.decorators" /> /// <reference lib="esnext.disposable" /> -/// <reference lib="esnext.promise" /> -/// <reference lib="esnext.object" /> /// <reference lib="esnext.collection" /> /// <reference lib="esnext.array" /> -/// <reference lib="esnext.regexp" /> -/// <reference lib="esnext.string" /> /// <reference lib="esnext.iterator" /> diff --git a/internal/bundled/libs_generated.go b/internal/bundled/libs_generated.go index e232624310..79c5512b41 100644 --- a/internal/bundled/libs_generated.go +++ b/internal/bundled/libs_generated.go @@ -25,6 +25,7 @@ var LibNames = []string{ "lib.es2016.d.ts", "lib.es2016.full.d.ts", "lib.es2016.intl.d.ts", + "lib.es2017.arraybuffer.d.ts", "lib.es2017.d.ts", "lib.es2017.date.d.ts", "lib.es2017.full.d.ts", @@ -70,13 +71,21 @@ var LibNames = []string{ "lib.es2022.intl.d.ts", "lib.es2022.object.d.ts", "lib.es2022.regexp.d.ts", - "lib.es2022.sharedmemory.d.ts", "lib.es2022.string.d.ts", "lib.es2023.array.d.ts", "lib.es2023.collection.d.ts", "lib.es2023.d.ts", "lib.es2023.full.d.ts", "lib.es2023.intl.d.ts", + "lib.es2024.arraybuffer.d.ts", + "lib.es2024.collection.d.ts", + "lib.es2024.d.ts", + "lib.es2024.full.d.ts", + "lib.es2024.object.d.ts", + "lib.es2024.promise.d.ts", + "lib.es2024.regexp.d.ts", + "lib.es2024.sharedmemory.d.ts", + "lib.es2024.string.d.ts", "lib.es5.d.ts", "lib.es6.d.ts", "lib.esnext.array.d.ts", @@ -87,10 +96,6 @@ var LibNames = []string{ "lib.esnext.full.d.ts", "lib.esnext.intl.d.ts", "lib.esnext.iterator.d.ts", - "lib.esnext.object.d.ts", - "lib.esnext.promise.d.ts", - "lib.esnext.regexp.d.ts", - "lib.esnext.string.d.ts", "lib.scripthost.d.ts", "lib.webworker.asynciterable.d.ts", "lib.webworker.d.ts", diff --git a/internal/checker/checker.go b/internal/checker/checker.go index b4c0e3520c..3383971d34 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -2,6 +2,7 @@ package checker import ( "fmt" + "iter" "maps" "math" "slices" @@ -14,8 +15,9 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" "github.com/microsoft/typescript-go/internal/collections" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" + "github.com/microsoft/typescript-go/internal/evaluator" "github.com/microsoft/typescript-go/internal/jsnum" "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/scanner" @@ -309,6 +311,15 @@ const ( DeclarationMeaningPropertyAssignmentOrMethod = DeclarationMeaningPropertyAssignment | DeclarationMeaningMethod ) +type DeclarationSpaces int32 + +const ( + DeclarationSpacesNone DeclarationSpaces = 0 + DeclarationSpacesExportValue DeclarationSpaces = 1 << 0 + DeclarationSpacesExportType DeclarationSpaces = 1 << 1 + DeclarationSpacesExportNamespace DeclarationSpaces = 1 << 2 +) + // IntrinsicTypeKind type IntrinsicTypeKind int32 @@ -513,6 +524,9 @@ type Program interface { GetEmitModuleFormatOfFile(sourceFile *ast.SourceFile) core.ModuleKind GetImpliedNodeFormatForEmit(sourceFile *ast.SourceFile) core.ModuleKind GetResolvedModule(currentSourceFile *ast.SourceFile, moduleReference string) *ast.SourceFile + GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData + GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node) + GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node } type Host interface{} @@ -522,290 +536,299 @@ type Host interface{} var nextCheckerID atomic.Uint32 type Checker struct { - id uint32 - program Program - host Host - compilerOptions *core.CompilerOptions - files []*ast.SourceFile - fileIndexMap map[*ast.SourceFile]int - compareSymbols func(*ast.Symbol, *ast.Symbol) int - TypeCount uint32 - symbolCount uint32 - totalInstantiationCount uint32 - instantiationCount uint32 - instantiationDepth uint32 - inlineLevel int - currentNode *ast.Node - varianceTypeParameter *Type - languageVersion core.ScriptTarget - moduleKind core.ModuleKind - isInferencePartiallyBlocked bool - legacyDecorators bool - emitStandardClassFields bool - allowSyntheticDefaultImports bool - strictNullChecks bool - strictFunctionTypes bool - strictBindCallApply bool - strictPropertyInitialization bool - strictBuiltinIteratorReturn bool - noImplicitAny bool - noImplicitThis bool - useUnknownInCatchVariables bool - exactOptionalPropertyTypes bool - canCollectSymbolAliasAccessibilityData bool - arrayVariances []VarianceFlags - globals ast.SymbolTable - globalSymbols []*ast.Symbol - evaluate Evaluator - stringLiteralTypes map[string]*Type - numberLiteralTypes map[jsnum.Number]*Type - bigintLiteralTypes map[PseudoBigInt]*Type - enumLiteralTypes map[EnumLiteralKey]*Type - indexedAccessTypes map[string]*Type - templateLiteralTypes map[string]*Type - stringMappingTypes map[StringMappingKey]*Type - uniqueESSymbolTypes map[*ast.Symbol]*Type - subtypeReductionCache map[string][]*Type - cachedTypes map[CachedTypeKey]*Type - cachedSignatures map[CachedSignatureKey]*Signature - undefinedProperties map[string]*ast.Symbol - narrowedTypes map[NarrowedTypeKey]*Type - assignmentReducedTypes map[AssignmentReducedKey]*Type - discriminatedContextualTypes map[DiscriminatedContextualTypeKey]*Type - instantiationExpressionTypes map[InstantiationExpressionKey]*Type - substitutionTypes map[SubstitutionTypeKey]*Type - reverseMappedCache map[ReverseMappedTypeKey]*Type - reverseHomomorphicMappedCache map[ReverseMappedTypeKey]*Type - iterationTypesCache map[IterationTypesKey]IterationTypes - markerTypes core.Set[*Type] - identifierSymbols map[*ast.Node]*ast.Symbol - undefinedSymbol *ast.Symbol - argumentsSymbol *ast.Symbol - requireSymbol *ast.Symbol - unknownSymbol *ast.Symbol - resolvingSymbol *ast.Symbol - unresolvedSymbols map[string]*ast.Symbol - errorTypes map[string]*Type - globalThisSymbol *ast.Symbol - resolveName func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol - resolveNameForSymbolSuggestion func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol - tupleTypes map[string]*Type - unionTypes map[string]*Type - unionOfUnionTypes map[UnionOfUnionKey]*Type - intersectionTypes map[string]*Type - diagnostics ast.DiagnosticsCollection - suggestionDiagnostics ast.DiagnosticsCollection - symbolPool core.Pool[ast.Symbol] - signaturePool core.Pool[Signature] - indexInfoPool core.Pool[IndexInfo] - mergedSymbols map[*ast.Symbol]*ast.Symbol - factory ast.NodeFactory - nodeLinks core.LinkStore[*ast.Node, NodeLinks] - signatureLinks core.LinkStore[*ast.Node, SignatureLinks] - typeNodeLinks core.LinkStore[*ast.Node, TypeNodeLinks] - enumMemberLinks core.LinkStore[*ast.Node, EnumMemberLinks] - assertionLinks core.LinkStore[*ast.Node, AssertionLinks] - arrayLiteralLinks core.LinkStore[*ast.Node, ArrayLiteralLinks] - switchStatementLinks core.LinkStore[*ast.Node, SwitchStatementLinks] - symbolReferenceLinks core.LinkStore[*ast.Symbol, SymbolReferenceLinks] - valueSymbolLinks core.LinkStore[*ast.Symbol, ValueSymbolLinks] - mappedSymbolLinks core.LinkStore[*ast.Symbol, MappedSymbolLinks] - deferredSymbolLinks core.LinkStore[*ast.Symbol, DeferredSymbolLinks] - aliasSymbolLinks core.LinkStore[*ast.Symbol, AliasSymbolLinks] - moduleSymbolLinks core.LinkStore[*ast.Symbol, ModuleSymbolLinks] - lateBoundLinks core.LinkStore[*ast.Symbol, LateBoundLinks] - exportTypeLinks core.LinkStore[*ast.Symbol, ExportTypeLinks] - membersAndExportsLinks core.LinkStore[*ast.Symbol, MembersAndExportsLinks] - typeAliasLinks core.LinkStore[*ast.Symbol, TypeAliasLinks] - declaredTypeLinks core.LinkStore[*ast.Symbol, DeclaredTypeLinks] - spreadLinks core.LinkStore[*ast.Symbol, SpreadLinks] - varianceLinks core.LinkStore[*ast.Symbol, VarianceLinks] - indexSymbolLinks core.LinkStore[*ast.Symbol, IndexSymbolLinks] - ReverseMappedSymbolLinks core.LinkStore[*ast.Symbol, ReverseMappedSymbolLinks] - markedAssignmentSymbolLinks core.LinkStore[*ast.Symbol, MarkedAssignmentSymbolLinks] - sourceFileLinks core.LinkStore[*ast.SourceFile, SourceFileLinks] - patternForType map[*Type]*ast.Node - contextFreeTypes map[*ast.Node]*Type - anyType *Type - autoType *Type - wildcardType *Type - blockedStringType *Type - errorType *Type - unresolvedType *Type - nonInferrableAnyType *Type - intrinsicMarkerType *Type - unknownType *Type - undefinedType *Type - undefinedWideningType *Type - missingType *Type - undefinedOrMissingType *Type - optionalType *Type - nullType *Type - nullWideningType *Type - stringType *Type - numberType *Type - bigintType *Type - regularFalseType *Type - falseType *Type - regularTrueType *Type - trueType *Type - booleanType *Type - esSymbolType *Type - voidType *Type - neverType *Type - silentNeverType *Type - implicitNeverType *Type - unreachableNeverType *Type - nonPrimitiveType *Type - stringOrNumberType *Type - stringNumberSymbolType *Type - numberOrBigIntType *Type - templateConstraintType *Type - numericStringType *Type - uniqueLiteralType *Type - uniqueLiteralMapper *TypeMapper - reliabilityFlags RelationComparisonResult - reportUnreliableMapper *TypeMapper - reportUnmeasurableMapper *TypeMapper - restrictiveMapper *TypeMapper - permissiveMapper *TypeMapper - emptyObjectType *Type - emptyTypeLiteralType *Type - unknownEmptyObjectType *Type - unknownUnionType *Type - emptyGenericType *Type - anyFunctionType *Type - noConstraintType *Type - circularConstraintType *Type - resolvingDefaultType *Type - markerSuperType *Type - markerSubType *Type - markerOtherType *Type - markerSuperTypeForCheck *Type - markerSubTypeForCheck *Type - noTypePredicate *TypePredicate - anySignature *Signature - unknownSignature *Signature - resolvingSignature *Signature - silentNeverSignature *Signature - enumNumberIndexInfo *IndexInfo - patternAmbientModules []ast.PatternAmbientModule - patternAmbientModuleAugmentations ast.SymbolTable - globalObjectType *Type - globalFunctionType *Type - globalCallableFunctionType *Type - globalNewableFunctionType *Type - globalArrayType *Type - globalReadonlyArrayType *Type - globalStringType *Type - globalNumberType *Type - globalBooleanType *Type - globalRegExpType *Type - globalThisType *Type - anyArrayType *Type - autoArrayType *Type - anyReadonlyArrayType *Type - deferredGlobalImportMetaExpressionType *Type - contextualBindingPatterns []*ast.Node - emptyStringType *Type - zeroType *Type - zeroBigIntType *Type - typeofType *Type - typeResolutions []TypeResolution - resolutionStart int - inVarianceComputation bool - suggestionCount int - apparentArgumentCount *int - lastGetCombinedNodeFlagsNode *ast.Node - lastGetCombinedNodeFlagsResult ast.NodeFlags - lastGetCombinedModifierFlagsNode *ast.Node - lastGetCombinedModifierFlagsResult ast.ModifierFlags - inferenceStates []InferenceState - flowStates []FlowState - flowLoopCache map[FlowLoopKey]*Type - flowLoopStack []FlowLoopInfo - sharedFlows []SharedFlow - antecedentTypes []*Type - flowAnalysisDisabled bool - flowInvocationCount int - flowTypeCache map[*ast.Node]*Type - lastFlowNode *ast.FlowNode - lastFlowNodeReachable bool - flowNodeReachable map[*ast.FlowNode]bool - flowNodePostSuper map[*ast.FlowNode]bool - renamedBindingElementsInTypes []*ast.Node - contextualInfos []ContextualInfo - inferenceContextInfos []InferenceContextInfo - awaitedTypeStack []*Type - reverseMappedSourceStack []*Type - reverseMappedTargetStack []*Type - reverseExpandingFlags ExpandingFlags - relaters []Relater - subtypeRelation *Relation - strictSubtypeRelation *Relation - assignableRelation *Relation - comparableRelation *Relation - identityRelation *Relation - enumRelation map[EnumRelationKey]RelationComparisonResult - getGlobalESSymbolType func() *Type - getGlobalBigIntType func() *Type - getGlobalImportMetaType func() *Type - getGlobalImportAttributesType func() *Type - getGlobalImportAttributesTypeChecked func() *Type - getGlobalNonNullableTypeAliasOrNil func() *ast.Symbol - getGlobalExtractSymbol func() *ast.Symbol - getGlobalDisposableType func() *Type - getGlobalAsyncDisposableType func() *Type - getGlobalAwaitedSymbol func() *ast.Symbol - getGlobalAwaitedSymbolOrNil func() *ast.Symbol - getGlobalNaNSymbolOrNil func() *ast.Symbol - getGlobalRecordSymbol func() *ast.Symbol - getGlobalTemplateStringsArrayType func() *Type - getGlobalESSymbolConstructorSymbolOrNil func() *ast.Symbol - getGlobalImportCallOptionsType func() *Type - getGlobalImportCallOptionsTypeChecked func() *Type - getGlobalPromiseType func() *Type - getGlobalPromiseTypeChecked func() *Type - getGlobalPromiseLikeType func() *Type - getGlobalPromiseConstructorSymbol func() *ast.Symbol - getGlobalPromiseConstructorSymbolOrNil func() *ast.Symbol - getGlobalOmitSymbol func() *ast.Symbol - getGlobalIteratorType func() *Type - getGlobalIterableType func() *Type - getGlobalIterableTypeChecked func() *Type - getGlobalIterableIteratorType func() *Type - getGlobalIterableIteratorTypeChecked func() *Type - getGlobalIteratorObjectType func() *Type - getGlobalGeneratorType func() *Type - getGlobalAsyncIteratorType func() *Type - getGlobalAsyncIterableType func() *Type - getGlobalAsyncIterableIteratorType func() *Type - getGlobalAsyncIterableIteratorTypeChecked func() *Type - getGlobalAsyncIteratorObjectType func() *Type - getGlobalAsyncGeneratorType func() *Type - getGlobalIteratorYieldResultType func() *Type - getGlobalIteratorReturnResultType func() *Type - getGlobalTypedPropertyDescriptorType func() *Type - getGlobalClassDecoratorContextType func() *Type - getGlobalClassMethodDecoratorContextType func() *Type - getGlobalClassGetterDecoratorContextType func() *Type - getGlobalClassSetterDecoratorContextType func() *Type - getGlobalClassAccessorDecoratorContxtType func() *Type - getGlobalClassAccessorDecoratorTargetType func() *Type - getGlobalClassAccessorDecoratorResultType func() *Type - getGlobalClassFieldDecoratorContextType func() *Type - syncIterationTypesResolver *IterationTypesResolver - asyncIterationTypesResolver *IterationTypesResolver - isPrimitiveOrObjectOrEmptyType func(*Type) bool - containsMissingType func(*Type) bool - couldContainTypeVariables func(*Type) bool - isStringIndexSignatureOnlyType func(*Type) bool - markNodeAssignments func(*ast.Node) bool - emitResolver *emitResolver - emitResolverOnce sync.Once + id uint32 + program Program + host Host + compilerOptions *core.CompilerOptions + files []*ast.SourceFile + fileIndexMap map[*ast.SourceFile]int + compareSymbols func(*ast.Symbol, *ast.Symbol) int + TypeCount uint32 + SymbolCount uint32 + TotalInstantiationCount uint32 + instantiationCount uint32 + instantiationDepth uint32 + inlineLevel int + currentNode *ast.Node + varianceTypeParameter *Type + languageVersion core.ScriptTarget + moduleKind core.ModuleKind + isInferencePartiallyBlocked bool + legacyDecorators bool + emitStandardClassFields bool + allowSyntheticDefaultImports bool + strictNullChecks bool + strictFunctionTypes bool + strictBindCallApply bool + strictPropertyInitialization bool + strictBuiltinIteratorReturn bool + noImplicitAny bool + noImplicitThis bool + useUnknownInCatchVariables bool + exactOptionalPropertyTypes bool + canCollectSymbolAliasAccessibilityData bool + arrayVariances []VarianceFlags + globals ast.SymbolTable + globalSymbols []*ast.Symbol + evaluate evaluator.Evaluator + stringLiteralTypes map[string]*Type + numberLiteralTypes map[jsnum.Number]*Type + bigintLiteralTypes map[jsnum.PseudoBigInt]*Type + enumLiteralTypes map[EnumLiteralKey]*Type + indexedAccessTypes map[string]*Type + templateLiteralTypes map[string]*Type + stringMappingTypes map[StringMappingKey]*Type + uniqueESSymbolTypes map[*ast.Symbol]*Type + subtypeReductionCache map[string][]*Type + cachedTypes map[CachedTypeKey]*Type + cachedSignatures map[CachedSignatureKey]*Signature + undefinedProperties map[string]*ast.Symbol + narrowedTypes map[NarrowedTypeKey]*Type + assignmentReducedTypes map[AssignmentReducedKey]*Type + discriminatedContextualTypes map[DiscriminatedContextualTypeKey]*Type + instantiationExpressionTypes map[InstantiationExpressionKey]*Type + substitutionTypes map[SubstitutionTypeKey]*Type + reverseMappedCache map[ReverseMappedTypeKey]*Type + reverseHomomorphicMappedCache map[ReverseMappedTypeKey]*Type + iterationTypesCache map[IterationTypesKey]IterationTypes + markerTypes core.Set[*Type] + undefinedSymbol *ast.Symbol + argumentsSymbol *ast.Symbol + requireSymbol *ast.Symbol + unknownSymbol *ast.Symbol + resolvingSymbol *ast.Symbol + unresolvedSymbols map[string]*ast.Symbol + errorTypes map[string]*Type + globalThisSymbol *ast.Symbol + resolveName func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol + resolveNameForSymbolSuggestion func(location *ast.Node, name string, meaning ast.SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *ast.Symbol + tupleTypes map[string]*Type + unionTypes map[string]*Type + unionOfUnionTypes map[UnionOfUnionKey]*Type + intersectionTypes map[string]*Type + diagnostics ast.DiagnosticsCollection + suggestionDiagnostics ast.DiagnosticsCollection + symbolPool core.Pool[ast.Symbol] + signaturePool core.Pool[Signature] + indexInfoPool core.Pool[IndexInfo] + mergedSymbols map[*ast.Symbol]*ast.Symbol + factory ast.NodeFactory + nodeLinks core.LinkStore[*ast.Node, NodeLinks] + signatureLinks core.LinkStore[*ast.Node, SignatureLinks] + symbolNodeLinks core.LinkStore[*ast.Node, SymbolNodeLinks] + typeNodeLinks core.LinkStore[*ast.Node, TypeNodeLinks] + enumMemberLinks core.LinkStore[*ast.Node, EnumMemberLinks] + assertionLinks core.LinkStore[*ast.Node, AssertionLinks] + arrayLiteralLinks core.LinkStore[*ast.Node, ArrayLiteralLinks] + switchStatementLinks core.LinkStore[*ast.Node, SwitchStatementLinks] + jsxElementLinks core.LinkStore[*ast.Node, JsxElementLinks] + symbolReferenceLinks core.LinkStore[*ast.Symbol, SymbolReferenceLinks] + valueSymbolLinks core.LinkStore[*ast.Symbol, ValueSymbolLinks] + mappedSymbolLinks core.LinkStore[*ast.Symbol, MappedSymbolLinks] + deferredSymbolLinks core.LinkStore[*ast.Symbol, DeferredSymbolLinks] + aliasSymbolLinks core.LinkStore[*ast.Symbol, AliasSymbolLinks] + moduleSymbolLinks core.LinkStore[*ast.Symbol, ModuleSymbolLinks] + lateBoundLinks core.LinkStore[*ast.Symbol, LateBoundLinks] + exportTypeLinks core.LinkStore[*ast.Symbol, ExportTypeLinks] + membersAndExportsLinks core.LinkStore[*ast.Symbol, MembersAndExportsLinks] + typeAliasLinks core.LinkStore[*ast.Symbol, TypeAliasLinks] + declaredTypeLinks core.LinkStore[*ast.Symbol, DeclaredTypeLinks] + spreadLinks core.LinkStore[*ast.Symbol, SpreadLinks] + varianceLinks core.LinkStore[*ast.Symbol, VarianceLinks] + indexSymbolLinks core.LinkStore[*ast.Symbol, IndexSymbolLinks] + ReverseMappedSymbolLinks core.LinkStore[*ast.Symbol, ReverseMappedSymbolLinks] + markedAssignmentSymbolLinks core.LinkStore[*ast.Symbol, MarkedAssignmentSymbolLinks] + sourceFileLinks core.LinkStore[*ast.SourceFile, SourceFileLinks] + patternForType map[*Type]*ast.Node + contextFreeTypes map[*ast.Node]*Type + anyType *Type + autoType *Type + wildcardType *Type + blockedStringType *Type + errorType *Type + unresolvedType *Type + nonInferrableAnyType *Type + intrinsicMarkerType *Type + unknownType *Type + undefinedType *Type + undefinedWideningType *Type + missingType *Type + undefinedOrMissingType *Type + optionalType *Type + nullType *Type + nullWideningType *Type + stringType *Type + numberType *Type + bigintType *Type + regularFalseType *Type + falseType *Type + regularTrueType *Type + trueType *Type + booleanType *Type + esSymbolType *Type + voidType *Type + neverType *Type + silentNeverType *Type + implicitNeverType *Type + unreachableNeverType *Type + nonPrimitiveType *Type + stringOrNumberType *Type + stringNumberSymbolType *Type + numberOrBigIntType *Type + templateConstraintType *Type + numericStringType *Type + uniqueLiteralType *Type + uniqueLiteralMapper *TypeMapper + reliabilityFlags RelationComparisonResult + reportUnreliableMapper *TypeMapper + reportUnmeasurableMapper *TypeMapper + restrictiveMapper *TypeMapper + permissiveMapper *TypeMapper + emptyObjectType *Type + emptyJsxObjectType *Type + emptyTypeLiteralType *Type + unknownEmptyObjectType *Type + unknownUnionType *Type + emptyGenericType *Type + anyFunctionType *Type + noConstraintType *Type + circularConstraintType *Type + resolvingDefaultType *Type + markerSuperType *Type + markerSubType *Type + markerOtherType *Type + markerSuperTypeForCheck *Type + markerSubTypeForCheck *Type + noTypePredicate *TypePredicate + anySignature *Signature + unknownSignature *Signature + resolvingSignature *Signature + silentNeverSignature *Signature + enumNumberIndexInfo *IndexInfo + patternAmbientModules []*ast.PatternAmbientModule + patternAmbientModuleAugmentations ast.SymbolTable + globalObjectType *Type + globalFunctionType *Type + globalCallableFunctionType *Type + globalNewableFunctionType *Type + globalArrayType *Type + globalReadonlyArrayType *Type + globalStringType *Type + globalNumberType *Type + globalBooleanType *Type + globalRegExpType *Type + globalThisType *Type + anyArrayType *Type + autoArrayType *Type + anyReadonlyArrayType *Type + deferredGlobalImportMetaExpressionType *Type + contextualBindingPatterns []*ast.Node + emptyStringType *Type + zeroType *Type + zeroBigIntType *Type + typeofType *Type + typeResolutions []TypeResolution + resolutionStart int + inVarianceComputation bool + suggestionCount int + apparentArgumentCount *int + lastGetCombinedNodeFlagsNode *ast.Node + lastGetCombinedNodeFlagsResult ast.NodeFlags + lastGetCombinedModifierFlagsNode *ast.Node + lastGetCombinedModifierFlagsResult ast.ModifierFlags + freeinferenceState *InferenceState + freeFlowState *FlowState + flowLoopCache map[FlowLoopKey]*Type + flowLoopStack []FlowLoopInfo + sharedFlows []SharedFlow + antecedentTypes []*Type + flowAnalysisDisabled bool + flowInvocationCount int + flowTypeCache map[*ast.Node]*Type + lastFlowNode *ast.FlowNode + lastFlowNodeReachable bool + flowNodeReachable map[*ast.FlowNode]bool + flowNodePostSuper map[*ast.FlowNode]bool + renamedBindingElementsInTypes []*ast.Node + contextualInfos []ContextualInfo + inferenceContextInfos []InferenceContextInfo + awaitedTypeStack []*Type + reverseMappedSourceStack []*Type + reverseMappedTargetStack []*Type + reverseExpandingFlags ExpandingFlags + freeRelater *Relater + subtypeRelation *Relation + strictSubtypeRelation *Relation + assignableRelation *Relation + comparableRelation *Relation + identityRelation *Relation + enumRelation map[EnumRelationKey]RelationComparisonResult + getGlobalESSymbolType func() *Type + getGlobalBigIntType func() *Type + getGlobalImportMetaType func() *Type + getGlobalImportAttributesType func() *Type + getGlobalImportAttributesTypeChecked func() *Type + getGlobalNonNullableTypeAliasOrNil func() *ast.Symbol + getGlobalExtractSymbol func() *ast.Symbol + getGlobalDisposableType func() *Type + getGlobalAsyncDisposableType func() *Type + getGlobalAwaitedSymbol func() *ast.Symbol + getGlobalAwaitedSymbolOrNil func() *ast.Symbol + getGlobalNaNSymbolOrNil func() *ast.Symbol + getGlobalRecordSymbol func() *ast.Symbol + getGlobalTemplateStringsArrayType func() *Type + getGlobalESSymbolConstructorSymbolOrNil func() *ast.Symbol + getGlobalImportCallOptionsType func() *Type + getGlobalImportCallOptionsTypeChecked func() *Type + getGlobalPromiseType func() *Type + getGlobalPromiseTypeChecked func() *Type + getGlobalPromiseLikeType func() *Type + getGlobalPromiseConstructorSymbol func() *ast.Symbol + getGlobalPromiseConstructorSymbolOrNil func() *ast.Symbol + getGlobalOmitSymbol func() *ast.Symbol + getGlobalNoInferSymbolOrNil func() *ast.Symbol + getGlobalIteratorType func() *Type + getGlobalIterableType func() *Type + getGlobalIterableTypeChecked func() *Type + getGlobalIterableIteratorType func() *Type + getGlobalIterableIteratorTypeChecked func() *Type + getGlobalIteratorObjectType func() *Type + getGlobalGeneratorType func() *Type + getGlobalAsyncIteratorType func() *Type + getGlobalAsyncIterableType func() *Type + getGlobalAsyncIterableIteratorType func() *Type + getGlobalAsyncIterableIteratorTypeChecked func() *Type + getGlobalAsyncIteratorObjectType func() *Type + getGlobalAsyncGeneratorType func() *Type + getGlobalIteratorYieldResultType func() *Type + getGlobalIteratorReturnResultType func() *Type + getGlobalTypedPropertyDescriptorType func() *Type + getGlobalClassDecoratorContextType func() *Type + getGlobalClassMethodDecoratorContextType func() *Type + getGlobalClassGetterDecoratorContextType func() *Type + getGlobalClassSetterDecoratorContextType func() *Type + getGlobalClassAccessorDecoratorContxtType func() *Type + getGlobalClassAccessorDecoratorContextType func() *Type + getGlobalClassAccessorDecoratorTargetType func() *Type + getGlobalClassAccessorDecoratorResultType func() *Type + getGlobalClassFieldDecoratorContextType func() *Type + syncIterationTypesResolver *IterationTypesResolver + asyncIterationTypesResolver *IterationTypesResolver + isPrimitiveOrObjectOrEmptyType func(*Type) bool + containsMissingType func(*Type) bool + couldContainTypeVariables func(*Type) bool + isStringIndexSignatureOnlyType func(*Type) bool + markNodeAssignments func(*ast.Node) bool + emitResolver *emitResolver + emitResolverOnce sync.Once + _jsxNamespace string + _jsxFactoryEntity *ast.Node + skipDirectInferenceNodes core.Set[*ast.Node] } func NewChecker(program Program) *Checker { + program.BindSourceFiles() + c := &Checker{} c.id = nextCheckerID.Add(1) c.program = program @@ -831,10 +854,10 @@ func NewChecker(program Program) *Checker { c.canCollectSymbolAliasAccessibilityData = c.compilerOptions.VerbatimModuleSyntax.IsFalseOrUnknown() c.arrayVariances = []VarianceFlags{VarianceFlagsCovariant} c.globals = make(ast.SymbolTable, countGlobalSymbols(c.files)) - c.evaluate = createEvaluator(c.evaluateEntity) + c.evaluate = evaluator.NewEvaluator(c.evaluateEntity, ast.OEKParentheses) c.stringLiteralTypes = make(map[string]*Type) c.numberLiteralTypes = make(map[jsnum.Number]*Type) - c.bigintLiteralTypes = make(map[PseudoBigInt]*Type) + c.bigintLiteralTypes = make(map[jsnum.PseudoBigInt]*Type) c.enumLiteralTypes = make(map[EnumLiteralKey]*Type) c.indexedAccessTypes = make(map[string]*Type) c.templateLiteralTypes = make(map[string]*Type) @@ -849,7 +872,6 @@ func NewChecker(program Program) *Checker { c.discriminatedContextualTypes = make(map[DiscriminatedContextualTypeKey]*Type) c.instantiationExpressionTypes = make(map[InstantiationExpressionKey]*Type) c.substitutionTypes = make(map[SubstitutionTypeKey]*Type) - c.identifierSymbols = make(map[*ast.Node]*ast.Symbol) c.reverseMappedCache = make(map[ReverseMappedTypeKey]*Type) c.reverseHomomorphicMappedCache = make(map[ReverseMappedTypeKey]*Type) c.iterationTypesCache = make(map[IterationTypesKey]IterationTypes) @@ -878,7 +900,7 @@ func NewChecker(program Program) *Checker { c.autoType = c.newIntrinsicTypeEx(TypeFlagsAny, "any", ObjectFlagsNonInferrableType) c.wildcardType = c.newIntrinsicType(TypeFlagsAny, "any") c.blockedStringType = c.newIntrinsicType(TypeFlagsAny, "any") - c.errorType = c.newIntrinsicType(TypeFlagsAny, "error") + c.errorType = c.newIntrinsicType(TypeFlagsAny, "any") c.unresolvedType = c.newIntrinsicType(TypeFlagsAny, "unresolved") c.nonInferrableAnyType = c.newIntrinsicTypeEx(TypeFlagsAny, "any", ObjectFlagsContainsWideningType) c.intrinsicMarkerType = c.newIntrinsicType(TypeFlagsAny, "intrinsic") @@ -921,6 +943,7 @@ func NewChecker(program Program) *Checker { c.restrictiveMapper = newFunctionTypeMapper(c.restrictiveMapperWorker) c.permissiveMapper = newFunctionTypeMapper(c.permissiveMapperWorker) c.emptyObjectType = c.newAnonymousType(nil /*symbol*/, nil, nil, nil, nil) + c.emptyJsxObjectType = c.newAnonymousType(nil /*symbol*/, nil, nil, nil, nil) c.emptyTypeLiteralType = c.newAnonymousType(c.newSymbol(ast.SymbolFlagsTypeLiteral, ast.InternalSymbolNameType), nil, nil, nil, nil) c.unknownEmptyObjectType = c.newAnonymousType(nil /*symbol*/, nil, nil, nil, nil) c.unknownUnionType = c.createUnknownUnionType() @@ -946,7 +969,7 @@ func NewChecker(program Program) *Checker { c.enumNumberIndexInfo = &IndexInfo{keyType: c.numberType, valueType: c.stringType, isReadonly: true} c.emptyStringType = c.getStringLiteralType("") c.zeroType = c.getNumberLiteralType(0) - c.zeroBigIntType = c.getBigIntLiteralType(PseudoBigInt{negative: false, base10Value: "0"}) + c.zeroBigIntType = c.getBigIntLiteralType(jsnum.PseudoBigInt{}) c.typeofType = c.getUnionType(core.Map(slices.Sorted(maps.Keys(typeofNEFacts)), c.getStringLiteralType)) c.flowLoopCache = make(map[FlowLoopKey]*Type) c.flowNodeReachable = make(map[*ast.FlowNode]bool) @@ -980,6 +1003,7 @@ func NewChecker(program Program) *Checker { c.getGlobalPromiseConstructorSymbol = c.getGlobalValueSymbolResolver("Promise", true /*reportErrors*/) c.getGlobalPromiseConstructorSymbolOrNil = c.getGlobalValueSymbolResolver("Promise", false /*reportErrors*/) c.getGlobalOmitSymbol = c.getGlobalTypeAliasResolver("Omit", 2 /*arity*/, true /*reportErrors*/) + c.getGlobalNoInferSymbolOrNil = c.getGlobalTypeAliasResolver("NoInfer", 1 /*arity*/, false /*reportErrors*/) c.getGlobalIteratorType = c.getGlobalTypeResolver("Iterator", 3 /*arity*/, false /*reportErrors*/) c.getGlobalIterableType = c.getGlobalTypeResolver("Iterable", 3 /*arity*/, false /*reportErrors*/) c.getGlobalIterableTypeChecked = c.getGlobalTypeResolver("Iterable", 3 /*arity*/, true /*reportErrors*/) @@ -1000,7 +1024,7 @@ func NewChecker(program Program) *Checker { c.getGlobalClassMethodDecoratorContextType = c.getGlobalTypeResolver("ClassMethodDecoratorContext", 2 /*arity*/, true /*reportErrors*/) c.getGlobalClassGetterDecoratorContextType = c.getGlobalTypeResolver("ClassGetterDecoratorContext", 2 /*arity*/, true /*reportErrors*/) c.getGlobalClassSetterDecoratorContextType = c.getGlobalTypeResolver("ClassSetterDecoratorContext", 2 /*arity*/, true /*reportErrors*/) - c.getGlobalClassAccessorDecoratorContxtType = c.getGlobalTypeResolver("ClassAccessorDecoratorContext", 2 /*arity*/, true /*reportErrors*/) + c.getGlobalClassAccessorDecoratorContextType = c.getGlobalTypeResolver("ClassAccessorDecoratorContext", 2 /*arity*/, true /*reportErrors*/) c.getGlobalClassAccessorDecoratorTargetType = c.getGlobalTypeResolver("ClassAccessorDecoratorTarget", 2 /*arity*/, true /*reportErrors*/) c.getGlobalClassAccessorDecoratorResultType = c.getGlobalTypeResolver("ClassAccessorDecoratorResult", 2 /*arity*/, true /*reportErrors*/) c.getGlobalClassFieldDecoratorContextType = c.getGlobalTypeResolver("ClassFieldDecoratorContext", 2 /*arity*/, true /*reportErrors*/) @@ -1021,7 +1045,7 @@ func createFileIndexMap(files []*ast.SourceFile) map[*ast.SourceFile]int { func countGlobalSymbols(files []*ast.SourceFile) int { count := 0 for _, file := range files { - if !ast.IsExternalOrCommonJsModule(file) { + if !ast.IsExternalOrCommonJSModule(file) { count += len(file.Locals) } } @@ -1133,7 +1157,7 @@ func (c *Checker) getGlobalSymbol(name string, meaning ast.SymbolFlags, diagnost func (c *Checker) initializeClosures() { c.isPrimitiveOrObjectOrEmptyType = func(t *Type) bool { - return t.flags&(TypeFlagsPrimitive|TypeFlagsNonPrimitive) != 0 || c.isEmptyAnonymousObjectType(t) + return t.flags&(TypeFlagsPrimitive|TypeFlagsNonPrimitive) != 0 || c.IsEmptyAnonymousObjectType(t) } c.containsMissingType = func(t *Type) bool { return t == c.missingType || t.flags&TypeFlagsUnion != 0 && t.Types()[0] == c.missingType @@ -1179,11 +1203,10 @@ func (c *Checker) initializeIterationResolvers() { } func (c *Checker) initializeChecker() { - c.program.BindSourceFiles() // Initialize global symbol table augmentations := make([][]*ast.Node, 0, len(c.files)) for _, file := range c.files { - if !ast.IsExternalOrCommonJsModule(file) { + if !ast.IsExternalOrCommonJSModule(file) { c.mergeSymbolTable(c.globals, file.Locals, false, nil) } c.patternAmbientModules = append(c.patternAmbientModules, file.PatternAmbientModules...) @@ -1234,7 +1257,7 @@ func (c *Checker) initializeChecker() { c.autoArrayType = c.newAnonymousType(nil, nil, nil, nil, nil) } c.globalReadonlyArrayType = c.getGlobalType("ReadonlyArray", 1 /*arity*/, false /*reportErrors*/) - if c.globalReadonlyArrayType == nil { + if c.globalReadonlyArrayType == c.emptyGenericType { c.globalReadonlyArrayType = c.globalArrayType } c.anyReadonlyArrayType = c.createTypeFromGenericGlobalType(c.globalReadonlyArrayType, []*Type{c.anyType}) @@ -1280,7 +1303,7 @@ func (c *Checker) mergeModuleAugmentation(moduleName *ast.Node) { // the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you // all the exports both from the pattern and from the augmentation, but // 'getMergedSymbol()' on *.foo only gives you exports from *.foo. - if core.Some(c.patternAmbientModules, func(module ast.PatternAmbientModule) bool { + if core.Some(c.patternAmbientModules, func(module *ast.PatternAmbientModule) bool { return mainModule == module.Symbol }) { merged := c.mergeSymbol(moduleAugmentation.Symbol, mainModule, true /*unidirectional*/) @@ -1326,6 +1349,8 @@ func (c *Checker) createNameResolver() *binder.NameResolver { Error: c.error, Globals: c.globals, ArgumentsSymbol: c.argumentsSymbol, + RequireSymbol: c.requireSymbol, + GetModuleSymbol: c.getModuleSymbol, Lookup: c.getSymbol, SymbolReferenced: c.symbolReferenced, SetRequiresScopeChangeCache: c.setRequiresScopeChangeCache, @@ -1343,6 +1368,8 @@ func (c *Checker) createNameResolverForSuggestion() *binder.NameResolver { Error: c.error, Globals: c.globals, ArgumentsSymbol: c.argumentsSymbol, + RequireSymbol: c.requireSymbol, + GetModuleSymbol: c.getModuleSymbol, Lookup: c.getSuggestionForSymbolNameLookup, SymbolReferenced: c.symbolReferenced, SetRequiresScopeChangeCache: c.setRequiresScopeChangeCache, @@ -1350,6 +1377,12 @@ func (c *Checker) createNameResolverForSuggestion() *binder.NameResolver { } } +func (c *Checker) getModuleSymbol(sourceFile *ast.Node) *ast.Symbol { + result := c.newSymbol(ast.SymbolFlagsModuleExports|ast.SymbolFlagsFunctionScopedVariable, ast.InternalSymbolNameModuleExports) + result.ValueDeclaration = sourceFile + return result +} + func (c *Checker) symbolReferenced(symbol *ast.Symbol, meaning ast.SymbolFlags) { c.symbolReferenceLinks.Get(symbol).referenceKinds |= meaning } @@ -1384,7 +1417,7 @@ func (c *Checker) checkAndReportErrorForInvalidInitializer(errorLocation *ast.No } func (c *Checker) checkAndReportErrorForMissingPrefix(errorLocation *ast.Node, name string) bool { - if !ast.IsIdentifier(errorLocation) || errorLocation.Text() != name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation) { + if !ast.IsIdentifier(errorLocation) || errorLocation.Text() != name || isTypeReferenceIdentifier(errorLocation) || IsInTypeQuery(errorLocation) { return false } container := c.getThisContainer(errorLocation, false /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/) @@ -1591,17 +1624,14 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name return symbol } allSymbols := slices.Collect(maps.Values(symbols)) - c.sortSymbols(allSymbols) if meaning&ast.SymbolFlagsGlobalLookup != 0 { - allSymbols = slices.Concat([]*ast.Symbol{ - c.newSymbol(ast.SymbolFlagsTypeAlias, "string"), - c.newSymbol(ast.SymbolFlagsTypeAlias, "number"), - c.newSymbol(ast.SymbolFlagsTypeAlias, "boolean"), - c.newSymbol(ast.SymbolFlagsTypeAlias, "object"), - c.newSymbol(ast.SymbolFlagsTypeAlias, "bigint"), - c.newSymbol(ast.SymbolFlagsTypeAlias, "symbol"), - }, allSymbols) + for _, s := range []string{"stringString", "numberNumber", "booleanBoolean", "objectObject", "bigintBigInt", "symbolSymbol"} { + if _, ok := symbols[s[len(s)/2:]]; ok { + allSymbols = append(allSymbols, c.newSymbol(ast.SymbolFlagsTypeAlias, s[:len(s)/2])) + } + } } + c.sortSymbols(allSymbols) return c.getSpellingSuggestionForName(name, allSymbols, meaning) } @@ -1640,7 +1670,7 @@ func (c *Checker) getSpellingSuggestionForName(name string, symbols []*ast.Symbo func (c *Checker) onSuccessfullyResolvedSymbol(errorLocation *ast.Node, result *ast.Symbol, meaning ast.SymbolFlags, lastLocation *ast.Node, associatedDeclarationForContainingInitializerOrBindingName *ast.Node, withinDeferredContext bool) { name := result.Name - isInExternalModule := lastLocation != nil && ast.IsSourceFile(lastLocation) && ast.IsExternalOrCommonJsModule(lastLocation.AsSourceFile()) + isInExternalModule := lastLocation != nil && ast.IsSourceFile(lastLocation) && ast.IsExternalOrCommonJSModule(lastLocation.AsSourceFile()) // Only check for block-scoped variable if we have an error location and are looking for the // name with variable meaning // For example, @@ -1699,7 +1729,7 @@ func (c *Checker) onSuccessfullyResolvedSymbol(errorLocation *ast.Node, result * importDecl := core.Find(nonValueSymbol.Declarations, func(d *ast.Node) bool { return ast.NodeKindIs(d, ast.KindImportSpecifier, ast.KindImportClause, ast.KindNamespaceImport, ast.KindImportEqualsDeclaration) }) - if importDecl != nil && !isTypeOnlyImportDeclaration(importDecl) { + if importDecl != nil && !ast.IsTypeOnlyImportDeclaration(importDecl) { c.error(importDecl, diagnostics.Import_0_conflicts_with_global_value_used_in_this_file_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, name) } } @@ -1745,7 +1775,7 @@ func (c *Checker) isBlockScopedNameDeclaredBeforeUse(declaration *ast.Node, usag useFile := ast.GetSourceFileOfNode(usage) declContainer := ast.GetEnclosingBlockScopeContainer(declaration) if declarationFile != useFile { - if (c.moduleKind != core.ModuleKindNone && (declarationFile.ExternalModuleIndicator != nil || useFile.ExternalModuleIndicator != nil)) || c.compilerOptions.OutFile == "" || isInTypeQuery(usage) || declaration.Flags&ast.NodeFlagsAmbient != 0 { + if (c.moduleKind != core.ModuleKindNone && (declarationFile.ExternalModuleIndicator != nil || useFile.ExternalModuleIndicator != nil)) || c.compilerOptions.OutFile == "" || IsInTypeQuery(usage) || declaration.Flags&ast.NodeFlagsAmbient != 0 { // nodes are in different files and order cannot be determined return true } @@ -1758,7 +1788,7 @@ func (c *Checker) isBlockScopedNameDeclaredBeforeUse(declaration *ast.Node, usag return slices.Index(sourceFiles, declarationFile) <= slices.Index(sourceFiles, useFile) } // deferred usage in a type context is always OK regardless of the usage position: - if usage.Flags&ast.NodeFlagsJSDoc != 0 || isInTypeQuery(usage) || c.isInAmbientOrTypeNode(usage) { + if usage.Flags&ast.NodeFlagsJSDoc != 0 || IsInTypeQuery(usage) || c.isInAmbientOrTypeNode(usage) { return true } if declaration.Pos() <= usage.Pos() && !(ast.IsPropertyDeclaration(declaration) && isThisProperty(usage.Parent) && declaration.Initializer() == nil && !isExclamationToken(declaration.AsPropertyDeclaration().PostfixToken)) { @@ -2016,7 +2046,7 @@ func (c *Checker) getSymbol(symbols ast.SymbolTable, name string, meaning ast.Sy } func (c *Checker) CheckSourceFile(sourceFile *ast.SourceFile) { - if skipTypeChecking(sourceFile, c.compilerOptions) { + if SkipTypeChecking(sourceFile, c.compilerOptions) { return } c.checkSourceFile(sourceFile) @@ -2031,7 +2061,8 @@ func (c *Checker) checkSourceFile(sourceFile *ast.SourceFile) { c.checkSourceElements(sourceFile.Statements.Nodes) c.checkDeferredNodes(sourceFile) c.checkJSDocNodes(sourceFile) - if ast.IsExternalOrCommonJsModule(sourceFile) { + if ast.IsExternalOrCommonJSModule(sourceFile) { + c.checkExternalModuleExports(sourceFile.AsNode()) c.registerForUnusedIdentifiersCheck(sourceFile.AsNode()) } // This relies on the results of other lazy diagnostics, so must be computed after them @@ -2166,10 +2197,12 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) { c.checkClassDeclaration(node) case ast.KindInterfaceDeclaration: c.checkInterfaceDeclaration(node) - case ast.KindTypeAliasDeclaration: + case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration: c.checkTypeAliasDeclaration(node) case ast.KindEnumDeclaration: c.checkEnumDeclaration(node) + case ast.KindEnumMember: + c.checkEnumMember(node) case ast.KindModuleDeclaration: c.checkModuleDeclaration(node) case ast.KindImportDeclaration: @@ -2178,7 +2211,7 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) { c.checkImportEqualsDeclaration(node) case ast.KindExportDeclaration: c.checkExportDeclaration(node) - case ast.KindExportAssignment: + case ast.KindExportAssignment, ast.KindJSExportAssignment: c.checkExportAssignment(node) case ast.KindEmptyStatement: c.checkGrammarStatementInAmbientContext(node) @@ -2186,6 +2219,8 @@ func (c *Checker) checkSourceElementWorker(node *ast.Node) { c.checkGrammarStatementInAmbientContext(node) case ast.KindMissingDeclaration: c.checkMissingDeclaration(node) + case ast.KindJSDocNonNullableType, ast.KindJSDocNullableType, ast.KindJSDocAllType, ast.KindJSDocTypeLiteral: + c.checkJSDocType(node) } } @@ -2304,6 +2339,30 @@ func (c *Checker) resolveJSDocMemberName(name *ast.Node, location *ast.Node) *as return nil } +func (c *Checker) checkJSDocType(node *ast.Node) { + c.checkJSDocTypeIsInJsFile(node) + node.ForEachChild(c.checkSourceElement) +} + +func (c *Checker) checkJSDocTypeIsInJsFile(node *ast.Node) { + if !ast.IsInJSFile(node) { + if ast.IsJSDocNonNullableType(node) || ast.IsJSDocNullableType(node) { + token := core.IfElse(ast.IsJSDocNonNullableType(node), "!", "?") + postfix := node.Pos() == node.Type().Pos() + message := core.IfElse(postfix, + diagnostics.X_0_at_the_end_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1, + diagnostics.X_0_at_the_start_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1) + t := c.getTypeFromTypeNode(node.Type()) + if ast.IsJSDocNullableType(node) && t != c.neverType && t != c.voidType { + t = c.getNullableType(t, core.IfElse(postfix, TypeFlagsUndefined, TypeFlagsNullable)) + } + c.grammarErrorOnNode(node, message, token, c.TypeToString(t)) + } else { + c.grammarErrorOnNode(node, diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments) + } + } +} + func (c *Checker) checkTypeParameter(node *ast.Node) { // Grammar Checking c.checkGrammarModifiers(node) @@ -2329,12 +2388,12 @@ func (c *Checker) checkTypeParameter(node *ast.Node) { } func (c *Checker) checkTypeParameterDeferred(node *ast.Node) { - if ast.IsInterfaceDeclaration(node.Parent) || ast.IsClassLike(node.Parent) || ast.IsTypeAliasDeclaration(node.Parent) { + if ast.IsInterfaceDeclaration(node.Parent) || ast.IsClassLike(node.Parent) || ast.IsTypeOrJSTypeAliasDeclaration(node.Parent) { typeParameter := c.getDeclaredTypeOfTypeParameter(c.getSymbolOfDeclaration(node)) modifiers := c.getTypeParameterModifiers(typeParameter) & (ast.ModifierFlagsIn | ast.ModifierFlagsOut) if modifiers != 0 { symbol := c.getSymbolOfDeclaration(node.Parent) - if ast.IsTypeAliasDeclaration(node.Parent) && c.getDeclaredTypeOfSymbol(symbol).objectFlags&(ObjectFlagsAnonymous|ObjectFlagsMapped) == 0 { + if ast.IsTypeOrJSTypeAliasDeclaration(node.Parent) && c.getDeclaredTypeOfSymbol(symbol).objectFlags&(ObjectFlagsAnonymous|ObjectFlagsMapped) == 0 { c.error(node, diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types) } else if modifiers == ast.ModifierFlagsIn || modifiers == ast.ModifierFlagsOut { source := c.createMarkerType(symbol, typeParameter, core.IfElse(modifiers == ast.ModifierFlagsOut, c.markerSubTypeForCheck, c.markerSuperTypeForCheck)) @@ -2462,7 +2521,6 @@ func (c *Checker) checkSignatureDeclaration(node *ast.Node) { // that in turn supplies a `resolve` function as one of its arguments and results in an // object with a callable `then` signature. func (c *Checker) checkAsyncFunctionReturnType(node *ast.Node, returnTypeNode *ast.Node) { - // !!! Possibly error if c.languageVersion < core.ScriptTargetES2015 returnType := c.getTypeFromTypeNode(returnTypeNode) if c.isErrorType(returnType) { return @@ -2645,8 +2703,8 @@ func (c *Checker) checkAccessorDeclaration(node *ast.Node) { setter := ast.GetDeclarationOfKind(symbol, ast.KindSetAccessor) if getter != nil && setter != nil && c.nodeLinks.Get(getter).flags&NodeCheckFlagsTypeChecked == 0 { c.nodeLinks.Get(getter).flags |= NodeCheckFlagsTypeChecked - getterFlags := getEffectiveModifierFlags(getter) - setterFlags := getEffectiveModifierFlags(setter) + getterFlags := getter.ModifierFlags() + setterFlags := setter.ModifierFlags() if (getterFlags & ast.ModifierFlagsAbstract) != (setterFlags & ast.ModifierFlagsAbstract) { c.error(getter.Name(), diagnostics.Accessors_must_both_be_abstract_or_non_abstract) c.error(setter.Name(), diagnostics.Accessors_must_both_be_abstract_or_non_abstract) @@ -2672,7 +2730,7 @@ func (c *Checker) checkTypeReferenceNode(node *ast.Node) { // If there was a token between the type name and the type arguments, check if it was a DotToken sourceFile := ast.GetSourceFileOfNode(node) if scanner.ScanTokenAtPosition(sourceFile, data.TypeName.End()) == ast.KindDotToken { - c.grammarErrorAtPos(node, scanner.SkipTrivia(sourceFile.Text, data.TypeName.End()), 1, diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments) + c.grammarErrorAtPos(node, scanner.SkipTrivia(sourceFile.Text(), data.TypeName.End()), 1, diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments) } } } @@ -2689,7 +2747,7 @@ func (c *Checker) checkTypeReferenceOrImport(node *ast.Node) { c.checkTypeArgumentConstraints(node, typeParameters) } } - symbol := c.typeNodeLinks.Get(node).resolvedSymbol + symbol := c.getResolvedSymbolOrNil(node) if symbol != nil { if core.Some(symbol.Declarations, func(d *ast.Node) bool { return isTypeDeclaration(d) && d.Flags&ast.NodeFlagsDeprecated != 0 }) { c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), symbol.Declarations, symbol.Name) @@ -2864,7 +2922,7 @@ func (c *Checker) checkObjectTypeForDuplicateDeclarations(node *ast.Node, checkP } // When a property has multiple declarations, check that only one of those declarations is in this object // type declaration (multiple merged object types are permitted to each declare the same property). - if ast.IsPropertyDeclaration(member) || ast.IsPropertySignatureDeclaration(member) { + if ast.IsPropertyDeclaration(member) && !ast.HasAccessorModifier(member) || ast.IsPropertySignatureDeclaration(member) { checkProperty(symbol, isStatic) } // Check that each private identifier is used only for instance members or only for static members. It is an @@ -3125,7 +3183,7 @@ func (c *Checker) checkFunctionOrMethodDeclaration(node *ast.Node) { if node.Type() == nil { // Report an implicit any error if there is no body, no explicit return type, and node is not a private method // in an ambient context - if ast.NodeIsMissing(body) && isPrivateWithinAmbient(node) { + if ast.NodeIsMissing(body) && !isPrivateWithinAmbient(node) { c.reportImplicitAny(node, c.anyType, WideningKindNormal) } if functionFlags&FunctionFlagsGenerator != 0 && ast.NodeIsPresent(body) { @@ -3375,7 +3433,7 @@ func (c *Checker) getEffectiveDeclarationFlags(n *ast.Node, flagsToCheck ast.Mod // because those flags have no useful semantics there. if !ast.IsInterfaceDeclaration(n.Parent) && !ast.IsClassDeclaration(n.Parent) && !ast.IsClassExpression(n.Parent) && n.Flags&ast.NodeFlagsAmbient != 0 { container := getEnclosingContainer(n) - if container != nil && container.Flags&ast.NodeFlagsExportContext != 0 && flags&ast.ModifierFlagsAmbient == 0 && !(ast.IsModuleBlock(n.Parent) && ast.IsModuleDeclaration(n.Parent.Parent) && ast.IsGlobalScopeAugmentation(n.Parent.Parent)) { + if container != nil && container.Flags&ast.NodeFlagsExportContext != 0 && flags&ast.ModifierFlagsAmbient == 0 && !(ast.IsModuleBlock(n.Parent) && ast.IsGlobalScopeAugmentation(n.Parent.Parent)) { // It is nested in an ambient export context, which means it is automatically exported flags |= ast.ModifierFlagsExport } @@ -3506,9 +3564,9 @@ func (c *Checker) checkTestingKnownTruthyType(condExpr *ast.Node, condType *Type if location != condExpr { t = c.checkExpression(location) } - if t.flags&TypeFlagsEnumLiteral != 0 && ast.IsPropertyAccessExpression(location) && core.OrElse(c.typeNodeLinks.Get(location.Expression()).resolvedSymbol, c.unknownSymbol).Flags&ast.SymbolFlagsEnum != 0 { + if t.flags&TypeFlagsEnumLiteral != 0 && ast.IsPropertyAccessExpression(location) && core.OrElse(c.getResolvedSymbolOrNil(location.Expression()), c.unknownSymbol).Flags&ast.SymbolFlagsEnum != 0 { // EnumLiteral type at condition with known value is always truthy or always falsy, likely an error - c.error(location, diagnostics.This_condition_will_always_return_0, anyToString(t.AsLiteralType().value)) + c.error(location, diagnostics.This_condition_will_always_return_0, core.IfElse(evaluator.IsTruthy(t.AsLiteralType().value), "true", "false")) return } isPropertyExpressionCast := ast.IsPropertyAccessExpression(location) && isTypeAssertion(location.Expression()) @@ -4086,8 +4144,8 @@ func (c *Checker) checkBaseTypeAccessibility(t *Type, node *ast.Node) { signatures := c.getSignaturesOfType(t, SignatureKindConstruct) if len(signatures) != 0 { declaration := signatures[0].declaration - if declaration != nil && hasEffectiveModifier(declaration, ast.ModifierFlagsPrivate) { - typeClassDeclaration := getClassLikeDeclarationOfSymbol(t.symbol) + if declaration != nil && hasModifier(declaration, ast.ModifierFlagsPrivate) { + typeClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(t.symbol) if !c.isNodeWithinClass(node, typeClassDeclaration) { c.error(node, diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, c.getFullyQualifiedName(t.symbol, nil)) } @@ -4180,7 +4238,7 @@ basePropertyCheck: // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - derivedClassDecl := getClassLikeDeclarationOfSymbol(t.symbol) + derivedClassDecl := ast.GetClassLikeDeclarationOfSymbol(t.symbol) if derivedClassDecl == nil || !ast.HasSyntacticModifier(derivedClassDecl, ast.ModifierFlagsAbstract) { // Searches other base types for a declaration that would satisfy the inherited abstract member. // (The class may have more than one base type via declaration merging with an interface with the @@ -4241,7 +4299,7 @@ basePropertyCheck: if uninitialized != nil && derived.Flags&ast.SymbolFlagsTransient == 0 && baseDeclarationFlags&ast.ModifierFlagsAbstract == 0 && derivedDeclarationFlags&ast.ModifierFlagsAbstract == 0 && !core.Some(derived.Declarations, func(d *ast.Node) bool { return d.Flags&ast.NodeFlagsAmbient != 0 }) { - constructor := ast.FindConstructorDeclaration(getClassLikeDeclarationOfSymbol(t.symbol)) + constructor := ast.FindConstructorDeclaration(ast.GetClassLikeDeclarationOfSymbol(t.symbol)) propName := uninitialized.Name() if isExclamationToken(uninitialized.AsPropertyDeclaration().PostfixToken) || constructor == nil || !ast.IsIdentifier(propName) || !c.strictNullChecks || !c.isPropertyInitializedInConstructor(propName, t, constructor) { errorMessage := diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration @@ -4269,7 +4327,7 @@ basePropertyCheck: for errorNode, memberInfo := range notImplementedInfo { switch { case len(memberInfo.missedProperties) == 1: - missedProperty := "'" + memberInfo.missedProperties[0] + "'" + missedProperty := memberInfo.missedProperties[0] if ast.IsClassExpression(errorNode) { c.error(errorNode, diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, missedProperty, memberInfo.baseTypeName) } else { @@ -4536,7 +4594,7 @@ func (c *Checker) checkPropertyInitialization(node *ast.Node) { } constructor := ast.FindConstructorDeclaration(node) for _, member := range node.Members() { - if getEffectiveModifierFlags(member)&ast.ModifierFlagsAmbient != 0 { + if member.ModifierFlags()&ast.ModifierFlagsAmbient != 0 { continue } if !ast.IsStatic(member) && c.isPropertyWithoutInitializer(member) { @@ -4710,6 +4768,15 @@ func (c *Checker) checkEnumDeclaration(node *ast.Node) { } } +func (c *Checker) checkEnumMember(node *ast.Node) { + if ast.IsPrivateIdentifier(node.Name()) { + c.error(node, diagnostics.An_enum_member_cannot_be_named_with_a_private_identifier) + } + if node.Initializer() != nil { + c.checkExpression(node.Initializer()) + } +} + func (c *Checker) checkModuleDeclaration(node *ast.Node) { if body := node.Body(); body != nil { c.checkSourceElement(body) @@ -4737,7 +4804,7 @@ func (c *Checker) checkModuleDeclaration(node *ast.Node) { } if ast.IsIdentifier(node.Name()) { c.checkCollisionsForDeclarationName(node, node.Name()) - if node.Flags&(ast.NodeFlagsNamespace|ast.NodeFlagsGlobalAugmentation) == 0 { + if node.AsModuleDeclaration().Keyword == ast.KindModuleKeyword { tokenRange := getNonModifierTokenRangeOfNode(node) c.suggestionDiagnostics.Add(ast.NewDiagnostic(ast.GetSourceFileOfNode(node), tokenRange, diagnostics.A_namespace_declaration_should_not_be_declared_using_the_module_keyword_Please_use_the_namespace_keyword_instead)) } @@ -4768,7 +4835,7 @@ func (c *Checker) checkModuleDeclaration(node *ast.Node) { } } if isAmbientExternalModule { - if isExternalModuleAugmentation(node) { + if ast.IsExternalModuleAugmentation(node) { // body of the augmentation should be checked for consistency only if augmentation was applied to its target (either global scope or module) // otherwise we'll be swamped in cascading errors. // We can detect if augmentation was applied using following rules: @@ -4823,7 +4890,7 @@ func (c *Checker) checkModuleAugmentationElement(node *ast.Node) { for _, decl := range node.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes { c.checkModuleAugmentationElement(decl) } - case ast.KindExportAssignment, ast.KindExportDeclaration: + case ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindExportDeclaration: c.grammarErrorOnFirstToken(node, diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations) case ast.KindImportEqualsDeclaration: // import a = e.x; in module augmentation is ok, but not import a = require('fs) @@ -4971,7 +5038,7 @@ func (c *Checker) checkImportAttributes(declaration *ast.Node) { if importAttributesType != c.emptyObjectType { c.checkTypeAssignableTo(c.getTypeFromImportAttributes(node), c.getNullableType(importAttributesType, TypeFlagsUndefined), node, nil) } - isTypeOnly := isTypeOnlyImportOrExportDeclaration(declaration) + isTypeOnly := isExclusivelyTypeOnlyImportOrExport(declaration) override := c.getResolutionModeOverride(node.AsImportAttributes(), isTypeOnly) isImportAttributes := node.AsImportAttributes().Token == ast.KindWithKeyword if isTypeOnly && override != core.ResolutionModeNone { @@ -5009,6 +5076,22 @@ func (c *Checker) checkImportAttributes(declaration *ast.Node) { } } +func isExclusivelyTypeOnlyImportOrExport(node *ast.Node) bool { + switch node.Kind { + case ast.KindExportDeclaration: + return node.AsExportDeclaration().IsTypeOnly + case ast.KindImportDeclaration: + if importClause := node.AsImportDeclaration().ImportClause; importClause != nil { + return importClause.AsImportClause().IsTypeOnly + } + case ast.KindJSDocImportTag: + if importClause := node.AsJSDocImportTag().ImportClause; importClause != nil { + return importClause.AsImportClause().IsTypeOnly + } + } + return false +} + func (c *Checker) getTypeFromImportAttributes(node *ast.Node) *Type { links := c.typeNodeLinks.Get(node) if links.resolvedType == nil { @@ -5128,8 +5211,7 @@ func (c *Checker) checkExportSpecifier(node *ast.Node) { } func (c *Checker) checkExportAssignment(node *ast.Node) { - exportAssignment := node.AsExportAssignment() - isExportEquals := exportAssignment.IsExportEquals + isExportEquals := ast.IsJSExportAssignment(node) || node.AsExportAssignment().IsExportEquals illegalContextMessage := core.IfElse(isExportEquals, diagnostics.An_export_assignment_must_be_at_the_top_level_of_a_file_or_module_declaration, diagnostics.A_default_export_must_be_at_the_top_level_of_a_file_or_module_declaration) @@ -5149,7 +5231,7 @@ func (c *Checker) checkExportAssignment(node *ast.Node) { } return } - if !c.checkGrammarModifiers(node) && exportAssignment.Modifiers() != nil { + if !c.checkGrammarModifiers(node) && ast.IsExportAssignment(node) && node.AsExportAssignment().Modifiers() != nil { c.grammarErrorOnFirstToken(node, diagnostics.An_export_assignment_cannot_have_modifiers) } isIllegalExportDefaultInCJS := !isExportEquals && node.Flags&ast.NodeFlagsAmbient == 0 && c.compilerOptions.VerbatimModuleSyntax.IsTrue() && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node)) == core.ModuleKindCommonJS @@ -5238,12 +5320,12 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { // Checks for export * conflicts for id, symbol := range c.getExportsOfModule(moduleSymbol) { if id == ast.InternalSymbolNameExportStar { - return + continue } // ECMA262: 15.2.1.1 It is a Syntax Error if the ExportedNames of ModuleItemList contains any duplicate entries. // (TS Exceptions: namespaces, function overloads, enums, and interfaces) if symbol.Flags&(ast.SymbolFlagsNamespace|ast.SymbolFlagsEnum) != 0 { - return + continue } exportedDeclarationsCount := core.CountWhere(symbol.Declarations, func(d *ast.Node) bool { return isNotOverload(d) && !ast.IsAccessor(d) && !ast.IsInterfaceDeclaration(d) @@ -5251,7 +5333,7 @@ func (c *Checker) checkExternalModuleExports(node *ast.Node) { if symbol.Flags&ast.SymbolFlagsTypeAlias != 0 && exportedDeclarationsCount <= 2 { // it is legal to merge type alias with other values // so count should be either 1 (just type alias) or 2 (type alias + merged value) - return + continue } if exportedDeclarationsCount > 1 { for _, declaration := range symbol.Declarations { @@ -5279,7 +5361,7 @@ func isNotOverload(node *ast.Node) bool { } func (c *Checker) collectLinkedAliases(node *ast.Node, setVisibility bool) { - // !!! + // !!! Implement if declaration emit needs it } func (c *Checker) checkMissingDeclaration(node *ast.Node) { @@ -5398,7 +5480,7 @@ func (c *Checker) checkVariableLikeDeclaration(node *ast.Node) { } // For a commonjs `const x = require`, validate the alias and exit symbol := c.getSymbolOfDeclaration(node) - if symbol.Flags&ast.SymbolFlagsAlias != 0 && (isVariableDeclarationInitializedToBareOrAccessedRequire(node) || isBindingElementOfBareOrAccessedRequire(node)) { + if symbol.Flags&ast.SymbolFlagsAlias != 0 && ast.IsVariableDeclarationInitializedToRequire(node) { c.checkAliasSymbol(node) return } @@ -5524,7 +5606,7 @@ func (c *Checker) checkVarDeclaredNamesNotShadowed(node *ast.Node) { namesShareScope := container != nil && (ast.IsBlock(container) && ast.IsFunctionLike(container.Parent) || ast.IsModuleBlock(container) || ast.IsModuleDeclaration(container) || ast.IsSourceFile(container)) // here we know that function scoped variable is "shadowed" by block scoped one - // a var declatation can't hoist past a lexical declaration and it results in a SyntaxError at runtime + // a var declaration can't hoist past a lexical declaration and it results in a SyntaxError at runtime if !namesShareScope { name := c.symbolToString(localDeclarationSymbol) c.error(node, diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name) @@ -5730,7 +5812,7 @@ func (c *Checker) getIterationTypesOfGeneratorFunctionReturnType(t *Type, isAsyn if result.hasTypes() { return result } - return c.getIterationTypesOfIterator(t, resolver, nil /*errorNode*/) + return c.getIterationTypesOfIterator(t, resolver, nil /*errorNode*/, nil /*diagnosticOutput*/) } // Gets the requested "iteration type" from an `Iterable`-like or `AsyncIterable`-like type. @@ -5796,14 +5878,15 @@ func (c *Checker) getIterationTypesOfIterableWorker(t *Type, use IterationUse, e return iterationTypes } } + var diags []*ast.Diagnostic if use&IterationUseAllowsAsyncIterablesFlag != 0 { - iterationTypes := c.getIterationTypesOfIterableSlow(t, c.asyncIterationTypesResolver, errorNode) + iterationTypes := c.getIterationTypesOfIterableSlow(t, c.asyncIterationTypesResolver, errorNode, &diags) if iterationTypes.hasTypes() { return iterationTypes } } if use&IterationUseAllowsSyncIterablesFlag != 0 { - iterationTypes := c.getIterationTypesOfIterableSlow(t, c.syncIterationTypesResolver, errorNode) + iterationTypes := c.getIterationTypesOfIterableSlow(t, c.syncIterationTypesResolver, errorNode, &diags) if iterationTypes.hasTypes() { if use&IterationUseAllowsAsyncIterablesFlag != 0 { return c.getAsyncFromSyncIterationTypes(iterationTypes, errorNode) @@ -5812,7 +5895,10 @@ func (c *Checker) getIterationTypesOfIterableWorker(t *Type, use IterationUse, e } } if errorNode != nil { - c.reportTypeNotIterableError(errorNode, t, use&IterationUseAllowsAsyncIterablesFlag != 0) + diagnostic := c.reportTypeNotIterableError(errorNode, t, use&IterationUseAllowsAsyncIterablesFlag != 0) + for _, d := range diags { + diagnostic.AddRelatedInfo(d) + } } return IterationTypes{} } @@ -5920,7 +6006,7 @@ func (c *Checker) getAsyncFromSyncIterationTypes(iterationTypes IterationTypes, // // NOTE: You probably don't want to call this directly and should be calling // `getIterationTypesOfIterable` instead. -func (c *Checker) getIterationTypesOfIterableSlow(t *Type, r *IterationTypesResolver, errorNode *ast.Node) IterationTypes { +func (c *Checker) getIterationTypesOfIterableSlow(t *Type, r *IterationTypesResolver, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { if method := c.getPropertyOfType(t, c.getPropertyNameForKnownSymbolName(r.iteratorSymbolName)); method != nil && method.Flags&ast.SymbolFlagsOptional == 0 { methodType := c.getTypeOfSymbol(method) if IsTypeAny(methodType) { @@ -5928,7 +6014,7 @@ func (c *Checker) getIterationTypesOfIterableSlow(t *Type, r *IterationTypesReso } if signatures := c.getSignaturesOfType(methodType, SignatureKindCall); len(signatures) != 0 { iteratorType := c.getIntersectionType(core.Map(signatures, c.getReturnTypeOfSignature)) - return c.getIterationTypesOfIteratorWorker(iteratorType, r, errorNode) + return c.getIterationTypesOfIteratorWorker(iteratorType, r, errorNode, diagnosticOutput) } } return IterationTypes{} @@ -5938,8 +6024,8 @@ func (c *Checker) getIterationTypesOfIterableSlow(t *Type, r *IterationTypesReso // // If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` with non-nil // members is returned. Otherwise, a default `IterationTypes{}` is returned. -func (c *Checker) getIterationTypesOfIterator(t *Type, r *IterationTypesResolver, errorNode *ast.Node) IterationTypes { - return c.getIterationTypesOfIteratorWorker(t, r, errorNode) +func (c *Checker) getIterationTypesOfIterator(t *Type, r *IterationTypesResolver, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { + return c.getIterationTypesOfIteratorWorker(t, r, errorNode, diagnosticOutput) } // Gets the *yield*, *return*, and *next* types from an `Iterator`-like or `AsyncIterator`-like type. @@ -5948,7 +6034,7 @@ func (c *Checker) getIterationTypesOfIterator(t *Type, r *IterationTypesResolver // members is returned. Otherwise, a default `IterationTypes{}` is returned. // // NOTE: You probably don't want to call this directly and should be calling `getIterationTypesOfIterator` instead. -func (c *Checker) getIterationTypesOfIteratorWorker(t *Type, r *IterationTypesResolver, errorNode *ast.Node) IterationTypes { +func (c *Checker) getIterationTypesOfIteratorWorker(t *Type, r *IterationTypesResolver, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { if IsTypeAny(t) { return IterationTypes{c.anyType, c.anyType, c.anyType} } @@ -5956,7 +6042,7 @@ func (c *Checker) getIterationTypesOfIteratorWorker(t *Type, r *IterationTypesRe if iterationTypes.hasTypes() { return iterationTypes } - return c.getIterationTypesOfIteratorSlow(t, r, errorNode) + return c.getIterationTypesOfIteratorSlow(t, r, errorNode, diagnosticOutput) } func (c *Checker) getIterationTypesOfIteratorFast(t *Type, r *IterationTypesResolver) IterationTypes { @@ -5986,15 +6072,15 @@ func (c *Checker) getIterationTypesOfIteratorFast(t *Type, r *IterationTypesReso return IterationTypes{} } -func (c *Checker) getIterationTypesOfIteratorSlow(t *Type, r *IterationTypesResolver, errorNode *ast.Node) IterationTypes { +func (c *Checker) getIterationTypesOfIteratorSlow(t *Type, r *IterationTypesResolver, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { return c.combineIterationTypes([]IterationTypes{ - c.getIterationTypesOfMethod(t, r, "next", errorNode), - c.getIterationTypesOfMethod(t, r, "return", errorNode), - c.getIterationTypesOfMethod(t, r, "throw", errorNode), + c.getIterationTypesOfMethod(t, r, "next", errorNode, diagnosticOutput), + c.getIterationTypesOfMethod(t, r, "return", errorNode, diagnosticOutput), + c.getIterationTypesOfMethod(t, r, "throw", errorNode, diagnosticOutput), }) } -func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesResolver, methodName string, errorNode *ast.Node) IterationTypes { +func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesResolver, methodName string, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { method := c.getPropertyOfType(t, methodName) // Ignore 'return' or 'throw' if they are missing. if method == nil && methodName != "next" { @@ -6019,7 +6105,7 @@ func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesRes if len(methodSignatures) == 0 { if errorNode != nil { diagnostic := core.IfElse(methodName == "next", resolver.mustHaveANextMethodDiagnostic, resolver.mustBeAMethodDiagnostic) - c.error(errorNode, diagnostic, methodName) + c.reportDiagnostic(NewDiagnosticForNode(errorNode, diagnostic, methodName), diagnosticOutput) } return IterationTypes{} } @@ -6086,7 +6172,7 @@ func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesRes iterationTypes := c.getIterationTypesOfIteratorResult(resolvedMethodReturnType) if !iterationTypes.hasTypes() { if errorNode != nil { - c.error(errorNode, resolver.mustHaveAValueDiagnostic, methodName) + c.reportDiagnostic(NewDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName), diagnosticOutput) } yieldType = c.anyType returnTypes = append(returnTypes, c.anyType) @@ -6152,7 +6238,7 @@ func (c *Checker) isIteratorResult(t *Type, kind IterationTypeKind) bool { return c.isTypeAssignableTo(core.IfElse(kind == IterationTypeKindYield, c.falseType, c.trueType), doneType) } -func (c *Checker) reportTypeNotIterableError(errorNode *ast.Node, t *Type, allowAsyncIterables bool) { +func (c *Checker) reportTypeNotIterableError(errorNode *ast.Node, t *Type, allowAsyncIterables bool) *ast.Diagnostic { var message *diagnostics.Message if allowAsyncIterables { message = diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator @@ -6164,7 +6250,7 @@ func (c *Checker) reportTypeNotIterableError(errorNode *ast.Node, t *Type, allow errorNode.Parent.Expression() == errorNode && c.getGlobalAsyncIterableType() != c.emptyGenericType && c.isTypeAssignableTo(t, c.createTypeFromGenericGlobalType(c.getGlobalAsyncIterableType(), []*Type{c.anyType, c.anyType, c.anyType}))) - c.errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, c.TypeToString(t)) + return c.errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, c.TypeToString(t)) } func (c *Checker) getIterationDiagnosticDetails(use IterationUse, inputType *Type, allowsStrings bool, downlevelIteration bool) (*diagnostics.Message, bool) { @@ -6220,12 +6306,12 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { } else if !ast.IsExportSpecifier(node) { // Look at 'compilerOptions.isolatedModules' and not 'getIsolatedModules(...)' (which considers 'verbatimModuleSyntax') // here because 'verbatimModuleSyntax' will already have an error for importing a type without 'import type'. - appearsValueyToTranspiler := c.compilerOptions.IsolatedModules.IsTrue() && ast.FindAncestor(node, isTypeOnlyImportOrExportDeclaration) == nil + appearsValueyToTranspiler := c.compilerOptions.IsolatedModules.IsTrue() && ast.FindAncestor(node, ast.IsTypeOnlyImportOrExportDeclaration) == nil if appearsValueyToTranspiler && symbol.Flags&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue) != 0 { c.error(node, diagnostics.Import_0_conflicts_with_local_value_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, c.symbolToString(symbol), c.getIsolatedModulesLikeFlagName()) } } - if c.compilerOptions.GetIsolatedModules() && !isTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 { + if c.compilerOptions.GetIsolatedModules() && !ast.IsTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 { typeOnlyAlias := c.getTypeOnlyAliasDeclaration(symbol) isType := targetFlags&ast.SymbolFlagsValue == 0 if isType || typeOnlyAlias != nil { @@ -6245,7 +6331,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { name := node.PropertyNameOrName().Text() c.addTypeOnlyDeclarationRelatedInfo(c.error(node, message, name), core.IfElse(isType, nil, typeOnlyAlias), name) } - if isType && node.Kind == ast.KindImportEqualsDeclaration && hasEffectiveModifier(node, ast.ModifierFlagsExport) { + if isType && node.Kind == ast.KindImportEqualsDeclaration && hasModifier(node, ast.ModifierFlagsExport) { c.error(node, diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, c.getIsolatedModulesLikeFlagName()) } case ast.KindExportSpecifier: @@ -6264,7 +6350,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { } } } - if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !ast.IsImportEqualsDeclaration(node) && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node)) == core.ModuleKindCommonJS { + if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !ast.IsImportEqualsDeclaration(node) && !ast.IsVariableDeclarationInitializedToRequire(node) && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node)) == core.ModuleKindCommonJS { c.error(node, diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled) } else if c.moduleKind == core.ModuleKindPreserve && !ast.IsImportEqualsDeclaration(node) && !ast.IsVariableDeclaration(node) && c.program.GetEmitModuleFormatOfFile(ast.GetSourceFileOfNode(node)) == core.ModuleKindCommonJS { // In `--module preserve`, ESM input syntax emits ESM output syntax, but there will be times @@ -6274,7 +6360,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { c.error(node, diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve) } // !!! - // if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !isTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 && targetFlags&ast.SymbolFlagsConstEnum != 0 { + // if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !ast.IsTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 && targetFlags&ast.SymbolFlagsConstEnum != 0 { // constEnumDeclaration := target.ValueDeclaration // redirect := host.getRedirectReferenceForResolutionFromSourceOfProject(ast.GetSourceFileOfNode(constEnumDeclaration).ResolvedPath) // if constEnumDeclaration.Flags&ast.NodeFlagsAmbient != 0 && (redirect == nil || !shouldPreserveConstEnums(redirect.commandLine.options)) { @@ -6299,7 +6385,7 @@ func (c *Checker) areDeclarationFlagsIdentical(left *ast.Declaration, right *ast return false } interestingFlags := ast.ModifierFlagsPrivate | ast.ModifierFlagsProtected | ast.ModifierFlagsAsync | ast.ModifierFlagsAbstract | ast.ModifierFlagsReadonly | ast.ModifierFlagsStatic - return getSelectedEffectiveModifierFlags(left, interestingFlags) == getSelectedEffectiveModifierFlags(right, interestingFlags) + return getSelectedModifierFlags(left, interestingFlags) == getSelectedModifierFlags(right, interestingFlags) } func (c *Checker) checkTypeAliasDeclaration(node *ast.Node) { @@ -6311,7 +6397,7 @@ func (c *Checker) checkTypeAliasDeclaration(node *ast.Node) { typeNode := node.AsTypeAliasDeclaration().Type typeParameters := node.TypeParameters() c.checkTypeParameters(typeParameters) - if typeNode.Kind == ast.KindIntrinsicKeyword { + if typeNode != nil && typeNode.Kind == ast.KindIntrinsicKeyword { if !(len(typeParameters) == 0 && node.Name().Text() == "BuiltinIteratorReturn" || len(typeParameters) == 1 && intrinsicTypeKinds[node.Name().Text()] != IntrinsicTypeKindUnknown) { c.error(typeNode, diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types) @@ -6332,7 +6418,98 @@ func (c *Checker) checkTypeNameIsReserved(name *ast.Node, message *diagnostics.M } func (c *Checker) checkExportsOnMergedDeclarations(node *ast.Node) { - // !!! + // If localSymbol is defined on node then node itself is exported - check is required. + symbol := node.LocalSymbol() + if symbol == nil { + // Local symbol is undefined => this declaration is non-exported. + // However, symbol might contain other declarations that are exported. + symbol = c.getSymbolOfDeclaration(node) + if symbol.ExportSymbol == nil { + // This is a pure local symbol (all declarations are non-exported) - no need to check anything. + return + } + } + // Run the check only for the first declaration in the list. + if ast.GetDeclarationOfKind(symbol, node.Kind) != node { + return + } + exportedDeclarationSpaces := DeclarationSpacesNone + nonExportedDeclarationSpaces := DeclarationSpacesNone + defaultExportedDeclarationSpaces := DeclarationSpacesNone + for _, d := range symbol.Declarations { + declarationSpaces := c.getDeclarationSpaces(d) + effectiveDeclarationFlags := c.getEffectiveDeclarationFlags(d, ast.ModifierFlagsExport|ast.ModifierFlagsDefault) + if effectiveDeclarationFlags&ast.ModifierFlagsExport != 0 { + if effectiveDeclarationFlags&ast.ModifierFlagsDefault != 0 { + defaultExportedDeclarationSpaces |= declarationSpaces + } else { + exportedDeclarationSpaces |= declarationSpaces + } + } else { + nonExportedDeclarationSpaces |= declarationSpaces + } + } + // Spaces for anything not declared a 'default export'. + nonDefaultExportedDeclarationSpaces := exportedDeclarationSpaces | nonExportedDeclarationSpaces + commonDeclarationSpacesForExportsAndLocals := exportedDeclarationSpaces & nonExportedDeclarationSpaces + commonDeclarationSpacesForDefaultAndNonDefault := defaultExportedDeclarationSpaces & nonDefaultExportedDeclarationSpaces + if commonDeclarationSpacesForExportsAndLocals != 0 || commonDeclarationSpacesForDefaultAndNonDefault != 0 { + // declaration spaces for exported and non-exported declarations intersect + for _, d := range symbol.Declarations { + declarationSpaces := c.getDeclarationSpaces(d) + name := ast.GetNameOfDeclaration(d) + // Only error on the declarations that contributed to the intersecting spaces. + if declarationSpaces&commonDeclarationSpacesForDefaultAndNonDefault != 0 { + c.error(name, diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, scanner.DeclarationNameToString(name)) + } else if declarationSpaces&commonDeclarationSpacesForExportsAndLocals != 0 { + c.error(name, diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, scanner.DeclarationNameToString(name)) + } + } + } +} + +func (c *Checker) getDeclarationSpaces(node *ast.Declaration) DeclarationSpaces { + switch node.Kind { + case ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindJSDocTypedefTag, ast.KindJSDocCallbackTag: + return DeclarationSpacesExportType + case ast.KindModuleDeclaration: + if ast.IsAmbientModule(node) || ast.GetModuleInstanceState(node) != ast.ModuleInstanceStateNonInstantiated { + return DeclarationSpacesExportNamespace | DeclarationSpacesExportValue + } + return DeclarationSpacesExportNamespace + case ast.KindClassDeclaration, ast.KindEnumDeclaration, ast.KindEnumMember: + return DeclarationSpacesExportType | DeclarationSpacesExportValue + case ast.KindSourceFile: + return DeclarationSpacesExportType | DeclarationSpacesExportValue | DeclarationSpacesExportNamespace + case ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindBinaryExpression: + var expression *ast.Node + if ast.IsExportAssignment(node) || ast.IsJSExportAssignment(node) { + expression = node.Expression() + } else { + expression = node.AsBinaryExpression().Right + } + // Export assigned entity name expressions act as aliases and should fall through, otherwise they export values. + if !ast.IsEntityNameExpression(expression) { + return DeclarationSpacesExportValue + } + node = expression + // The below options all declare an Alias, which is allowed to merge with other values within the importing module. + fallthrough + case ast.KindImportEqualsDeclaration, ast.KindNamespaceImport, ast.KindImportClause: + result := DeclarationSpacesNone + target := c.resolveAlias(c.getSymbolOfDeclaration(node)) + for _, d := range target.Declarations { + result |= c.getDeclarationSpaces(d) + } + return result + case ast.KindCommonJSExport: + return DeclarationSpacesExportValue + case ast.KindVariableDeclaration, ast.KindBindingElement, ast.KindFunctionDeclaration, ast.KindImportSpecifier: + return DeclarationSpacesExportValue + case ast.KindMethodSignature, ast.KindPropertySignature: + return DeclarationSpacesExportType + } + panic("Unhandled case in getDeclarationSpaces: " + node.Kind.String()) } func (c *Checker) checkTypeParameters(typeParameterDeclarations []*ast.Node) { @@ -6396,7 +6573,7 @@ func (c *Checker) checkUnusedIdentifiers(potentiallyUnusedIdentifiers []*ast.Nod } c.checkUnusedTypeParameters(node) case ast.KindMethodSignature, ast.KindCallSignature, ast.KindConstructSignature, ast.KindFunctionType, ast.KindConstructorType, - ast.KindTypeAliasDeclaration, ast.KindInterfaceDeclaration: + ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindInterfaceDeclaration: c.checkUnusedTypeParameters(node) case ast.KindInferType: c.checkUnusedInferTypeParameter(node) @@ -6425,7 +6602,7 @@ func (c *Checker) reportUnusedVariable(location *ast.Node, diagnostic *ast.Diagn } func (c *Checker) reportUnused(location *ast.Node, kind UnusedKind, diagnostic *ast.Diagnostic) { - if location.Flags&ast.NodeFlagsAmbient == 0 && + if location.Flags&(ast.NodeFlagsAmbient|ast.NodeFlagsThisNodeOrAnySubNodesHasError) == 0 && (kind == UnusedKindLocal && c.compilerOptions.NoUnusedLocals.IsTrue() || (kind == UnusedKindParameter && c.compilerOptions.NoUnusedParameters.IsTrue())) { c.diagnostics.Add(diagnostic) @@ -6440,7 +6617,7 @@ func (c *Checker) checkUnusedClassMembers(node *ast.Node) { break // Already would have reported an error on the getter. } symbol := c.getSymbolOfDeclaration(member) - if !c.isReferenced(symbol) && (hasEffectiveModifier(member, ast.ModifierFlagsPrivate) || member.Name() != nil && ast.IsPrivateIdentifier(member.Name())) && member.Flags&ast.NodeFlagsAmbient == 0 { + if !c.isReferenced(symbol) && (hasModifier(member, ast.ModifierFlagsPrivate) || member.Name() != nil && ast.IsPrivateIdentifier(member.Name())) && member.Flags&ast.NodeFlagsAmbient == 0 { c.reportUnused(member, UnusedKindLocal, NewDiagnosticForNode(member.Name(), diagnostics.X_0_is_declared_but_its_value_is_never_read, c.symbolToString(symbol))) } case ast.KindConstructor: @@ -6479,7 +6656,7 @@ func (c *Checker) checkUnusedLocalsAndParameters(node *ast.Node) { importClauses[importClause] = append(importClauses[importClause], declaration) } default: - if !ast.IsAmbientModule(declaration) { + if !ast.IsTypeParameterDeclaration(declaration) && !ast.IsAmbientModule(declaration) { c.reportUnusedLocal(declaration, ast.SymbolName(local)) } } @@ -6499,17 +6676,13 @@ func (c *Checker) checkUnusedLocalsAndParameters(node *ast.Node) { func (c *Checker) reportUnusedLocal(node *ast.Node, name string) { message := core.IfElse(isTypeDeclaration(node), diagnostics.X_0_is_declared_but_never_used, diagnostics.X_0_is_declared_but_its_value_is_never_read) - c.reportUnused(node, UnusedKindLocal, NewDiagnosticForNode(node, message, name)) + c.reportUnused(node, UnusedKindLocal, NewDiagnosticForNode(core.OrElse(node.Name(), node), message, name)) } func (c *Checker) reportUnusedVariables(node *ast.Node) { declarations := node.AsVariableDeclarationList().Declarations.Nodes - if core.Every(declarations, c.isUnreferencedVariableDeclaration) { - if len(declarations) == 1 && ast.IsIdentifier(declarations[0].Name()) { - c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.X_0_is_declared_but_its_value_is_never_read, declarations[0].Name().Text())) - } else { - c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.All_variables_are_unused)) - } + if len(declarations) > 1 && core.Every(declarations, c.isUnreferencedVariableDeclaration) { + c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.All_variables_are_unused)) } else { c.reportUnusedVariableDeclarations(declarations) } @@ -6521,12 +6694,8 @@ func (c *Checker) reportUnusedParameters(node *ast.Node) { func (c *Checker) reportUnusedBindingElements(node *ast.Node) { declarations := node.AsBindingPattern().Elements.Nodes - if core.Every(declarations, c.isUnreferencedVariableDeclaration) { - if len(declarations) == 1 && ast.IsIdentifier(declarations[0].Name()) { - c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.X_0_is_declared_but_its_value_is_never_read, declarations[0].Name().Text())) - } else { - c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.All_destructured_elements_are_unused)) - } + if len(declarations) > 1 && core.Every(declarations, c.isUnreferencedVariableDeclaration) { + c.reportUnusedVariable(node, NewDiagnosticForNode(node, diagnostics.All_destructured_elements_are_unused)) } else { c.reportUnusedVariableDeclarations(declarations) } @@ -6539,7 +6708,7 @@ func (c *Checker) reportUnusedVariableDeclarations(declarations []*ast.Node) { if ast.IsBindingPattern(name) { c.reportUnusedBindingElements(name) } else if c.isUnreferencedVariableDeclaration(declaration) { - c.reportUnusedVariable(declaration, NewDiagnosticForNode(declaration, diagnostics.X_0_is_declared_but_its_value_is_never_read, name.Text())) + c.reportUnusedVariable(declaration, NewDiagnosticForNode(name, diagnostics.X_0_is_declared_but_its_value_is_never_read, name.Text())) } } } @@ -6556,6 +6725,13 @@ func (c *Checker) isUnreferencedVariableDeclaration(node *ast.Node) bool { if c.symbolReferenceLinks.Get(c.getSymbolOfDeclaration(node)).referenceKinds&ast.SymbolFlagsVariable != 0 { return false } + if ast.IsBindingElement(node) && ast.IsObjectBindingPattern(node.Parent) { + // In `{ a, ...b }, `a` is considered used since it removes a property from `b`. `b` may still be unused though. + lastElement := core.LastOrNil(node.Parent.AsBindingPattern().Elements.Nodes) + if node != lastElement && hasDotDotDotToken(lastElement) { + return false + } + } if (ast.IsParameter(node) || ast.IsVariableDeclaration(node) && (ast.IsForInOrOfStatement(node.Parent.Parent) || c.getCombinedNodeFlagsCached(node)&ast.NodeFlagsUsing != 0) || ast.IsBindingElement(node) && !(ast.IsObjectBindingPattern(node.Parent) && node.PropertyName() == nil)) && @@ -6575,12 +6751,8 @@ func (c *Checker) reportUnusedImports(node *ast.Node, unuseds []*ast.Node) { declarationCount += len(namedBindings.AsNamedImports().Elements.Nodes) } } - if declarationCount == len(unuseds) { - if declarationCount == 1 { - c.reportUnused(node, UnusedKindLocal, NewDiagnosticForNode(node.Parent, diagnostics.X_0_is_declared_but_its_value_is_never_read, unuseds[0].Name().Text())) - } else { - c.reportUnused(node, UnusedKindLocal, NewDiagnosticForNode(node.Parent, diagnostics.All_imports_in_import_declaration_are_unused)) - } + if declarationCount > 1 && declarationCount == len(unuseds) { + c.reportUnused(node, UnusedKindLocal, NewDiagnosticForNode(node.Parent, diagnostics.All_imports_in_import_declaration_are_unused)) } else { for _, unused := range unuseds { c.reportUnusedLocal(unused, unused.Name().Text()) @@ -6606,7 +6778,7 @@ func importClauseFromImported(node *ast.Node) *ast.Node { func (c *Checker) checkUnusedInferTypeParameter(node *ast.Node) { typeParameter := node.AsInferTypeNode().TypeParameter if c.isUnreferencedTypeParameter(typeParameter) { - c.reportUnused(node, UnusedKindParameter, NewDiagnosticForNode(typeParameter, diagnostics.X_0_is_declared_but_never_used, typeParameter.Name().Text())) + c.reportUnused(node, UnusedKindParameter, NewDiagnosticForNode(typeParameter.Name(), diagnostics.X_0_is_declared_but_never_used, typeParameter.Name().Text())) } } @@ -6618,14 +6790,10 @@ func (c *Checker) checkUnusedTypeParameters(node *ast.Node) { if typeParameterList == nil { return } - if core.Every(typeParameterList.Nodes, c.isUnreferencedTypeParameter) { + if len(typeParameterList.Nodes) > 1 && core.Every(typeParameterList.Nodes, c.isUnreferencedTypeParameter) { file := ast.GetSourceFileOfNode(node) loc := rangeOfTypeParameters(file, typeParameterList) - if len(typeParameterList.Nodes) == 1 { - c.reportUnused(node, UnusedKindParameter, ast.NewDiagnostic(file, loc, diagnostics.X_0_is_declared_but_never_used, typeParameterList.Nodes[0].Name().Text())) - } else { - c.reportUnused(node, UnusedKindParameter, ast.NewDiagnostic(file, loc, diagnostics.All_type_parameters_are_unused)) - } + c.reportUnused(node, UnusedKindParameter, ast.NewDiagnostic(file, loc, diagnostics.All_type_parameters_are_unused)) } else { for _, typeParameter := range typeParameterList.Nodes { if c.isUnreferencedTypeParameter(typeParameter) { @@ -6697,7 +6865,7 @@ func (c *Checker) getQuickTypeOfExpression(node *ast.Node) *Type { return nil // Optimize for the common case of a call to a function with a single non-generic call // signature where we can just fetch the return type without checking the arguments. - case ast.IsCallExpression(expr) && expr.Expression().Kind != ast.KindSuperKeyword && !isRequireCall(expr, true /*requireStringLiteralLikeArgument*/) && !c.isSymbolOrSymbolForCall(expr): + case ast.IsCallExpression(expr) && expr.Expression().Kind != ast.KindSuperKeyword && !ast.IsVariableDeclarationInitializedToRequire(expr.Parent) && !c.isSymbolOrSymbolForCall(expr): if isCallChain(expr) { return c.getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) } @@ -6751,10 +6919,11 @@ func (c *Checker) checkNonNullTypeWithReporter(t *Type, node *ast.Node, reportEr facts := c.getTypeFacts(t, TypeFactsIsUndefinedOrNull) if facts&TypeFactsIsUndefinedOrNull != 0 { reportError(c, node, facts) - nonNullable := c.getNonNullableType(t) + nonNullable := c.GetNonNullableType(t) if nonNullable.flags&(TypeFlagsNullable|TypeFlagsNever) != 0 { return c.errorType } + return nonNullable } return t } @@ -6933,7 +7102,7 @@ func (c *Checker) instantiateTypeWithSingleGenericCallSignature(node *ast.Node, if contextualType == nil { return t } - contextualSignature := c.getSingleSignature(c.getNonNullableType(contextualType), core.IfElse(callSignature != nil, SignatureKindCall, SignatureKindConstruct), false /*allowMembers*/) + contextualSignature := c.getSingleSignature(c.GetNonNullableType(contextualType), core.IfElse(callSignature != nil, SignatureKindCall, SignatureKindConstruct), false /*allowMembers*/) if contextualSignature == nil || len(contextualSignature.typeParameters) != 0 { return t } @@ -7071,10 +7240,7 @@ func (c *Checker) checkExpressionWorker(node *ast.Node, checkMode CheckMode) *Ty return c.getFreshTypeOfLiteralType(c.getNumberLiteralType(jsnum.FromString(node.Text()))) case ast.KindBigIntLiteral: c.checkGrammarBigIntLiteral(node.AsBigIntLiteral()) - return c.getFreshTypeOfLiteralType(c.getBigIntLiteralType(PseudoBigInt{ - negative: false, - base10Value: parsePseudoBigInt(node.Text()), - })) + return c.getFreshTypeOfLiteralType(c.getBigIntLiteralType(jsnum.NewPseudoBigInt(jsnum.ParsePseudoBigInt(node.Text()), false /*negative*/))) case ast.KindTrueKeyword: return c.trueType case ast.KindFalseKeyword: @@ -7168,12 +7334,11 @@ func (c *Checker) checkPrivateIdentifierExpression(node *ast.Node) *Type { } func (c *Checker) getSymbolForPrivateIdentifierExpression(node *ast.Node) *ast.Symbol { - if symbol := c.identifierSymbols[node]; symbol != nil { - return symbol + links := c.symbolNodeLinks.Get(node) + if links.resolvedSymbol == nil { + links.resolvedSymbol = c.lookupSymbolForPrivateIdentifierDeclaration(node.Text(), node) } - symbol := c.lookupSymbolForPrivateIdentifierDeclaration(node.Text(), node) - c.identifierSymbols[node] = symbol - return symbol + return links.resolvedSymbol } func (c *Checker) checkSuperExpression(node *ast.Node) *Type { @@ -7245,7 +7410,7 @@ func (c *Checker) checkSuperExpression(node *ast.Node) *Type { // // block scope containers so that we can report potential collisions with // // `Reflect`. // forEachEnclosingBlockScopeContainer(node.Parent, func(current *ast.Node) { - // if !isSourceFile(current) || isExternalOrCommonJsModule(current) { + // if !isSourceFile(current) || isExternalOrCommonJSModule(current) { // c.getNodeLinks(current).flags |= NodeCheckFlagsContainsSuperPropertyInStaticInitializer // } // }) @@ -7393,7 +7558,7 @@ func (c *Checker) checkTemplateExpression(node *ast.Node) *Type { } var evaluated any if !ast.IsTaggedTemplateExpression(node.Parent) { - evaluated = c.evaluate(node, node).value + evaluated = c.evaluate(node, node).Value } if evaluated != nil { return c.getFreshTypeOfLiteralType(c.getStringLiteralType(evaluated.(string))) @@ -7575,7 +7740,7 @@ func (c *Checker) checkElementAccessExpression(node *ast.Node, exprType *Type, c core.IfElse(c.isGenericObjectType(objectType) && !isThisTypeParameter(objectType), AccessFlagsNoIndexSignatures, 0) } indexedAccessType := core.OrElse(c.getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node, nil), c.errorType) - return c.checkIndexedAccessIndexType(c.getFlowTypeOfAccessExpression(node, c.typeNodeLinks.Get(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node) + return c.checkIndexedAccessIndexType(c.getFlowTypeOfAccessExpression(node, c.getResolvedSymbolOrNil(node), indexedAccessType, indexExpression, checkMode), node) } // Return true if given node is an expression consisting of an identifier (possibly parenthesized) @@ -7656,7 +7821,7 @@ func (c *Checker) checkIndexedAccessIndexType(t *Type, accessNode *ast.Node) *Ty } func (c *Checker) getConstituentProperty(objectType *Type, propertyName string) *ast.Symbol { - for _, t := range objectType.Distributed() { + for _, t := range c.getApparentType(objectType).Distributed() { prop := c.getPropertyOfType(t, propertyName) if prop != nil { return prop @@ -7733,6 +7898,9 @@ func (c *Checker) checkCallExpression(node *ast.Node, checkMode CheckMode) *Type return c.anyType } } + if ast.IsInJSFile(node) && c.isCommonJSRequire(node) { + return c.resolveExternalModuleTypeByLiteral(node.AsCallExpression().Arguments.Nodes[0]) + } returnType := c.getReturnTypeOfSignature(signature) // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property // as a fresh unique symbol literal type. @@ -7930,7 +8098,7 @@ func (c *Checker) resolveCallExpression(node *ast.Node, candidatesOutArray *[]*S } else { var relatedInformation *ast.Diagnostic if len(node.Arguments()) == 1 { - text := ast.GetSourceFileOfNode(node).Text + text := ast.GetSourceFileOfNode(node).Text() options := scanner.SkipTriviaOptions{StopAfterLineBreak: true} if stringutil.IsLineBreak(rune(text[scanner.SkipTriviaEx(text, node.Expression().End(), &options)-1])) { relatedInformation = createDiagnosticForNode(node.Expression(), diagnostics.Are_you_missing_a_semicolon) @@ -8003,8 +8171,8 @@ func (c *Checker) resolveNewExpression(node *ast.Node, candidatesOutArray *[]*Si return c.resolveErrorCall(node) } if expressionType.symbol != nil { - valueDecl := getClassLikeDeclarationOfSymbol(expressionType.symbol) - if valueDecl != nil && hasEffectiveModifier(valueDecl, ast.ModifierFlagsAbstract) { + valueDecl := ast.GetClassLikeDeclarationOfSymbol(expressionType.symbol) + if valueDecl != nil && hasModifier(valueDecl, ast.ModifierFlagsAbstract) { c.error(node, diagnostics.Cannot_create_an_instance_of_an_abstract_class) return c.resolveErrorCall(node) } @@ -8037,12 +8205,12 @@ func (c *Checker) isConstructorAccessible(node *ast.Node, signature *Signature) return true } declaration := signature.declaration - modifiers := getSelectedEffectiveModifierFlags(declaration, ast.ModifierFlagsNonPublicAccessibilityModifier) + modifiers := getSelectedModifierFlags(declaration, ast.ModifierFlagsNonPublicAccessibilityModifier) // (1) Public constructors and (2) constructor functions are always accessible. - if modifiers == 0 || ast.IsConstructorDeclaration(declaration) { + if modifiers == 0 || !ast.IsConstructorDeclaration(declaration) { return true } - declaringClassDeclaration := getClassLikeDeclarationOfSymbol(declaration.Parent.Symbol()) + declaringClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(declaration.Parent.Symbol()) declaringClass := c.getDeclaredTypeOfSymbol(declaration.Parent.Symbol()) // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) if !c.isNodeWithinClass(node, declaringClassDeclaration) { @@ -8177,12 +8345,34 @@ func (c *Checker) getDiagnosticHeadMessageForDecoratorResolution(node *ast.Node) panic("Unhandled case in getDiagnosticHeadMessageForDecoratorResolution") } -func (c *Checker) resolveJsxOpeningLikeElement(node *ast.Node, candidatesOutArray *[]*Signature, checkMode CheckMode) *Signature { - return c.unknownSignature // !!! -} - func (c *Checker) resolveInstanceofExpression(node *ast.Node, candidatesOutArray *[]*Signature, checkMode CheckMode) *Signature { - return c.unknownSignature // !!! + // if rightType is an object type with a custom `[Symbol.hasInstance]` method, then it is potentially + // valid on the right-hand side of the `instanceof` operator. This allows normal `object` types to + // participate in `instanceof`, as per Step 2 of https://tc39.es/ecma262/#sec-instanceofoperator. + right := node.AsBinaryExpression().Right + rightType := c.checkExpression(right) + if !IsTypeAny(rightType) { + hasInstanceMethodType := c.getSymbolHasInstanceMethodOfObjectType(rightType) + if hasInstanceMethodType != nil { + apparentType := c.getApparentType(hasInstanceMethodType) + if c.isErrorType(apparentType) { + return c.resolveErrorCall(node) + } + callSignatures := c.getSignaturesOfType(apparentType, SignatureKindCall) + constructSignatures := c.getSignaturesOfType(apparentType, SignatureKindConstruct) + if c.isUntypedFunctionCall(hasInstanceMethodType, apparentType, len(callSignatures), len(constructSignatures)) { + return c.resolveUntypedCall(node) + } + if len(callSignatures) != 0 { + return c.resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlagsNone, nil) + } + } else if !(c.typeHasCallOrConstructSignatures(rightType) || c.isTypeSubtypeOf(rightType, c.globalFunctionType)) { + c.error(right, diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_either_of_type_any_a_class_function_or_other_type_assignable_to_the_Function_interface_type_or_an_object_type_with_a_Symbol_hasInstance_method) + return c.resolveErrorCall(node) + } + } + // fall back to a default signature + return c.anySignature } type CallState struct { @@ -8496,37 +8686,25 @@ func (c *Checker) hasCorrectArity(node *ast.Node, args []*ast.Node, signature *S // Specifically, a template only can end in a TemplateTail or a Missing literal. lastSpan := core.LastOrNil(template.AsTemplateExpression().TemplateSpans.Nodes) // we should always have at least one span. - callIsIncomplete = ast.NodeIsMissing(lastSpan.AsTemplateSpan().Literal) // !!! || lastSpan.AsTemplateSpan().Literal.IsUnterminated + callIsIncomplete = ast.NodeIsMissing(lastSpan.AsTemplateSpan().Literal) || ast.IsUnterminatedLiteral(lastSpan.AsTemplateSpan().Literal) } else { // If the template didn't end in a backtick, or its beginning occurred right prior to EOF, // then this might actually turn out to be a TemplateHead in the future; // so we consider the call to be incomplete. - callIsIncomplete = false // !!! template.AsNoSubstitutionTemplateLiteral().IsUnterminated + callIsIncomplete = ast.IsUnterminatedLiteral(template) } case ast.IsDecorator(node): argCount = c.getDecoratorArgumentCount(node, signature) case ast.IsBinaryExpression(node): argCount = 1 case isJsxOpeningLikeElement(node): - argCount = len(args) - // !!! - // callIsIncomplete = node.Attributes.End == node.End - // if callIsIncomplete { - // return true - // } - // if effectiveMinimumArguments == 0 { - // argCount = args.length - // } else { - // argCount = 1 - // } - // if args.length == 0 { - // effectiveParameterCount = effectiveParameterCount - // } else { - // effectiveParameterCount = 1 - // } - // // class may have argumentless ctor functions - still resolve ctor and compare vs props member type - // effectiveMinimumArguments = min(effectiveMinimumArguments, 1) - // // sfc may specify context argument - handled by framework and not typechecked + callIsIncomplete = node.Attributes().End() == node.End() + if callIsIncomplete { + return true + } + argCount = core.IfElse(effectiveMinimumArguments == 0, len(args), 1) + effectiveParameterCount = core.IfElse(len(args) == 0, effectiveParameterCount, 1) // class may have argumentless ctor functions - still resolve ctor and compare vs props member type + effectiveMinimumArguments = min(effectiveMinimumArguments, 1) // sfc may specify context argument - handled by framework and not typechecked case ast.IsNewExpression(node) && node.ArgumentList() == nil: // This only happens when we have something of the form: 'new C' return c.getMinArgumentCount(signature) == 0 @@ -8640,12 +8818,7 @@ func (c *Checker) checkTypeArguments(signature *Signature, typeArgumentNodes []* func (c *Checker) isSignatureApplicable(node *ast.Node, args []*ast.Node, signature *Signature, relation *Relation, checkMode CheckMode, reportErrors bool, inferenceContext *InferenceContext, diagnosticOutput *[]*ast.Diagnostic) bool { if isJsxOpeningLikeElement(node) { - // !!! - // if !c.checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer) { - // Debug.assert(!reportErrors || errorOutputContainer.errors != nil, "jsx should have errors when reporting errors") - // return errorOutputContainer.errors || emptyArray - // } - return true + return c.checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, diagnosticOutput) } thisType := c.getThisTypeOfSignature(signature) if thisType != nil && thisType != c.voidType && !(ast.IsNewExpression(node) || ast.IsCallExpression(node) && isSuperProperty(node.Expression())) { @@ -8674,7 +8847,8 @@ func (c *Checker) isSignatureApplicable(node *ast.Node, args []*ast.Node, signat } else { argCount = len(args) } - for i, arg := range args { + for i := range argCount { + arg := args[i] if !ast.IsOmittedExpression(arg) { paramType := c.getTypeAtPosition(signature, i) argType := c.checkExpressionWithContextualType(arg, paramType, nil /*inferenceContext*/, checkMode) @@ -8768,7 +8942,7 @@ func (c *Checker) getThisArgumentType(node *ast.Node) *Type { thisArgumentType := c.checkExpression(node) switch { case ast.IsOptionalChainRoot(node.Parent): - return c.getNonNullableType(thisArgumentType) + return c.GetNonNullableType(thisArgumentType) case ast.IsOptionalChain(node.Parent): return c.removeOptionalTypeMarker(thisArgumentType) } @@ -8785,9 +8959,7 @@ func (c *Checker) getEffectiveCheckNode(argument *ast.Node) *ast.Node { func (c *Checker) inferTypeArguments(node *ast.Node, signature *Signature, args []*ast.Node, checkMode CheckMode, context *InferenceContext) []*Type { if isJsxOpeningLikeElement(node) { - // !!! - // return c.inferJsxTypeArguments(node, signature, checkMode, context) - return core.Map(context.inferences, func(*InferenceInfo) *Type { return c.anyType }) + return c.inferJsxTypeArguments(node, signature, checkMode, context) } // If a contextual type is available, infer from that type to the return type of the call expression. For // example, given a 'function wrap<T, U>(cb: (x: T) => U): (x: T) => U' and a call expression @@ -9057,7 +9229,7 @@ func (c *Checker) reportCallResolutionErrors(s *CallState, signatures []*Signatu if last.declaration != nil && len(s.candidatesForArgumentError) > 1 { diagnostic.AddRelatedInfo(NewDiagnosticForNode(last.declaration, diagnostics.The_last_overload_is_declared_here)) } - // !!! addImplementationSuccessElaboration(last, d) + c.addImplementationSuccessElaboration(s, last, diagnostic) c.diagnostics.Add(diagnostic) } case s.candidateForArgumentArityError != nil: @@ -9076,6 +9248,26 @@ func (c *Checker) reportCallResolutionErrors(s *CallState, signatures []*Signatu } } +func (c *Checker) addImplementationSuccessElaboration(s *CallState, failed *Signature, diagnostic *ast.Diagnostic) { + if failed.declaration != nil && failed.declaration.Symbol() != nil { + declarations := failed.declaration.Symbol().Declarations + if len(declarations) > 1 { + implementation := core.Find(declarations, func(d *ast.Declaration) bool { + return ast.IsFunctionLikeDeclaration(d) && ast.NodeIsPresent(d.Body()) + }) + if implementation != nil { + candidate := c.getSignatureFromDeclaration(implementation) + localState := *s + localState.candidates = []*Signature{candidate} + localState.isSingleNonGenericCandidate = candidate.typeParameters == nil + if c.chooseOverload(&localState, c.assignableRelation) != nil { + diagnostic.AddRelatedInfo(NewDiagnosticForNode(implementation, diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible)) + } + } + } + } +} + func (c *Checker) getArgumentArityError(node *ast.Node, signatures []*Signature, args []*ast.Node, headMessage *diagnostics.Message) *ast.Diagnostic { spreadIndex := c.getSpreadArgumentIndex(args) if spreadIndex > -1 { @@ -9163,7 +9355,7 @@ func (c *Checker) getArgumentArityError(node *ast.Node, signatures []*Signature, return diagnostic default: sourceFile := ast.GetSourceFileOfNode(node) - pos := scanner.SkipTrivia(sourceFile.Text, args[maxCount].Pos()) + pos := scanner.SkipTrivia(sourceFile.Text(), args[maxCount].Pos()) end := args[len(args)-1].End() if end == pos { end++ @@ -9336,7 +9528,7 @@ func (c *Checker) invocationErrorDetails(errorTarget *ast.Node, apparentType *Ty headMessage := core.IfElse(isCall, diagnostics.This_expression_is_not_callable, diagnostics.This_expression_is_not_constructable) // Diagnose get accessors incorrectly called as functions if ast.IsCallExpression(errorTarget.Parent) && len(errorTarget.Parent.Arguments()) == 0 { - resolvedSymbol := c.typeNodeLinks.Get(errorTarget).resolvedSymbol + resolvedSymbol := c.getResolvedSymbolOrNil(errorTarget) if resolvedSymbol != nil && resolvedSymbol.Flags&ast.SymbolFlagsGetAccessor != 0 { headMessage = diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without } @@ -9633,7 +9825,7 @@ func (c *Checker) isAritySmaller(signature *Signature, target *ast.Node) bool { } targetParameterCount++ } - if len(parameters) != 0 && parameterIsThisKeyword(parameters[0]) { + if len(parameters) != 0 && ast.IsThisParameter(parameters[0]) { targetParameterCount-- } return !c.hasEffectiveRestParameter(signature) && c.getParameterCount(signature) < targetParameterCount @@ -9760,7 +9952,7 @@ func (c *Checker) checkCollisionWithRequireExportsInGeneratedCode(node *ast.Node } // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent parent := ast.GetDeclarationContainer(node) - if ast.IsSourceFile(parent) && ast.IsExternalOrCommonJsModule(parent.AsSourceFile()) { + if ast.IsSourceFile(parent) && ast.IsExternalOrCommonJSModule(parent.AsSourceFile()) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords c.error(name, diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, scanner.DeclarationNameToString(name), scanner.DeclarationNameToString(name)) } @@ -9782,7 +9974,7 @@ func (c *Checker) needCollisionCheckForIdentifier(node *ast.Node, identifier *as } if ast.IsImportClause(node) || ast.IsImportEqualsDeclaration(node) || ast.IsImportSpecifier(node) { // type-only imports do not require collision checks against runtime values. - if isTypeOnlyImportOrExportDeclaration(node) { + if ast.IsTypeOnlyImportOrExportDeclaration(node) { return false } } @@ -9803,13 +9995,13 @@ func (c *Checker) checkNonNullAssertion(node *ast.Node) *Type { if node.Flags&ast.NodeFlagsOptionalChain != 0 { return c.checkNonNullChain(node) } - return c.getNonNullableType(c.checkExpression(node.Expression())) + return c.GetNonNullableType(c.checkExpression(node.Expression())) } func (c *Checker) checkNonNullChain(node *ast.Node) *Type { leftType := c.checkExpression(node.Expression()) nonOptionalType := c.getOptionalExpressionType(leftType, node.Expression()) - return c.propagateOptionalTypeMarker(c.getNonNullableType(nonOptionalType), node, nonOptionalType != leftType) + return c.propagateOptionalTypeMarker(c.GetNonNullableType(nonOptionalType), node, nonOptionalType != leftType) } func (c *Checker) checkExpressionWithTypeArguments(node *ast.Node) *Type { @@ -9910,7 +10102,7 @@ func (c *Checker) getInstantiationExpressionType(exprType *Type, node *ast.Node) } if errorType != nil { sourceFile := ast.GetSourceFileOfNode(node) - loc := core.NewTextRange(scanner.SkipTrivia(sourceFile.Text, typeArguments.Pos()), typeArguments.End()) + loc := core.NewTextRange(scanner.SkipTrivia(sourceFile.Text(), typeArguments.Pos()), typeArguments.End()) c.diagnostics.Add(ast.NewDiagnostic(sourceFile, loc, diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, c.TypeToString(errorType))) } return result @@ -9959,10 +10151,10 @@ func (c *Checker) checkNewTargetMetaProperty(node *ast.Node) *Type { func (c *Checker) checkImportMetaProperty(node *ast.Node) *Type { if c.moduleKind == core.ModuleKindNode16 || c.moduleKind == core.ModuleKindNodeNext { - // !!! Enable this once ImpliedNodeFormat is computed at program construction - // if ast.GetSourceFileOfNode(node).ImpliedNodeFormat != core.ModuleKindESNext { - // c.error(node, diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output) - // } + sourceFileMetaData := c.program.GetSourceFileMetaData(ast.GetSourceFileOfNode(node).Path()) + if sourceFileMetaData == nil || sourceFileMetaData.ImpliedNodeFormat != core.ModuleKindESNext { + c.error(node, diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output) + } } else if c.moduleKind < core.ModuleKindES2020 && c.moduleKind != core.ModuleKindSystem { c.error(node, diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext) } @@ -9989,8 +10181,7 @@ func (c *Checker) checkDeleteExpression(node *ast.Node) *Type { if ast.IsPropertyAccessExpression(expr) && ast.IsPrivateIdentifier(expr.Name()) { c.error(expr, diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_identifier) } - links := c.typeNodeLinks.Get(expr) - symbol := c.getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol) + symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbolOrNil(expr)) if symbol != nil { if c.isReadonlySymbol(symbol) { c.error(expr, diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property) @@ -10047,10 +10238,7 @@ func (c *Checker) checkPrefixUnaryExpression(node *ast.Node) *Type { } case ast.KindBigIntLiteral: if expr.Operator == ast.KindMinusToken { - return c.getFreshTypeOfLiteralType(c.getBigIntLiteralType(PseudoBigInt{ - negative: true, - base10Value: parsePseudoBigInt(expr.Operand.Text()), - })) + return c.getFreshTypeOfLiteralType(c.getBigIntLiteralType(jsnum.NewPseudoBigInt(jsnum.ParsePseudoBigInt(expr.Operand.Text()), true /*negative*/))) } } switch expr.Operator { @@ -10212,42 +10400,8 @@ func (c *Checker) checkSyntheticExpression(node *ast.Node) *Type { return t } -func (c *Checker) checkJsxExpression(node *ast.Node, checkMode CheckMode) *Type { - // !!! - return c.errorType -} - -func (c *Checker) checkJsxElement(node *ast.Node, checkMode CheckMode) *Type { - c.checkNodeDeferred(node) - // !!! - return c.errorType -} - -func (c *Checker) checkJsxElementDeferred(node *ast.Node) { -} - -func (c *Checker) checkJsxSelfClosingElement(node *ast.Node, checkMode CheckMode) *Type { - c.checkNodeDeferred(node) - // !!! - return c.errorType -} - -func (c *Checker) checkJsxSelfClosingElementDeferred(node *ast.Node) { - // !!! -} - -func (c *Checker) checkJsxFragment(node *ast.Node) *Type { - // !!! - return c.errorType -} - -func (c *Checker) checkJsxAttributes(node *ast.Node, checkMode CheckMode) *Type { - // !!! - return c.errorType -} - func (c *Checker) checkIdentifier(node *ast.Node, checkMode CheckMode) *Type { - if isThisInTypeQuery(node) { + if ast.IsThisInTypeQuery(node) { return c.checkThisExpression(node) } symbol := c.getResolvedSymbol(node) @@ -10360,7 +10514,7 @@ func (c *Checker) checkIdentifier(node *ast.Node, checkMode CheckMode) *Type { isSpreadDestructuringAssignmentTarget || isModuleExports || c.isSameScopedBindingElement(node, declaration) || - t != c.autoType && t != c.autoArrayType && (!c.strictNullChecks || t.flags&(TypeFlagsAnyOrUnknown|TypeFlagsVoid) != 0 || isInTypeQuery(node) || c.isInAmbientOrTypeNode(node) || node.Parent.Kind == ast.KindExportSpecifier) || + t != c.autoType && t != c.autoArrayType && (!c.strictNullChecks || t.flags&(TypeFlagsAnyOrUnknown|TypeFlagsVoid) != 0 || IsInTypeQuery(node) || c.isInAmbientOrTypeNode(node) || node.Parent.Kind == ast.KindExportSpecifier) || ast.IsNonNullExpression(node.Parent) || ast.IsVariableDeclaration(declaration) && declaration.AsVariableDeclaration().ExclamationToken != nil || declaration.Flags&ast.NodeFlagsAmbient != 0 @@ -10379,7 +10533,7 @@ func (c *Checker) checkIdentifier(node *ast.Node, checkMode CheckMode) *Type { } var flowType *Type if isAutomaticTypeInNonNull { - flowType = c.getNonNullableType(c.getFlowTypeOfReferenceEx(node, t, initialType, flowContainer, nil)) + flowType = c.GetNonNullableType(c.getFlowTypeOfReferenceEx(node, t, initialType, flowContainer, nil)) } else { flowType = c.getFlowTypeOfReferenceEx(node, t, initialType, flowContainer, nil) } @@ -10444,7 +10598,7 @@ func (c *Checker) parameterInitializerContainsUndefined(declaration *ast.Node) b func (c *Checker) isInAmbientOrTypeNode(node *ast.Node) bool { return node.Flags&ast.NodeFlagsAmbient != 0 || ast.FindAncestor(node, func(n *ast.Node) bool { - return ast.IsInterfaceDeclaration(n) || ast.IsTypeAliasDeclaration(n) || ast.IsTypeLiteralNode(n) + return ast.IsInterfaceDeclaration(n) || ast.IsTypeAliasDeclaration(n) || ast.IsJSTypeAliasDeclaration(n) || ast.IsTypeLiteralNode(n) }) != nil } @@ -10463,7 +10617,7 @@ func (c *Checker) checkPropertyAccessChain(node *ast.Node, checkMode CheckMode) } func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, left *ast.Node, leftType *Type, right *ast.Node, checkMode CheckMode, writeOnly bool) *Type { - parentSymbol := c.typeNodeLinks.Get(node).resolvedSymbol + parentSymbol := c.getResolvedSymbolOrNil(left) assignmentKind := getAssignmentTargetKind(node) widenedType := leftType if assignmentKind != AssignmentKindNone || c.isMethodAccessForCall(node) { @@ -10499,7 +10653,7 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l } // !!! // containingClass := getContainingClassExcludingClassDecorators(right) - // if containingClass && isPlainJsFile(ast.GetSourceFileOfNode(containingClass), c.compilerOptions.checkJs) { + // if containingClass && isPlainJSFile(ast.GetSourceFileOfNode(containingClass), c.compilerOptions.checkJs) { // c.grammarErrorOnNode(right, diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, right.Text()) // } } else { @@ -10552,7 +10706,7 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l if c.compilerOptions.NoPropertyAccessFromIndexSignature == core.TSTrue && ast.IsPropertyAccessExpression(node) { c.error(right, diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, right.Text()) } - if indexInfo.declaration != nil && c.isDeprecatedDeclaration(indexInfo.declaration) { + if indexInfo.declaration != nil && c.IsDeprecatedDeclaration(indexInfo.declaration) { c.addDeprecatedSuggestion(right, []*ast.Node{indexInfo.declaration}, right.Text()) } } else { @@ -10562,7 +10716,7 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l } c.checkPropertyNotUsedBeforeDeclaration(prop, node, right) c.markPropertyAsReferenced(prop, node, c.isSelfTypeAccess(left, parentSymbol)) - c.typeNodeLinks.Get(node).resolvedSymbol = prop + c.symbolNodeLinks.Get(node).resolvedSymbol = prop c.checkPropertyAccessibility(node, left.Kind == ast.KindSuperKeyword, isWriteAccess(node), apparentType, prop) if c.isAssignmentToReadonlyEntity(node, prop, assignmentKind) { c.error(right, diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, right.Text()) @@ -10631,7 +10785,7 @@ func (c *Checker) getControlFlowContainer(node *ast.Node) *ast.Node { func (c *Checker) getFlowTypeOfProperty(reference *ast.Node, prop *ast.Symbol) *Type { initialType := c.undefinedType - if prop != nil && prop.ValueDeclaration != nil && (!c.isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.ValueDeclaration)&ast.ModifierFlagsAmbient != 0) { + if prop != nil && prop.ValueDeclaration != nil && (!c.isAutoTypedProperty(prop) || prop.ValueDeclaration.ModifierFlags()&ast.ModifierFlagsAmbient != 0) { initialType = c.getTypeOfPropertyInBaseClass(prop) } return c.getFlowTypeOfReferenceEx(reference, c.autoType, initialType, nil, nil) @@ -10728,7 +10882,7 @@ func (c *Checker) reportNonexistentProperty(propNode *ast.Node, containingType * typeName := c.TypeToString(containingType) diagnostic = NewDiagnosticChainForNode(diagnostic, propNode, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName, typeName, typeName+"."+propName) } else { - promisedType := c.getPromisedTypeOfPromise(containingType) + promisedType := c.GetPromisedTypeOfPromise(containingType) if promisedType != nil && c.getPropertyOfType(promisedType, propNode.Text()) != nil { diagnostic = NewDiagnosticChainForNode(diagnostic, propNode, diagnostics.Property_0_does_not_exist_on_type_1, scanner.DeclarationNameToString(propNode), c.TypeToString(containingType)) diagnostic.AddRelatedInfo(NewDiagnosticForNode(propNode, diagnostics.Did_you_forget_to_use_await)) @@ -10824,7 +10978,15 @@ func (c *Checker) isPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { - return false // !!! + return !slices.Contains(c.compilerOptions.Lib, "lib.dom.d.ts") && everyContainedType(containingType, hasCommonDomTypeName) && c.isEmptyObjectType(containingType) +} + +func hasCommonDomTypeName(t *Type) bool { + if t.symbol == nil { + return false + } + name := t.symbol.Name + return name == "EventTarget" || name == "Node" || name == "Element" || strings.HasPrefix(name, "HTML") && strings.HasSuffix(name, "Element") } func (c *Checker) checkAndReportErrorForExtendingInterface(errorLocation *ast.Node) bool { @@ -10860,11 +11022,11 @@ func (c *Checker) isUncalledFunctionReference(node *ast.Node, symbol *ast.Symbol if parent == nil { parent = node.Parent } - if isCallLikeExpression(parent) { + if ast.IsCallLikeExpression(parent) { return isCallOrNewExpression(parent) && ast.IsIdentifier(node) && c.hasMatchingArgument(parent, node) } return core.Every(symbol.Declarations, func(d *ast.Node) bool { - return !ast.IsFunctionLike(d) || c.isDeprecatedDeclaration(d) + return !ast.IsFunctionLike(d) || c.IsDeprecatedDeclaration(d) }) } return true @@ -10884,7 +11046,7 @@ func (c *Checker) checkPropertyNotUsedBeforeDeclaration(prop *ast.Symbol, node * !(ast.IsMethodDeclaration(valueDeclaration) && c.getCombinedModifierFlagsCached(valueDeclaration)&ast.ModifierFlagsStatic != 0) && (c.compilerOptions.UseDefineForClassFields.IsTrue() || !c.isPropertyDeclaredInAncestorClass(prop)) { diagnostic = c.error(right, diagnostics.Property_0_is_used_before_its_initialization, declarationName) - } else if ast.IsClassDeclaration(valueDeclaration) && ast.IsTypeReferenceNode(node.Parent) && valueDeclaration.Flags&ast.NodeFlagsAmbient == 0 && !c.isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) { + } else if ast.IsClassDeclaration(valueDeclaration) && !ast.IsTypeReferenceNode(node.Parent) && valueDeclaration.Flags&ast.NodeFlagsAmbient == 0 && !c.isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) { diagnostic = c.error(right, diagnostics.Class_0_used_before_its_declaration, declarationName) } if diagnostic != nil { @@ -10996,7 +11158,7 @@ func (c *Checker) checkPropertyAccessibilityAtLocation(location *ast.Node, isSup if flags&ast.ModifierFlagsAbstract != 0 && c.symbolHasNonMethodDeclaration(prop) && (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) || ast.IsObjectBindingPattern(location.Parent) && isThisInitializedDeclaration(location.Parent.Parent)) { - declaringClassDeclaration := getClassLikeDeclarationOfSymbol(c.getParentOfSymbol(prop)) + declaringClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(c.getParentOfSymbol(prop)) if declaringClassDeclaration != nil && c.isNodeUsedDuringClassInitialization(location) { if errorNode != nil { c.error(errorNode, diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, c.symbolToString(prop), declaringClassDeclaration.Name().Text()) @@ -11011,7 +11173,7 @@ func (c *Checker) checkPropertyAccessibilityAtLocation(location *ast.Node, isSup // Property is known to be private or protected at this point // Private property is accessible if the property is within the declaring class if flags&ast.ModifierFlagsPrivate != 0 { - declaringClassDeclaration := getClassLikeDeclarationOfSymbol(c.getParentOfSymbol(prop)) + declaringClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(c.getParentOfSymbol(prop)) if !c.isNodeWithinClass(location, declaringClassDeclaration) { if errorNode != nil { c.error(errorNode, diagnostics.Property_0_is_private_and_only_accessible_within_class_1, c.symbolToString(prop), c.TypeToString(c.getDeclaringClass(prop))) @@ -11226,7 +11388,7 @@ func (c *Checker) getContextualThisParameterType(fn *ast.Node) *Type { // for 'this' is the non-null form of the contextual type for the containing object literal or // the type of the object literal itself. if contextualType != nil { - thisType = c.getNonNullableType(contextualType) + thisType = c.GetNonNullableType(contextualType) } else { thisType = c.checkExpressionCached(containingLiteral) } @@ -11280,7 +11442,7 @@ func (c *Checker) checkThisExpression(node *ast.Node) *Type { // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks } } - t := c.tryGetThisTypeAtEx(node, true /*includeGlobalThis*/, container) + t := c.TryGetThisTypeAtEx(node, true /*includeGlobalThis*/, container) if c.noImplicitThis { globalThisType := c.getTypeOfSymbol(c.globalThisSymbol) if t == globalThisType && capturedByArrowFunction { @@ -11303,10 +11465,13 @@ func (c *Checker) checkThisExpression(node *ast.Node) *Type { } func (c *Checker) tryGetThisTypeAt(node *ast.Node) *Type { - return c.tryGetThisTypeAtEx(node, true /*includeGlobalThis*/, c.getThisContainer(node, false /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/)) + return c.TryGetThisTypeAtEx(node, true /*includeGlobalThis*/, nil /*container*/) } -func (c *Checker) tryGetThisTypeAtEx(node *ast.Node, includeGlobalThis bool, container *ast.Node) *Type { +func (c *Checker) TryGetThisTypeAtEx(node *ast.Node, includeGlobalThis bool, container *ast.Node) *Type { + if container == nil { + container = c.getThisContainer(node, false /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/) + } if ast.IsFunctionLike(container) && (!c.isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container) != nil) { thisType := c.getThisTypeOfDeclaration(container) // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. @@ -11483,8 +11648,21 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N } leftType := c.checkExpressionEx(left, checkMode) rightType := c.checkExpressionEx(right, checkMode) - if ast.IsLogicalBinaryOperator(operator) { - c.checkTruthinessOfType(leftType, left) + if ast.IsLogicalOrCoalescingBinaryOperator(operator) { + parent := left.Parent.Parent + for ast.IsParenthesizedExpression(parent) || ast.IsLogicalOrCoalescingBinaryExpression(parent) { + parent = parent.Parent + } + if operator == ast.KindAmpersandAmpersandToken || ast.IsIfStatement(parent) { + var body *ast.Node + if ast.IsIfStatement(parent) { + body = parent.AsIfStatement().ThenStatement + } + c.checkTestingKnownTruthyCallableOrAwaitableOrEnumMemberType(left, leftType, body) + } + if ast.IsLogicalBinaryOperator(operator) { + c.checkTruthinessOfType(leftType, left) + } } switch operator { case ast.KindAsteriskToken, ast.KindAsteriskAsteriskToken, ast.KindAsteriskEqualsToken, ast.KindAsteriskAsteriskEqualsToken, @@ -11534,8 +11712,9 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N ast.KindGreaterThanGreaterThanEqualsToken, ast.KindGreaterThanGreaterThanGreaterThanToken, ast.KindGreaterThanGreaterThanGreaterThanEqualsToken: rhsEval := c.evaluate(right, right) - if numValue, ok := rhsEval.value.(jsnum.Number); ok && numValue.Abs() >= 32 { - c.errorOrSuggestion(ast.IsEnumMember(ast.WalkUpParenthesizedExpressions(right.Parent.Parent)), errorNode, diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2, scanner.GetTextOfNode(left), scanner.TokenToString(operator), (numValue / 32).Floor()) + if numValue, ok := rhsEval.Value.(jsnum.Number); ok && numValue.Abs() >= 32 { + // Elevate from suggestion to error within an enum member + c.errorOrSuggestion(ast.IsEnumMember(ast.WalkUpParenthesizedExpressions(right.Parent.Parent)), errorNode, diagnostics.This_operation_can_be_simplified_This_shift_is_identical_to_0_1_2, scanner.GetTextOfNode(left), scanner.TokenToString(operator), numValue.Remainder(32)) } } } @@ -11636,7 +11815,7 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N case ast.KindBarBarToken, ast.KindBarBarEqualsToken: resultType := leftType if c.hasTypeFacts(leftType, TypeFactsFalsy) { - resultType = c.getUnionTypeEx([]*Type{c.getNonNullableType(c.removeDefinitelyFalsyTypes(leftType)), rightType}, UnionReductionSubtype, nil, nil) + resultType = c.getUnionTypeEx([]*Type{c.GetNonNullableType(c.removeDefinitelyFalsyTypes(leftType)), rightType}, UnionReductionSubtype, nil, nil) } if operator == ast.KindBarBarEqualsToken { c.checkAssignmentOperator(left, operator, right, leftType, rightType) @@ -11648,7 +11827,7 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N } resultType := leftType if c.hasTypeFacts(leftType, TypeFactsEQUndefinedOrNull) { - resultType = c.getUnionTypeEx([]*Type{c.getNonNullableType(leftType), rightType}, UnionReductionSubtype, nil, nil) + resultType = c.getUnionTypeEx([]*Type{c.GetNonNullableType(leftType), rightType}, UnionReductionSubtype, nil, nil) } if operator == ast.KindQuestionQuestionEqualsToken { c.checkAssignmentOperator(left, operator, right, leftType, rightType) @@ -11660,7 +11839,7 @@ func (c *Checker) checkBinaryLikeExpression(left *ast.Node, operatorToken *ast.N case ast.KindCommaToken: if !c.compilerOptions.AllowUnreachableCode.IsTrue() && c.isSideEffectFree(left) && !c.isIndirectCall(left.Parent) { sf := ast.GetSourceFileOfNode(left) - start := scanner.SkipTrivia(sf.Text, left.Pos()) + start := scanner.SkipTrivia(sf.Text(), left.Pos()) isInDiag2657 := core.Some(sf.Diagnostics(), func(d *ast.Diagnostic) bool { if d.Code() != diagnostics.JSX_expressions_must_have_one_parent_element.Code() { return false @@ -12171,7 +12350,7 @@ func (c *Checker) checkInExpression(left *ast.Expression, right *ast.Expression, if ast.IsPrivateIdentifier(left) { // Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type // which provides us with the opportunity to emit more detailed errors - if c.identifierSymbols[left] == nil && ast.GetContainingClass(left) != nil { + if c.symbolNodeLinks.Get(left).resolvedSymbol == nil && ast.GetContainingClass(left) != nil { c.reportNonexistentProperty(left, rightType) } } else { @@ -12194,7 +12373,16 @@ func (c *Checker) checkInExpression(left *ast.Expression, right *ast.Expression, func (c *Checker) hasEmptyObjectIntersection(t *Type) bool { return someType(t, func(t *Type) bool { - return t == c.unknownEmptyObjectType || t.flags&TypeFlagsIntersection != 0 && c.isEmptyAnonymousObjectType(c.getBaseConstraintOrType(t)) + return t == c.unknownEmptyObjectType || t.flags&TypeFlagsIntersection != 0 && c.IsEmptyAnonymousObjectType(c.getBaseConstraintOrType(t)) + }) +} + +func (c *Checker) getExactOptionalUnassignableProperties(source *Type, target *Type) []*ast.Symbol { + if isTupleType(source) && isTupleType(target) { + return nil + } + return core.Filter(c.getPropertiesOfType(target), func(targetProp *ast.Symbol) bool { + return c.isExactOptionalPropertyMismatch(c.getTypeOfPropertyOfType(source, targetProp.Name), c.getTypeOfSymbol(targetProp)) }) } @@ -12881,10 +13069,6 @@ func (c *Checker) checkObjectLiteralMethod(node *ast.Node, checkMode CheckMode) return c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode) } -func (c *Checker) checkJsxAttribute(node *ast.JsxAttribute, checkMode CheckMode) *Type { - return c.anyType // !!! -} - func (c *Checker) checkExpressionForMutableLocation(node *ast.Node, checkMode CheckMode) *Type { t := c.checkExpressionEx(node, checkMode) switch { @@ -12898,19 +13082,20 @@ func (c *Checker) checkExpressionForMutableLocation(node *ast.Node, checkMode Ch } func (c *Checker) getResolvedSymbol(node *ast.Node) *ast.Symbol { - if symbol := c.identifierSymbols[node]; symbol != nil { - return symbol - } - var symbol *ast.Symbol - if !ast.NodeIsMissing(node) { - symbol = c.resolveName(node, node.AsIdentifier().Text, ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, - c.getCannotFindNameDiagnosticForName(node), !isWriteOnlyAccess(node), false /*excludeGlobals*/) - } - if symbol == nil { - symbol = c.unknownSymbol + links := c.symbolNodeLinks.Get(node) + if links.resolvedSymbol == nil { + var symbol *ast.Symbol + if !ast.NodeIsMissing(node) { + symbol = c.resolveName(node, node.AsIdentifier().Text, ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, + c.getCannotFindNameDiagnosticForName(node), !isWriteOnlyAccess(node), false /*excludeGlobals*/) + } + links.resolvedSymbol = core.OrElse(symbol, c.unknownSymbol) } - c.identifierSymbols[node] = symbol - return symbol + return links.resolvedSymbol +} + +func (c *Checker) getResolvedSymbolOrNil(node *ast.Node) *ast.Symbol { + return c.symbolNodeLinks.Get(node).resolvedSymbol } func (c *Checker) getCannotFindNameDiagnosticForName(node *ast.Node) *diagnostics.Message { @@ -12978,11 +13163,12 @@ func (c *Checker) errorOrSuggestion(isError bool, location *ast.Node, message *d c.addErrorOrSuggestion(isError, NewDiagnosticForNode(location, message, args...)) } -func (c *Checker) errorAndMaybeSuggestAwait(location *ast.Node, maybeMissingAwait bool, message *diagnostics.Message, args ...any) { +func (c *Checker) errorAndMaybeSuggestAwait(location *ast.Node, maybeMissingAwait bool, message *diagnostics.Message, args ...any) *ast.Diagnostic { diagnostic := c.error(location, message, args...) if maybeMissingAwait { diagnostic.AddRelatedInfo(createDiagnosticForNode(location, diagnostics.Did_you_forget_to_use_await)) } + return diagnostic } func (c *Checker) addErrorOrSuggestion(isError bool, diagnostic *ast.Diagnostic) { @@ -12995,7 +13181,7 @@ func (c *Checker) addErrorOrSuggestion(isError bool, diagnostic *ast.Diagnostic) } } -func (c *Checker) isDeprecatedDeclaration(declaration *ast.Node) bool { +func (c *Checker) IsDeprecatedDeclaration(declaration *ast.Node) bool { return c.getCombinedNodeFlagsCached(declaration)&ast.NodeFlagsDeprecated != 0 } @@ -13020,12 +13206,12 @@ func (c *Checker) isDeprecatedSymbol(symbol *ast.Symbol) bool { parentSymbol := c.getParentOfSymbol(symbol) if parentSymbol != nil && len(symbol.Declarations) > 1 { if parentSymbol.Flags&ast.SymbolFlagsInterface != 0 { - return core.Some(symbol.Declarations, c.isDeprecatedDeclaration) + return core.Some(symbol.Declarations, c.IsDeprecatedDeclaration) } else { - return core.Every(symbol.Declarations, c.isDeprecatedDeclaration) + return core.Every(symbol.Declarations, c.IsDeprecatedDeclaration) } } - return symbol.ValueDeclaration != nil && c.isDeprecatedDeclaration(symbol.ValueDeclaration) || len(symbol.Declarations) != 0 && core.Every(symbol.Declarations, c.isDeprecatedDeclaration) + return symbol.ValueDeclaration != nil && c.IsDeprecatedDeclaration(symbol.ValueDeclaration) || len(symbol.Declarations) != 0 && core.Every(symbol.Declarations, c.IsDeprecatedDeclaration) } func (c *Checker) hasParseDiagnostics(sourceFile *ast.SourceFile) bool { @@ -13033,7 +13219,7 @@ func (c *Checker) hasParseDiagnostics(sourceFile *ast.SourceFile) bool { } func (c *Checker) newSymbol(flags ast.SymbolFlags, name string) *ast.Symbol { - c.symbolCount++ + c.SymbolCount++ result := c.symbolPool.New() result.Flags = flags | ast.SymbolFlagsTransient result.Name = name @@ -13096,7 +13282,9 @@ func (c *Checker) mergeSymbolTable(target ast.SymbolTable, source ast.SymbolTabl // When merging the module augmentation into a.ts, the symbol for `A` will itself be merged, so its parent // should be the merged module symbol. But the symbol for `B` has only one declaration, so its parent should // be the module augmentation symbol, which contains its only declaration. - merged.Parent = mergedParent + if merged.Flags&ast.SymbolFlagsTransient != 0 { + merged.Parent = mergedParent + } } target[id] = merged } @@ -13201,10 +13389,10 @@ func (c *Checker) reportMergeSymbolError(target *ast.Symbol, source *ast.Symbol) // "secondFileLocations": []never{}, // }) // }) - // if !isSourcePlainJs { + // if !isSourcePlainJS { // addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source) // } - // if !isTargetPlainJs { + // if !isTargetPlainJS { // addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target) // } // } else { @@ -13424,15 +13612,6 @@ func (c *Checker) resolveSymbolEx(symbol *ast.Symbol, dontResolveAlias bool) *as func (c *Checker) getTargetOfImportEqualsDeclaration(node *ast.Node, dontResolveAlias bool) *ast.Symbol { // Node is ImportEqualsDeclaration | VariableDeclaration - commonJSPropertyAccess := c.getCommonJSPropertyAccess(node) - if commonJSPropertyAccess != nil { - access := commonJSPropertyAccess.AsPropertyAccessExpression() - name := getLeftmostAccessExpression(access.Expression).AsCallExpression().Arguments.Nodes[0] - if ast.IsIdentifier(access.Name()) { - return c.resolveSymbol(c.getPropertyOfType(c.resolveExternalModuleTypeByLiteral(name), access.Name().Text())) - } - return nil - } if ast.IsVariableDeclaration(node) || node.AsImportEqualsDeclaration().ModuleReference.Kind == ast.KindExternalModuleReference { moduleReference := getExternalModuleRequireArgument(node) if moduleReference == nil { @@ -13448,16 +13627,6 @@ func (c *Checker) getTargetOfImportEqualsDeclaration(node *ast.Node, dontResolve return resolved } -func (c *Checker) getCommonJSPropertyAccess(node *ast.Node) *ast.Node { - if ast.IsVariableDeclaration(node) { - initializer := node.Initializer() - if initializer != nil && ast.IsPropertyAccessExpression(initializer) { - return initializer - } - } - return nil -} - func (c *Checker) resolveExternalModuleTypeByLiteral(name *ast.Node) *Type { moduleSym := c.resolveExternalModuleName(name, name, false /*ignoreErrors*/) if moduleSym != nil { @@ -13503,8 +13672,8 @@ func (c *Checker) checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(nod diagnostics.X_0_was_imported_here) // TODO: how to get name for export *? name := "*" - if typeOnlyDeclaration.Kind == ast.KindImportDeclaration { - name = getNameFromImportDeclaration(typeOnlyDeclaration).AsIdentifier().Text + if !ast.IsExportDeclaration(typeOnlyDeclaration) { + name = getNameFromImportDeclaration(typeOnlyDeclaration).Text() } c.error(decl.ModuleReference, message).AddRelatedInfo(createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)) } @@ -13566,7 +13735,27 @@ func (c *Checker) getTargetOfModuleDefault(moduleSymbol *ast.Symbol, node *ast.N } func (c *Checker) reportNonDefaultExport(moduleSymbol *ast.Symbol, node *ast.Node) { - // !!! + if moduleSymbol.Exports != nil && moduleSymbol.Exports[node.Symbol().Name] != nil { + c.error(node, diagnostics.Module_0_has_no_default_export_Did_you_mean_to_use_import_1_from_0_instead, c.symbolToString(moduleSymbol), c.symbolToString(node.Symbol())) + } else { + diagnostic := c.error(node.Name(), diagnostics.Module_0_has_no_default_export, c.symbolToString(moduleSymbol)) + var exportStar *ast.Symbol + if moduleSymbol.Exports != nil { + exportStar = moduleSymbol.Exports[ast.InternalSymbolNameExportStar] + } + if exportStar != nil { + defaultExport := core.Find(exportStar.Declarations, func(decl *ast.Declaration) bool { + if !(ast.IsExportDeclaration(decl) && decl.AsExportDeclaration().ModuleSpecifier != nil) { + return false + } + resolvedExternalModuleName := c.resolveExternalModuleName(decl, decl.AsExportDeclaration().ModuleSpecifier, false /*ignoreErrors*/) + return resolvedExternalModuleName != nil && resolvedExternalModuleName.Exports[ast.InternalSymbolNameDefault] != nil + }) + if defaultExport != nil { + diagnostic.AddRelatedInfo(createDiagnosticForNode(defaultExport, diagnostics.X_export_Asterisk_does_not_re_export_a_default)) + } + } + } } func (c *Checker) resolveExportByName(moduleSymbol *ast.Symbol, name string, sourceNode *ast.Node, dontResolveAlias bool) *ast.Symbol { @@ -13603,7 +13792,7 @@ func (c *Checker) getTargetOfNamespaceExport(node *ast.Node, dontResolveAlias bo func (c *Checker) getTargetOfImportSpecifier(node *ast.Node, dontResolveAlias bool) *ast.Symbol { name := node.PropertyNameOrName() - if ast.ModuleExportNameIsDefault(name) { + if ast.IsImportSpecifier(node) && ast.ModuleExportNameIsDefault(name) { specifier := c.getModuleSpecifierForImportOrExport(node) if specifier != nil { moduleSymbol := c.resolveExternalModuleName(node, specifier, false /*ignoreErrors*/) @@ -13613,6 +13802,9 @@ func (c *Checker) getTargetOfImportSpecifier(node *ast.Node, dontResolveAlias bo } } root := node.Parent.Parent.Parent // ImportDeclaration + if ast.IsBindingElement(node) { + root = ast.GetRootDeclaration(node) + } resolved := c.getExternalModuleMember(root, node, dontResolveAlias) c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "") return resolved @@ -13636,7 +13828,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d return nil } nameText := name.Text() - suppressInteropError := nameText == ast.InternalSymbolNameDefault && c.allowSyntheticDefaultImports + suppressInteropError := node.Kind == ast.KindVariableDeclaration || nameText == ast.InternalSymbolNameDefault && c.allowSyntheticDefaultImports targetSymbol := c.resolveESModuleSymbol(moduleSymbol, moduleSpecifier /*dontResolveAlias*/, false, suppressInteropError) if targetSymbol != nil { // Note: The empty string is a valid module export name: @@ -13754,7 +13946,7 @@ func (c *Checker) isOnlyImportableAsDefault(usage *ast.Node, resolvedModule *ast } var targetFile *ast.SourceFile if resolvedModule != nil { - targetFile = getSourceFileOfModule(resolvedModule) + targetFile = ast.GetSourceFileOfModule(resolvedModule) } return targetFile != nil && (ast.IsJsonSourceFile(targetFile) || tspath.GetDeclarationFileExtension(targetFile.FileName()) == ".d.json.ts") } @@ -13763,31 +13955,29 @@ func (c *Checker) isOnlyImportableAsDefault(usage *ast.Node, resolvedModule *ast } func (c *Checker) canHaveSyntheticDefault(file *ast.Node, moduleSymbol *ast.Symbol, dontResolveAlias bool, usage *ast.Node) bool { - // !!! - // var usageMode ResolutionMode - // if file != nil { - // usageMode = c.getEmitSyntaxForModuleSpecifierExpression(usage) - // } - // if file != nil && usageMode != core.ModuleKindNone { - // targetMode := host.getImpliedNodeFormatForEmit(file) - // if usageMode == core.ModuleKindESNext && targetMode == core.ModuleKindCommonJS && core.ModuleKindNode16 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext { - // // In Node.js, CommonJS modules always have a synthetic default when imported into ESM - // return true - // } - // if usageMode == core.ModuleKindESNext && targetMode == core.ModuleKindESNext { - // // No matter what the `module` setting is, if we're confident that both files - // // are ESM, there cannot be a synthetic default. - // return false - // } - // } + var usageMode core.ResolutionMode + if file != nil { + usageMode = c.getEmitSyntaxForModuleSpecifierExpression(usage) + } + if file != nil && usageMode != core.ModuleKindNone { + targetMode := c.program.GetImpliedNodeFormatForEmit(file.AsSourceFile()) + if usageMode == core.ModuleKindESNext && targetMode == core.ModuleKindCommonJS && core.ModuleKindNode16 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext { + // In Node.js, CommonJS modules always have a synthetic default when imported into ESM + return true + } + if usageMode == core.ModuleKindESNext && targetMode == core.ModuleKindESNext { + // No matter what the `module` setting is, if we're confident that both files + // are ESM, there cannot be a synthetic default. + return false + } + } if !c.allowSyntheticDefaultImports { return false } // Declaration files (and ambient modules) if file == nil || file.AsSourceFile().IsDeclarationFile { // Definitely cannot have a synthetic default if they have a syntactic default member specified - defaultExportSymbol := c.resolveExportByName(moduleSymbol, ast.InternalSymbolNameDefault /*sourceNode*/, nil /*dontResolveAlias*/, true) - // Dont resolve alias because we want the immediately exported symbol's declaration + defaultExportSymbol := c.resolveExportByName(moduleSymbol, ast.InternalSymbolNameDefault /*sourceNode*/, nil /*dontResolveAlias*/, true) // Dont resolve alias because we want the immediately exported symbol's declaration if defaultExportSymbol != nil && core.Some(defaultExportSymbol.Declarations, isSyntacticDefault) { return false } @@ -13804,7 +13994,12 @@ func (c *Checker) canHaveSyntheticDefault(file *ast.Node, moduleSymbol *ast.Symb return true } // TypeScript files never have a synthetic default (as they are always emitted with an __esModule marker) _unless_ they contain an export= statement - return hasExportAssignmentSymbol(moduleSymbol) + if !ast.IsInJSFile(file) { + return hasExportAssignmentSymbol(moduleSymbol) + } + + // JS files have a synthetic default if they do not contain ES2015+ module syntax (export = is not valid in js) _and_ do not have an __esModule marker + return !ast.IsExternalModule(file.AsSourceFile()) && c.resolveExportByName(moduleSymbol, "__esModule", nil /*sourceNode*/, dontResolveAlias) == nil } func (c *Checker) getEmitSyntaxForModuleSpecifierExpression(usage *ast.Node) core.ResolutionMode { @@ -13932,7 +14127,7 @@ func (c *Checker) getTargetOfAliasLikeExpression(expression *ast.Node, dontResol return aliasLike } c.checkExpressionCached(expression) - return c.typeNodeLinks.Get(expression).resolvedSymbol + return c.getResolvedSymbolOrNil(expression) } func (c *Checker) getTargetOfNamespaceExportDeclaration(node *ast.Node, dontResolveAlias bool) *ast.Symbol { @@ -14013,7 +14208,7 @@ func (c *Checker) markSymbolOfAliasDeclarationIfTypeOnly(aliasDeclaration *ast.N } // If the declaration itself is type-only, mark it and return. No need to check what it resolves to. sourceSymbol := c.getSymbolOfDeclaration(aliasDeclaration) - if isTypeOnlyImportOrExportDeclaration(aliasDeclaration) { + if ast.IsTypeOnlyImportOrExportDeclaration(aliasDeclaration) { links := c.aliasSymbolLinks.Get(sourceSymbol) links.typeOnlyDeclaration = aliasDeclaration return true @@ -14034,7 +14229,7 @@ func (c *Checker) markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationL if target != nil && (!aliasDeclarationLinks.typeOnlyDeclarationResolved || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration == nil) { exportSymbol := core.OrElse(target.Exports[ast.InternalSymbolNameExportEquals], target) aliasDeclarationLinks.typeOnlyDeclarationResolved = true - if typeOnly := core.Find(exportSymbol.Declarations, isTypeOnlyImportOrExportDeclaration); typeOnly != nil { + if typeOnly := core.Find(exportSymbol.Declarations, ast.IsTypeOnlyImportOrExportDeclaration); typeOnly != nil { aliasDeclarationLinks.typeOnlyDeclaration = typeOnly } else { aliasDeclarationLinks.typeOnlyDeclaration = c.aliasSymbolLinks.Get(exportSymbol).typeOnlyDeclaration @@ -14067,6 +14262,7 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri // !!! The following only implements simple module resolution sourceFile := c.program.GetResolvedModule(ast.GetSourceFileOfNode(location), moduleReference) if sourceFile != nil { + // !!! if sourceFile.Symbol != nil { return c.getMergedSymbol(sourceFile.Symbol) } @@ -14075,9 +14271,29 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri } return nil } - if errorNode != nil && moduleNotFoundError != nil { + + if len(c.patternAmbientModules) != 0 { + pattern := core.FindBestPatternMatch(c.patternAmbientModules, func(v *ast.PatternAmbientModule) core.Pattern { return v.Pattern }, moduleReference) + if pattern != nil { + augmentation := c.patternAmbientModuleAugmentations[moduleReference] + if augmentation != nil { + return c.getMergedSymbol(augmentation) + } + return c.getMergedSymbol(pattern.Symbol) + } + } + + if errorNode == nil { + return nil + } + + // !!! + + if moduleNotFoundError != nil { + // !!! c.error(errorNode, moduleNotFoundError, moduleReference) } + return nil } @@ -14096,48 +14312,13 @@ func (c *Checker) tryFindAmbientModule(moduleName string, withAugmentations bool func (c *Checker) resolveExternalModuleSymbol(moduleSymbol *ast.Symbol, dontResolveAlias bool) *ast.Symbol { if moduleSymbol != nil { exportEquals := c.resolveSymbolEx(moduleSymbol.Exports[ast.InternalSymbolNameExportEquals], dontResolveAlias) - exported := c.getMergedSymbol(c.getCommonJsExportEquals(c.getMergedSymbol(exportEquals), c.getMergedSymbol(moduleSymbol))) - if exported != nil { - return exported + if exportEquals != nil { + return c.getMergedSymbol(exportEquals) } } return moduleSymbol } -func (c *Checker) getCommonJsExportEquals(exported *ast.Symbol, moduleSymbol *ast.Symbol) *ast.Symbol { - if exported == nil || exported == c.unknownSymbol || exported == moduleSymbol || len(moduleSymbol.Exports) == 1 || exported.Flags&ast.SymbolFlagsAlias != 0 { - return exported - } - links := c.moduleSymbolLinks.Get(exported) - if links.cjsExportMerged != nil { - return links.cjsExportMerged - } - var merged *ast.Symbol - if exported.Flags&ast.SymbolFlagsTransient != 0 { - merged = exported - } else { - merged = c.cloneSymbol(exported) - } - merged.Flags |= ast.SymbolFlagsValueModule - mergedExports := ast.GetExports(merged) - for name, s := range moduleSymbol.Exports { - if name != ast.InternalSymbolNameExportEquals { - if existing, ok := mergedExports[name]; ok { - s = c.mergeSymbol(existing, s /*unidirectional*/, false) - } - mergedExports[name] = s - } - } - if merged == exported { - // We just mutated a symbol, reset any cached links we may have already set - // (Notably required to make late bound members appear) - c.moduleSymbolLinks.Get(merged).resolvedExports = nil - } - c.moduleSymbolLinks.Get(merged).cjsExportMerged = merged - links.cjsExportMerged = merged - return links.cjsExportMerged -} - // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). @@ -14226,6 +14407,39 @@ func (c *Checker) getTypeWithSyntheticDefaultImportType(t *Type, symbol *ast.Sym return t } +func (c *Checker) isCommonJSRequire(node *ast.Node) bool { + if !ast.IsVariableDeclarationInitializedToRequire(node.Parent) { + return false + } + if !ast.IsIdentifier(node.Expression()) { + panic("Expected identifier for require call") + } + // Make sure require is not a local function + resolvedRequire := c.resolveName(node.Expression(), node.Expression().Text(), ast.SymbolFlagsValue, nil /*nameNotFoundMessage*/, true /*isUse*/, false /*excludeGlobals*/) + if resolvedRequire == c.requireSymbol { + return true + } + // project includes symbol named 'require' - make sure that it is ambient and local non-alias + if resolvedRequire == nil || resolvedRequire.Flags&ast.SymbolFlagsAlias != 0 { + return false + } + + var targetDeclarationKind ast.Kind + if resolvedRequire.Flags&ast.SymbolFlagsFunction != 0 { + targetDeclarationKind = ast.KindFunctionDeclaration + } else if resolvedRequire.Flags&ast.SymbolFlagsVariable != 0 { + targetDeclarationKind = ast.KindVariableDeclaration + } else { + targetDeclarationKind = ast.KindUnknown + } + if targetDeclarationKind != ast.KindUnknown { + decl := ast.GetDeclarationOfKind(resolvedRequire, targetDeclarationKind) + // function/variable declaration should be ambient + return decl != nil && decl.Flags&ast.NodeFlagsAmbient != 0 + } + return false +} + func (c *Checker) createDefaultPropertyWrapperForModule(symbol *ast.Symbol, originalSymbol *ast.Symbol, anonymousSymbol *ast.Symbol) *Type { memberTable := make(ast.SymbolTable) newSymbol := c.newSymbol(ast.SymbolFlagsAlias, ast.InternalSymbolNameDefault) @@ -14264,11 +14478,11 @@ func (c *Checker) getTargetOfAliasDeclaration(node *ast.Node, dontRecursivelyRes return c.getTargetOfNamespaceImport(node, dontRecursivelyResolve) case ast.KindNamespaceExport: return c.getTargetOfNamespaceExport(node, dontRecursivelyResolve) - case ast.KindImportSpecifier: + case ast.KindImportSpecifier, ast.KindBindingElement: return c.getTargetOfImportSpecifier(node, dontRecursivelyResolve) case ast.KindExportSpecifier: return c.getTargetOfExportSpecifier(node, ast.SymbolFlagsValue|ast.SymbolFlagsType|ast.SymbolFlagsNamespace, dontRecursivelyResolve) - case ast.KindExportAssignment: + case ast.KindExportAssignment, ast.KindJSExportAssignment: return c.getTargetOfExportAssignment(node, dontRecursivelyResolve) case ast.KindBinaryExpression: return c.getTargetOfBinaryExpression(node, dontRecursivelyResolve) @@ -14281,7 +14495,7 @@ func (c *Checker) getTargetOfAliasDeclaration(node *ast.Node, dontRecursivelyRes case ast.KindElementAccessExpression, ast.KindPropertyAccessExpression: return c.getTargetOfAccessExpression(node, dontRecursivelyResolve) } - panic("Unhandled case in getTargetOfAliasDeclaration") + panic("Unhandled case in getTargetOfAliasDeclaration: " + node.Kind.String()) } /** @@ -14317,7 +14531,10 @@ func (c *Checker) resolveEntityName(name *ast.Node, meaning ast.SymbolFlags, ign panic("Unknown entity name kind") } if symbol != nil && symbol != c.unknownSymbol { - if !ast.NodeIsSynthesized(name) && ast.IsEntityName(name) && (symbol.Flags&ast.SymbolFlagsAlias != 0 || name.Parent != nil && name.Parent.Kind == ast.KindExportAssignment) { + if !ast.NodeIsSynthesized(name) && ast.IsEntityName(name) && + (symbol.Flags&ast.SymbolFlagsAlias != 0 || + name.Parent != nil && name.Parent.Kind == ast.KindExportAssignment || + name.Parent != nil && name.Parent.Kind == ast.KindJSExportAssignment) { c.markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, nil /*finalTarget*/, true /*overwriteEmpty*/, nil, "") } if symbol.Flags&meaning == 0 && !dontResolveAlias { @@ -14335,9 +14552,24 @@ func (c *Checker) resolveQualifiedName(name *ast.Node, left *ast.Node, right *as if namespace == c.unknownSymbol { return namespace } + if namespace.ValueDeclaration != nil && + ast.IsInJSFile(namespace.ValueDeclaration) && + c.compilerOptions.GetModuleResolutionKind() != core.ModuleResolutionKindBundler && + ast.IsVariableDeclaration(namespace.ValueDeclaration) && + namespace.ValueDeclaration.AsVariableDeclaration().Initializer != nil && + c.isCommonJSRequire(namespace.ValueDeclaration.AsVariableDeclaration().Initializer) { + moduleName := namespace.ValueDeclaration.AsVariableDeclaration().Initializer.AsCallExpression().Arguments.Nodes[0] + moduleSym := c.resolveExternalModuleName(moduleName, moduleName, false /*ignoreErrors*/) + if moduleSym != nil { + resolvedModuleSymbol := c.resolveExternalModuleSymbol(moduleSym, false /*dontResolveAlias*/) + if resolvedModuleSymbol != nil { + namespace = resolvedModuleSymbol + } + } + } text := right.AsIdentifier().Text symbol := c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(namespace), text, meaning)) - if symbol != nil && namespace.Flags&ast.SymbolFlagsAlias != 0 { + if symbol == nil && namespace.Flags&ast.SymbolFlagsAlias != 0 { // `namespace` can be resolved further if there was a symbol merge with a re-export symbol = c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(c.resolveAlias(namespace)), text, meaning)) } @@ -14458,38 +14690,40 @@ func (c *Checker) getResolvedMembersOrExportsOfSymbol(symbol *ast.Symbol, resolu } } } - resolved := c.combineSymbolTables(earlySymbols, lateSymbols) - if symbol.Flags&ast.SymbolFlagsTransient != 0 && len(symbol.Declarations) != 0 { - moduleLinks := c.moduleSymbolLinks.Get(symbol) - if moduleLinks.cjsExportMerged != nil { - for _, decl := range symbol.Declarations { - original := c.membersAndExportsLinks.Get(decl.Symbol())[resolutionKind] - if resolved == nil { - resolved = original - continue - } - if original == nil { - continue - } - for name, s := range original { - existing := resolved[name] - if existing == nil { - resolved[name] = s - } else if existing != s { - resolved[name] = c.mergeSymbol(existing, s, false) - } - } - } - } - } - links[resolutionKind] = resolved + links[resolutionKind] = c.combineSymbolTables(earlySymbols, lateSymbols) } return links[resolutionKind] } +// Performs late-binding of a dynamic member. This performs the same function for +// late-bound members that `declareSymbol` in binder.ts performs for early-bound +// members. +// +// If a symbol is a dynamic name from a computed property, we perform an additional "late" +// binding phase to attempt to resolve the name for the symbol from the type of the computed +// property's expression. If the type of the expression is a string-literal, numeric-literal, +// or unique symbol type, we can use that type as the name of the symbol. +// +// For example, given: +// +// const x = Symbol(); +// +// interface I { +// [x]: number; +// } +// +// The binder gives the property `[x]: number` a special symbol with the name "__computed". +// In the late-binding phase we can type-check the expression `x` and see that it has a +// unique symbol type which we can then use as the name of the member. This allows users +// to define custom symbols that can be used in the members of an object type. +// +// @param parent The containing symbol for the member. +// @param earlySymbols The early-bound symbols of the parent. +// @param lateSymbols The late-bound symbols of the parent. +// @param decl The member to bind. func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTable, lateSymbols ast.SymbolTable, decl *ast.Node) *ast.Symbol { // Debug.assert(decl.Symbol, "The member is expected to have a symbol.") - links := c.typeNodeLinks.Get(decl) + links := c.symbolNodeLinks.Get(decl) if links.resolvedSymbol == nil { // In the event we attempt to resolve the late-bound name of this member recursively, // fall back to the early-bound name of this member. @@ -14517,8 +14751,7 @@ func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTabl } // Report an error if there's a symbol declaration with the same name and conflicting flags. earlySymbol := earlySymbols[memberName] - // Duplicate property declarations of classes are checked in checkClassForDuplicateDeclarations. - if parent.Flags&ast.SymbolFlagsClass == 0 && lateSymbol.Flags&getExcludedSymbolFlags(symbolFlags) != 0 { + if lateSymbol.Flags&getExcludedSymbolFlags(symbolFlags) != 0 { // If we have an existing early-bound member, combine its declarations so that we can // report an error at each declaration. var declarations []*ast.Node @@ -14532,9 +14765,12 @@ func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTabl name = scanner.DeclarationNameToString(declName) } for _, d := range declarations { - c.error(core.OrElse(ast.GetNameOfDeclaration(d), d), diagnostics.Property_0_was_also_declared_here, name) + c.error(core.OrElse(ast.GetNameOfDeclaration(d), d), diagnostics.Duplicate_identifier_0, name) + } + c.error(core.OrElse(declName, decl), diagnostics.Duplicate_identifier_0, name) + if lateSymbol.Flags&ast.SymbolFlagsAccessor != 0 && lateSymbol.Flags&ast.SymbolFlagsAccessor != symbolFlags&ast.SymbolFlagsAccessor { + lateSymbol.Flags |= ast.SymbolFlagsAccessor } - c.error(core.OrElse(declName, decl), diagnostics.Duplicate_property_0, name) lateSymbol = c.newSymbolEx(ast.SymbolFlagsNone, memberName, ast.CheckFlagsLate) } c.valueSymbolLinks.Get(lateSymbol).nameType = t @@ -14719,7 +14955,7 @@ func (c *Checker) resolveAlias(symbol *ast.Symbol) *ast.Symbol { links.aliasTarget = c.resolvingSymbol node := c.getDeclarationOfAliasSymbol(symbol) if node == nil { - panic("Unexpected nil in resolveAlias") + panic("Unexpected nil in resolveAlias for symbol: " + c.symbolToString(symbol)) } target := c.getTargetOfAliasDeclaration(node, false /*dontRecursivelyResolve*/) if links.aliasTarget == c.resolvingSymbol { @@ -15005,16 +15241,20 @@ func (c *Checker) getTypeOfVariableOrParameterOrPropertyWorker(symbol *ast.Symbo if symbol == c.requireSymbol { return c.anyType } - // !!! Handle SymbolFlagsModuleExports + if symbol.Flags&ast.SymbolFlagsModuleExports != 0 && symbol.ValueDeclaration != nil { + fileSymbol := c.resolveExternalModuleSymbol(symbol.ValueDeclaration.Symbol(), false /*dontResolveAlias*/) + members := make(ast.SymbolTable, 1) + members["exports"] = fileSymbol + return c.newAnonymousType(symbol, members, nil, nil, nil) + } // Debug.assertIsDefined(symbol.valueDeclaration) declaration := symbol.ValueDeclaration - // !!! Handle export default expressions if ast.IsSourceFile(declaration) && ast.IsJsonSourceFile(declaration.AsSourceFile()) { statements := declaration.AsSourceFile().Statements.Nodes if len(statements) == 0 { return c.emptyObjectType } - return c.getWidenedType(c.getWidenedLiteralType(c.checkExpression(statements[0].AsExpressionStatement().Expression))) + return c.getWidenedType(c.getWidenedLiteralType(c.checkExpression(statements[0].Expression()))) } // Handle variable, parameter or property if !c.pushTypeResolution(symbol, TypeSystemPropertyNameType) { @@ -15028,19 +15268,21 @@ func (c *Checker) getTypeOfVariableOrParameterOrPropertyWorker(symbol *ast.Symbo case ast.KindPropertyAssignment: result = c.checkPropertyAssignment(declaration, CheckModeNormal) case ast.KindShorthandPropertyAssignment: - result = c.checkExpressionForMutableLocation(declaration, CheckModeNormal) + result = c.checkExpressionForMutableLocation(declaration.Name(), CheckModeNormal) case ast.KindMethodDeclaration: result = c.checkObjectLiteralMethod(declaration, CheckModeNormal) - case ast.KindExportAssignment: + case ast.KindExportAssignment, ast.KindJSExportAssignment: result = c.widenTypeForVariableLikeDeclaration(c.checkExpressionCached(declaration.AsExportAssignment().Expression), declaration, false /*reportErrors*/) case ast.KindBinaryExpression: result = c.getWidenedTypeForAssignmentDeclaration(symbol) case ast.KindJsxAttribute: - result = c.checkJsxAttribute(declaration.AsJsxAttribute(), CheckModeNormal) + result = c.checkJsxAttribute(declaration, CheckModeNormal) case ast.KindEnumMember: result = c.getTypeOfEnumMember(symbol) + case ast.KindCommonJSExport: + result = c.checkExpression(declaration.AsCommonJSExport().Initializer) default: - panic("Unhandled case in getTypeOfVariableOrParameterOrPropertyWorker") + panic("Unhandled case in getTypeOfVariableOrParameterOrPropertyWorker: " + declaration.Kind.String()) } if !c.popTypeResolution() { return c.reportCircularityError(symbol) @@ -15087,7 +15329,7 @@ func (c *Checker) getTypeForVariableLikeDeclaration(declaration *ast.Node, inclu isProperty := ast.IsPropertyDeclaration(declaration) && !ast.HasAccessorModifier(declaration) || ast.IsPropertySignatureDeclaration(declaration) isOptional := includeOptionality && isOptionalDeclaration(declaration) // Use type from type annotation if one is present - declaredType := c.tryGetTypeFromEffectiveTypeNode(declaration) + declaredType := c.tryGetTypeFromTypeNode(declaration) if ast.IsCatchClauseVariableDeclarationOrBindingElement(declaration) { if declaredType != nil { // If the catch clause is explicitly annotated with any or unknown, accept it, otherwise error. @@ -15503,7 +15745,7 @@ func (c *Checker) getInferredTypeParameterConstraint(t *Type, omitTypeReferences // present, we form an intersection of the inferred constraint types. child := declaration.Parent parent := child.Parent - for parent != nil && ast.IsParenthesizedExpression(parent) { + for parent != nil && ast.IsParenthesizedTypeNode(parent) { child = parent parent = child.Parent } @@ -15568,7 +15810,7 @@ func (c *Checker) getInferredTypeParameterConstraint(t *Type, omitTypeReferences func (c *Checker) getTypeParametersForTypeReferenceOrImport(node *ast.Node) []*Type { t := c.getTypeFromTypeNode(node) if !c.isErrorType(t) { - symbol := c.typeNodeLinks.Get(node).resolvedSymbol + symbol := c.getResolvedSymbolOrNil(node) if symbol != nil { return c.getTypeParametersForTypeAndSymbol(t, symbol) } @@ -16107,7 +16349,7 @@ func (c *Checker) getBindingElementTypeFromParentType(declaration *ast.Node, par pattern := declaration.Parent // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation if c.strictNullChecks && declaration.Flags&ast.NodeFlagsAmbient != 0 && ast.IsPartOfParameterDeclaration(declaration) { - parentType = c.getNonNullableType(parentType) + parentType = c.GetNonNullableType(parentType) } else if c.strictNullChecks && pattern.Parent.Initializer() != nil && !(c.hasTypeFacts(c.getTypeOfInitializer(pattern.Parent.Initializer()), TypeFactsEQUndefined)) { parentType = c.getTypeWithFacts(parentType, TypeFactsNEUndefined) } @@ -16449,7 +16691,7 @@ func (c *Checker) getWidenedTypeForAssignmentDeclaration(symbol *ast.Symbol) *Ty var types []*Type for _, declaration := range symbol.Declarations { if ast.IsBinaryExpression(declaration) { - types = core.AppendIfUnique(types, c.getWidenedLiteralType(c.checkExpressionCached(declaration.AsBinaryExpression().Right))) + types = core.AppendIfUnique(types, c.checkExpressionForMutableLocation(declaration.AsBinaryExpression().Right, CheckModeNormal)) } } return c.getWidenedType(c.getUnionType(types)) @@ -16785,16 +17027,13 @@ func (c *Checker) getTypeOfAlias(symbol *ast.Symbol) *Type { } targetSymbol := c.resolveAlias(symbol) exportSymbol := c.getTargetOfAliasDeclaration(c.getDeclarationOfAliasSymbol(symbol), true /*dontRecursivelyResolve*/) - declaredType := c.getExportAssignmentType(exportSymbol) // It only makes sense to get the type of a value symbol. If the result of resolving // the alias is not a value, then it has no type. To get the type associated with a // type symbol, call getDeclaredTypeOfSymbol. // This check is important because without it, a call to getTypeOfSymbol could end // up recursively calling getTypeOfAlias, causing a stack overflow. if links.resolvedType == nil { - if declaredType != nil { - links.resolvedType = declaredType - } else if c.getSymbolFlags(targetSymbol)&ast.SymbolFlagsValue != 0 { + if c.getSymbolFlags(targetSymbol)&ast.SymbolFlagsValue != 0 { links.resolvedType = c.getTypeOfSymbol(targetSymbol) } else { links.resolvedType = c.errorType @@ -16811,20 +17050,6 @@ func (c *Checker) getTypeOfAlias(symbol *ast.Symbol) *Type { return links.resolvedType } -func (c *Checker) getExportAssignmentType(symbol *ast.Symbol) *Type { - if symbol != nil { - for _, d := range symbol.Declarations { - if ast.IsExportAssignment(d) { - t := c.tryGetTypeFromEffectiveTypeNode(d) - if t != nil { - return t - } - } - } - } - return nil -} - func (c *Checker) addOptionality(t *Type) *Type { return c.addOptionalityEx(t, false /*isProperty*/, true /*isOptional*/) } @@ -16859,20 +17084,20 @@ func (c *Checker) getNullableType(t *Type, flags TypeFlags) *Type { return c.getUnionType([]*Type{t, c.undefinedType, c.nullType}) } -func (c *Checker) getNonNullableType(t *Type) *Type { +func (c *Checker) GetNonNullableType(t *Type) *Type { if c.strictNullChecks { return c.getAdjustedTypeWithFacts(t, TypeFactsNEUndefinedOrNull) } return t } -func (c *Checker) isNullableType(t *Type) bool { +func (c *Checker) IsNullableType(t *Type) bool { return c.hasTypeFacts(t, TypeFactsIsUndefinedOrNull) } func (c *Checker) getNonNullableTypeIfNeeded(t *Type) *Type { - if c.isNullableType(t) { - return c.getNonNullableType(t) + if c.IsNullableType(t) { + return c.GetNonNullableType(t) } return t } @@ -16915,10 +17140,10 @@ func (c *Checker) tryGetNameFromType(t *Type) (name string, ok bool) { case t.flags&TypeFlagsUniqueESSymbol != 0: return t.AsUniqueESSymbolType().name, true case t.flags&TypeFlagsStringLiteral != 0: - s := t.AsLiteralType().value.(string) + s := getStringLiteralValue(t) return s, true case t.flags&TypeFlagsNumberLiteral != 0: - s := t.AsLiteralType().value.(jsnum.Number).String() + s := getNumberLiteralValue(t).String() return s, true default: return "", false @@ -17244,7 +17469,7 @@ func (c *Checker) isApplicableIndexType(source *Type, target *Type) bool { // signature applies to types assignable to 'number', `${number}` and numeric string literal types. return c.isTypeAssignableTo(source, target) || target == c.stringType && c.isTypeAssignableTo(source, c.numberType) || - target == c.numberType && (source == c.numericStringType || source.flags&TypeFlagsStringLiteral != 0 && isNumericLiteralName(source.AsLiteralType().value.(string))) + target == c.numberType && (source == c.numericStringType || source.flags&TypeFlagsStringLiteral != 0 && isNumericLiteralName(getStringLiteralValue(source))) } func (c *Checker) resolveStructuredTypeMembers(t *Type) *StructuredType { @@ -17451,7 +17676,7 @@ func (c *Checker) resolveBaseTypesOfClass(t *Type) { } func getBaseTypeNodeOfClass(t *Type) *ast.Node { - decl := getClassLikeDeclarationOfSymbol(t.symbol) + decl := ast.GetClassLikeDeclarationOfSymbol(t.symbol) if decl != nil { return ast.GetExtendsHeritageClauseElement(decl) } @@ -17729,7 +17954,7 @@ func (c *Checker) isValidBaseType(t *Type) bool { return c.isValidBaseType(constraint) } } - // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? + // TODO: Given that we allow type parameters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly<T>` should not. return t.flags&(TypeFlagsObject|TypeFlagsNonPrimitive|TypeFlagsAny) != 0 && !c.isGenericMappedType(t) || t.flags&TypeFlagsIntersection != 0 && core.Every(t.Types(), c.isValidBaseType) @@ -17800,8 +18025,9 @@ func (c *Checker) addInheritedMembers(symbols ast.SymbolTable, baseSymbols []*as func (c *Checker) resolveDeclaredMembers(t *Type) *InterfaceType { d := t.AsInterfaceType() if !d.declaredMembersResolved { + members := c.getMembersOfSymbol(t.symbol) d.declaredMembersResolved = true - d.declaredMembers = c.getMembersOfSymbol(t.symbol) + d.declaredMembers = members d.declaredCallSignatures = c.getSignaturesOfSymbol(d.declaredMembers[ast.InternalSymbolNameCall]) d.declaredConstructSignatures = c.getSignaturesOfSymbol(d.declaredMembers[ast.InternalSymbolNameNew]) d.declaredIndexInfos = c.getIndexInfosOfSymbol(t.symbol) @@ -17840,7 +18066,7 @@ func (c *Checker) getIndexInfosOfIndexSymbol(indexSymbol *ast.Symbol, siblingSym } forEachType(c.getTypeFromTypeNode(typeNode), func(keyType *Type) { if c.isValidIndexKeyType(keyType) && findIndexInfo(indexInfos, keyType) == nil { - indexInfo := c.newIndexInfo(keyType, valueType, hasEffectiveModifier(declaration, ast.ModifierFlagsReadonly), declaration) + indexInfo := c.newIndexInfo(keyType, valueType, hasModifier(declaration, ast.ModifierFlagsReadonly), declaration) indexInfos = append(indexInfos, indexInfo) } }) @@ -17866,17 +18092,17 @@ func (c *Checker) getIndexInfosOfIndexSymbol(indexSymbol *ast.Symbol, siblingSym if c.isTypeAssignableTo(keyType, c.stringNumberSymbolType) { if c.isTypeAssignableTo(keyType, c.numberType) { hasComputedNumberProperty = true - if !hasEffectiveReadonlyModifier(declaration) { + if !hasReadonlyModifier(declaration) { readonlyComputedNumberProperty = false } } else if c.isTypeAssignableTo(keyType, c.esSymbolType) { hasComputedSymbolProperty = true - if !hasEffectiveReadonlyModifier(declaration) { + if !hasReadonlyModifier(declaration) { readonlyComputedSymbolProperty = false } } else { hasComputedStringProperty = true - if !hasEffectiveReadonlyModifier(declaration) { + if !hasReadonlyModifier(declaration) { readonlyComputedStringProperty = false } } @@ -17922,7 +18148,7 @@ func (c *Checker) getObjectLiteralIndexInfo(isReadonly bool, properties []*ast.S } func (c *Checker) isSymbolWithSymbolName(symbol *ast.Symbol) bool { - if isKnownSymbol(symbol) { + if IsKnownSymbol(symbol) { return true } if len(symbol.Declarations) != 0 { @@ -17997,7 +18223,7 @@ func (c *Checker) getSignaturesOfSymbol(symbol *ast.Symbol) []*Signature { } } // If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters. - // Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible. + // Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would suppress checks that the two are compatible. result = append(result, c.getSignatureFromDeclaration(decl)) } return result @@ -18259,7 +18485,7 @@ func getEffectiveSetAccessorTypeAnnotationNode(node *ast.Node) *ast.Node { func getSetAccessorValueParameter(accessor *ast.Node) *ast.Node { parameters := accessor.Parameters() if len(parameters) > 0 { - hasThis := len(parameters) == 2 && parameterIsThisKeyword(parameters[0]) + hasThis := len(parameters) == 2 && ast.IsThisParameter(parameters[0]) return parameters[core.IfElse(hasThis, 1, 0)] } return nil @@ -18543,7 +18769,7 @@ func (c *Checker) getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(t *Ty case contextualSignatureReturnType == nil: // No contextual type case isAsync: - contextualType = c.getPromisedTypeOfPromise(contextualSignatureReturnType) + contextualType = c.GetPromisedTypeOfPromise(contextualSignatureReturnType) default: contextualType = contextualSignatureReturnType } @@ -18992,7 +19218,7 @@ func isThislessTypeParameter(node *ast.Node) bool { func (c *Checker) getDefaultConstructSignatures(classType *Type) []*Signature { baseConstructorType := c.getBaseConstructorTypeOfClass(classType) baseSignatures := c.getSignaturesOfType(baseConstructorType, SignatureKindConstruct) - declaration := getClassLikeDeclarationOfSymbol(classType.symbol) + declaration := ast.GetClassLikeDeclarationOfSymbol(classType.symbol) isAbstract := declaration != nil && ast.HasSyntacticModifier(declaration, ast.ModifierFlagsAbstract) if len(baseSignatures) == 0 { flags := core.IfElse(isAbstract, SignatureFlagsConstruct|SignatureFlagsAbstract, SignatureFlagsConstruct) @@ -19337,7 +19563,7 @@ func (c *Checker) combineUnionOrIntersectionMemberSignatures(left *Signature, ri } else { leftSignatures = []*Signature{left} } - result.composite = &CompositeSignature{isUnion: true, signatures: append(leftSignatures, right)} + result.composite = &CompositeSignature{isUnion: isUnion, signatures: append(leftSignatures, right)} if paramMapper != nil { if left.composite != nil && left.composite.isUnion == isUnion && left.mapper != nil { result.mapper = c.combineTypeMappers(left.mapper, paramMapper) @@ -20216,15 +20442,8 @@ func (c *Checker) isNamedMember(symbol *ast.Symbol, id string) bool { return !isReservedMemberName(id) && c.symbolIsValue(symbol) } -// A reserved member name consists of the byte 0xFE (which is an invalid UTF-8 encoding) followed by one or more -// characters where the first character is not '@' or '#'. The '@' character indicates that the name is denoted by -// a well known ES Symbol instance and the '#' character indicates that the name is a PrivateIdentifier. -func isReservedMemberName(name string) bool { - return len(name) >= 2 && name[0] == '\xFE' && name[1] != '@' && name[1] != '#' -} - func (c *Checker) symbolIsValue(symbol *ast.Symbol) bool { - return c.symbolIsValueEx(symbol, false /*includeTyoeOnlyMembers*/) + return c.symbolIsValueEx(symbol, false /*includeTypeOnlyMembers*/) } func (c *Checker) symbolIsValueEx(symbol *ast.Symbol, includeTypeOnlyMembers bool) bool { @@ -20242,12 +20461,12 @@ func (c *Checker) instantiateTypeWithAlias(t *Type, m *TypeMapper, alias *TypeAl } if c.instantiationDepth == 100 || c.instantiationCount >= 5_000_000 { // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement - // or expression. There is a very high likelyhood we're dealing with a combination of infinite generic types + // or expression. There is a very high likelihood we're dealing with a combination of infinite generic types // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. c.error(c.currentNode, diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite) return c.errorType } - c.totalInstantiationCount++ + c.TotalInstantiationCount++ c.instantiationCount++ c.instantiationDepth++ result := c.instantiateTypeWorker(t, m, alias) @@ -20279,6 +20498,9 @@ func (c *Checker) couldContainTypeVariablesWorker(t *Type) bool { func (c *Checker) isNonGenericTopLevelType(t *Type) bool { if t.alias != nil && len(t.alias.typeArguments) == 0 { declaration := ast.GetDeclarationOfKind(t.alias.symbol, ast.KindTypeAliasDeclaration) + if declaration == nil { + declaration = ast.GetDeclarationOfKind(t.alias.symbol, ast.KindJSTypeAliasDeclaration) + } return declaration != nil && ast.FindAncestorOrQuit(declaration.Parent, func(n *ast.Node) ast.FindAncestorResult { switch n.Kind { case ast.KindSourceFile: @@ -20371,7 +20593,7 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias return t } -// Handles instantion of the following object types: +// Handles instantiation of the following object types: // AnonymousType (ObjectFlagsAnonymous) // TypeReference with node != nil (ObjectFlagsReference) // SingleSignatureType (ObjectFlagsSingleSignatureType) @@ -20443,7 +20665,7 @@ func (c *Checker) getObjectTypeInstantiation(t *Type, m *TypeMapper, alias *Type newAlias = c.instantiateTypeAlias(t.alias, m) } data := target.AsObjectType() - key := getTypeInstantiationKey(typeArguments, alias, t.objectFlags&ObjectFlagsSingleSignatureType != 0) + key := getTypeInstantiationKey(typeArguments, newAlias, t.objectFlags&ObjectFlagsSingleSignatureType != 0) if data.instantiations == nil { data.instantiations = make(map[string]*Type) data.instantiations[getTypeInstantiationKey(typeParameters, target.alias, false)] = target @@ -20465,6 +20687,20 @@ func (c *Checker) getObjectTypeInstantiation(t *Type, m *TypeMapper, alias *Type result = c.instantiateAnonymousType(target, newMapper, newAlias) } data.instantiations[key] = result + if result.flags&TypeFlagsObjectFlagsType != 0 && result.objectFlags&ObjectFlagsCouldContainTypeVariablesComputed == 0 { + // if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments + resultCouldContainObjectFlags := core.Some(typeArguments, c.couldContainTypeVariables) + if result.objectFlags&ObjectFlagsCouldContainTypeVariablesComputed == 0 { + if result.objectFlags&(ObjectFlagsMapped|ObjectFlagsAnonymous|ObjectFlagsReference) != 0 { + result.objectFlags |= ObjectFlagsCouldContainTypeVariablesComputed | core.IfElse(resultCouldContainObjectFlags, ObjectFlagsCouldContainTypeVariables, 0) + } else { + // If none of the type arguments for the outer type parameters contain type variables, it follows + // that the instantiated type doesn't reference type variables. + // Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType` + result.objectFlags |= core.IfElse(!resultCouldContainObjectFlags, ObjectFlagsCouldContainTypeVariablesComputed, 0) + } + } + } } return result } @@ -20477,7 +20713,7 @@ func (c *Checker) isTypeParameterPossiblyReferenced(tp *Type, node *ast.Node) bo return tp.AsTypeParameter().isThisType case ast.KindTypeReference: // use worker because we're looking for === equality - if !tp.AsTypeParameter().isThisType && len(node.TypeArguments()) == 0 && c.getTypeFromTypeNodeWorker(node) == tp { + if !tp.AsTypeParameter().isThisType && len(node.TypeArguments()) == 0 && c.getSymbolFromTypeReference(node) == tp.symbol { return true } case ast.KindTypeQuery: @@ -20512,7 +20748,7 @@ func (c *Checker) isTypeParameterPossiblyReferenced(tp *Type, node *ast.Node) bo // between the node and the type parameter declaration, if the node contains actual references to the // type parameter, or if the node contains type queries that we can't prove couldn't contain references to the type parameter, // we consider the type parameter possibly referenced. - if tp.symbol != nil && tp.symbol.Declarations != nil && len(tp.symbol.Declarations) == 1 { + if tp.symbol != nil && len(tp.symbol.Declarations) == 1 { container := tp.symbol.Declarations[0].Parent for n := node; n != container; n = n.Parent { if n == nil || ast.IsBlock(n) || ast.IsConditionalTypeNode(n) && containsReference(n.AsConditionalTypeNode().ExtendsType) { @@ -20867,7 +21103,7 @@ func instantiateList[T comparable](c *Checker, values []T, m *TypeMapper, instan return values } -func (c *Checker) tryGetTypeFromEffectiveTypeNode(node *ast.Node) *Type { +func (c *Checker) tryGetTypeFromTypeNode(node *ast.Node) *Type { typeNode := node.Type() if typeNode != nil { return c.getTypeFromTypeNode(typeNode) @@ -20881,8 +21117,21 @@ func (c *Checker) getTypeFromTypeNode(node *ast.Node) *Type { func (c *Checker) getTypeFromTypeNodeWorker(node *ast.Node) *Type { switch node.Kind { - case ast.KindAnyKeyword: + case ast.KindAnyKeyword, ast.KindJSDocAllType: return c.anyType + case ast.KindJSDocNonNullableType: + return c.getTypeFromTypeNode(node.AsJSDocNonNullableType().Type) + case ast.KindJSDocNullableType: + t := c.getTypeFromTypeNode(node.AsJSDocNullableType().Type) + if c.strictNullChecks { + return c.getNullableType(t, TypeFlagsNull) + } else { + return t + } + case ast.KindJSDocVariadicType: + return c.createArrayType(c.getTypeFromTypeNode(node.AsJSDocVariadicType().Type)) + case ast.KindJSDocOptionalType: + return c.addOptionality(c.getTypeFromTypeNode(node.AsJSDocOptionalType().Type)) case ast.KindUnknownKeyword: return c.unknownType case ast.KindStringKeyword: @@ -20904,11 +21153,7 @@ func (c *Checker) getTypeFromTypeNodeWorker(node *ast.Node) *Type { case ast.KindNeverKeyword: return c.neverType case ast.KindObjectKeyword: - if node.Flags&ast.NodeFlagsJavaScriptFile != 0 && !c.noImplicitAny { - return c.anyType - } else { - return c.nonPrimitiveType - } + return c.nonPrimitiveType case ast.KindIntrinsicKeyword: return c.intrinsicMarkerType case ast.KindThisType, ast.KindThisKeyword: @@ -21065,22 +21310,31 @@ func (c *Checker) getESSymbolLikeTypeForNode(node *ast.Node) *Type { func (c *Checker) getTypeFromTypeReference(node *ast.Node) *Type { links := c.typeNodeLinks.Get(node) if links.resolvedType == nil { + // Cache both the resolved symbol and the resolved type. The resolved symbol is needed when we check the + // type reference in checkTypeReferenceNode. + symbol := c.getSymbolFromTypeReference(node) // handle LS queries on the `const` in `x as const` by resolving to the type of `x` if isConstTypeReference(node) && ast.IsAssertionExpression(node.Parent) { - links.resolvedSymbol = c.unknownSymbol links.resolvedType = c.checkExpressionCached(node.Parent.Expression()) - return links.resolvedType + } else { + links.resolvedType = c.getTypeReferenceType(node, symbol) } - symbol := c.resolveTypeReferenceName(node, ast.SymbolFlagsType, false /*ignoreErrors*/) - t := c.getTypeReferenceType(node, symbol) - // Cache both the resolved symbol and the resolved type. The resolved symbol is needed when we check the - // type reference in checkTypeReferenceNode. - links.resolvedSymbol = symbol - links.resolvedType = t } return links.resolvedType } +func (c *Checker) getSymbolFromTypeReference(node *ast.Node) *ast.Symbol { + links := c.symbolNodeLinks.Get(node) + if links.resolvedSymbol == nil { + if isConstTypeReference(node) && ast.IsAssertionExpression(node.Parent) { + links.resolvedSymbol = c.unknownSymbol + } else { + links.resolvedSymbol = c.resolveTypeReferenceName(node, ast.SymbolFlagsType, false /*ignoreErrors*/) + } + } + return links.resolvedSymbol +} + func (c *Checker) resolveTypeReferenceName(typeReference *ast.Node, meaning ast.SymbolFlags, ignoreErrors bool) *ast.Symbol { name := getTypeReferenceName(typeReference) if name == nil { @@ -21235,7 +21489,7 @@ func (c *Checker) isResolvedByTypeAlias(node *ast.Node) bool { case ast.KindParenthesizedType, ast.KindNamedTupleMember, ast.KindTypeReference, ast.KindUnionType, ast.KindIntersectionType, ast.KindIndexedAccessType, ast.KindConditionalType, ast.KindTypeOperator, ast.KindArrayType, ast.KindTupleType: return c.isResolvedByTypeAlias(parent) - case ast.KindTypeAliasDeclaration: + case ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration: return true } return false @@ -21733,7 +21987,7 @@ func (c *Checker) getOuterTypeParameters(node *ast.Node, includeThisTypes bool) switch kind { case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration, ast.KindCallSignature, ast.KindConstructSignature, ast.KindMethodSignature, ast.KindFunctionType, ast.KindConstructorType, ast.KindFunctionDeclaration, - ast.KindMethodDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindTypeAliasDeclaration, ast.KindMappedType, + ast.KindMethodDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, ast.KindConditionalType: outerTypeParameters := c.getOuterTypeParameters(node, includeThisTypes) if (kind == ast.KindFunctionExpression || kind == ast.KindArrowFunction || ast.IsObjectLiteralMethod(node)) && c.isContextSensitive(node) { @@ -21812,7 +22066,7 @@ func (c *Checker) getDeclaredTypeOfTypeAlias(symbol *ast.Symbol) *Type { if !c.pushTypeResolution(symbol, TypeSystemPropertyNameDeclaredType) { return c.errorType } - declaration := core.Find(symbol.Declarations, ast.IsTypeAliasDeclaration) + declaration := core.Find(symbol.Declarations, ast.IsTypeOrJSTypeAliasDeclaration) typeNode := declaration.AsTypeAliasDeclaration().Type t := c.getTypeFromTypeNode(typeNode) if c.popTypeResolution() { @@ -21851,7 +22105,7 @@ func (c *Checker) getDeclaredTypeOfEnum(symbol *ast.Symbol) *Type { for _, member := range declaration.Members() { if c.hasBindableName(member) { memberSymbol := c.getSymbolOfDeclaration(member) - value := c.getEnumMemberValue(member).value + value := c.getEnumMemberValue(member).Value var memberType *Type if value != nil { memberType = c.getEnumLiteralType(value, symbol, memberSymbol) @@ -21879,7 +22133,7 @@ func (c *Checker) getDeclaredTypeOfEnum(symbol *ast.Symbol) *Type { return links.declaredType } -func (c *Checker) getEnumMemberValue(node *ast.Node) EvaluatorResult { +func (c *Checker) getEnumMemberValue(node *ast.Node) evaluator.Result { c.computeEnumMemberValues(node.Parent) return c.enumMemberLinks.Get(node).value } @@ -21890,6 +22144,7 @@ func (c *Checker) createComputedEnumType(symbol *ast.Symbol) *Type { freshType := c.newLiteralType(TypeFlagsEnum, nil, regularType) freshType.symbol = symbol regularType.AsLiteralType().freshType = freshType + freshType.AsLiteralType().freshType = freshType return regularType } @@ -21913,7 +22168,7 @@ func (c *Checker) computeEnumMemberValues(node *ast.Node) { for _, member := range node.Members() { result := c.computeEnumMemberValue(member, autoValue, previous) c.enumMemberLinks.Get(member).value = result - if value, isNumber := result.value.(jsnum.Number); isNumber { + if value, isNumber := result.Value.(jsnum.Number); isNumber { autoValue = value + 1 } else { autoValue = jsnum.NaN() @@ -21923,7 +22178,7 @@ func (c *Checker) computeEnumMemberValues(node *ast.Node) { } } -func (c *Checker) computeEnumMemberValue(member *ast.Node, autoValue jsnum.Number, previous *ast.Node) EvaluatorResult { +func (c *Checker) computeEnumMemberValue(member *ast.Node, autoValue jsnum.Number, previous *ast.Node) evaluator.Result { if ast.IsComputedNonLiteralName(member.Name()) { c.error(member.Name(), diagnostics.Computed_property_names_are_not_allowed_in_enums) } else { @@ -21938,7 +22193,7 @@ func (c *Checker) computeEnumMemberValue(member *ast.Node, autoValue jsnum.Numbe // In ambient non-const numeric enum declarations, enum members without initializers are // considered computed members (as opposed to having auto-incremented values). if member.Parent.Flags&ast.NodeFlagsAmbient != 0 && !ast.IsEnumConst(member.Parent) { - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) } // If the member declaration specifies no value, the member is considered a constant enum member. // If the member is the first member in the enum declaration, it is assigned the value zero. @@ -21946,33 +22201,33 @@ func (c *Checker) computeEnumMemberValue(member *ast.Node, autoValue jsnum.Numbe // occurs if the immediately preceding member is not a constant enum member. if autoValue.IsNaN() { c.error(member.Name(), diagnostics.Enum_member_must_have_initializer) - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) } if c.compilerOptions.GetIsolatedModules() && previous != nil && previous.AsEnumMember().Initializer != nil { prevValue := c.getEnumMemberValue(previous) - _, prevIsNum := prevValue.value.(jsnum.Number) - if !prevIsNum || prevValue.resolvedOtherFiles { + _, prevIsNum := prevValue.Value.(jsnum.Number) + if !prevIsNum || prevValue.ResolvedOtherFiles { c.error(member.Name(), diagnostics.Enum_member_following_a_non_literal_numeric_member_must_have_an_initializer_when_isolatedModules_is_enabled) } } - return evaluatorResult(autoValue, false, false, false) + return evaluator.NewResult(autoValue, false, false, false) } -func (c *Checker) computeConstantEnumMemberValue(member *ast.Node) EvaluatorResult { +func (c *Checker) computeConstantEnumMemberValue(member *ast.Node) evaluator.Result { isConstEnum := ast.IsEnumConst(member.Parent) initializer := member.Initializer() result := c.evaluate(initializer, member) switch { - case result.value != nil: + case result.Value != nil: if isConstEnum { - if numValue, isNumber := result.value.(jsnum.Number); isNumber && (numValue.IsInf() || numValue.IsNaN()) { + if numValue, isNumber := result.Value.(jsnum.Number); isNumber && (numValue.IsInf() || numValue.IsNaN()) { c.error(initializer, core.IfElse(numValue.IsNaN(), diagnostics.X_const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN, diagnostics.X_const_enum_member_initializer_was_evaluated_to_a_non_finite_value)) } } if c.compilerOptions.GetIsolatedModules() { - if _, isString := result.value.(string); isString && !result.isSyntacticallyString { + if _, isString := result.Value.(string); isString && !result.IsSyntacticallyString { memberName := member.Parent.Name().Text() + "." + member.Name().Text() c.error(initializer, diagnostics.X_0_has_a_string_type_but_must_have_syntactically_recognizable_string_syntax_when_isolatedModules_is_enabled, memberName) } @@ -21987,19 +22242,19 @@ func (c *Checker) computeConstantEnumMemberValue(member *ast.Node) EvaluatorResu return result } -func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) EvaluatorResult { +func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) evaluator.Result { switch expr.Kind { case ast.KindIdentifier, ast.KindPropertyAccessExpression: symbol := c.resolveEntityName(expr, ast.SymbolFlagsValue, true /*ignoreErrors*/, false, nil) if symbol == nil { - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) } if expr.Kind == ast.KindIdentifier { if isInfinityOrNaNString(expr.Text()) && (symbol == c.getGlobalSymbol(expr.Text(), ast.SymbolFlagsValue, nil /*diagnostic*/)) { // Technically we resolved a global lib file here, but the decision to treat this as numeric // is more predicated on the fact that the single-file resolution *didn't* resolve to a // different meaning of `Infinity` or `NaN`. Transpilers handle this no problem. - return evaluatorResult(jsnum.FromString(expr.Text()), false, false, false) + return evaluator.NewResult(jsnum.FromString(expr.Text()), false, false, false) } } if symbol.Flags&ast.SymbolFlagsEnumMember != 0 { @@ -22010,16 +22265,16 @@ func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) EvaluatorRe } if c.isConstantVariable(symbol) { declaration := symbol.ValueDeclaration - if declaration != nil && declaration.Type() == nil && declaration.Initializer() != nil && + if declaration != nil && ast.IsVariableDeclaration(declaration) && declaration.Type() == nil && declaration.Initializer() != nil && (location == nil || declaration != location && c.isBlockScopedNameDeclaredBeforeUse(declaration, location)) { result := c.evaluate(declaration.Initializer(), declaration) if location != nil && ast.GetSourceFileOfNode(location) != ast.GetSourceFileOfNode(declaration) { - return evaluatorResult(result.value, false, true, true) + return evaluator.NewResult(result.Value, false, true, true) } - return evaluatorResult(result.value, result.isSyntacticallyString, result.resolvedOtherFiles, true /*hasExternalReferences*/) + return evaluator.NewResult(result.Value, result.IsSyntacticallyString, result.ResolvedOtherFiles, true /*hasExternalReferences*/) } } - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) case ast.KindElementAccessExpression: root := expr.Expression() if ast.IsEntityNameExpression(root) && ast.IsStringLiteralLike(expr.AsElementAccessExpression().ArgumentExpression) { @@ -22036,24 +22291,24 @@ func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) EvaluatorRe } } } - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) } panic("Unhandled case in evaluateEntity") } -func (c *Checker) evaluateEnumMember(expr *ast.Node, symbol *ast.Symbol, location *ast.Node) EvaluatorResult { +func (c *Checker) evaluateEnumMember(expr *ast.Node, symbol *ast.Symbol, location *ast.Node) evaluator.Result { declaration := symbol.ValueDeclaration if declaration == nil || declaration == location { c.error(expr, diagnostics.Property_0_is_used_before_being_assigned, c.symbolToString(symbol)) - return evaluatorResult(nil, false, false, false) + return evaluator.NewResult(nil, false, false, false) } if !c.isBlockScopedNameDeclaredBeforeUse(declaration, location) { c.error(expr, diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums) - return evaluatorResult(jsnum.Number(0), false, false, false) + return evaluator.NewResult(jsnum.Number(0), false, false, false) } value := c.getEnumMemberValue(declaration) if location.Parent != declaration.Parent { - return evaluatorResult(value.value, value.isSyntacticallyString, value.resolvedOtherFiles, true /*hasExternalReferences*/) + return evaluator.NewResult(value.Value, value.IsSyntacticallyString, value.ResolvedOtherFiles, true /*hasExternalReferences*/) } return value } @@ -22541,7 +22796,7 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { n := node.AsImportTypeNode() if !ast.IsLiteralImportTypeNode(node) { c.error(n.Argument, diagnostics.String_literal_expected) - links.resolvedSymbol = c.unknownSymbol + c.symbolNodeLinks.Get(node).resolvedSymbol = c.unknownSymbol links.resolvedType = c.errorType return links.resolvedType } @@ -22549,7 +22804,7 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { // TODO: Future work: support unions/generics/whatever via a deferred import-type innerModuleSymbol := c.resolveExternalModuleName(node, n.Argument.AsLiteralTypeNode().Literal, false /*ignoreErrors*/) if innerModuleSymbol == nil { - links.resolvedSymbol = c.unknownSymbol + c.symbolNodeLinks.Get(node).resolvedSymbol = c.unknownSymbol links.resolvedType = c.errorType return links.resolvedType } @@ -22579,20 +22834,20 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { links.resolvedType = c.errorType return links.resolvedType } - c.typeNodeLinks.Get(current).resolvedSymbol = next - c.typeNodeLinks.Get(current.Parent).resolvedSymbol = next + c.symbolNodeLinks.Get(current).resolvedSymbol = next + c.symbolNodeLinks.Get(current.Parent).resolvedSymbol = next currentNamespace = next } - links.resolvedType = c.resolveImportSymbolType(node, links, currentNamespace, targetMeaning) + links.resolvedType = c.resolveImportSymbolType(node, currentNamespace, targetMeaning) } else { if moduleSymbol.Flags&targetMeaning != 0 { - links.resolvedType = c.resolveImportSymbolType(node, links, moduleSymbol, targetMeaning) + links.resolvedType = c.resolveImportSymbolType(node, moduleSymbol, targetMeaning) } else { message := core.IfElse(targetMeaning == ast.SymbolFlagsValue, diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here, diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0) c.error(node, message, n.Argument.AsLiteralTypeNode().Literal.Text()) - links.resolvedSymbol = c.unknownSymbol + c.symbolNodeLinks.Get(node).resolvedSymbol = c.unknownSymbol links.resolvedType = c.errorType } } @@ -22607,9 +22862,9 @@ func (c *Checker) getIdentifierChain(node *ast.Node) []*ast.Node { return append(c.getIdentifierChain(node.AsQualifiedName().Left), node.AsQualifiedName().Right) } -func (c *Checker) resolveImportSymbolType(node *ast.Node, links *TypeNodeLinks, symbol *ast.Symbol, meaning ast.SymbolFlags) *Type { +func (c *Checker) resolveImportSymbolType(node *ast.Node, symbol *ast.Symbol, meaning ast.SymbolFlags) *Type { resolvedSymbol := c.resolveSymbol(symbol) - links.resolvedSymbol = resolvedSymbol + c.symbolNodeLinks.Get(node).resolvedSymbol = resolvedSymbol if meaning == ast.SymbolFlagsValue { // intentionally doesn't use resolved symbol so type is cached as expected on the alias return c.getInstantiationExpressionType(c.getTypeOfSymbol(symbol), node) @@ -23266,7 +23521,7 @@ func (c *Checker) getNumberLiteralType(value jsnum.Number) *Type { return t } -func (c *Checker) getBigIntLiteralType(value PseudoBigInt) *Type { +func (c *Checker) getBigIntLiteralType(value jsnum.PseudoBigInt) *Type { t := c.bigintLiteralTypes[value] if t == nil { t = c.newLiteralType(TypeFlagsBigIntLiteral, value, nil) @@ -23275,6 +23530,12 @@ func (c *Checker) getBigIntLiteralType(value PseudoBigInt) *Type { return t } +// text is a valid bigint string excluding a trailing `n`, but including a possible prefix `-`. +// Use `isValidBigIntString(text, roundTripOnly)` before calling this function. +func (c *Checker) parseBigIntLiteralType(text string) *Type { + return c.getBigIntLiteralType(jsnum.ParseValidBigInt(text)) +} + func getStringLiteralValue(t *Type) string { return t.AsLiteralType().value.(string) } @@ -23283,8 +23544,8 @@ func getNumberLiteralValue(t *Type) jsnum.Number { return t.AsLiteralType().value.(jsnum.Number) } -func getBigIntLiteralValue(t *Type) PseudoBigInt { - return t.AsLiteralType().value.(PseudoBigInt) +func getBigIntLiteralValue(t *Type) jsnum.PseudoBigInt { + return t.AsLiteralType().value.(jsnum.PseudoBigInt) } func getBooleanLiteralValue(t *Type) bool { @@ -23512,6 +23773,9 @@ func (c *Checker) mapTypeEx(t *Type, f func(*Type) *Type, noReductions bool) *Ty } } if changed { + if len(mappedTypes) == 0 { + return nil + } return c.getUnionTypeEx(slices.Clone(mappedTypes), core.IfElse(noReductions, UnionReductionNone, UnionReductionLiteral), nil /*alias*/, nil /*origin*/) } return t @@ -23672,6 +23936,10 @@ func (c *Checker) getUnionTypeFromSortedList(types []*Type, precomputedObjectFla return t } +func (c *Checker) UnionTypes() iter.Seq[*Type] { + return maps.Values(c.unionTypes) +} + func (c *Checker) addTypesToUnion(typeSet []*Type, includes TypeFlags, types []*Type) ([]*Type, TypeFlags) { var lastType *Type for _, t := range types { @@ -23713,7 +23981,7 @@ func (c *Checker) addTypeToUnion(typeSet []*Type, includes TypeFlags, t *Type) ( includes |= TypeFlagsIncludesNonWideningType } } else { - if index, ok := slices.BinarySearchFunc(typeSet, t, compareTypes); !ok { + if index, ok := slices.BinarySearchFunc(typeSet, t, CompareTypes); !ok { typeSet = slices.Insert(typeSet, index, t) } } @@ -24155,7 +24423,7 @@ func (c *Checker) addTypeToIntersection(typeSet *orderedSet[*Type], includes Typ if flags&TypeFlagsIntersection != 0 { return c.addTypesToIntersection(typeSet, includes, t.Types()) } - if c.isEmptyAnonymousObjectType(t) { + if c.IsEmptyAnonymousObjectType(t) { if includes&TypeFlagsIncludesEmptyObject == 0 { includes |= TypeFlagsIncludesEmptyObject typeSet.add(t) @@ -24197,7 +24465,7 @@ func (c *Checker) removeRedundantSupertypes(types []*Type, includes TypeFlags) [ t.flags&TypeFlagsBigInt != 0 && includes&TypeFlagsBigIntLiteral != 0 || t.flags&TypeFlagsESSymbol != 0 && includes&TypeFlagsUniqueESSymbol != 0 || t.flags&TypeFlagsVoid != 0 && includes&TypeFlagsUndefined != 0 || - c.isEmptyAnonymousObjectType(t) && includes&TypeFlagsDefinitelyNonNullable != 0 + c.IsEmptyAnonymousObjectType(t) && includes&TypeFlagsDefinitelyNonNullable != 0 if remove { types = slices.Delete(types, i, i+1) } @@ -24363,7 +24631,7 @@ func (c *Checker) filterTypes(types []*Type, predicate func(*Type) bool) { } } -func (c *Checker) isEmptyAnonymousObjectType(t *Type) bool { +func (c *Checker) IsEmptyAnonymousObjectType(t *Type) bool { return t.objectFlags&ObjectFlagsAnonymous != 0 && (t.objectFlags&ObjectFlagsMembersResolved != 0 && c.isEmptyResolvedType(t.AsStructuredType()) || t.symbol != nil && t.symbol.Flags&ast.SymbolFlagsTypeLiteral != 0 && len(c.getMembersOfSymbol(t.symbol)) == 0) } @@ -24438,6 +24706,13 @@ func everyType(t *Type, f func(*Type) bool) bool { return f(t) } +func everyContainedType(t *Type, f func(*Type) bool) bool { + if t.flags&TypeFlagsUnionOrIntersection != 0 { + return core.Every(t.Types(), f) + } + return f(t) +} + func (c *Checker) filterType(t *Type, f func(*Type) bool) *Type { if t.flags&TypeFlagsUnion != 0 { types := t.Types() @@ -24479,12 +24754,12 @@ func (c *Checker) removeType(t *Type, targetType *Type) *Type { } func containsType(types []*Type, t *Type) bool { - _, ok := slices.BinarySearchFunc(types, t, compareTypes) + _, ok := slices.BinarySearchFunc(types, t, CompareTypes) return ok } func insertType(types []*Type, t *Type) ([]*Type, bool) { - if i, ok := slices.BinarySearchFunc(types, t, compareTypes); !ok { + if i, ok := slices.BinarySearchFunc(types, t, CompareTypes); !ok { return slices.Insert(types, i, t), true } return types, false @@ -24601,7 +24876,7 @@ func (c *Checker) getLiteralTypeFromProperty(prop *ast.Symbol, include TypeFlags if name != nil { t = c.getLiteralTypeFromPropertyName(name) } - if t == nil && !isKnownSymbol(prop) { + if t == nil && !IsKnownSymbol(prop) { t = c.getStringLiteralType(ast.SymbolName(prop)) } } @@ -24678,7 +24953,7 @@ func (c *Checker) shouldDeferIndexType(t *Type, indexFlags IndexFlags) bool { c.isGenericTupleType(t) || c.isGenericMappedType(t) && (!c.hasDistributiveNameType(t) || c.getMappedTypeNameTypeKind(t) == MappedTypeNameTypeKindRemapping) || t.flags&TypeFlagsUnion != 0 && indexFlags&IndexFlagsNoReducibleCheck == 0 && c.isGenericReducibleType(t) || - t.flags&TypeFlagsIntersection != 0 && c.maybeTypeOfKind(t, TypeFlagsInstantiable) && core.Some(t.Types(), c.isEmptyAnonymousObjectType) + t.flags&TypeFlagsIntersection != 0 && c.maybeTypeOfKind(t, TypeFlagsInstantiable) && core.Some(t.Types(), c.IsEmptyAnonymousObjectType) } // Ordinarily we reduce a keyof M, where M is a mapped type { [P in K as N<P>]: X }, to simply N<K>. This however presumes @@ -24908,7 +25183,7 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy return nil } if accessFlags&AccessFlagsCacheSymbol != 0 { - c.typeNodeLinks.Get(accessNode).resolvedSymbol = prop + c.symbolNodeLinks.Get(accessNode).resolvedSymbol = prop } if c.isThisPropertyAccessInConstructor(accessExpression, prop) { return c.autoType @@ -25114,6 +25389,11 @@ func (c *Checker) getSuggestionForNonexistentIndexSignature(objectType *Type, ex return suggestion + "." + suggestedMethod } +func (c *Checker) getSuggestedTypeForNonexistentStringLiteralType(source *Type, target *Type) *Type { + candidates := core.Filter(target.Types(), func(t *Type) bool { return t.flags&TypeFlagsStringLiteral != 0 }) + return core.GetSpellingSuggestion(getStringLiteralValue(source), candidates, getStringLiteralValue) +} + func getIndexNodeForAccessExpression(accessNode *ast.Node) *ast.Node { switch accessNode.Kind { case ast.KindElementAccessExpression: @@ -25141,6 +25421,21 @@ func (c *Checker) isAssignmentToReadonlyEntity(expr *ast.Node, symbol *ast.Symbo // no assignment means it doesn't matter whether the entity is readonly return false } + if ast.IsAccessExpression(expr) { + node := ast.SkipParentheses(expr.Expression()) + if ast.IsIdentifier(node) { + expressionSymbol := c.getResolvedSymbol(node) + // CommonJS module.exports is never readonly + if expressionSymbol.Flags&ast.SymbolFlagsModuleExports != 0 { + return false + } + // references through namespace import should be readonly + if expressionSymbol.Flags&ast.SymbolFlagsAlias != 0 { + declaration := c.getDeclarationOfAliasSymbol(expressionSymbol) + return declaration != nil && ast.IsNamespaceImport(declaration) + } + } + } if c.isReadonlySymbol(symbol) { // Allow assignments to readonly properties within constructors of the same class declaration. if symbol.Flags&ast.SymbolFlagsProperty != 0 && ast.IsAccessExpression(expr) && expr.Expression().Kind == ast.KindThisKeyword { @@ -25161,17 +25456,6 @@ func (c *Checker) isAssignmentToReadonlyEntity(expr *ast.Node, symbol *ast.Symbo } return true } - if ast.IsAccessExpression(expr) { - // references through namespace import should be readonly - node := ast.SkipParentheses(expr.Expression()) - if ast.IsIdentifier(node) { - symbol := c.getResolvedSymbol(node) - if symbol.Flags&ast.SymbolFlagsAlias != 0 { - declaration := c.getDeclarationOfAliasSymbol(symbol) - return declaration != nil && ast.IsNamespaceImport(declaration) - } - } - } return false } @@ -25248,7 +25532,7 @@ func (c *Checker) isNoInferTargetType(t *Type) bool { // examine all object type members. return t.flags&TypeFlagsUnionOrIntersection != 0 && core.Some(t.AsUnionOrIntersectionType().types, c.isNoInferTargetType) || t.flags&TypeFlagsSubstitution != 0 && !c.isNoInferType(t) && c.isNoInferTargetType(t.AsSubstitutionType().baseType) || - t.flags&TypeFlagsObject != 0 && !c.isEmptyAnonymousObjectType(t) || + t.flags&TypeFlagsObject != 0 && !c.IsEmptyAnonymousObjectType(t) || t.flags&(TypeFlagsInstantiable & ^TypeFlagsSubstitution) != 0 && !c.isPatternLiteralType(t) } @@ -25542,7 +25826,7 @@ func (c *Checker) markPropertyAsReferenced(prop *ast.Symbol, nodeForCheckWriteOn if prop.Flags&ast.SymbolFlagsClassMember == 0 || prop.ValueDeclaration == nil { return } - hasPrivateModifier := hasEffectiveModifier(prop.ValueDeclaration, ast.ModifierFlagsPrivate) + hasPrivateModifier := hasModifier(prop.ValueDeclaration, ast.ModifierFlagsPrivate) hasPrivateIdentifier := prop.ValueDeclaration.Name() != nil && ast.IsPrivateIdentifier(prop.ValueDeclaration.Name()) if !hasPrivateModifier && !hasPrivateIdentifier { return @@ -25564,6 +25848,73 @@ func (c *Checker) markPropertyAsReferenced(prop *ast.Symbol, nodeForCheckWriteOn c.symbolReferenceLinks.Get(target).referenceKinds |= ast.SymbolFlagsAll } +func (c *Checker) GetExpandedParameters(signature *Signature /* !!! skipUnionExpanding */) []*ast.Symbol { + if signatureHasRestParameter(signature) { + restIndex := len(signature.parameters) - 1 + restSymbol := signature.parameters[restIndex] + restType := c.getTypeOfSymbol(restSymbol) + if isTupleType(restType) { + return c.expandSignatureParametersWithTupleMembers(signature, restType.AsTypeReference(), restIndex, restSymbol) + } + } + return signature.parameters +} + +func (c *Checker) expandSignatureParametersWithTupleMembers(signature *Signature, restType *TypeReference, restIndex int, restSymbol *ast.Symbol) []*ast.Symbol { + elementTypes := c.getTypeArguments(restType.AsType()) + elementInfos := restType.TargetTupleType().elementInfos + associatedNames := c.getUniqAssociatedNamesFromTupleType(restType, restSymbol) + expanded := append(make([]*ast.Symbol, 0, restIndex+len(elementTypes)), signature.parameters[:restIndex]...) + for i, t := range elementTypes { + flags := elementInfos[i].flags + checkFlags := ast.CheckFlagsNone + switch { + case flags&ElementFlagsVariable != 0: + checkFlags = ast.CheckFlagsRestParameter + case flags&ElementFlagsOptional != 0: + checkFlags = ast.CheckFlagsOptionalParameter + } + symbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable, associatedNames[i], checkFlags) + links := c.valueSymbolLinks.Get(symbol) + if flags&ElementFlagsRest != 0 { + links.resolvedType = c.createArrayType(t) + } else { + links.resolvedType = t + } + expanded = append(expanded, symbol) + } + return expanded +} + +func (c *Checker) getUniqAssociatedNamesFromTupleType(t *TypeReference, restSymbol *ast.Symbol) []string { + elementInfos := t.TargetTupleType().elementInfos + names := make([]string, len(elementInfos)) + counters := make(map[string]int) + for i, info := range elementInfos { + names[i] = c.getTupleElementLabel(info, restSymbol, i) + // count duplicates using negative values + counters[names[i]]-- + } + for i, name := range names { + if counters[name] == -1 { + continue + } + for { + if counters[name] < 0 { + // switch to a positive suffix counter + counters[name] = 0 + } + counters[name]++ + candidateName := name + "_" + strconv.Itoa(counters[name]) + if counters[candidateName] == 0 { + names[i] = candidateName + break + } + } + } + return names +} + func hasRestParameter(signature *ast.Node) bool { last := core.LastOrNil(signature.Parameters()) return last != nil && isRestParameter(last) @@ -25585,7 +25936,7 @@ func (c *Checker) isUnknownLikeUnionType(t *Type) bool { if t.objectFlags&ObjectFlagsIsUnknownLikeUnionComputed == 0 { t.objectFlags |= ObjectFlagsIsUnknownLikeUnionComputed types := t.Types() - if len(types) >= 3 && types[0].flags&TypeFlagsUndefined != 0 && types[1].flags&TypeFlagsNull != 0 && core.Some(types, c.isEmptyAnonymousObjectType) { + if len(types) >= 3 && types[0].flags&TypeFlagsUndefined != 0 && types[1].flags&TypeFlagsNull != 0 && core.Some(types, c.IsEmptyAnonymousObjectType) { t.objectFlags |= ObjectFlagsIsUnknownLikeUnion } } @@ -25800,7 +26151,7 @@ func (c *Checker) shouldNormalizeIntersection(t *Type) bool { hasNullableOrEmpty := false for _, t := range t.Types() { hasInstantiable = hasInstantiable || t.flags&TypeFlagsInstantiable != 0 - hasNullableOrEmpty = hasNullableOrEmpty || t.flags&TypeFlagsNullable != 0 || c.isEmptyAnonymousObjectType(t) + hasNullableOrEmpty = hasNullableOrEmpty || t.flags&TypeFlagsNullable != 0 || c.IsEmptyAnonymousObjectType(t) if hasInstantiable && hasNullableOrEmpty { return true } @@ -26020,7 +26371,7 @@ func isExportOrExportExpression(location *ast.Node) bool { return ast.FindAncestor(location, func(n *ast.Node) bool { parent := n.Parent if parent != nil { - if ast.IsExportAssignment(parent) { + if ast.IsAnyExportAssignment(parent) { return parent.AsExportAssignment().Expression == n && ast.IsEntityNameExpression(n) } if ast.IsExportSpecifier(parent) { @@ -26059,7 +26410,7 @@ func isInternalModuleImportEqualsDeclaration(node *ast.Node) bool { func (c *Checker) markIdentifierAliasReferenced(location *ast.IdentifierNode) { symbol := c.getResolvedSymbol(location) - if symbol != nil && symbol != c.argumentsSymbol && symbol != c.unknownSymbol && !isThisInTypeQuery(location) { + if symbol != nil && symbol != c.argumentsSymbol && symbol != c.unknownSymbol && !ast.IsThisInTypeQuery(location) { c.markAliasReferenced(symbol, location) } } @@ -26144,7 +26495,39 @@ func (c *Checker) markExportAssignmentAliasReferenced(location *ast.Node /*Expor } func (c *Checker) markJsxAliasReferenced(node *ast.Node /*JsxOpeningLikeElement | JsxOpeningFragment*/) { - // !!! + if c.getJsxNamespaceContainerForImplicitImport(node) != nil { + return + } + // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. + // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. + jsxFactoryRefErr := core.IfElse(c.compilerOptions.Jsx == core.JsxEmitReact, diagnostics.This_JSX_tag_requires_0_to_be_in_scope_but_it_could_not_be_found, nil) + jsxFactoryNamespace := c.getJsxNamespace(node) + jsxFactoryLocation := node + if isJsxOpeningLikeElement(node) { + jsxFactoryLocation = node.TagName() + } + // allow null as jsxFragmentFactory + var jsxFactorySym *ast.Symbol + if !(ast.IsJsxOpeningFragment(node) && jsxFactoryNamespace == "null") { + jsxFactorySym = c.resolveName(jsxFactoryLocation, jsxFactoryNamespace, ast.SymbolFlagsValue, jsxFactoryRefErr, true /*isUse*/, false /*excludeGlobals*/) + } + if jsxFactorySym != nil { + // Mark local symbol as referenced here because it might not have been marked + // if jsx emit was not jsxFactory as there wont be error being emitted + c.symbolReferenced(jsxFactorySym, ast.SymbolFlagsAll) + // If react/jsxFactory symbol is alias, mark it as refereced + if c.canCollectSymbolAliasAccessibilityData && jsxFactorySym.Flags&ast.SymbolFlagsAlias != 0 && c.getTypeOnlyAliasDeclaration(jsxFactorySym) == nil { + c.markAliasSymbolAsReferenced(jsxFactorySym) + } + } + // For JsxFragment, mark jsx pragma as referenced via resolveName + if ast.IsJsxOpeningFragment(node) { + file := ast.GetSourceFileOfNode(node) + localJsxNamespace := c.getLocalJsxNamespace(file) + if localJsxNamespace != "" { + c.resolveName(jsxFactoryLocation, localJsxNamespace, ast.SymbolFlagsValue, jsxFactoryRefErr, true /*isUse*/, false /*excludeGlobals*/) + } + } } func (c *Checker) markImportEqualsAliasReferenced(location *ast.Node /*ImportEqualsDeclaration*/) { @@ -26179,14 +26562,14 @@ func (c *Checker) markExportSpecifierAliasReferenced(location *ast.ExportSpecifi } func (c *Checker) markDecoratorAliasReferenced(node *ast.Node /*HasDecorators*/) { - // !!! + // !!! Implement if/when we support emitDecoratorMetadata } func (c *Checker) markAliasReferenced(symbol *ast.Symbol, location *ast.Node) { if !c.canCollectSymbolAliasAccessibilityData { return } - if ast.IsNonLocalAlias(symbol, ast.SymbolFlagsValue /*excludes*/) && !isInTypeQuery(location) { + if ast.IsNonLocalAlias(symbol, ast.SymbolFlagsValue /*excludes*/) && !IsInTypeQuery(location) { target := c.resolveAlias(symbol) if c.getSymbolFlagsEx(symbol, true /*excludeTypeOnlyMeanings*/, false /*excludeLocalMeanings*/)&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue) != 0 { // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled @@ -26256,7 +26639,7 @@ func (c *Checker) markEntityNameOrEntityExpressionAsReference(typeName *ast.Node c.compilerOptions.GetIsolatedModules() && c.compilerOptions.GetEmitModuleKind() >= core.ModuleKindES2015 && !c.symbolIsValue(rootSymbol) && - !core.Some(rootSymbol.Declarations, isTypeOnlyImportOrExportDeclaration) { + !core.Some(rootSymbol.Declarations, ast.IsTypeOnlyImportOrExportDeclaration) { diag := c.error(typeName, diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled) var aliasDeclaration *ast.Node for _, decl := range rootSymbol.Declarations { @@ -26299,11 +26682,7 @@ func (c *Checker) markTypeNodeAsReferenced(node *ast.TypeNode) { } } -func (c *Checker) markDecoratorMedataDataTypeNodeAsReferenced(node *ast.TypeNode) { - // !!! -} - -func (c *Checker) getPromisedTypeOfPromise(t *Type) *Type { +func (c *Checker) GetPromisedTypeOfPromise(t *Type) *Type { return c.getPromisedTypeOfPromiseEx(t, nil, nil) } @@ -26451,7 +26830,7 @@ func isPartialMappedType(t *Type) bool { func (c *Checker) getOptionalExpressionType(exprType *Type, expression *ast.Node) *Type { switch { case ast.IsExpressionOfOptionalChainRoot(expression): - return c.getNonNullableType(exprType) + return c.GetNonNullableType(exprType) case ast.IsOptionalChain(expression): return c.removeOptionalTypeMarker(exprType) default: @@ -26508,8 +26887,8 @@ func (c *Checker) getDefinitelyFalsyPartOfType(t *Type) *Type { return c.zeroBigIntType case t == c.regularFalseType || t == c.falseType || t.flags&(TypeFlagsVoid|TypeFlagsUndefined|TypeFlagsNull|TypeFlagsAnyOrUnknown) != 0 || - t.flags&TypeFlagsStringLiteral != 0 && t.AsLiteralType().value.(string) == "" || - t.flags&TypeFlagsNumberLiteral != 0 && t.AsLiteralType().value.(jsnum.Number) == 0 || + t.flags&TypeFlagsStringLiteral != 0 && getStringLiteralValue(t) == "" || + t.flags&TypeFlagsNumberLiteral != 0 && getNumberLiteralValue(t) == 0 || t.flags&TypeFlagsBigIntLiteral != 0 && isZeroBigInt(t): return t } @@ -26518,9 +26897,12 @@ func (c *Checker) getDefinitelyFalsyPartOfType(t *Type) *Type { func (c *Checker) getConstraintDeclaration(t *Type) *ast.Node { if t.symbol != nil { - declaration := core.Find(t.symbol.Declarations, ast.IsTypeParameterDeclaration) - if declaration != nil { - return declaration.AsTypeParameter().Constraint + for _, d := range t.symbol.Declarations { + if ast.IsTypeParameterDeclaration(d) { + if constraint := d.AsTypeParameter().Constraint; constraint != nil { + return constraint + } + } } } return nil @@ -26597,7 +26979,7 @@ func (c *Checker) getTemplateLiteralType(texts []string, types []*Type) *Type { func (c *Checker) getTemplateStringForType(t *Type) string { switch { case t.flags&(TypeFlagsStringLiteral|TypeFlagsNumberLiteral|TypeFlagsBooleanLiteral|TypeFlagsBigIntLiteral) != 0: - return anyToString(t.AsLiteralType().value) + return evaluator.AnyToString(t.AsLiteralType().value) case t.flags&TypeFlagsNullable != 0: return t.AsIntrinsicType().intrinsicName } @@ -26777,7 +27159,7 @@ func (c *Checker) getContextualType(node *ast.Node, contextFlags ContextFlags) * case ast.KindSatisfiesExpression: return c.getTypeFromTypeNode(parent.AsSatisfiesExpression().Type) case ast.KindExportAssignment: - return c.tryGetTypeFromEffectiveTypeNode(parent) + return c.tryGetTypeFromTypeNode(parent) case ast.KindJsxExpression: return c.getContextualTypeForJsxExpression(parent, contextFlags) case ast.KindJsxAttribute, ast.KindJsxSpreadAttribute: @@ -26842,7 +27224,7 @@ func (c *Checker) getContextuallyTypedParameterType(parameter *ast.Node) *Type { return nil } iife := ast.GetImmediatelyInvokedFunctionExpression(fn) - if iife != nil && len(iife.Arguments()) != 0 { + if iife != nil { args := c.getEffectiveCallArguments(iife) indexOfParameter := slices.Index(fn.Parameters(), parameter) if hasDotDotDotToken(parameter) { @@ -27166,10 +27548,9 @@ func (c *Checker) getContextualTypeForArgumentAtIndex(callTarget *ast.Node, argI } else { signature = c.getResolvedSignature(callTarget, nil, CheckModeNormal) } - // !!! - // if isJsxOpeningLikeElement(callTarget) && argIndex == 0 { - // return c.getEffectiveFirstArgumentForJsxSignature(signature, callTarget) - // } + if isJsxOpeningLikeElement(callTarget) && argIndex == 0 { + return c.getEffectiveFirstArgumentForJsxSignature(signature, callTarget) + } restIndex := len(signature.parameters) - 1 if signatureHasRestParameter(signature) && argIndex >= restIndex { return c.getIndexedAccessTypeEx(c.getTypeOfSymbol(signature.parameters[restIndex]), c.getNumberLiteralType(jsnum.Number(argIndex-restIndex)), AccessFlagsContextual, nil, nil) @@ -27189,9 +27570,9 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags binary := node.Parent.AsBinaryExpression() switch binary.OperatorToken.Kind { case ast.KindEqualsToken, ast.KindAmpersandAmpersandEqualsToken, ast.KindBarBarEqualsToken, ast.KindQuestionQuestionEqualsToken: - // In an assignment expression, the right operand is contextually typed by the type of the left operand. - // If the binary operator has a symbol, this is an assignment declaration and there is no contextual type. - if node == binary.Right && binary.Symbol == nil { + // In an assignment expression, the right operand is contextually typed by the type of the left operand + // unless it's an assignment declaration. + if node == binary.Right && !c.isReferenceToModuleExports(binary.Left) && (binary.Symbol == nil || c.canGetContextualTypeForAssignmentDeclaration(binary.Left)) { return c.getContextualTypeFromAssignmentTarget(binary.Left) } case ast.KindBarBarToken, ast.KindQuestionQuestionToken: @@ -27213,6 +27594,27 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags return nil } +func (c *Checker) canGetContextualTypeForAssignmentDeclaration(node *ast.Node) bool { + // Node is the left operand of an assignment declaration (a binary expression with a symbol assigned by the + // binder) of the form 'F.id = expr' or 'F[xxx] = expr'. If 'F' is declared as a variable with a type annotation, + // we can obtain a contextual type from the annotated type without triggering a circularity. Otherwise, the + // assignment declaration has no contextual type. + symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(node.Expression())) + return symbol.ValueDeclaration != nil && ast.IsVariableDeclaration(symbol.ValueDeclaration) && symbol.ValueDeclaration.Type() != nil +} + +func (c *Checker) isReferenceToModuleExports(node *ast.Node) bool { + if ast.IsAccessExpression(node) { + expr := node.Expression() + if ast.IsIdentifier(expr) { + // Node is the left operand of an assignment expression of the form 'module.exports = expr'. + symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(expr)) + return symbol.Flags&ast.SymbolFlagsModuleExports != 0 + } + } + return false +} + func (c *Checker) getContextualTypeFromAssignmentTarget(node *ast.Node) *Type { if ast.IsAccessExpression(node) && node.Expression().Kind == ast.KindThisKeyword { var symbol *ast.Symbol @@ -27354,18 +27756,6 @@ func (c *Checker) getContextualTypeForSubstitutionExpression(template *ast.Node, return nil } -func (c *Checker) getContextualTypeForJsxExpression(node *ast.Node, contextFlags ContextFlags) *Type { - return nil // !!! -} - -func (c *Checker) getContextualTypeForJsxAttribute(attribute *ast.Node, contextFlags ContextFlags) *Type { - return nil // !!! -} - -func (c *Checker) getContextualJsxElementAttributesType(attribute *ast.Node, contextFlags ContextFlags) *Type { - return nil // !!! -} - func (c *Checker) getContextualImportAttributeType(node *ast.Node) *Type { return c.getTypeOfPropertyOfContextualType(c.getGlobalImportAttributesType(), node.Name().Text()) } @@ -27388,11 +27778,13 @@ func (c *Checker) getEffectiveCallArguments(node *ast.Node) []*ast.Node { return args case ast.IsDecorator(node): return c.getEffectiveDecoratorArguments(node) + case ast.IsBinaryExpression(node): + // Handles instanceof operator + return []*ast.Node{node.AsBinaryExpression().Left} case isJsxOpeningLikeElement(node): - // !!! - // if node.Attributes.Properties.length > 0 || (isJsxOpeningElement(node) && node.Parent.Children.length > 0) { - // return []JsxAttributes{node.Attributes} - // } + if len(node.Attributes().AsJsxAttributes().Properties.Nodes) != 0 || (ast.IsJsxOpeningElement(node) && len(node.Parent.Children().Nodes) != 0) { + return []*ast.Node{node.Attributes()} + } return nil default: args := node.Arguments() @@ -27748,7 +28140,7 @@ func (c *Checker) newClassSetterDecoratorContextType(classType *Type, valueType } func (c *Checker) newClassAccessorDecoratorContextType(thisType *Type, valueType *Type) *Type { - return c.tryCreateTypeReference(c.getGlobalClassAccessorDecoratorContxtType(), []*Type{thisType, valueType}) + return c.tryCreateTypeReference(c.getGlobalClassAccessorDecoratorContextType(), []*Type{thisType, valueType}) } func (c *Checker) newClassFieldDecoratorContextType(thisType *Type, valueType *Type) *Type { @@ -28057,8 +28449,13 @@ func (d *ObjectLiteralDiscriminator) matches(index int, t *Type) bool { var propType *Type if index < len(d.props) { prop := d.props[index] - if ast.IsPropertyAssignment(prop) { - propType = d.c.getContextFreeTypeOfExpression(prop.Initializer()) + if ast.IsPropertyAssignment(prop) || ast.IsJsxAttribute(prop) { + initializer := prop.Initializer() + if initializer != nil { + propType = d.c.getContextFreeTypeOfExpression(prop.Initializer()) + } else { + propType = d.c.trueType // JsxAttribute without initializer is always true + } } else { propType = d.c.getContextFreeTypeOfExpression(prop.Name()) } @@ -28127,17 +28524,12 @@ func (c *Checker) isPossiblyDiscriminantValue(node *ast.Node) bool { return true case ast.KindPropertyAccessExpression, ast.KindParenthesizedExpression: return c.isPossiblyDiscriminantValue(node.Expression()) - // !!! - // case ast.KindJsxExpression: - // return node.AsJsxExpression().Expression == nil || c.isPossiblyDiscriminantValue(node.AsJsxExpression().Expression) + case ast.KindJsxExpression: + return node.AsJsxExpression().Expression == nil || c.isPossiblyDiscriminantValue(node.AsJsxExpression().Expression) } return false } -func (c *Checker) discriminateContextualTypeByJSXAttributes(node *ast.Node, contextualType *Type) *Type { - return contextualType // !!! -} - // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. func (c *Checker) instantiateContextualType(contextualType *Type, node *ast.Node, contextFlags ContextFlags) *Type { @@ -28230,17 +28622,16 @@ func (c *Checker) isContextSensitive(node *ast.Node) bool { return c.isContextSensitive(node.Initializer()) case ast.KindParenthesizedExpression: return c.isContextSensitive(node.Expression()) - // !!! - // case ast.KindJsxAttributes: - // return core.Some(node.AsJsxAttributes().Properties, c.isContextSensitive) || isJsxOpeningElement(node.Parent) && core.Some(node.Parent.Parent.Children, c.isContextSensitive) - // case ast.KindJsxAttribute: - // // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. - // TODO_IDENTIFIER := node.AsJsxAttribute() - // return initializer != nil && c.isContextSensitive(initializer) - // case ast.KindJsxExpression: - // // It is possible to that node.expression is undefined (e.g <div x={} />) - // TODO_IDENTIFIER := node.AsJsxExpression() - // return expression != nil && c.isContextSensitive(expression) + case ast.KindJsxAttributes: + return core.Some(node.AsJsxAttributes().Properties.Nodes, c.isContextSensitive) || ast.IsJsxOpeningElement(node.Parent) && core.Some(node.Parent.Parent.Children().Nodes, c.isContextSensitive) + case ast.KindJsxAttribute: + // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. + initializer := node.Initializer() + return initializer != nil && c.isContextSensitive(initializer) + case ast.KindJsxExpression: + // It is possible to that node.expression is undefined (e.g <div x={} />) + expression := node.Expression() + return expression != nil && c.isContextSensitive(expression) } return false } @@ -28305,7 +28696,7 @@ func (c *Checker) getTypeFactsWorker(t *Type, callerOnlyNeeds TypeFacts) TypeFac } return TypeFactsStringFacts case flags&(TypeFlagsStringLiteral|TypeFlagsTemplateLiteral) != 0: - isEmpty := flags&TypeFlagsStringLiteral != 0 && t.AsLiteralType().value.(string) == "" + isEmpty := flags&TypeFlagsStringLiteral != 0 && getStringLiteralValue(t) == "" if c.strictNullChecks { if isEmpty { return TypeFactsEmptyStringStrictFacts @@ -28322,7 +28713,7 @@ func (c *Checker) getTypeFactsWorker(t *Type, callerOnlyNeeds TypeFacts) TypeFac } return TypeFactsNumberFacts case flags&TypeFlagsNumberLiteral != 0: - isZero := t.AsLiteralType().value.(jsnum.Number) == 0 + isZero := getNumberLiteralValue(t) == 0 if c.strictNullChecks { if isZero { return TypeFactsZeroNumberStrictFacts @@ -28445,7 +28836,7 @@ func (c *Checker) getIntersectionTypeFacts(t *Type, callerOnlyNeeds TypeFacts) T } func isZeroBigInt(t *Type) bool { - return t.AsLiteralType().value.(PseudoBigInt).base10Value == "0" + return getBigIntLiteralValue(t) == jsnum.PseudoBigInt{} } func (c *Checker) isFunctionObjectType(t *Type) bool { @@ -28496,7 +28887,7 @@ func (c *Checker) removeNullableByIntersection(t *Type, targetFacts TypeFacts, o // By default we intersect with a union of {} and the opposite nullable. emptyAndOtherUnion := c.getUnionType([]*Type{c.emptyObjectType, otherType}) // For each constituent type that can compare equal to the target nullable, intersect with the above union - // if the type doesn't already include the opppsite nullable and the constituent can compare equal to the + // if the type doesn't already include the opposite nullable and the constituent can compare equal to the // opposite nullable; otherwise, just intersect with {}. return c.mapType(t, func(t *Type) *Type { if c.hasTypeFacts(t, targetFacts) { @@ -28907,7 +29298,7 @@ func (c *Checker) GetSymbolAtLocation(node *ast.Node) *ast.Symbol { // `getSymbolOfDeclaration` for a declaration, etc. func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Symbol { if ast.IsSourceFile(node) { - if ast.IsExternalModule(node.AsSourceFile()) { + if ast.IsExternalOrCommonJSModule(node.AsSourceFile()) { return c.getMergedSymbol(node.Symbol()) } return nil @@ -28963,7 +29354,7 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy switch node.Kind { case ast.KindIdentifier, ast.KindPrivateIdentifier, ast.KindPropertyAccessExpression, ast.KindQualifiedName: - if !isThisInTypeQuery(node) { + if !ast.IsThisInTypeQuery(node) { return c.getSymbolOfNameOrPropertyAccessExpression(node) } fallthrough @@ -28993,9 +29384,11 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy case ast.KindStringLiteral, ast.KindNoSubstitutionTemplateLiteral: // 1). import x = require("./mo/*gotToDefinitionHere*/d") // 2). External module name in an import declaration + // 3). Require in Javascript // 4). type A = import("./f/*gotToDefinitionHere*/oo") if (ast.IsExternalModuleImportEqualsDeclaration(grandParent) && getExternalModuleImportEqualsDeclarationExpression(grandParent) == node) || ((parent.Kind == ast.KindImportDeclaration || parent.Kind == ast.KindExportDeclaration) && parent.AsImportDeclaration().ModuleSpecifier == node) || + ast.IsVariableDeclarationInitializedToRequire(grandParent) || (ast.IsLiteralTypeNode(parent) && ast.IsLiteralImportTypeNode(grandParent) && grandParent.AsImportTypeNode().Argument == parent) { return c.resolveExternalModuleName(node, node, ignoreErrors) } @@ -29062,15 +29455,6 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy } } -// Looks up an intrinsic tag name and returns a symbol that either points to an intrinsic -// property (in which case nodeLinks.jsxFlags will be IntrinsicNamedElement) or an intrinsic -// string index signature (in which case nodeLinks.jsxFlags will be IntrinsicIndexedElement). -// May also return unknownSymbol if both of these lookups fail. -func (c *Checker) getIntrinsicTagSymbol(node *ast.Node) *ast.Symbol { - // !!! JSX - return nil -} - func (c *Checker) getSymbolOfNameOrPropertyAccessExpression(name *ast.Node) *ast.Symbol { if ast.IsDeclarationName(name) { return c.getSymbolOfNode(name.Parent) @@ -29098,7 +29482,7 @@ func (c *Checker) getSymbolOfNameOrPropertyAccessExpression(name *ast.Node) *ast possibleImportNode := isImportTypeQualifierPart(name) if possibleImportNode != nil { c.getTypeFromTypeNode(possibleImportNode) - sym := c.typeNodeLinks.Get(name).resolvedSymbol + sym := c.getResolvedSymbolOrNil(name) return core.IfElse(sym == c.unknownSymbol, nil, sym) } } @@ -29153,7 +29537,7 @@ func (c *Checker) getSymbolOfNameOrPropertyAccessExpression(name *ast.Node) *ast } else if ast.IsPrivateIdentifier(name) { return c.getSymbolForPrivateIdentifierExpression(name) } else if name.Kind == ast.KindPropertyAccessExpression || name.Kind == ast.KindQualifiedName { - links := c.typeNodeLinks.Get(name) + links := c.symbolNodeLinks.Get(name) if links.resolvedSymbol != nil { return links.resolvedSymbol } @@ -29209,7 +29593,7 @@ func (c *Checker) isThisPropertyAndThisTyped(node *ast.Node) bool { } func (c *Checker) getTypeOfNode(node *ast.Node) *Type { - if ast.IsSourceFile(node) && !ast.IsExternalModule(node.AsSourceFile()) { + if ast.IsSourceFile(node) && !ast.IsExternalOrCommonJSModule(node.AsSourceFile()) { return c.errorType } @@ -29420,3 +29804,13 @@ func (c *Checker) GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool) pr } return c.emitResolver } + +// !!! +func (c *Checker) GetAccessibleSymbolChain( + symbol *ast.Symbol, + enclosingDeclaration *ast.Node, + meaning ast.SymbolFlags, + useOnlyExternalAliasing bool, +) []*ast.Symbol { + return nil +} diff --git a/internal/checker/emitresolver.go b/internal/checker/emitresolver.go index 090f2b3d66..978cf716d3 100644 --- a/internal/checker/emitresolver.go +++ b/internal/checker/emitresolver.go @@ -38,7 +38,7 @@ func (r *emitResolver) IsReferencedAliasDeclaration(node *ast.Node) bool { return true } target := aliasLinks.aliasTarget - if target != nil && getEffectiveModifierFlags(node)&ast.ModifierFlagsExport != 0 && + if target != nil && node.ModifierFlags()&ast.ModifierFlagsExport != 0 && c.getSymbolFlags(target)&ast.SymbolFlagsValue != 0 && (c.compilerOptions.ShouldPreserveConstEnums() || !isConstEnumOrConstEnumOnlyModule(target)) { return true @@ -79,9 +79,9 @@ func (r *emitResolver) isValueAliasDeclarationWorker(node *ast.Node) bool { } return exportClause != nil && (ast.IsNamespaceExport(exportClause) || core.Some(exportClause.AsNamedExports().Elements.Nodes, r.isValueAliasDeclaration)) - case ast.KindExportAssignment: + case ast.KindExportAssignment, ast.KindJSExportAssignment: if node.AsExportAssignment().Expression != nil && node.AsExportAssignment().Expression.Kind == ast.KindIdentifier { - return r.isAliasResolvedToValue(c.getSymbolOfDeclaration(node) /*excludeTypeOnlyValues*/, true) + return r.isAliasResolvedToValue(c.getSymbolOfDeclaration(node), true /*excludeTypeOnlyValues*/) } return true } @@ -97,7 +97,7 @@ func (r *emitResolver) isAliasResolvedToValue(symbol *ast.Symbol, excludeTypeOnl if container := ast.GetSourceFileOfNode(symbol.ValueDeclaration); container != nil { fileSymbol := c.getSymbolOfDeclaration(container.AsNode()) // Ensures cjs export assignment is setup, since this symbol may point at, and merge with, the file itself. - // If we don't, the merge may not have yet occured, and the flags check below will be missing flags that + // If we don't, the merge may not have yet occurred, and the flags check below will be missing flags that // are added as a result of the merge. c.resolveExternalModuleSymbol(fileSymbol, false /*dontResolveAlias*/) } @@ -121,8 +121,8 @@ func (r *emitResolver) IsTopLevelValueImportEqualsWithEntityName(node *ast.Node) if !ast.IsParseTreeNode(node) || node.Kind != ast.KindImportEqualsDeclaration || node.Parent.Kind != ast.KindSourceFile { return false } - n := node.AsImportEqualsDeclaration() - if ast.NodeIsMissing(n.ModuleReference) || n.ModuleReference.Kind != ast.KindExternalModuleReference { + if ast.IsImportEqualsDeclaration(node) && + (ast.NodeIsMissing(node.AsImportEqualsDeclaration().ModuleReference) || node.AsImportEqualsDeclaration().ModuleReference.Kind != ast.KindExternalModuleReference) { return false } @@ -142,6 +142,9 @@ func (r *emitResolver) MarkLinkedReferencesRecursively(file *ast.SourceFile) { if ast.IsImportEqualsDeclaration(n) && n.ModifierFlags()&ast.ModifierFlagsExport == 0 { return false // These are deferred and marked in a chain when referenced } + if ast.IsJSExportAssignment(n) { + return false + } if ast.IsImportDeclaration(n) { return false // likewise, these are ultimately what get marked by calls on other nodes - we want to skip them } @@ -166,7 +169,7 @@ func (r *emitResolver) GetExternalModuleFileFromDeclaration(node *ast.Node) *ast func (r *emitResolver) getReferenceResolver() binder.ReferenceResolver { if r.referenceResolver == nil { - r.referenceResolver = binder.NewReferenceResolver(binder.ReferenceResolverHooks{ + r.referenceResolver = binder.NewReferenceResolver(r.checker.compilerOptions, binder.ReferenceResolverHooks{ ResolveName: r.checker.resolveName, GetResolvedSymbol: r.checker.getResolvedSymbol, GetMergedSymbol: r.checker.getMergedSymbol, diff --git a/internal/checker/flow.go b/internal/checker/flow.go index 2c0b570ee7..58dcf30b9c 100644 --- a/internal/checker/flow.go +++ b/internal/checker/flow.go @@ -8,8 +8,9 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" + "github.com/microsoft/typescript-go/internal/evaluator" "github.com/microsoft/typescript-go/internal/scanner" ) @@ -35,15 +36,32 @@ type SharedFlow struct { } type FlowState struct { - reference *ast.Node - declaredType *Type - initialType *Type - flowContainer *ast.Node - refKey string - depth int - sharedFlowStart int - reduceLabels []*ast.FlowReduceLabelData - reduceLabelsBuffer [4]*ast.FlowReduceLabelData + reference *ast.Node + declaredType *Type + initialType *Type + flowContainer *ast.Node + refKey string + depth int + sharedFlowStart int + reduceLabels []*ast.FlowReduceLabelData + next *FlowState +} + +func (c *Checker) getFlowState() *FlowState { + f := c.freeFlowState + if f == nil { + f = &FlowState{} + } + c.freeFlowState = f.next + return f +} + +func (c *Checker) putFlowState(f *FlowState) { + *f = FlowState{ + reduceLabels: f.reduceLabels[:0], + next: c.freeFlowState, + } + c.freeFlowState = f } func getFlowNodeOfNode(node *ast.Node) *ast.FlowNode { @@ -68,20 +86,16 @@ func (c *Checker) getFlowTypeOfReferenceEx(reference *ast.Node, declaredType *Ty return declaredType } } - flowStateCount := len(c.flowStates) - c.flowStates = slices.Grow(c.flowStates, 1)[:flowStateCount+1] - f := &c.flowStates[flowStateCount] + f := c.getFlowState() f.reference = reference f.declaredType = declaredType f.initialType = core.Coalesce(initialType, declaredType) f.flowContainer = flowContainer f.sharedFlowStart = len(c.sharedFlows) - f.reduceLabels = f.reduceLabelsBuffer[:0] c.flowInvocationCount++ evolvedType := c.getTypeAtFlowNode(f, flowNode).t c.sharedFlows = c.sharedFlows[:f.sharedFlowStart] - c.flowStates[flowStateCount] = FlowState{} - c.flowStates = c.flowStates[:flowStateCount] + c.putFlowState(f) // When the reference is 'x' in an 'x.length', 'x.push(value)', 'x.unshift(value)' or x[n] = value' operation, // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations // on empty arrays are possible without implicit any errors and new element types can be inferred without @@ -295,7 +309,7 @@ func (c *Checker) narrowTypeByTypePredicate(f *FlowState, t *Type, predicate *Ty if c.isMatchingReference(f.reference, predicateArgument) { return c.getNarrowedType(t, predicate.t, assumeTrue, false /*checkDerived*/) } - if c.strictNullChecks && c.optionalChainContainsReference(predicateArgument, f.reference) && (assumeTrue && !(c.hasTypeFacts(predicate.t, TypeFactsEQUndefined)) || !assumeTrue && everyType(predicate.t, c.isNullableType)) { + if c.strictNullChecks && c.optionalChainContainsReference(predicateArgument, f.reference) && (assumeTrue && !(c.hasTypeFacts(predicate.t, TypeFactsEQUndefined)) || !assumeTrue && everyType(predicate.t, c.IsNullableType)) { t = c.getAdjustedTypeWithFacts(t, TypeFactsNEUndefinedOrNull) } access := c.getDiscriminantPropertyAccess(f, predicateArgument, t) @@ -552,8 +566,8 @@ func (c *Checker) narrowTypeByEquality(t *Type, operator ast.Kind, value *ast.No return c.getAdjustedTypeWithFacts(t, facts) } if assumeTrue { - if !doubleEquals && (t.flags&TypeFlagsUnknown != 0 || someType(t, c.isEmptyAnonymousObjectType)) { - if valueType.flags&(TypeFlagsPrimitive|TypeFlagsNonPrimitive) != 0 || c.isEmptyAnonymousObjectType(valueType) { + if !doubleEquals && (t.flags&TypeFlagsUnknown != 0 || someType(t, c.IsEmptyAnonymousObjectType)) { + if valueType.flags&(TypeFlagsPrimitive|TypeFlagsNonPrimitive) != 0 || c.IsEmptyAnonymousObjectType(valueType) { return valueType } if valueType.flags&TypeFlagsObject != 0 { @@ -798,7 +812,7 @@ func (c *Checker) narrowTypeByInstanceof(f *FlowState, t *Type, expr *ast.Binary instanceType := c.mapType(rightType, c.getInstanceType) // Don't narrow from `any` if the target type is exactly `Object` or `Function`, and narrow // in the false branch only if the target is a non-empty object type. - if IsTypeAny(t) && (instanceType == c.globalObjectType || instanceType == c.globalFunctionType) || !assumeTrue && !(instanceType.flags&TypeFlagsObject != 0 && !c.isEmptyAnonymousObjectType(instanceType)) { + if IsTypeAny(t) && (instanceType == c.globalObjectType || instanceType == c.globalFunctionType) || !assumeTrue && !(instanceType.flags&TypeFlagsObject != 0 && !c.IsEmptyAnonymousObjectType(instanceType)) { return t } return c.getNarrowedType(t, instanceType, assumeTrue, true /*checkDerived*/) @@ -854,7 +868,7 @@ func (c *Checker) getNarrowedTypeWorker(t *Type, candidate *Type, assumeTrue boo } } } - // For each constituent t in the current type, if t and and c are directly related, pick the most + // For each constituent t in the current type, if t and c are directly related, pick the most // specific of the two. When t and c are related in both directions, we prefer c for type predicates // because that is the asserted type, but t for `instanceof` because generics aren't reflected in // prototype object types. @@ -1148,7 +1162,7 @@ func (c *Checker) narrowTypeBySwitchOnTrue(f *FlowState, t *Type, data *ast.Flow } } // If our current set has a default, then none the other cases were hit either. - // There's no point in narrowing by the the other cases in the set, since we can + // There's no point in narrowing by the other cases in the set, since we can // get here through other paths. if hasDefaultClause { for i := clauseEnd; i < len(clauses); i++ { @@ -1405,7 +1419,7 @@ func (c *Checker) getDiscriminantPropertyAccess(f *FlowState, expr *ast.Node, co func (c *Checker) getCandidateDiscriminantPropertyAccess(f *FlowState, expr *ast.Node) *ast.Node { switch { case ast.IsBindingPattern(f.reference) || ast.IsFunctionExpressionOrArrowFunction(f.reference) || ast.IsObjectLiteralMethod(f.reference): - // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in + // When the reference is a binding pattern or function or arrow expression, we are narrowing a pseudo-reference in // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or // parameter declared in the same parameter list is a candidate. if ast.IsIdentifier(expr) { @@ -1549,7 +1563,7 @@ func (c *Checker) isMatchingReference(source *ast.Node, target *ast.Node) bool { case ast.KindMetaProperty: return ast.IsMetaProperty(target) && source.AsMetaProperty().KeywordToken == target.AsMetaProperty().KeywordToken && source.Name().Text() == target.Name().Text() case ast.KindIdentifier, ast.KindPrivateIdentifier: - if isThisInTypeQuery(source) { + if ast.IsThisInTypeQuery(source) { return target.Kind == ast.KindThisKeyword } return ast.IsIdentifier(target) && c.getResolvedSymbol(source) == c.getResolvedSymbol(target) || @@ -1605,7 +1619,7 @@ func (c *Checker) getFlowReferenceKey(f *FlowState) string { func (c *Checker) writeFlowCacheKey(b *KeyBuilder, node *ast.Node, declaredType *Type, initialType *Type, flowContainer *ast.Node) bool { switch node.Kind { case ast.KindIdentifier: - if !isThisInTypeQuery(node) { + if !ast.IsThisInTypeQuery(node) { symbol := c.getResolvedSymbol(node) if symbol == c.unknownSymbol { return false @@ -1699,7 +1713,7 @@ func (c *Checker) tryGetNameFromEntityNameExpression(node *ast.Node) (string, bo if declaration == nil { return "", false } - t := c.tryGetTypeFromEffectiveTypeNode(declaration) + t := c.tryGetTypeFromTypeNode(declaration) if t != nil { if name, ok := tryGetNameFromType(t); ok { return name, true @@ -1729,7 +1743,7 @@ func tryGetNameFromType(t *Type) (string, bool) { case t.flags&TypeFlagsUniqueESSymbol != 0: return t.AsUniqueESSymbolType().name, true case t.flags&TypeFlagsStringOrNumberLiteral != 0: - return anyToString(t.AsLiteralType().value), true + return evaluator.AnyToString(t.AsLiteralType().value), true } return "", false } @@ -1754,7 +1768,7 @@ func (c *Checker) getDestructuringPropertyName(node *ast.Node) (string, bool) { func (c *Checker) getLiteralPropertyNameText(name *ast.Node) (string, bool) { t := c.getLiteralTypeFromPropertyName(name) if t.flags&(TypeFlagsStringLiteral|TypeFlagsNumberLiteral) != 0 { - return anyToString(t.AsLiteralType().value), true + return evaluator.AnyToString(t.AsLiteralType().value), true } return "", false } @@ -1764,14 +1778,14 @@ func (c *Checker) isConstantReference(node *ast.Node) bool { case ast.KindThisKeyword: return true case ast.KindIdentifier: - if !isThisInTypeQuery(node) { + if !ast.IsThisInTypeQuery(node) { symbol := c.getResolvedSymbol(node) return c.isConstantVariable(symbol) || c.isParameterOrMutableLocalVariable(symbol) && !c.isSymbolAssigned(symbol) || symbol.ValueDeclaration != nil && ast.IsFunctionExpression(symbol.ValueDeclaration) } case ast.KindPropertyAccessExpression, ast.KindElementAccessExpression: // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. if c.isConstantReference(node.Expression()) { - symbol := c.typeNodeLinks.Get(node).resolvedSymbol + symbol := c.getResolvedSymbolOrNil(node) if symbol != nil { return c.isReadonlySymbol(symbol) } @@ -2409,7 +2423,7 @@ func (c *Checker) getFlowTypeInConstructor(symbol *ast.Symbol, constructor *ast. c.error(symbol.ValueDeclaration, diagnostics.Member_0_implicitly_has_an_1_type, c.symbolToString(symbol), c.TypeToString(flowType)) } // We don't infer a type if assignments are only null or undefined. - if everyType(flowType, c.isNullableType) { + if everyType(flowType, c.IsNullableType) { return nil } return c.convertAutoToAny(flowType) @@ -2432,7 +2446,7 @@ func (c *Checker) getFlowTypeInStaticBlocks(symbol *ast.Symbol, staticBlocks []* c.error(symbol.ValueDeclaration, diagnostics.Member_0_implicitly_has_an_1_type, c.symbolToString(symbol), c.TypeToString(flowType)) } // We don't infer a type if assignments are only null or undefined. - if everyType(flowType, c.isNullableType) { + if everyType(flowType, c.IsNullableType) { continue } return c.convertAutoToAny(flowType) @@ -2441,15 +2455,15 @@ func (c *Checker) getFlowTypeInStaticBlocks(symbol *ast.Symbol, staticBlocks []* } func (c *Checker) isReachableFlowNode(flow *ast.FlowNode) bool { - result := c.isReachableFlowNodeWorker(flow, false /*noCacheCheck*/) + f := c.getFlowState() + result := c.isReachableFlowNodeWorker(f, flow, false /*noCacheCheck*/) + c.putFlowState(f) c.lastFlowNode = flow c.lastFlowNodeReachable = result return result } -func (c *Checker) isReachableFlowNodeWorker(flow *ast.FlowNode, noCacheCheck bool) bool { - var reduceLabelsBuffer [4]*ast.FlowReduceLabelData - reduceLabels := reduceLabelsBuffer[:0] +func (c *Checker) isReachableFlowNodeWorker(f *FlowState, flow *ast.FlowNode, noCacheCheck bool) bool { for { if flow == c.lastFlowNode { return c.lastFlowNodeReachable @@ -2460,7 +2474,7 @@ func (c *Checker) isReachableFlowNodeWorker(flow *ast.FlowNode, noCacheCheck boo if reachable, ok := c.flowNodeReachable[flow]; ok { return reachable } - reachable := c.isReachableFlowNodeWorker(flow, true /*noCacheCheck*/) + reachable := c.isReachableFlowNodeWorker(f, flow, true /*noCacheCheck*/) c.flowNodeReachable[flow] = reachable return reachable } @@ -2486,8 +2500,8 @@ func (c *Checker) isReachableFlowNodeWorker(flow *ast.FlowNode, noCacheCheck boo flow = flow.Antecedent case flags&ast.FlowFlagsBranchLabel != 0: // A branching point is reachable if any branch is reachable. - for list := getBranchLabelAntecedents(flow, reduceLabels); list != nil; list = list.Next { - if c.isReachableFlowNodeWorker(list.Flow, false /*noCacheCheck*/) { + for list := getBranchLabelAntecedents(flow, f.reduceLabels); list != nil; list = list.Next { + if c.isReachableFlowNodeWorker(f, list.Flow, false /*noCacheCheck*/) { return true } } @@ -2509,9 +2523,9 @@ func (c *Checker) isReachableFlowNodeWorker(flow *ast.FlowNode, noCacheCheck boo case flags&ast.FlowFlagsReduceLabel != 0: // Cache is unreliable once we start adjusting labels c.lastFlowNode = nil - reduceLabels = append(reduceLabels, flow.Node.AsFlowReduceLabelData()) - result := c.isReachableFlowNodeWorker(flow.Antecedent, false /*noCacheCheck*/) - reduceLabels = reduceLabels[:len(reduceLabels)-1] + f.reduceLabels = append(f.reduceLabels, flow.Node.AsFlowReduceLabelData()) + result := c.isReachableFlowNodeWorker(f, flow.Antecedent, false /*noCacheCheck*/) + f.reduceLabels = f.reduceLabels[:len(f.reduceLabels)-1] return result default: return flags&ast.FlowFlagsUnreachable == 0 @@ -2535,8 +2549,13 @@ func (c *Checker) isFalseExpression(expr *ast.Node) bool { // Return true if the given flow node is preceded by a 'super(...)' call in every possible code path // leading to the node. func (c *Checker) isPostSuperFlowNode(flow *ast.FlowNode, noCacheCheck bool) bool { - var reduceLabelsBuffer [4]*ast.FlowReduceLabelData - reduceLabels := reduceLabelsBuffer[:0] + f := c.getFlowState() + result := c.isPostSuperFlowNodeWorker(f, flow, noCacheCheck) + c.putFlowState(f) + return result +} + +func (c *Checker) isPostSuperFlowNodeWorker(f *FlowState, flow *ast.FlowNode, noCacheCheck bool) bool { for { flags := flow.Flags if flags&ast.FlowFlagsShared != 0 { @@ -2544,7 +2563,7 @@ func (c *Checker) isPostSuperFlowNode(flow *ast.FlowNode, noCacheCheck bool) boo if postSuper, ok := c.flowNodePostSuper[flow]; ok { return postSuper } - postSuper := c.isPostSuperFlowNode(flow, true /*noCacheCheck*/) + postSuper := c.isPostSuperFlowNodeWorker(f, flow, true /*noCacheCheck*/) c.flowNodePostSuper[flow] = postSuper } noCacheCheck = false @@ -2558,8 +2577,8 @@ func (c *Checker) isPostSuperFlowNode(flow *ast.FlowNode, noCacheCheck bool) boo } flow = flow.Antecedent case flags&ast.FlowFlagsBranchLabel != 0: - for list := getBranchLabelAntecedents(flow, reduceLabels); list != nil; list = list.Next { - if !c.isPostSuperFlowNode(list.Flow, false /*noCacheCheck*/) { + for list := getBranchLabelAntecedents(flow, f.reduceLabels); list != nil; list = list.Next { + if !c.isPostSuperFlowNodeWorker(f, list.Flow, false /*noCacheCheck*/) { return false } } @@ -2568,9 +2587,9 @@ func (c *Checker) isPostSuperFlowNode(flow *ast.FlowNode, noCacheCheck bool) boo // A loop is post-super if the control flow path that leads to the top is post-super. flow = flow.Antecedents.Flow case flags&ast.FlowFlagsReduceLabel != 0: - reduceLabels = append(reduceLabels, flow.Node.AsFlowReduceLabelData()) - result := c.isPostSuperFlowNode(flow.Antecedent, false /*noCacheCheck*/) - reduceLabels = reduceLabels[:len(reduceLabels)-1] + f.reduceLabels = append(f.reduceLabels, flow.Node.AsFlowReduceLabelData()) + result := c.isPostSuperFlowNodeWorker(f, flow.Antecedent, false /*noCacheCheck*/) + f.reduceLabels = f.reduceLabels[:len(f.reduceLabels)-1] return result default: // Unreachable nodes are considered post-super to silence errors @@ -2667,6 +2686,7 @@ func (c *Checker) markNodeAssignmentsWorker(node *ast.Node) bool { return false case ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, + ast.KindJSTypeAliasDeclaration, ast.KindEnumDeclaration: return false } diff --git a/internal/checker/grammarchecks.go b/internal/checker/grammarchecks.go index 9c0de302c5..6e61fdaaf8 100644 --- a/internal/checker/grammarchecks.go +++ b/internal/checker/grammarchecks.go @@ -6,8 +6,8 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/jsnum" "github.com/microsoft/typescript-go/internal/scanner" "github.com/microsoft/typescript-go/internal/tspath" @@ -201,7 +201,7 @@ func (c *Checker) checkGrammarModifiers(node *ast.Node /*Union[HasModifiers, Has if c.reportObviousDecoratorErrors(node) || c.reportObviousModifierErrors(node) { return true } - if ast.IsParameter(node) && parameterIsThisKeyword(node) { + if ast.IsParameter(node) && ast.IsThisParameter(node) { return c.grammarErrorOnFirstToken(node, diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters) } blockScopeKind := ast.NodeFlagsNone @@ -400,7 +400,7 @@ func (c *Checker) checkGrammarModifiers(node *ast.Node /*Union[HasModifiers, Has return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "abstract") } else if flags&ast.ModifierFlagsAsync != 0 { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_must_precede_1_modifier, "export", "async") - } else if ast.IsClassLike(node.Parent) { + } else if ast.IsClassLike(node.Parent) && !ast.IsJSTypeAliasDeclaration(node) { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_class_elements_of_this_kind, "export") } else if node.Kind == ast.KindParameter { return c.grammarErrorOnNode(modifier, diagnostics.X_0_modifier_cannot_appear_on_a_parameter, "export") @@ -601,10 +601,12 @@ func (c *Checker) findFirstIllegalModifier(node *ast.Node) *ast.Node { ast.KindImportEqualsDeclaration, ast.KindExportDeclaration, ast.KindExportAssignment, + ast.KindJSExportAssignment, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindParameter, - ast.KindTypeParameter: + ast.KindTypeParameter, + ast.KindJSTypeAliasDeclaration: return nil case ast.KindClassStaticBlockDeclaration, ast.KindPropertyAssignment, @@ -686,7 +688,7 @@ func (c *Checker) checkGrammarForDisallowedTrailingComma(list *ast.NodeList, dia func (c *Checker) checkGrammarTypeParameterList(typeParameters *ast.NodeList, file *ast.SourceFile) bool { if typeParameters != nil && len(typeParameters.Nodes) == 0 { start := typeParameters.Pos() - len("<") - end := scanner.SkipTrivia(file.Text, typeParameters.End()) + len(">") + end := scanner.SkipTrivia(file.Text(), typeParameters.End()) + len(">") return c.grammarErrorAtPos(file.AsNode(), start, end-start, diagnostics.Type_parameter_list_cannot_be_empty) } return false @@ -856,7 +858,7 @@ func (c *Checker) checkGrammarForAtLeastOneTypeArgument(node *ast.Node, typeArgu if typeArguments != nil && len(typeArguments.Nodes) == 0 { sourceFile := ast.GetSourceFileOfNode(node) start := typeArguments.Pos() - len("<") - end := scanner.SkipTrivia(sourceFile.Text, typeArguments.End()) + len(">") + end := scanner.SkipTrivia(sourceFile.Text(), typeArguments.End()) + len(">") return c.grammarErrorAtPos(sourceFile.AsNode(), start, end-start, diagnostics.Type_argument_list_cannot_be_empty) } return false @@ -1002,7 +1004,7 @@ func (c *Checker) checkGrammarForGenerator(node *ast.Node) bool { } func (c *Checker) checkGrammarForInvalidQuestionMark(postfixToken *ast.TokenNode, message *diagnostics.Message) bool { - return postfixToken != nil && postfixToken.Kind == ast.KindQuestionQuestionToken && c.grammarErrorOnNode(postfixToken, message) + return postfixToken != nil && postfixToken.Kind == ast.KindQuestionToken && c.grammarErrorOnNode(postfixToken, message) } func (c *Checker) checkGrammarForInvalidExclamationToken(postfixToken *ast.TokenNode, message *diagnostics.Message) bool { @@ -1149,21 +1151,14 @@ func (c *Checker) checkGrammarObjectLiteralExpression(node *ast.ObjectLiteralExp return false } -func (c *Checker) checkGrammarJsxElement(node *ast.Node, jsxCommon struct { - tagName *ast.JsxTagNameExpression - typeArguments *ast.NodeList - attributes *ast.JsxAttributesNode -}, -) bool { - c.checkGrammarJsxName(jsxCommon.tagName) - c.checkGrammarTypeArguments(node, jsxCommon.typeArguments) +func (c *Checker) checkGrammarJsxElement(node *ast.Node) bool { + c.checkGrammarJsxName(node.TagName()) + c.checkGrammarTypeArguments(node, node.TypeArgumentList()) var seen core.Set[string] - - for _, attrNode := range jsxCommon.attributes.AsJsxAttributes().Properties.Nodes { + for _, attrNode := range node.Attributes().AsJsxAttributes().Properties.Nodes { if attrNode.Kind == ast.KindJsxSpreadAttribute { continue } - attr := attrNode.AsJsxAttribute() name := attr.Name() initializer := attr.Initializer @@ -1173,7 +1168,6 @@ func (c *Checker) checkGrammarJsxElement(node *ast.Node, jsxCommon struct { } else { return c.grammarErrorOnNode(name, diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name) } - if initializer != nil && initializer.Kind == ast.KindJsxExpression && initializer.Expression() == nil { return c.grammarErrorOnNode(initializer, diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression) } @@ -1217,7 +1211,8 @@ func (c *Checker) checkGrammarForInOrForOfStatement(forInOrOfStatement *ast.ForI } switch c.moduleKind { case core.ModuleKindNode16, core.ModuleKindNodeNext: - if sourceFile.ImpliedNodeFormat == core.ModuleKindCommonJS { + sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path()) + if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { c.diagnostics.Add(createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level)) break } @@ -1402,7 +1397,7 @@ func (c *Checker) checkGrammarTypeOperatorNode(node *ast.TypeOperatorNode) bool return c.grammarErrorOnNode((parent.AsVariableDeclaration()).Name(), diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const) } case ast.KindPropertyDeclaration: - if !ast.IsStatic(parent) || !hasEffectiveReadonlyModifier(parent) { + if !ast.IsStatic(parent) || !hasReadonlyModifier(parent) { return c.grammarErrorOnNode((parent.AsPropertyDeclaration()).Name(), diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly) } case ast.KindPropertySignature: @@ -1719,7 +1714,8 @@ func (c *Checker) checkGrammarAwaitOrAwaitUsing(node *ast.Node) bool { switch c.moduleKind { case core.ModuleKindNode16, core.ModuleKindNodeNext: - if sourceFile.ImpliedNodeFormat == core.ModuleKindCommonJS { + sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path()) + if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { if !spanCalculated { span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) } @@ -1854,23 +1850,13 @@ func (c *Checker) checkGrammarMetaProperty(node *ast.MetaProperty) bool { } func (c *Checker) checkGrammarConstructorTypeParameters(node *ast.ConstructorDeclaration) bool { - // !!! - // var jsdocTypeParameters []*ast.TypeParameterDeclaration - // if ast.IsInJSFile(node.AsNode()) { - // jsdocTypeParameters = getJSDocTypeParameterDeclarations(node) - // } else { - // jsdocTypeParameters = nil - // } - // if range_ == nil { - // range_ = core.FirstOrNil(jsdocTypeParameters) - // } range_ := node.TypeParameters if range_ != nil { var pos int if range_.Pos() == range_.End() { pos = range_.Pos() } else { - pos = scanner.SkipTrivia(ast.GetSourceFileOfNode(node.AsNode()).Text, range_.Pos()) + pos = scanner.SkipTrivia(ast.GetSourceFileOfNode(node.AsNode()).Text(), range_.Pos()) } return c.grammarErrorAtPos(node.AsNode(), pos, range_.End()-pos, diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration) } @@ -1907,24 +1893,22 @@ func (c *Checker) checkGrammarProperty(node *ast.Node /*Union[PropertyDeclaratio if ast.IsAutoAccessorPropertyDeclaration(node) && c.checkGrammarForInvalidQuestionMark(node.AsPropertyDeclaration().PostfixToken, diagnostics.An_accessor_property_cannot_be_declared_optional) { return true } - } else if node.Parent.Kind == ast.KindInterfaceDeclaration { + } else if ast.IsInterfaceDeclaration(node.Parent) { if c.checkGrammarForInvalidDynamicName(propertyName, diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) { return true } - if !ast.IsPropertySignatureDeclaration(node) { // Interfaces cannot contain property declarations panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } - if initializer := node.AsPropertySignatureDeclaration().Initializer; initializer != nil { return c.grammarErrorOnNode(initializer, diagnostics.An_interface_property_cannot_have_an_initializer) } - } else if ast.IsTypeAliasDeclaration(node.Parent) { + } else if ast.IsTypeLiteralNode(node.Parent) { if c.checkGrammarForInvalidDynamicName(node.Name(), diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type) { return true } - if ast.IsPropertySignatureDeclaration(node) { + if !ast.IsPropertySignatureDeclaration(node) { // Type literals cannot contain property declarations panic(fmt.Sprintf("Unexpected node kind %q", node.Kind)) } @@ -2037,7 +2021,7 @@ func (c *Checker) checkGrammarTopLevelElementForRequiredDeclareModifier(node *as // export_opt AmbientDeclaration // // TODO: The spec needs to be amended to reflect this grammar. - if node.Kind == ast.KindInterfaceDeclaration || node.Kind == ast.KindTypeAliasDeclaration || node.Kind == ast.KindImportDeclaration || node.Kind == ast.KindImportEqualsDeclaration || node.Kind == ast.KindExportDeclaration || node.Kind == ast.KindExportAssignment || node.Kind == ast.KindNamespaceExportDeclaration || ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient|ast.ModifierFlagsExport|ast.ModifierFlagsDefault) { + if node.Kind == ast.KindInterfaceDeclaration || node.Kind == ast.KindTypeAliasDeclaration || node.Kind == ast.KindImportDeclaration || node.Kind == ast.KindImportEqualsDeclaration || node.Kind == ast.KindExportDeclaration || node.Kind == ast.KindExportAssignment || node.Kind == ast.KindJSExportAssignment || node.Kind == ast.KindNamespaceExportDeclaration || ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient|ast.ModifierFlagsExport|ast.ModifierFlagsDefault) { return false } diff --git a/internal/checker/inference.go b/internal/checker/inference.go index 0d1cd5945e..80e465aada 100644 --- a/internal/checker/inference.go +++ b/internal/checker/inference.go @@ -26,12 +26,32 @@ type InferenceState struct { visited map[InferenceKey]InferencePriority sourceStack []*Type targetStack []*Type + next *InferenceState +} + +func (c *Checker) getInferenceState() *InferenceState { + n := c.freeinferenceState + if n == nil { + n = &InferenceState{} + } + c.freeinferenceState = n.next + return n +} + +func (c *Checker) putInferenceState(n *InferenceState) { + clear(n.visited) + *n = InferenceState{ + inferences: n.inferences[:0], + visited: n.visited, + sourceStack: n.sourceStack[:0], + targetStack: n.targetStack[:0], + next: c.freeinferenceState, + } + c.freeinferenceState = n } func (c *Checker) inferTypes(inferences []*InferenceInfo, originalSource *Type, originalTarget *Type, priority InferencePriority, contravariant bool) { - inferenceStateCount := len(c.inferenceStates) - c.inferenceStates = slices.Grow(c.inferenceStates, 1)[:inferenceStateCount+1] - n := &c.inferenceStates[inferenceStateCount] + n := c.getInferenceState() n.inferences = inferences n.originalSource = originalSource n.originalTarget = originalTarget @@ -39,8 +59,7 @@ func (c *Checker) inferTypes(inferences []*InferenceInfo, originalSource *Type, n.inferencePriority = InferencePriorityMaxValue n.contravariant = contravariant c.inferFromTypes(n, originalSource, originalTarget) - c.inferenceStates[inferenceStateCount] = InferenceState{} - c.inferenceStates = c.inferenceStates[:inferenceStateCount] + c.putInferenceState(n) } func (c *Checker) inferFromTypes(n *InferenceState, source *Type, target *Type) { @@ -552,7 +571,7 @@ func (c *Checker) inferToTemplateLiteralType(n *InferenceState, source *Type, ta case left.flags&TypeFlagsBigInt != 0: return left case right.flags&TypeFlagsBigInt != 0: - return c.getBigIntLiteralType(PseudoBigInt{}) // !!! + return c.parseBigIntLiteralType(str) case left.flags&TypeFlagsBigIntLiteral != 0: return left case right.flags&TypeFlagsBigIntLiteral != 0 && pseudoBigIntToString(getBigIntLiteralValue(right)) == str: @@ -740,7 +759,7 @@ func (c *Checker) inferFromProperties(n *InferenceState, source *Type, target *T properties := c.getPropertiesOfObjectType(target) for _, targetProp := range properties { sourceProp := c.getPropertyOfType(source, targetProp.Name) - if sourceProp != nil && !core.Some(sourceProp.Declarations, c.hasSkipDirectInferenceFlag) { + if sourceProp != nil && !core.Some(sourceProp.Declarations, c.isSkipDirectInferenceNode) { c.inferFromTypes(n, c.removeMissingType(c.getTypeOfSymbol(sourceProp), sourceProp.Flags&ast.SymbolFlagsOptional != 0), c.removeMissingType(c.getTypeOfSymbol(targetProp), targetProp.Flags&ast.SymbolFlagsOptional != 0)) } } @@ -1495,13 +1514,11 @@ func (c *Checker) literalTypesWithSameBaseType(types []*Type) bool { } func (c *Checker) isFromInferenceBlockedSource(t *Type) bool { - return t.symbol != nil && core.Some(t.symbol.Declarations, c.hasSkipDirectInferenceFlag) + return t.symbol != nil && core.Some(t.symbol.Declarations, c.isSkipDirectInferenceNode) } -func (c *Checker) hasSkipDirectInferenceFlag(node *ast.Node) bool { - // !!! Make this a new NodeFlag - // return c.getNodeLinks(node).skipDirectInference - return false +func (c *Checker) isSkipDirectInferenceNode(node *ast.Node) bool { + return c.skipDirectInferenceNodes.Has(node) } // Returns `true` if `type` has the shape `[T[0]]` where `T` is `typeParameter` diff --git a/internal/checker/jsx.go b/internal/checker/jsx.go new file mode 100644 index 0000000000..10a172eec6 --- /dev/null +++ b/internal/checker/jsx.go @@ -0,0 +1,1370 @@ +package checker + +import ( + "iter" + "math" + "slices" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" + "github.com/microsoft/typescript-go/internal/jsnum" + "github.com/microsoft/typescript-go/internal/parser" + "github.com/microsoft/typescript-go/internal/scanner" +) + +type JsxFlags uint32 + +const ( + JsxFlagsNone JsxFlags = 0 + JsxFlagsIntrinsicNamedElement JsxFlags = 1 << 0 // An element from a named property of the JSX.IntrinsicElements interface + JsxFlagsIntrinsicIndexedElement JsxFlags = 1 << 1 // An element inferred from the string index signature of the JSX.IntrinsicElements interface + JsxFlagsIntrinsicElement JsxFlags = JsxFlagsIntrinsicNamedElement | JsxFlagsIntrinsicIndexedElement +) + +type JsxReferenceKind int32 + +const ( + JsxReferenceKindComponent JsxReferenceKind = iota + JsxReferenceKindFunction + JsxReferenceKindMixed +) + +type JsxElementLinks struct { + jsxFlags JsxFlags // Flags for the JSX element + resolvedJsxElementAttributesType *Type // Resolved element attributes type of a JSX opening-like element + jsxNamespace *ast.Symbol // Resolved JSX namespace symbol for this node + jsxImplicitImportContainer *ast.Symbol // Resolved module symbol the implicit JSX import of this file should refer to +} + +var JsxNames = struct { + JSX string + IntrinsicElements string + ElementClass string + ElementAttributesPropertyNameContainer string + ElementChildrenAttributeNameContainer string + Element string + ElementType string + IntrinsicAttributes string + IntrinsicClassAttributes string + LibraryManagedAttributes string +}{ + JSX: "JSX", + IntrinsicElements: "IntrinsicElements", + ElementClass: "ElementClass", + ElementAttributesPropertyNameContainer: "ElementAttributesProperty", + ElementChildrenAttributeNameContainer: "ElementChildrenAttribute", + Element: "Element", + ElementType: "ElementType", + IntrinsicAttributes: "IntrinsicAttributes", + IntrinsicClassAttributes: "IntrinsicClassAttributes", + LibraryManagedAttributes: "LibraryManagedAttributes", +} + +func (c *Checker) checkJsxElement(node *ast.Node, checkMode CheckMode) *Type { + c.checkNodeDeferred(node) + return c.getJsxElementTypeAt(node) +} + +func (c *Checker) checkJsxElementDeferred(node *ast.Node) { + jsxElement := node.AsJsxElement() + c.checkJsxOpeningLikeElementOrOpeningFragment(jsxElement.OpeningElement) + // Perform resolution on the closing tag so that rename/go to definition/etc work + if isJsxIntrinsicTagName(jsxElement.ClosingElement.TagName()) { + c.getIntrinsicTagSymbol(jsxElement.ClosingElement) + } else { + c.checkExpression(jsxElement.ClosingElement.TagName()) + } + c.checkJsxChildren(node, CheckModeNormal) +} + +func (c *Checker) checkJsxExpression(node *ast.Node, checkMode CheckMode) *Type { + c.checkGrammarJsxExpression(node.AsJsxExpression()) + if node.Expression() == nil { + return c.errorType + } + t := c.checkExpressionEx(node.Expression(), checkMode) + if node.AsJsxExpression().DotDotDotToken != nil && t != c.anyType && !c.isArrayType(t) { + c.error(node, diagnostics.JSX_spread_child_must_be_an_array_type) + } + return t +} + +func (c *Checker) checkJsxSelfClosingElement(node *ast.Node, checkMode CheckMode) *Type { + c.checkNodeDeferred(node) + return c.getJsxElementTypeAt(node) +} + +func (c *Checker) checkJsxSelfClosingElementDeferred(node *ast.Node) { + c.checkJsxOpeningLikeElementOrOpeningFragment(node) +} + +func (c *Checker) checkJsxFragment(node *ast.Node) *Type { + c.checkJsxOpeningLikeElementOrOpeningFragment(node.AsJsxFragment().OpeningFragment) + // by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment + // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too + nodeSourceFile := ast.GetSourceFileOfNode(node) + if c.compilerOptions.GetJSXTransformEnabled() && (c.compilerOptions.JsxFactory != "" || ast.GetPragmaFromSourceFile(nodeSourceFile, "jsx") != nil) && c.compilerOptions.JsxFragmentFactory == "" && ast.GetPragmaFromSourceFile(nodeSourceFile, "jsxfrag") == nil { + message := core.IfElse(c.compilerOptions.JsxFactory != "", + diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option, + diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments) + c.error(node, message) + } + c.checkJsxChildren(node, CheckModeNormal) + return c.getJsxElementTypeAt(node) +} + +func (c *Checker) checkJsxAttributes(node *ast.Node, checkMode CheckMode) *Type { + return c.createJsxAttributesTypeFromAttributesProperty(node.Parent, checkMode) +} + +func (c *Checker) checkJsxOpeningLikeElementOrOpeningFragment(node *ast.Node) { + isNodeOpeningLikeElement := isJsxOpeningLikeElement(node) + if isNodeOpeningLikeElement { + c.checkGrammarJsxElement(node) + } + c.checkJsxPreconditions(node) + c.markJsxAliasReferenced(node) + if isNodeOpeningLikeElement { + sig := c.getResolvedSignature(node, nil, CheckModeNormal) + c.checkDeprecatedSignature(sig, node) + elementTypeConstraint := c.getJsxElementTypeTypeAt(node) + if elementTypeConstraint != nil { + tagName := node.TagName() + var tagType *Type + if isJsxIntrinsicTagName(tagName) { + tagType = c.getStringLiteralType(tagName.Text()) + } else { + tagType = c.checkExpression(tagName) + } + var diags []*ast.Diagnostic + if !c.checkTypeRelatedToEx(tagType, elementTypeConstraint, c.assignableRelation, tagName, diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, &diags) { + c.diagnostics.Add(ast.NewDiagnosticChain(diags[0], diagnostics.X_0_cannot_be_used_as_a_JSX_component, scanner.GetTextOfNode(tagName))) + } + } else { + c.checkJsxReturnAssignableToAppropriateBound(c.getJsxReferenceKind(node), c.getReturnTypeOfSignature(sig), node) + } + } +} + +func (c *Checker) checkJsxPreconditions(errorNode *ast.Node) { + // Preconditions for using JSX + if c.compilerOptions.Jsx == core.JsxEmitNone { + c.error(errorNode, diagnostics.Cannot_use_JSX_unless_the_jsx_flag_is_provided) + } + if c.noImplicitAny && c.getJsxElementTypeAt(errorNode) == nil { + c.error(errorNode, diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist) + } +} + +func (c *Checker) checkJsxReturnAssignableToAppropriateBound(refKind JsxReferenceKind, elemInstanceType *Type, openingLikeElement *ast.Node) { + var diags []*ast.Diagnostic + switch refKind { + case JsxReferenceKindFunction: + sfcReturnConstraint := c.getJsxStatelessElementTypeAt(openingLikeElement) + if sfcReturnConstraint != nil { + c.checkTypeRelatedToEx(elemInstanceType, sfcReturnConstraint, c.assignableRelation, openingLikeElement.TagName(), diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, &diags) + } + case JsxReferenceKindComponent: + classConstraint := c.getJsxElementClassTypeAt(openingLikeElement) + if classConstraint != nil { + // Issue an error if this return type isn't assignable to JSX.ElementClass, failing that + c.checkTypeRelatedToEx(elemInstanceType, classConstraint, c.assignableRelation, openingLikeElement.TagName(), diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, &diags) + } + default: + sfcReturnConstraint := c.getJsxStatelessElementTypeAt(openingLikeElement) + classConstraint := c.getJsxElementClassTypeAt(openingLikeElement) + if sfcReturnConstraint == nil || classConstraint == nil { + return + } + combined := c.getUnionType([]*Type{sfcReturnConstraint, classConstraint}) + c.checkTypeRelatedToEx(elemInstanceType, combined, c.assignableRelation, openingLikeElement.TagName(), diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, &diags) + } + if len(diags) != 0 { + c.diagnostics.Add(ast.NewDiagnosticChain(diags[0], diagnostics.X_0_cannot_be_used_as_a_JSX_component, scanner.GetTextOfNode(openingLikeElement.TagName()))) + } +} + +func (c *Checker) inferJsxTypeArguments(node *ast.Node, signature *Signature, checkMode CheckMode, context *InferenceContext) []*Type { + paramType := c.getEffectiveFirstArgumentForJsxSignature(signature, node) + checkAttrType := c.checkExpressionWithContextualType(node.Attributes(), paramType, context, checkMode) + c.inferTypes(context.inferences, checkAttrType, paramType, InferencePriorityNone, false) + return c.getInferredTypes(context) +} + +func (c *Checker) getContextualTypeForJsxExpression(node *ast.Node, contextFlags ContextFlags) *Type { + switch { + case ast.IsJsxAttributeLike(node.Parent): + return c.getContextualType(node, contextFlags) + case ast.IsJsxElement(node.Parent): + return c.getContextualTypeForChildJsxExpression(node.Parent, node, contextFlags) + } + return nil +} + +func (c *Checker) getContextualTypeForJsxAttribute(attribute *ast.Node, contextFlags ContextFlags) *Type { + // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type + // which is a type of the parameter of the signature we are trying out. + // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName + if ast.IsJsxAttribute(attribute) { + attributesType := c.getApparentTypeOfContextualType(attribute.Parent, contextFlags) + if attributesType == nil || IsTypeAny(attributesType) { + return nil + } + return c.getTypeOfPropertyOfContextualType(attributesType, attribute.Name().Text()) + } + return c.getContextualType(attribute.Parent, contextFlags) +} + +func (c *Checker) getContextualJsxElementAttributesType(node *ast.Node, contextFlags ContextFlags) *Type { + if ast.IsJsxOpeningElement(node) && contextFlags != ContextFlagsCompletions { + index := c.findContextualNode(node.Parent, contextFlags == ContextFlagsNone) + if index >= 0 { + // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit + // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type + // (as below) instead! + return c.contextualInfos[index].t + } + } + return c.getContextualTypeForArgumentAtIndex(node, 0) +} + +func (c *Checker) getContextualTypeForChildJsxExpression(node *ast.Node, child *ast.JsxChild, contextFlags ContextFlags) *Type { + attributesType := c.getApparentTypeOfContextualType(node.AsJsxElement().OpeningElement.Attributes(), contextFlags) + // JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty) + jsxChildrenPropertyName := c.getJsxElementChildrenPropertyName(c.getJsxNamespaceAt(node)) + if !(attributesType != nil && !IsTypeAny(attributesType) && jsxChildrenPropertyName != ast.InternalSymbolNameMissing && jsxChildrenPropertyName != "") { + return nil + } + realChildren := getSemanticJsxChildren(node.Children().Nodes) + childIndex := slices.Index(realChildren, child) + childFieldType := c.getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) + if childFieldType == nil { + return nil + } + if len(realChildren) == 1 { + return childFieldType + } + return c.mapTypeEx(childFieldType, func(t *Type) *Type { + if c.isArrayLikeType(t) { + return c.getIndexedAccessType(t, c.getNumberLiteralType(jsnum.Number(childIndex))) + } + return t + }, true /*noReductions*/) +} + +func (c *Checker) discriminateContextualTypeByJSXAttributes(node *ast.Node, contextualType *Type) *Type { + key := DiscriminatedContextualTypeKey{nodeId: ast.GetNodeId(node), typeId: contextualType.id} + if discriminated := c.discriminatedContextualTypes[key]; discriminated != nil { + return discriminated + } + jsxChildrenPropertyName := c.getJsxElementChildrenPropertyName(c.getJsxNamespaceAt(node)) + discriminantProperties := core.Filter(node.AsJsxAttributes().Properties.Nodes, func(p *ast.Node) bool { + symbol := p.Symbol() + if symbol == nil || !ast.IsJsxAttribute(p) { + return false + } + initializer := p.Initializer() + return (initializer == nil || c.isPossiblyDiscriminantValue(initializer)) && c.isDiscriminantProperty(contextualType, symbol.Name) + }) + discriminantMembers := core.Filter(c.getPropertiesOfType(contextualType), func(s *ast.Symbol) bool { + if s.Flags&ast.SymbolFlagsOptional == 0 || node.Symbol() == nil || len(node.Symbol().Members) == 0 { + return false + } + element := node.Parent.Parent + if s.Name == jsxChildrenPropertyName && ast.IsJsxElement(element) && len(getSemanticJsxChildren(element.Children().Nodes)) != 0 { + return false + } + return node.Symbol().Members[s.Name] == nil && c.isDiscriminantProperty(contextualType, s.Name) + }) + discriminator := &ObjectLiteralDiscriminator{c: c, props: discriminantProperties, members: discriminantMembers} + discriminated := c.discriminateTypeByDiscriminableItems(contextualType, discriminator) + c.discriminatedContextualTypes[key] = discriminated + return discriminated +} + +func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *Type, relation *Relation, diagnosticOutput *[]*ast.Diagnostic) bool { + reportedError := false + for _, prop := range node.AsJsxAttributes().Properties.Nodes { + if !ast.IsJsxSpreadAttribute(prop) && !isHyphenatedJsxName(prop.Name().Text()) { + nameType := c.getStringLiteralType(prop.Name().Text()) + if nameType != nil && nameType.flags&TypeFlagsNever == 0 { + reportedError = c.elaborateElement(source, target, relation, prop.Name(), prop.Initializer(), nameType, nil, diagnosticOutput) || reportedError + } + } + } + if ast.IsJsxOpeningElement(node.Parent) && ast.IsJsxElement(node.Parent.Parent) { + containingElement := node.Parent.Parent // Containing JSXElement + childrenPropName := c.getJsxElementChildrenPropertyName(c.getJsxNamespaceAt(node)) + if childrenPropName == ast.InternalSymbolNameMissing { + childrenPropName = "children" + } + childrenNameType := c.getStringLiteralType(childrenPropName) + childrenTargetType := c.getIndexedAccessType(target, childrenNameType) + validChildren := getSemanticJsxChildren(containingElement.Children().Nodes) + if len(validChildren) == 0 { + return reportedError + } + moreThanOneRealChildren := len(validChildren) > 1 + var arrayLikeTargetParts *Type + var nonArrayLikeTargetParts *Type + iterableType := c.getGlobalIterableType() + if iterableType != c.emptyGenericType { + anyIterable := c.createIterableType(c.anyType) + arrayLikeTargetParts = c.filterType(childrenTargetType, func(t *Type) bool { return c.isTypeAssignableTo(t, anyIterable) }) + nonArrayLikeTargetParts = c.filterType(childrenTargetType, func(t *Type) bool { return !c.isTypeAssignableTo(t, anyIterable) }) + } else { + arrayLikeTargetParts = c.filterType(childrenTargetType, c.isArrayOrTupleLikeType) + nonArrayLikeTargetParts = c.filterType(childrenTargetType, func(t *Type) bool { return !c.isArrayOrTupleLikeType(t) }) + } + var invalidTextDiagnostic *diagnostics.Message + getInvalidTextualChildDiagnostic := func() *diagnostics.Message { + if invalidTextDiagnostic == nil { + tagNameText := scanner.GetTextOfNode(node.Parent.TagName()) + diagnostic := diagnostics.X_0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2 + invalidTextDiagnostic = diagnostics.FormatMessage(diagnostic, tagNameText, childrenPropName, c.TypeToString(childrenTargetType)) + } + return invalidTextDiagnostic + } + if moreThanOneRealChildren { + if arrayLikeTargetParts != c.neverType { + realSource := c.createTupleType(c.checkJsxChildren(containingElement, CheckModeNormal)) + children := c.generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic) + reportedError = c.elaborateIterableOrArrayLikeTargetElementwise(children, realSource, arrayLikeTargetParts, relation, diagnosticOutput) || reportedError + } else if !c.isTypeRelatedTo(c.getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) { + // arity mismatch + diag := c.error(containingElement.AsJsxElement().OpeningElement.TagName(), diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, childrenPropName, c.TypeToString(childrenTargetType)) + c.reportDiagnostic(diag, diagnosticOutput) + reportedError = true + } + } else { + if nonArrayLikeTargetParts != c.neverType { + child := validChildren[0] + e := c.getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic) + if e.errorNode != nil { + reportedError = c.elaborateElement(source, target, relation, e.errorNode, e.innerExpression, e.nameType, e.errorMessage, diagnosticOutput) || reportedError + } + } else if !c.isTypeRelatedTo(c.getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) { + // arity mismatch + diag := c.error(containingElement.AsJsxElement().OpeningElement.TagName(), diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, childrenPropName, c.TypeToString(childrenTargetType)) + c.reportDiagnostic(diag, diagnosticOutput) + reportedError = true + } + } + } + return reportedError +} + +type JsxElaborationElement struct { + errorNode *ast.Node + innerExpression *ast.Node + nameType *Type + errorMessage *diagnostics.Message +} + +func (c *Checker) generateJsxChildren(node *ast.Node, getInvalidTextDiagnostic func() *diagnostics.Message) iter.Seq[JsxElaborationElement] { + return func(yield func(JsxElaborationElement) bool) { + memberOffset := 0 + for i, child := range node.Children().Nodes { + nameType := c.getNumberLiteralType(jsnum.Number(i - memberOffset)) + e := c.getElaborationElementForJsxChild(child, nameType, getInvalidTextDiagnostic) + if e.errorNode != nil { + if !yield(e) { + return + } + } else { + memberOffset++ + } + } + } +} + +func (c *Checker) getElaborationElementForJsxChild(child *ast.Node, nameType *Type, getInvalidTextDiagnostic func() *diagnostics.Message) JsxElaborationElement { + switch child.Kind { + case ast.KindJsxExpression: + // child is of the type of the expression + return JsxElaborationElement{errorNode: child, innerExpression: child.Expression(), nameType: nameType} + case ast.KindJsxText: + if child.AsJsxText().ContainsOnlyTriviaWhiteSpaces { + // Whitespace only jsx text isn't real jsx text + return JsxElaborationElement{} + } + // child is a string + return JsxElaborationElement{errorNode: child, innerExpression: nil, nameType: nameType, errorMessage: getInvalidTextDiagnostic()} + case ast.KindJsxElement, ast.KindJsxSelfClosingElement, ast.KindJsxFragment: + // child is of type JSX.Element + return JsxElaborationElement{errorNode: child, innerExpression: child, nameType: nameType} + } + panic("Unhandled case in getElaborationElementForJsxChild") +} + +func (c *Checker) elaborateIterableOrArrayLikeTargetElementwise(iterator iter.Seq[JsxElaborationElement], source *Type, target *Type, relation *Relation, diagnosticOutput *[]*ast.Diagnostic) bool { + tupleOrArrayLikeTargetParts := c.filterType(target, c.isArrayOrTupleLikeType) + nonTupleOrArrayLikeTargetParts := c.filterType(target, func(t *Type) bool { return !c.isArrayOrTupleLikeType(t) }) + // If `nonTupleOrArrayLikeTargetParts` is not `never`, then that should mean `Iterable` is defined. + var iterationType *Type + if nonTupleOrArrayLikeTargetParts != c.neverType { + iterationType = c.getIterationTypeOfIterable(IterationUseForOf, IterationTypeKindYield, nonTupleOrArrayLikeTargetParts, nil /*errorNode*/) + } + reportedError := false + for e := range iterator { + prop := e.errorNode + next := e.innerExpression + nameType := e.nameType + targetPropType := iterationType + var targetIndexedPropType *Type + if tupleOrArrayLikeTargetParts != c.neverType { + targetIndexedPropType = c.getBestMatchIndexedAccessTypeOrUndefined(source, tupleOrArrayLikeTargetParts, nameType) + } + if targetIndexedPropType != nil && targetIndexedPropType.flags&TypeFlagsIndexedAccess == 0 { + if iterationType != nil { + targetPropType = c.getUnionType([]*Type{iterationType, targetIndexedPropType}) + } else { + targetPropType = targetIndexedPropType + } + } + if targetPropType == nil { + continue + } + sourcePropType := c.getIndexedAccessTypeOrUndefined(source, nameType, AccessFlagsNone, nil, nil) + if sourcePropType == nil { + continue + } + propName := c.getPropertyNameFromIndex(nameType, nil /*accessNode*/) + if !c.checkTypeRelatedTo(sourcePropType, targetPropType, relation, nil /*errorNode*/) { + elaborated := next != nil && c.elaborateError(next, sourcePropType, targetPropType, relation, nil /*headMessage*/, diagnosticOutput) + reportedError = true + if !elaborated { + // Issue error on the prop itself, since the prop couldn't elaborate the error. Use the expression type, if available. + specificSource := sourcePropType + if next != nil { + specificSource = c.checkExpressionForMutableLocationWithContextualType(next, sourcePropType) + } + if c.exactOptionalPropertyTypes && c.isExactOptionalPropertyMismatch(specificSource, targetPropType) { + diag := createDiagnosticForNode(prop, diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, c.TypeToString(specificSource), c.TypeToString(targetPropType)) + c.reportDiagnostic(diag, diagnosticOutput) + } else { + targetIsOptional := propName != ast.InternalSymbolNameMissing && core.OrElse(c.getPropertyOfType(tupleOrArrayLikeTargetParts, propName), c.unknownSymbol).Flags&ast.SymbolFlagsOptional != 0 + sourceIsOptional := propName != ast.InternalSymbolNameMissing && core.OrElse(c.getPropertyOfType(source, propName), c.unknownSymbol).Flags&ast.SymbolFlagsOptional != 0 + targetPropType = c.removeMissingType(targetPropType, targetIsOptional) + sourcePropType = c.removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional) + result := c.checkTypeRelatedToEx(specificSource, targetPropType, relation, prop, e.errorMessage, diagnosticOutput) + if result && specificSource != sourcePropType { + // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType + c.checkTypeRelatedToEx(sourcePropType, targetPropType, relation, prop, e.errorMessage, diagnosticOutput) + } + } + } + } + } + return reportedError +} + +func (c *Checker) getSuggestedSymbolForNonexistentJSXAttribute(name string, containingType *Type) *ast.Symbol { + properties := c.getPropertiesOfType(containingType) + var jsxSpecific *ast.Symbol + switch name { + case "for": + jsxSpecific = core.Find(properties, func(x *ast.Symbol) bool { return ast.SymbolName(x) == "htmlFor" }) + case "class": + jsxSpecific = core.Find(properties, func(x *ast.Symbol) bool { return ast.SymbolName(x) == "className" }) + } + if jsxSpecific != nil { + return jsxSpecific + } + return c.getSpellingSuggestionForName(name, properties, ast.SymbolFlagsValue) +} + +func (c *Checker) resolveJsxOpeningLikeElement(node *ast.Node, candidatesOutArray *[]*Signature, checkMode CheckMode) *Signature { + if isJsxIntrinsicTagName(node.TagName()) { + result := c.getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node) + fakeSignature := c.createSignatureForJSXIntrinsic(node, result) + c.checkTypeAssignableToAndOptionallyElaborate(c.checkExpressionWithContextualType(node.Attributes(), c.getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), nil /*inferenceContext*/, CheckModeNormal), result, node.TagName(), node.Attributes(), nil, nil) + typeArguments := node.TypeArguments() + if len(typeArguments) != 0 { + c.checkSourceElements(typeArguments) + c.diagnostics.Add(ast.NewDiagnostic(ast.GetSourceFileOfNode(node), node.TypeArgumentList().Loc, diagnostics.Expected_0_type_arguments_but_got_1, 0, len(typeArguments))) + } + return fakeSignature + } + exprTypes := c.checkExpression(node.TagName()) + apparentType := c.getApparentType(exprTypes) + if c.isErrorType(apparentType) { + return c.resolveErrorCall(node) + } + signatures := c.getUninstantiatedJsxSignaturesOfType(exprTypes, node) + if c.isUntypedFunctionCall(exprTypes, apparentType, len(signatures), 0 /*constructSignatures*/) { + return c.resolveUntypedCall(node) + } + if len(signatures) == 0 { + // We found no signatures at all, which is an error + c.error(node.TagName(), diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, scanner.GetTextOfNode(node.TagName())) + return c.resolveErrorCall(node) + } + return c.resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlagsNone, nil) +} + +// Check if the given signature can possibly be a signature called by the JSX opening-like element. +// @param node a JSX opening-like element we are trying to figure its call signature +// @param signature a candidate signature we are trying whether it is a call signature +// @param relation a relationship to check parameter and argument type +func (c *Checker) checkApplicableSignatureForJsxOpeningLikeElement(node *ast.Node, signature *Signature, relation *Relation, checkMode CheckMode, reportErrors bool, diagnosticOutput *[]*ast.Diagnostic) bool { + // Stateless function components can have maximum of three arguments: "props", "context", and "updater". + // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, + // can be specified by users through attributes property. + paramType := c.getEffectiveFirstArgumentForJsxSignature(signature, node) + attributesType := c.checkExpressionWithContextualType(node.Attributes(), paramType, nil /*inferenceContext*/, checkMode) + var checkAttributesType *Type + checkTagNameDoesNotExpectTooManyArguments := func() bool { + if c.getJsxNamespaceContainerForImplicitImport(node) != nil { + return true // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet) + } + var tagType *Type + if (ast.IsJsxOpeningElement(node) || ast.IsJsxSelfClosingElement(node)) && !(isJsxIntrinsicTagName(node.TagName()) || ast.IsJsxNamespacedName(node.TagName())) { + tagType = c.checkExpression(node.TagName()) + } + if tagType == nil { + return true + } + tagCallSignatures := c.getSignaturesOfType(tagType, SignatureKindCall) + if len(tagCallSignatures) == 0 { + return true + } + factory := c.getJsxFactoryEntity(node) + if factory == nil { + return true + } + factorySymbol := c.resolveEntityName(factory, ast.SymbolFlagsValue, true /*ignoreErrors*/, false /*dontResolveAlias*/, node) + if factorySymbol == nil { + return true + } + + factoryType := c.getTypeOfSymbol(factorySymbol) + callSignatures := c.getSignaturesOfType(factoryType, SignatureKindCall) + if len(callSignatures) == 0 { + return true + } + hasFirstParamSignatures := false + maxParamCount := 0 + // Check that _some_ first parameter expects a FC-like thing, and that some overload of the SFC expects an acceptable number of arguments + for _, sig := range callSignatures { + firstparam := c.getTypeAtPosition(sig, 0) + signaturesOfParam := c.getSignaturesOfType(firstparam, SignatureKindCall) + if len(signaturesOfParam) == 0 { + continue + } + for _, paramSig := range signaturesOfParam { + hasFirstParamSignatures = true + if c.hasEffectiveRestParameter(paramSig) { + return true // some signature has a rest param, so function components can have an arbitrary number of arguments + } + paramCount := c.getParameterCount(paramSig) + if paramCount > maxParamCount { + maxParamCount = paramCount + } + } + } + if !hasFirstParamSignatures { + // Not a single signature had a first parameter which expected a signature - for back compat, and + // to guard against generic factories which won't have signatures directly, do not error + return true + } + absoluteMinArgCount := math.MaxInt + for _, tagSig := range tagCallSignatures { + tagRequiredArgCount := c.getMinArgumentCount(tagSig) + if tagRequiredArgCount < absoluteMinArgCount { + absoluteMinArgCount = tagRequiredArgCount + } + } + if absoluteMinArgCount <= maxParamCount { + return true // some signature accepts the number of arguments the function component provides + } + if reportErrors { + diag := NewDiagnosticForNode(node.TagName(), diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.TagName()), absoluteMinArgCount, entityNameToString(factory), maxParamCount) + tagNameSymbol := c.getSymbolAtLocation(node.TagName(), false) + if tagNameSymbol != nil && tagNameSymbol.ValueDeclaration != nil { + diag.AddRelatedInfo(NewDiagnosticForNode(tagNameSymbol.ValueDeclaration, diagnostics.X_0_is_declared_here, entityNameToString(node.TagName()))) + } + c.reportDiagnostic(diag, diagnosticOutput) + } + return false + } + if checkMode&CheckModeSkipContextSensitive != 0 { + checkAttributesType = c.getRegularTypeOfObjectLiteral(attributesType) + } else { + checkAttributesType = attributesType + } + if !checkTagNameDoesNotExpectTooManyArguments() { + return false + } + var errorNode *ast.Node + if reportErrors { + errorNode = node.TagName() + } + return c.checkTypeRelatedToAndOptionallyElaborate(checkAttributesType, paramType, relation, errorNode, node.Attributes(), nil, diagnosticOutput) +} + +// Get attributes type of the JSX opening-like element. The result is from resolving "attributes" property of the opening-like element. +// +// @param openingLikeElement a JSX opening-like element +// @param filter a function to remove attributes that will not participate in checking whether attributes are assignable +// @return an anonymous type (similar to the one returned by checkObjectLiteral) in which its properties are attributes property. +// @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, +// which also calls getSpreadType. +func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeElement *ast.Node, checkMode CheckMode) *Type { + attributes := openingLikeElement.Attributes() + contextualType := c.getContextualType(attributes, ContextFlagsNone) + var allAttributesTable ast.SymbolTable + if c.strictNullChecks { + allAttributesTable = make(ast.SymbolTable) + } + attributesTable := make(ast.SymbolTable) + spread := c.emptyJsxObjectType + var hasSpreadAnyType bool + var typeToIntersect *Type + var explicitlySpecifyChildrenAttribute bool + objectFlags := ObjectFlagsJsxAttributes + createJsxAttributesType := func() *Type { + objectFlags |= ObjectFlagsFreshLiteral + result := c.newAnonymousType(attributes.Symbol(), attributesTable, nil, nil, nil) + result.objectFlags |= objectFlags | ObjectFlagsObjectLiteral | ObjectFlagsContainsObjectOrArrayLiteral + return result + } + jsxChildrenPropertyName := c.getJsxElementChildrenPropertyName(c.getJsxNamespaceAt(openingLikeElement)) + // Create anonymous type from given attributes symbol table. + // @param symbol a symbol of JsxAttributes containing attributes corresponding to attributesTable + // @param attributesTable a symbol table of attributes property + for _, attributeDecl := range attributes.AsJsxAttributes().Properties.Nodes { + member := attributeDecl.Symbol() + if ast.IsJsxAttribute(attributeDecl) { + exprType := c.checkJsxAttribute(attributeDecl, checkMode) + objectFlags |= exprType.objectFlags & ObjectFlagsPropagatingFlags + attributeSymbol := c.newSymbol(ast.SymbolFlagsProperty|member.Flags, member.Name) + attributeSymbol.Declarations = member.Declarations + attributeSymbol.Parent = member.Parent + if member.ValueDeclaration != nil { + attributeSymbol.ValueDeclaration = member.ValueDeclaration + } + links := c.valueSymbolLinks.Get(attributeSymbol) + links.resolvedType = exprType + links.target = member + attributesTable[attributeSymbol.Name] = attributeSymbol + if allAttributesTable != nil { + allAttributesTable[attributeSymbol.Name] = attributeSymbol + } + if attributeDecl.Name().Text() == jsxChildrenPropertyName { + explicitlySpecifyChildrenAttribute = true + } + if contextualType != nil { + prop := c.getPropertyOfType(contextualType, member.Name) + if prop != nil && prop.Declarations != nil && c.isDeprecatedSymbol(prop) && ast.IsIdentifier(attributeDecl.Name()) { + c.addDeprecatedSuggestion(attributeDecl.Name(), prop.Declarations, attributeDecl.Name().Text()) + } + } + if contextualType != nil && checkMode&CheckModeInferential != 0 && checkMode&CheckModeSkipContextSensitive == 0 && c.isContextSensitive(attributeDecl) { + inferenceContext := c.getInferenceContext(attributes) + // Debug.assert(inferenceContext) + // In CheckMode.Inferential we should always have an inference context + inferenceNode := attributeDecl.Initializer().Expression() + c.addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType) + } + } else { + // Debug.assert(attributeDecl.Kind == ast.KindJsxSpreadAttribute) + if len(attributesTable) != 0 { + spread = c.getSpreadType(spread, createJsxAttributesType(), attributes.Symbol(), objectFlags, false /*readonly*/) + attributesTable = make(ast.SymbolTable) + } + exprType := c.getReducedType(c.checkExpressionEx(attributeDecl.Expression(), checkMode&CheckModeInferential)) + if IsTypeAny(exprType) { + hasSpreadAnyType = true + } + if c.isValidSpreadType(exprType) { + spread = c.getSpreadType(spread, exprType, attributes.Symbol(), objectFlags, false /*readonly*/) + if allAttributesTable != nil { + c.checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl) + } + } else { + c.error(attributeDecl.Expression(), diagnostics.Spread_types_may_only_be_created_from_object_types) + if typeToIntersect != nil { + typeToIntersect = c.getIntersectionType([]*Type{typeToIntersect, exprType}) + } else { + typeToIntersect = exprType + } + } + } + } + if !hasSpreadAnyType { + if len(attributesTable) != 0 { + spread = c.getSpreadType(spread, createJsxAttributesType(), attributes.Symbol(), objectFlags, false /*readonly*/) + } + } + // Handle children attribute + var parent *ast.Node + if ast.IsJsxElement(openingLikeElement.Parent) { + parent = openingLikeElement.Parent + } + // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement + if parent != nil && parent.AsJsxElement().OpeningElement == openingLikeElement && len(getSemanticJsxChildren(parent.AsJsxElement().Children.Nodes)) != 0 { + var childTypes []*Type = c.checkJsxChildren(parent, checkMode) + if !hasSpreadAnyType && jsxChildrenPropertyName != ast.InternalSymbolNameMissing && jsxChildrenPropertyName != "" { + // Error if there is a attribute named "children" explicitly specified and children element. + // This is because children element will overwrite the value from attributes. + // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. + if explicitlySpecifyChildrenAttribute { + c.error(attributes, diagnostics.X_0_are_specified_twice_The_attribute_named_0_will_be_overwritten, jsxChildrenPropertyName) + } + var childrenContextualType *Type + if contextualType := c.getApparentTypeOfContextualType(openingLikeElement.Attributes(), ContextFlagsNone); contextualType != nil { + childrenContextualType = c.getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName) + } + // If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process + childrenPropSymbol := c.newSymbol(ast.SymbolFlagsProperty, jsxChildrenPropertyName) + links := c.valueSymbolLinks.Get(childrenPropSymbol) + switch { + case len(childTypes) == 1: + links.resolvedType = childTypes[0] + case childrenContextualType != nil && someType(childrenContextualType, c.isTupleLikeType): + links.resolvedType = c.createTupleType(childTypes) + default: + links.resolvedType = c.createArrayType(c.getUnionType(childTypes)) + } + // Fake up a property declaration for the children + childrenPropSymbol.ValueDeclaration = c.factory.NewPropertySignatureDeclaration(nil, c.factory.NewIdentifier(jsxChildrenPropertyName), nil /*postfixToken*/, nil /*type*/, nil /*initializer*/) + childrenPropSymbol.ValueDeclaration.Parent = attributes + childrenPropSymbol.ValueDeclaration.AsPropertySignatureDeclaration().Symbol = childrenPropSymbol + childPropMap := make(ast.SymbolTable) + childPropMap[jsxChildrenPropertyName] = childrenPropSymbol + spread = c.getSpreadType(spread, c.newAnonymousType(attributes.Symbol(), childPropMap, nil, nil, nil), attributes.Symbol(), objectFlags, false /*readonly*/) + } + } + if hasSpreadAnyType { + return c.anyType + } + if typeToIntersect != nil { + if spread != c.emptyJsxObjectType { + return c.getIntersectionType([]*Type{typeToIntersect, spread}) + } + return typeToIntersect + } + if spread == c.emptyJsxObjectType { + return createJsxAttributesType() + } + return spread +} + +func getSemanticJsxChildren(children []*ast.JsxChild) []*ast.JsxChild { + return core.Filter(children, func(i *ast.JsxChild) bool { + switch i.Kind { + case ast.KindJsxExpression: + return i.Expression() != nil + case ast.KindJsxText: + return !i.AsJsxText().ContainsOnlyTriviaWhiteSpaces + default: + return true + } + }) +} + +func (c *Checker) checkJsxAttribute(node *ast.Node, checkMode CheckMode) *Type { + if node.Initializer() != nil { + return c.checkExpressionForMutableLocation(node.Initializer(), checkMode) + } + // <Elem attr /> is sugar for <Elem attr={true} /> + return c.trueType +} + +func (c *Checker) checkJsxChildren(node *ast.Node, checkMode CheckMode) []*Type { + var childTypes []*Type + for _, child := range node.Children().Nodes { + // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that + // because then type of children property will have constituent of string type. + if ast.IsJsxText(child) { + if !child.AsJsxText().ContainsOnlyTriviaWhiteSpaces { + childTypes = append(childTypes, c.stringType) + } + } else if ast.IsJsxExpression(child) && child.Expression() == nil { + // empty jsx expressions don't *really* count as present children + continue + } else { + childTypes = append(childTypes, c.checkExpressionForMutableLocation(child, checkMode)) + } + } + return childTypes +} + +func (c *Checker) getUninstantiatedJsxSignaturesOfType(elementType *Type, caller *ast.Node) []*Signature { + if elementType.flags&TypeFlagsString != 0 { + return []*Signature{c.anySignature} + } + if elementType.flags&TypeFlagsStringLiteral != 0 { + intrinsicType := c.getIntrinsicAttributesTypeFromStringLiteralType(elementType, caller) + if intrinsicType == nil { + c.error(caller, diagnostics.Property_0_does_not_exist_on_type_1, getStringLiteralValue(elementType), "JSX."+JsxNames.IntrinsicElements) + return nil + } + fakeSignature := c.createSignatureForJSXIntrinsic(caller, intrinsicType) + return []*Signature{fakeSignature} + } + apparentElemType := c.getApparentType(elementType) + // Resolve the signatures, preferring constructor + signatures := c.getSignaturesOfType(apparentElemType, SignatureKindConstruct) + if len(signatures) == 0 { + // No construct signatures, try call signatures + signatures = c.getSignaturesOfType(apparentElemType, SignatureKindCall) + } + if len(signatures) == 0 && apparentElemType.flags&TypeFlagsUnion != 0 { + // If each member has some combination of new/call signatures; make a union signature list for those + signatures = c.getUnionSignatures(core.Map(apparentElemType.Types(), func(t *Type) []*Signature { + return c.getUninstantiatedJsxSignaturesOfType(t, caller) + })) + } + return signatures +} + +func (c *Checker) getEffectiveFirstArgumentForJsxSignature(signature *Signature, node *ast.Node) *Type { + if c.getJsxReferenceKind(node) != JsxReferenceKindComponent { + return c.getJsxPropsTypeFromCallSignature(signature, node) + } + return c.getJsxPropsTypeFromClassType(signature, node) +} + +func (c *Checker) getJsxPropsTypeFromCallSignature(sig *Signature, context *ast.Node) *Type { + propsType := c.getTypeOfFirstParameterOfSignatureWithFallback(sig, c.unknownType) + propsType = c.getJsxManagedAttributesFromLocatedAttributes(context, c.getJsxNamespaceAt(context), propsType) + intrinsicAttribs := c.getJsxType(JsxNames.IntrinsicAttributes, context) + if !c.isErrorType(intrinsicAttribs) { + propsType = c.intersectTypes(intrinsicAttribs, propsType) + } + return propsType +} + +func (c *Checker) getJsxPropsTypeFromClassType(sig *Signature, context *ast.Node) *Type { + ns := c.getJsxNamespaceAt(context) + forcedLookupLocation := c.getJsxElementPropertiesName(ns) + var attributesType *Type + switch forcedLookupLocation { + case ast.InternalSymbolNameMissing: + attributesType = c.getTypeOfFirstParameterOfSignatureWithFallback(sig, c.unknownType) + case "": + attributesType = c.getReturnTypeOfSignature(sig) + default: + attributesType = c.getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation) + if attributesType == nil && len(context.Attributes().AsJsxAttributes().Properties.Nodes) != 0 { + // There is no property named 'props' on this instance type + c.error(context, diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, forcedLookupLocation) + } + } + if attributesType == nil { + return c.unknownType + } + attributesType = c.getJsxManagedAttributesFromLocatedAttributes(context, ns, attributesType) + if IsTypeAny(attributesType) { + // Props is of type 'any' or unknown + return attributesType + } + // Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements + apparentAttributesType := attributesType + intrinsicClassAttribs := c.getJsxType(JsxNames.IntrinsicClassAttributes, context) + if !c.isErrorType(intrinsicClassAttribs) { + typeParams := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol) + hostClassType := c.getReturnTypeOfSignature(sig) + var libraryManagedAttributeType *Type + if typeParams != nil { + // apply JSX.IntrinsicClassElements<hostClassType, ...> + inferredArgs := c.fillMissingTypeArguments([]*Type{hostClassType}, typeParams, c.getMinTypeArgumentCount(typeParams)) + libraryManagedAttributeType = c.instantiateType(intrinsicClassAttribs, newTypeMapper(typeParams, inferredArgs)) + } else { + libraryManagedAttributeType = intrinsicClassAttribs + } + apparentAttributesType = c.intersectTypes(libraryManagedAttributeType, apparentAttributesType) + } + intrinsicAttribs := c.getJsxType(JsxNames.IntrinsicAttributes, context) + if !c.isErrorType(intrinsicAttribs) { + apparentAttributesType = c.intersectTypes(intrinsicAttribs, apparentAttributesType) + } + return apparentAttributesType +} + +func (c *Checker) getJsxPropsTypeForSignatureFromMember(sig *Signature, forcedLookupLocation string) *Type { + if sig.composite != nil { + // JSX Elements using the legacy `props`-field based lookup (eg, react class components) need to treat the `props` member as an input + // instead of an output position when resolving the signature. We need to go back to the input signatures of the composite signature, + // get the type of `props` on each return type individually, and then _intersect them_, rather than union them (as would normally occur + // for a union signature). It's an unfortunate quirk of looking in the output of the signature for the type we want to use for the input. + // The default behavior of `getTypeOfFirstParameterOfSignatureWithFallback` when no `props` member name is defined is much more sane. + var results []*Type + for _, signature := range sig.composite.signatures { + instance := c.getReturnTypeOfSignature(signature) + if IsTypeAny(instance) { + return instance + } + propType := c.getTypeOfPropertyOfType(instance, forcedLookupLocation) + if propType == nil { + return nil + } + results = append(results, propType) + } + return c.getIntersectionType(results) + // Same result for both union and intersection signatures + } + instanceType := c.getReturnTypeOfSignature(sig) + if IsTypeAny(instanceType) { + return instanceType + } + return c.getTypeOfPropertyOfType(instanceType, forcedLookupLocation) +} + +func (c *Checker) getJsxManagedAttributesFromLocatedAttributes(context *ast.Node, ns *ast.Symbol, attributesType *Type) *Type { + managedSym := c.getJsxLibraryManagedAttributes(ns) + if managedSym != nil { + ctorType := c.getStaticTypeOfReferencedJsxConstructor(context) + result := c.instantiateAliasOrInterfaceWithDefaults(managedSym, []*Type{ctorType, attributesType}) + if result != nil { + return result + } + } + return attributesType +} + +func (c *Checker) instantiateAliasOrInterfaceWithDefaults(managedSym *ast.Symbol, typeArguments []*Type) *Type { + declaredManagedType := c.getDeclaredTypeOfSymbol(managedSym) + // fetches interface type, or initializes symbol links type parmaeters + if managedSym.Flags&ast.SymbolFlagsTypeAlias != 0 { + params := c.typeAliasLinks.Get(managedSym).typeParameters + if len(params) >= len(typeArguments) { + args := c.fillMissingTypeArguments(typeArguments, params, len(typeArguments)) + if len(args) == 0 { + return declaredManagedType + } + return c.getTypeAliasInstantiation(managedSym, args, nil) + } + } + if len(declaredManagedType.AsInterfaceType().TypeParameters()) >= len(typeArguments) { + args := c.fillMissingTypeArguments(typeArguments, declaredManagedType.AsInterfaceType().TypeParameters(), len(typeArguments)) + return c.createTypeReference(declaredManagedType, args) + } + return nil +} + +func (c *Checker) getJsxLibraryManagedAttributes(jsxNamespace *ast.Symbol) *ast.Symbol { + if jsxNamespace != nil { + return c.getSymbol(jsxNamespace.Exports, JsxNames.LibraryManagedAttributes, ast.SymbolFlagsType) + } + return nil +} + +func (c *Checker) getJsxElementTypeSymbol(jsxNamespace *ast.Symbol) *ast.Symbol { + // JSX.ElementType [symbol] + if jsxNamespace != nil { + return c.getSymbol(jsxNamespace.Exports, JsxNames.ElementType, ast.SymbolFlagsType) + } + return nil +} + +// e.g. "props" for React.d.ts, +// or InternalSymbolNameMissing if ElementAttributesProperty doesn't exist (which means all +// +// non-intrinsic elements' attributes type is 'any'), +// +// or "" if it has 0 properties (which means every +// +// non-intrinsic elements' attributes type is the element instance type) +func (c *Checker) getJsxElementPropertiesName(jsxNamespace *ast.Symbol) string { + return c.getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace) +} + +func (c *Checker) getJsxElementChildrenPropertyName(jsxNamespace *ast.Symbol) string { + return c.getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace) +} + +// Look into JSX namespace and then look for container with matching name as nameOfAttribPropContainer. +// Get a single property from that container if existed. Report an error if there are more than one property. +// +// @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer +// +// if other string is given or the container doesn't exist, return undefined. +func (c *Checker) getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer string, jsxNamespace *ast.Symbol) string { + // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] + if jsxNamespace != nil { + jsxElementAttribPropInterfaceSym := c.getSymbol(jsxNamespace.Exports, nameOfAttribPropContainer, ast.SymbolFlagsType) + if jsxElementAttribPropInterfaceSym != nil { + jsxElementAttribPropInterfaceType := c.getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym) + propertiesOfJsxElementAttribPropInterface := c.getPropertiesOfType(jsxElementAttribPropInterfaceType) + // Element Attributes has zero properties, so the element attributes type will be the class instance type + if len(propertiesOfJsxElementAttribPropInterface) == 0 { + return "" + } + if len(propertiesOfJsxElementAttribPropInterface) == 1 { + return propertiesOfJsxElementAttribPropInterface[0].Name + } + if len(propertiesOfJsxElementAttribPropInterface) > 1 && len(jsxElementAttribPropInterfaceSym.Declarations) != 0 { + // More than one property on ElementAttributesProperty is an error + c.error(jsxElementAttribPropInterfaceSym.Declarations[0], diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, nameOfAttribPropContainer) + } + } + } + return ast.InternalSymbolNameMissing +} + +func (c *Checker) getStaticTypeOfReferencedJsxConstructor(context *ast.Node) *Type { + if isJsxIntrinsicTagName(context.TagName()) { + result := c.getIntrinsicAttributesTypeFromJsxOpeningLikeElement(context) + fakeSignature := c.createSignatureForJSXIntrinsic(context, result) + return c.getOrCreateTypeFromSignature(fakeSignature, nil) + } + tagType := c.checkExpressionCached(context.TagName()) + if tagType.flags&TypeFlagsStringLiteral != 0 { + result := c.getIntrinsicAttributesTypeFromStringLiteralType(tagType, context) + if result == nil { + return c.errorType + } + fakeSignature := c.createSignatureForJSXIntrinsic(context, result) + return c.getOrCreateTypeFromSignature(fakeSignature, nil) + } + return tagType +} + +func (c *Checker) getIntrinsicAttributesTypeFromStringLiteralType(t *Type, location *ast.Node) *Type { + // If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type + // For example: + // var CustomTag: "h1" = "h1"; + // <CustomTag> Hello World </CustomTag> + intrinsicElementsType := c.getJsxType(JsxNames.IntrinsicElements, location) + if !c.isErrorType(intrinsicElementsType) { + stringLiteralTypeName := getStringLiteralValue(t) + intrinsicProp := c.getPropertyOfType(intrinsicElementsType, stringLiteralTypeName) + if intrinsicProp != nil { + return c.getTypeOfSymbol(intrinsicProp) + } + indexSignatureType := c.getIndexTypeOfType(intrinsicElementsType, c.stringType) + if indexSignatureType != nil { + return indexSignatureType + } + return nil + } + // If we need to report an error, we already done so here. So just return any to prevent any more error downstream + return c.anyType +} + +func (c *Checker) getJsxReferenceKind(node *ast.Node) JsxReferenceKind { + if isJsxIntrinsicTagName(node.TagName()) { + return JsxReferenceKindMixed + } + tagType := c.getApparentType(c.checkExpression(node.TagName())) + if len(c.getSignaturesOfType(tagType, SignatureKindConstruct)) != 0 { + return JsxReferenceKindComponent + } + if len(c.getSignaturesOfType(tagType, SignatureKindCall)) != 0 { + return JsxReferenceKindFunction + } + return JsxReferenceKindMixed +} + +func (c *Checker) createSignatureForJSXIntrinsic(node *ast.Node, result *Type) *Signature { + elementType := c.errorType + if namespace := c.getJsxNamespaceAt(node); namespace != nil { + if typeSymbol := c.getSymbol(c.getExportsOfSymbol(namespace), JsxNames.Element, ast.SymbolFlagsType); typeSymbol != nil { + elementType = c.getDeclaredTypeOfSymbol(typeSymbol) + } + } + // returnNode := typeSymbol && c.nodeBuilder.symbolToEntityName(typeSymbol, ast.SymbolFlagsType, node) + // declaration := factory.createFunctionTypeNode(nil, []ParameterDeclaration{factory.createParameterDeclaration(nil, nil /*dotDotDotToken*/, "props", nil /*questionToken*/, c.nodeBuilder.typeToTypeNode(result, node))}, ifElse(returnNode != nil, factory.createTypeReferenceNode(returnNode, nil /*typeArguments*/), factory.createKeywordTypeNode(ast.KindAnyKeyword))) + parameterSymbol := c.newSymbol(ast.SymbolFlagsFunctionScopedVariable, "props") + c.valueSymbolLinks.Get(parameterSymbol).resolvedType = result + return c.newSignature(SignatureFlagsNone, nil, nil, nil, []*ast.Symbol{parameterSymbol}, elementType, nil, 1) +} + +// Get attributes type of the given intrinsic opening-like Jsx element by resolving the tag name. +// The function is intended to be called from a function which has checked that the opening element is an intrinsic element. +// @param node an intrinsic JSX opening-like element +func (c *Checker) getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node *ast.Node) *Type { + // Debug.assert(c.isJsxIntrinsicTagName(node.TagName())) + links := c.jsxElementLinks.Get(node) + if links.resolvedJsxElementAttributesType != nil { + return links.resolvedJsxElementAttributesType + } + symbol := c.getIntrinsicTagSymbol(node) + if links.jsxFlags&JsxFlagsIntrinsicNamedElement != 0 { + links.resolvedJsxElementAttributesType = core.OrElse(c.getTypeOfSymbol(symbol), c.errorType) + return links.resolvedJsxElementAttributesType + } + if links.jsxFlags&JsxFlagsIntrinsicIndexedElement != 0 { + indexInfo := c.getApplicableIndexInfoForName(c.getJsxType(JsxNames.IntrinsicElements, node), node.TagName().Text()) + if indexInfo != nil { + links.resolvedJsxElementAttributesType = indexInfo.valueType + return links.resolvedJsxElementAttributesType + } + } + links.resolvedJsxElementAttributesType = c.errorType + return links.resolvedJsxElementAttributesType +} + +// Looks up an intrinsic tag name and returns a symbol that either points to an intrinsic +// property (in which case nodeLinks.jsxFlags will be IntrinsicNamedElement) or an intrinsic +// string index signature (in which case nodeLinks.jsxFlags will be IntrinsicIndexedElement). +// May also return unknownSymbol if both of these lookups fail. +func (c *Checker) getIntrinsicTagSymbol(node *ast.Node) *ast.Symbol { + links := c.symbolNodeLinks.Get(node) + if links.resolvedSymbol != nil { + return links.resolvedSymbol + } + intrinsicElementsType := c.getJsxType(JsxNames.IntrinsicElements, node) + if !c.isErrorType(intrinsicElementsType) { + // Property case + tagName := node.TagName() + if !ast.IsIdentifier(tagName) && !ast.IsJsxNamespacedName(tagName) { + panic("Invalid tag name") + } + propName := tagName.Text() + intrinsicProp := c.getPropertyOfType(intrinsicElementsType, propName) + if intrinsicProp != nil { + c.jsxElementLinks.Get(node).jsxFlags |= JsxFlagsIntrinsicNamedElement + links.resolvedSymbol = intrinsicProp + return links.resolvedSymbol + } + // Intrinsic string indexer case + indexSymbol := c.getApplicableIndexSymbol(intrinsicElementsType, c.getStringLiteralType(propName)) + if indexSymbol != nil { + c.jsxElementLinks.Get(node).jsxFlags |= JsxFlagsIntrinsicIndexedElement + links.resolvedSymbol = indexSymbol + return links.resolvedSymbol + } + if c.getTypeOfPropertyOrIndexSignatureOfType(intrinsicElementsType, propName) != nil { + c.jsxElementLinks.Get(node).jsxFlags |= JsxFlagsIntrinsicIndexedElement + links.resolvedSymbol = intrinsicElementsType.symbol + return links.resolvedSymbol + } + // Wasn't found + c.error(node, diagnostics.Property_0_does_not_exist_on_type_1, tagName.Text(), "JSX."+JsxNames.IntrinsicElements) + links.resolvedSymbol = c.unknownSymbol + return links.resolvedSymbol + } + if c.noImplicitAny { + c.error(node, diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, JsxNames.IntrinsicElements) + } + links.resolvedSymbol = c.unknownSymbol + return links.resolvedSymbol +} + +func (c *Checker) getJsxStatelessElementTypeAt(location *ast.Node) *Type { + jsxElementType := c.getJsxElementTypeAt(location) + if jsxElementType == nil { + return nil + } + return c.getUnionType([]*Type{jsxElementType, c.nullType}) +} + +func (c *Checker) getJsxElementClassTypeAt(location *ast.Node) *Type { + t := c.getJsxType(JsxNames.ElementClass, location) + if c.isErrorType(t) { + return nil + } + return t +} + +func (c *Checker) getJsxElementTypeAt(location *ast.Node) *Type { + return c.getJsxType(JsxNames.Element, location) +} + +func (c *Checker) getJsxElementTypeTypeAt(location *ast.Node) *Type { + ns := c.getJsxNamespaceAt(location) + if ns == nil { + return nil + } + sym := c.getJsxElementTypeSymbol(ns) + if sym == nil { + return nil + } + t := c.instantiateAliasOrInterfaceWithDefaults(sym, nil) + if t == nil || c.isErrorType(t) { + return nil + } + return t +} + +func (c *Checker) getJsxType(name string, location *ast.Node) *Type { + if namespace := c.getJsxNamespaceAt(location); namespace != nil { + if exports := c.getExportsOfSymbol(namespace); exports != nil { + if typeSymbol := c.getSymbol(exports, name, ast.SymbolFlagsType); typeSymbol != nil { + return c.getDeclaredTypeOfSymbol(typeSymbol) + } + } + } + return c.errorType +} + +func (c *Checker) getJsxNamespaceAt(location *ast.Node) *ast.Symbol { + var links *JsxElementLinks + if location != nil { + links = c.jsxElementLinks.Get(location) + } + if links != nil && links.jsxNamespace != nil && links.jsxNamespace != c.unknownSymbol { + return links.jsxNamespace + } + if links == nil || links.jsxNamespace != c.unknownSymbol { + resolvedNamespace := c.getJsxNamespaceContainerForImplicitImport(location) + if resolvedNamespace == nil || resolvedNamespace == c.unknownSymbol { + namespaceName := c.getJsxNamespace(location) + resolvedNamespace = c.resolveName(location, namespaceName, ast.SymbolFlagsNamespace, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/) + } + if resolvedNamespace != nil { + candidate := c.resolveSymbol(c.getSymbol(c.getExportsOfSymbol(c.resolveSymbol(resolvedNamespace)), JsxNames.JSX, ast.SymbolFlagsNamespace)) + if candidate != nil && candidate != c.unknownSymbol { + if links != nil { + links.jsxNamespace = candidate + } + return candidate + } + } + if links != nil { + links.jsxNamespace = c.unknownSymbol + } + } + // JSX global fallback + s := c.resolveSymbol(c.getGlobalSymbol(JsxNames.JSX, ast.SymbolFlagsNamespace, nil /*diagnostic*/)) + if s == c.unknownSymbol { + return nil + } + return s +} + +func (c *Checker) getJsxNamespace(location *ast.Node) string { + if location != nil { + file := ast.GetSourceFileOfNode(location) + if file != nil { + links := c.sourceFileLinks.Get(file) + if ast.IsJsxOpeningFragment(location) { + if links.localJsxFragmentNamespace != "" { + return links.localJsxFragmentNamespace + } + jsxFragmentPragma := ast.GetPragmaFromSourceFile(file, "jsxfrag") + if jsxFragmentPragma != nil { + links.localJsxFragmentFactory = c.parseIsolatedEntityName(jsxFragmentPragma.Args["factory"].Value) + if links.localJsxFragmentFactory != nil { + links.localJsxFragmentNamespace = ast.GetFirstIdentifier(links.localJsxFragmentFactory).Text() + return links.localJsxFragmentNamespace + } + } + entity := c.getJsxFragmentFactoryEntity(location) + if entity != nil { + links.localJsxFragmentFactory = entity + links.localJsxFragmentNamespace = ast.GetFirstIdentifier(entity).Text() + return links.localJsxFragmentNamespace + } + } else { + localJsxNamespace := c.getLocalJsxNamespace(file) + if localJsxNamespace != "" { + links.localJsxNamespace = localJsxNamespace + return links.localJsxNamespace + } + } + } + } + if c._jsxNamespace == "" { + c._jsxNamespace = "React" + if c.compilerOptions.JsxFactory != "" { + c._jsxFactoryEntity = c.parseIsolatedEntityName(c.compilerOptions.JsxFactory) + if c._jsxFactoryEntity != nil { + c._jsxNamespace = ast.GetFirstIdentifier(c._jsxFactoryEntity).Text() + } + } else if c.compilerOptions.ReactNamespace != "" { + c._jsxNamespace = c.compilerOptions.ReactNamespace + } + } + if c._jsxFactoryEntity == nil { + c._jsxFactoryEntity = c.factory.NewQualifiedName(c.factory.NewIdentifier(c._jsxNamespace), c.factory.NewIdentifier("createElement")) + } + return c._jsxNamespace +} + +func (c *Checker) getLocalJsxNamespace(file *ast.SourceFile) string { + links := c.sourceFileLinks.Get(file) + if links.localJsxNamespace != "" { + return links.localJsxNamespace + } + jsxPragma := ast.GetPragmaFromSourceFile(file, "jsx") + if jsxPragma != nil { + links.localJsxFactory = c.parseIsolatedEntityName(jsxPragma.Args["factory"].Value) + if links.localJsxFactory != nil { + links.localJsxNamespace = ast.GetFirstIdentifier(links.localJsxFactory).Text() + return links.localJsxNamespace + } + } + return "" +} + +func (c *Checker) getJsxFactoryEntity(location *ast.Node) *ast.Node { + if location != nil { + c.getJsxNamespace(location) + if localJsxFactory := c.sourceFileLinks.Get(ast.GetSourceFileOfNode(location)).localJsxFactory; localJsxFactory != nil { + return localJsxFactory + } + } + return c._jsxFactoryEntity +} + +func (c *Checker) getJsxFragmentFactoryEntity(location *ast.Node) *ast.EntityName { + if location != nil { + file := ast.GetSourceFileOfNode(location) + if file != nil { + links := c.sourceFileLinks.Get(file) + if links.localJsxFragmentFactory != nil { + return links.localJsxFragmentFactory + } + jsxFragPragma := ast.GetPragmaFromSourceFile(file, "jsxfrag") + if jsxFragPragma != nil { + links.localJsxFragmentFactory = c.parseIsolatedEntityName(jsxFragPragma.Args["factory"].Value) + return links.localJsxFragmentFactory + } + } + } + if c.compilerOptions.JsxFragmentFactory != "" { + return c.parseIsolatedEntityName(c.compilerOptions.JsxFragmentFactory) + } + return nil +} + +func (c *Checker) parseIsolatedEntityName(name string) *ast.Node { + result := parser.ParseIsolatedEntityName(name, c.languageVersion) + if result != nil { + markAsSynthetic(result) + } + return result +} + +func markAsSynthetic(node *ast.Node) bool { + node.Loc = core.NewTextRange(-1, -1) + node.ForEachChild(markAsSynthetic) + return false +} + +func (c *Checker) getJsxNamespaceContainerForImplicitImport(location *ast.Node) *ast.Symbol { + var file *ast.SourceFile + var links *JsxElementLinks + if location != nil { + if file = ast.GetSourceFileOfNode(location); file != nil { + links = c.jsxElementLinks.Get(file.AsNode()) + } + } + if links != nil && links.jsxImplicitImportContainer != nil { + return core.IfElse(links.jsxImplicitImportContainer == c.unknownSymbol, nil, links.jsxImplicitImportContainer) + } + moduleReference, specifier := c.getJSXRuntimeImportSpecifier(file) + if moduleReference == "" { + return nil + } + errorMessage := diagnostics.This_JSX_tag_requires_the_module_path_0_to_exist_but_none_could_be_found_Make_sure_you_have_types_for_the_appropriate_package_installed + mod := c.resolveExternalModule(core.OrElse(specifier, location), moduleReference, errorMessage, location, false) + var result *ast.Symbol + if mod != nil && mod != c.unknownSymbol { + result = c.getMergedSymbol(c.resolveSymbol(mod)) + } + if links != nil { + links.jsxImplicitImportContainer = core.OrElse(result, c.unknownSymbol) + } + return result +} + +func (c *Checker) getJSXRuntimeImportSpecifier(file *ast.SourceFile) (moduleReference string, specifier *ast.Node) { + return c.program.GetJSXRuntimeImportSpecifier(file.Path()) +} diff --git a/internal/checker/printer.go b/internal/checker/printer.go index 03f16080fa..454b8680c5 100644 --- a/internal/checker/printer.go +++ b/internal/checker/printer.go @@ -6,6 +6,7 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/jsnum" + "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/scanner" ) @@ -18,10 +19,12 @@ func (c *Checker) getTypePrecedence(t *Type) ast.TypePrecedence { return ast.TypePrecedenceIntersection case t.flags&TypeFlagsUnion != 0 && t.flags&TypeFlagsBoolean == 0: return ast.TypePrecedenceUnion - case t.flags&TypeFlagsIndex != 0: + case t.flags&TypeFlagsIndex != 0 || isInferTypeParameter(t): return ast.TypePrecedenceTypeOperator case c.isArrayType(t): return ast.TypePrecedencePostfix + case t.objectFlags&ObjectFlagsClassOrInterface == 0 && c.getSingleCallOrConstructSignature(t) != nil: + return ast.TypePrecedenceFunction } } return ast.TypePrecedenceNonArray @@ -36,13 +39,16 @@ func (c *Checker) symbolToString(s *ast.Symbol) string { return s.Name } if s.ValueDeclaration != nil { + if ast.IsJsxAttribute(s.ValueDeclaration) { + return "\"" + s.Name + "\"" + } name := ast.GetNameOfDeclaration(s.ValueDeclaration) if name != nil { return scanner.GetTextOfNode(name) } } if len(s.Name) == 0 || s.Name[0] != '\xFE' { - return "\"" + s.Name + "\"" // !!! Implement escaping + return s.Name // !!! Implement escaping } switch s.Name { case ast.InternalSymbolNameClass: @@ -66,6 +72,9 @@ func (c *Checker) TypeToString(t *Type) string { func (c *Checker) typeToStringEx(t *Type, enclosingDeclaration *ast.Node, flags TypeFormatFlags) string { p := c.newPrinter(flags) + if flags&TypeFormatFlagsNoTypeReduction == 0 { + t = c.getReducedType(t) + } p.printType(t) return p.string() } @@ -98,11 +107,12 @@ func (c *Checker) valueToString(value any) string { } type Printer struct { - c *Checker - flags TypeFormatFlags - sb strings.Builder - printing core.Set[*Type] - depth int + c *Checker + flags TypeFormatFlags + sb strings.Builder + printing core.Set[*Type] + depth int32 + extendsTypeDepth int32 } func (c *Checker) newPrinter(flags TypeFormatFlags) *Printer { @@ -121,6 +131,20 @@ func (p *Printer) printName(symbol *ast.Symbol) { p.print(p.c.symbolToString(symbol)) } +func (p *Printer) printQualifiedName(symbol *ast.Symbol) { + if p.flags&TypeFormatFlagsUseFullyQualifiedType != 0 && symbol.Parent != nil { + p.printQualifiedName(symbol.Parent) + p.print(".") + } + if symbol.Flags&ast.SymbolFlagsModule != 0 && strings.HasPrefix(symbol.Name, "\"") { + p.print("import(") + p.print(symbol.Name) + p.print(")") + return + } + p.printName(symbol) +} + func (p *Printer) printTypeEx(t *Type, precedence ast.TypePrecedence) { if p.c.getTypePrecedence(t) < precedence { p.print("(") @@ -132,8 +156,13 @@ func (p *Printer) printTypeEx(t *Type, precedence ast.TypePrecedence) { } func (p *Printer) printType(t *Type) { + if p.sb.Len() > 1_000_000 { + p.print("...") + return + } + if t.alias != nil && (p.flags&TypeFormatFlagsInTypeAlias == 0 || p.depth > 0) { - p.printName(t.alias.symbol) + p.printQualifiedName(t.alias.symbol) p.printTypeArguments(t.alias.typeArguments) } else { p.printTypeNoAlias(t) @@ -161,11 +190,20 @@ func (p *Printer) printTypeNoAlias(t *Type) { p.printRecursive(t, (*Printer).printIndexType) case t.flags&TypeFlagsIndexedAccess != 0: p.printRecursive(t, (*Printer).printIndexedAccessType) + case t.flags&TypeFlagsConditional != 0: + p.printRecursive(t, (*Printer).printConditionalType) case t.flags&TypeFlagsTemplateLiteral != 0: p.printTemplateLiteralType(t) case t.flags&TypeFlagsStringMapping != 0: p.printStringMappingType(t) case t.flags&TypeFlagsSubstitution != 0: + if p.c.isNoInferType(t) { + if noInferSymbol := p.c.getGlobalNoInferSymbolOrNil(); noInferSymbol != nil { + p.printQualifiedName(noInferSymbol) + p.printTypeArguments([]*Type{t.AsSubstitutionType().baseType}) + break + } + } p.printType(t.AsSubstitutionType().baseType) } p.depth-- @@ -197,14 +235,14 @@ func (p *Printer) printValue(value any) { p.printNumberLiteral(value) case bool: p.printBooleanLiteral(value) - case PseudoBigInt: + case jsnum.PseudoBigInt: p.printBigIntLiteral(value) } } func (p *Printer) printStringLiteral(s string) { p.print("\"") - p.print(s) + p.print(printer.EscapeString(s, '"')) p.print("\"") } @@ -216,11 +254,8 @@ func (p *Printer) printBooleanLiteral(b bool) { p.print(core.IfElse(b, "true", "false")) } -func (p *Printer) printBigIntLiteral(b PseudoBigInt) { - if b.negative { - p.print("-") - } - p.print(b.base10Value) +func (p *Printer) printBigIntLiteral(b jsnum.PseudoBigInt) { + p.print(b.String() + "n") } func (p *Printer) printUniqueESSymbolType(t *Type) { @@ -249,9 +284,15 @@ func (p *Printer) printStringMappingType(t *Type) { } func (p *Printer) printEnumLiteral(t *Type) { - p.printName(p.c.getParentOfSymbol(t.symbol)) - p.print(".") - p.printName(t.symbol) + if parent := p.c.getParentOfSymbol(t.symbol); parent != nil { + p.printQualifiedName(parent) + if p.c.getDeclaredTypeOfSymbol(parent) != t { + p.print(".") + p.printName(t.symbol) + } + return + } + p.printQualifiedName(t.symbol) } func (p *Printer) printObjectType(t *Type) { @@ -259,7 +300,7 @@ func (p *Printer) printObjectType(t *Type) { case t.objectFlags&ObjectFlagsReference != 0: p.printParameterizedType(t) case t.objectFlags&ObjectFlagsClassOrInterface != 0: - p.printName(t.symbol) + p.printQualifiedName(t.symbol) case p.c.isGenericMappedType(t) || t.objectFlags&ObjectFlagsMapped != 0 && t.AsMappedType().containsError: p.printMappedType(t) default: @@ -279,14 +320,14 @@ func (p *Printer) printParameterizedType(t *Type) { } func (p *Printer) printTypeReference(t *Type) { - p.printName(t.symbol) + p.printQualifiedName(t.symbol) p.printTypeArguments(p.c.getTypeArguments(t)[:p.c.getTypeReferenceArity(t)]) } func (p *Printer) printTypeArguments(typeArguments []*Type) { if len(typeArguments) != 0 { p.print("<") - tail := false + var tail bool for _, t := range typeArguments { if tail { p.print(", ") @@ -308,10 +349,13 @@ func (p *Printer) printArrayType(t *Type) { } func (p *Printer) printTupleType(t *Type) { - tail := false + if t.TargetTupleType().readonly { + p.print("readonly ") + } p.print("[") elementInfos := t.TargetTupleType().elementInfos typeArguments := p.c.getTypeArguments(t) + var tail bool for i, info := range elementInfos { t := typeArguments[i] if tail { @@ -323,18 +367,20 @@ func (p *Printer) printTupleType(t *Type) { if info.labeledDeclaration != nil { p.print(info.labeledDeclaration.Name().Text()) if info.flags&ElementFlagsOptional != 0 { - p.print("?") - } - p.print(": ") - if info.flags&ElementFlagsRest != 0 { - p.printTypeEx(t, ast.TypePrecedencePostfix) - p.print("[]") + p.print("?: ") + p.printType(p.c.removeMissingType(t, true)) } else { - p.printType(t) + p.print(": ") + if info.flags&ElementFlagsRest != 0 { + p.printTypeEx(t, ast.TypePrecedencePostfix) + p.print("[]") + } else { + p.printType(t) + } } } else { if info.flags&ElementFlagsOptional != 0 { - p.printTypeEx(t, ast.TypePrecedencePostfix) + p.printTypeEx(p.c.removeMissingType(t, true), ast.TypePrecedencePostfix) p.print("?") } else if info.flags&ElementFlagsRest != 0 { p.printTypeEx(t, ast.TypePrecedencePostfix) @@ -349,6 +395,15 @@ func (p *Printer) printTupleType(t *Type) { } func (p *Printer) printAnonymousType(t *Type) { + if t.symbol != nil && len(t.symbol.Name) != 0 { + if t.symbol.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsEnum|ast.SymbolFlagsValueModule) != 0 { + if t == p.c.getTypeOfSymbol(t.symbol) { + p.print("typeof ") + p.printQualifiedName(t.symbol) + return + } + } + } props := p.c.getPropertiesOfObjectType(t) callSignatures := p.c.getSignaturesOfType(t, SignatureKindCall) constructSignatures := p.c.getSignaturesOfType(t, SignatureKindConstruct) @@ -400,7 +455,7 @@ func (p *Printer) printAnonymousType(t *Type) { p.print("?") } p.print(": ") - p.printType(p.c.getTypeOfSymbol(prop)) + p.printType(p.c.getNonMissingTypeOfSymbol(prop)) p.print(";") hasMembers = true } @@ -418,23 +473,33 @@ func (p *Printer) printSignature(sig *Signature, returnSeparator string) { if tail { p.print(", ") } - p.printName(tp.symbol) + p.printTypeParameterAndConstraint(tp) tail = true } p.print(">") } p.print("(") var tail bool - for i, param := range sig.parameters { + if sig.thisParameter != nil { + p.print("this: ") + p.printType(p.c.getTypeOfSymbol(sig.thisParameter)) + tail = true + } + expandedParameters := p.c.GetExpandedParameters(sig) + // If the expanded parameter list had a variadic in a non-trailing position, don't expand it + parameters := core.IfElse(core.Some(expandedParameters, func(s *ast.Symbol) bool { + return s != expandedParameters[len(expandedParameters)-1] && s.CheckFlags&ast.CheckFlagsRestParameter != 0 + }), sig.parameters, expandedParameters) + for i, param := range parameters { if tail { p.print(", ") } - if sig.flags&SignatureFlagsHasRestParameter != 0 && i == len(sig.parameters)-1 { + if param.ValueDeclaration != nil && isRestParameter(param.ValueDeclaration) || param.CheckFlags&ast.CheckFlagsRestParameter != 0 { p.print("...") p.printName(param) } else { p.printName(param) - if i >= int(sig.minArgumentCount) { + if i >= p.c.getMinArgumentCountEx(sig, MinArgumentCountFlagsVoidIsNonOptional) { p.print("?") } } @@ -467,21 +532,33 @@ func (p *Printer) printTypePredicate(pred *TypePredicate) { } func (p *Printer) printTypeParameter(t *Type) { - if t.AsTypeParameter().isThisType { + switch { + case t.AsTypeParameter().isThisType: p.print("this") - } else if t.symbol != nil { + case p.extendsTypeDepth > 0 && isInferTypeParameter(t): + p.print("infer ") + p.printTypeParameterAndConstraint(t) + case t.symbol != nil: p.printName(t.symbol) - } else { + default: p.print("???") } } +func (p *Printer) printTypeParameterAndConstraint(t *Type) { + p.printName(t.symbol) + if constraint := p.c.getConstraintOfTypeParameter(t); constraint != nil { + p.print(" extends ") + p.printType(constraint) + } +} + func (p *Printer) printUnionType(t *Type) { switch { case t.flags&TypeFlagsBoolean != 0: p.print("boolean") case t.flags&TypeFlagsEnumLiteral != 0: - p.printName(t.symbol) + p.printQualifiedName(t.symbol) default: u := t.AsUnionType() if u.origin != nil { @@ -522,6 +599,18 @@ func (p *Printer) printIndexedAccessType(t *Type) { p.print("]") } +func (p *Printer) printConditionalType(t *Type) { + p.printType(t.AsConditionalType().checkType) + p.print(" extends ") + p.extendsTypeDepth++ + p.printType(t.AsConditionalType().extendsType) + p.extendsTypeDepth-- + p.print(" ? ") + p.printType(p.c.getTrueTypeFromConditionalType(t)) + p.print(" : ") + p.printType(p.c.getFalseTypeFromConditionalType(t)) +} + func (p *Printer) printMappedType(t *Type) { d := t.AsMappedType().declaration p.print("{ ") @@ -549,7 +638,7 @@ func (p *Printer) printMappedType(t *Type) { } p.print(": ") p.printType(p.c.getTemplateTypeFromMappedType(t)) - p.print(" }") + p.print("; }") } func (p *Printer) printSourceFileWithTypes(sourceFile *ast.SourceFile) { @@ -558,7 +647,7 @@ func (p *Printer) printSourceFileWithTypes(sourceFile *ast.SourceFile) { var typesPrinted bool lineStarts := scanner.GetLineStarts(sourceFile) printLinesBefore := func(node *ast.Node) { - line := scanner.ComputeLineOfPosition(lineStarts, scanner.SkipTrivia(sourceFile.Text, node.Pos())) + line := scanner.ComputeLineOfPosition(lineStarts, scanner.SkipTrivia(sourceFile.Text(), node.Pos())) var nextLineStart int if line+1 < len(lineStarts) { nextLineStart = int(lineStarts[line+1]) @@ -569,7 +658,7 @@ func (p *Printer) printSourceFileWithTypes(sourceFile *ast.SourceFile) { if typesPrinted { p.print("\n") } - p.print(sourceFile.Text[pos:nextLineStart]) + p.print(sourceFile.Text()[pos:nextLineStart]) pos = nextLineStart typesPrinted = false } @@ -592,7 +681,7 @@ func (p *Printer) printSourceFileWithTypes(sourceFile *ast.SourceFile) { return node.ForEachChild(visit) } visit(sourceFile.AsNode()) - p.print(sourceFile.Text[pos:sourceFile.End()]) + p.print(sourceFile.Text()[pos:sourceFile.End()]) } func (c *Checker) getTextAndTypeOfNode(node *ast.Node) (string, *Type, bool) { @@ -647,3 +736,7 @@ func (c *Checker) formatUnionTypes(types []*Type) []*Type { } return result } + +func isInferTypeParameter(t *Type) bool { + return t.flags&TypeFlagsTypeParameter != 0 && t.symbol != nil && core.Some(t.symbol.Declarations, func(d *ast.Node) bool { return ast.IsInferTypeNode(d.Parent) }) +} diff --git a/internal/checker/relater.go b/internal/checker/relater.go index 3e1878edea..907307ed7b 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -7,8 +7,8 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/jsnum" "github.com/microsoft/typescript-go/internal/scanner" ) @@ -256,7 +256,7 @@ func (c *Checker) isSimpleTypeRelatedTo(source *Type, target *Type, relation *Re if s&TypeFlagsNull != 0 && (!c.strictNullChecks && t&TypeFlagsUnionOrIntersection == 0 || t&TypeFlagsNull != 0) { return true } - if s&TypeFlagsObject != 0 && t&TypeFlagsNonPrimitive != 0 && !(relation == c.strictSubtypeRelation && c.isEmptyAnonymousObjectType(source) && source.objectFlags&ObjectFlagsFreshLiteral == 0) { + if s&TypeFlagsObject != 0 && t&TypeFlagsNonPrimitive != 0 && !(relation == c.strictSubtypeRelation && c.IsEmptyAnonymousObjectType(source) && source.objectFlags&ObjectFlagsFreshLiteral == 0) { return true } if relation == c.assignableRelation || relation == c.comparableRelation { @@ -304,8 +304,8 @@ func (c *Checker) isEnumTypeRelatedTo(source *ast.Symbol, target *ast.Symbol, er c.enumRelation[key] = RelationComparisonResultFailed return false } - sourceValue := c.getEnumMemberValue(ast.GetDeclarationOfKind(sourceProperty, ast.KindEnumMember)).value - targetValue := c.getEnumMemberValue(ast.GetDeclarationOfKind(targetProperty, ast.KindEnumMember)).value + sourceValue := c.getEnumMemberValue(ast.GetDeclarationOfKind(sourceProperty, ast.KindEnumMember)).Value + targetValue := c.getEnumMemberValue(ast.GetDeclarationOfKind(targetProperty, ast.KindEnumMember)).Value if sourceValue != targetValue { // If we have 2 enums with *known* values that differ, they are incompatible. if sourceValue != nil && targetValue != nil { @@ -365,10 +365,7 @@ func (c *Checker) checkTypeRelatedToEx( headMessage *diagnostics.Message, diagnosticOutput *[]*ast.Diagnostic, ) bool { - relaterCount := len(c.relaters) - c.relaters = slices.Grow(c.relaters, 1)[:relaterCount+1] - r := &c.relaters[relaterCount] - r.c = c + r := c.getRelater() r.relation = relation r.errorNode = errorNode r.relationCount = (16_000_000 - relation.size()) / 8 @@ -396,14 +393,7 @@ func (c *Checker) checkTypeRelatedToEx( } c.reportDiagnostic(createDiagnosticChainFromErrorChain(r.errorChain, r.errorNode, r.relatedInfo), diagnosticOutput) } - c.relaters = c.relaters[:relaterCount] - r.maybeKeysSet.Clear() - *r = Relater{ - maybeKeys: r.maybeKeys[:0], - maybeKeysSet: r.maybeKeysSet, - sourceStack: r.sourceStack[:0], - targetStack: r.targetStack[:0], - } + c.putRelater(r) return result != TernaryFalse } @@ -472,8 +462,8 @@ func (c *Checker) elaborateError(node *ast.Node, source *Type, target *Type, rel return c.elaborateArrayLiteral(node, source, target, relation, diagnosticOutput) case ast.KindArrowFunction: return c.elaborateArrowFunction(node, source, target, relation, diagnosticOutput) - // case ast.KindJsxAttributes: - // return c.elaborateJsxComponents(node.AsJsxAttributes(), source, target, relation, containingMessageChain, errorOutputContainer) + case ast.KindJsxAttributes: + return c.elaborateJsxComponents(node, source, target, relation, diagnosticOutput) } return false } @@ -1421,7 +1411,7 @@ func (c *Checker) getTypeParameterModifiers(tp *Type) ast.ModifierFlags { var flags ast.ModifierFlags if tp.symbol != nil { for _, d := range tp.symbol.Declarations { - flags |= getEffectiveModifierFlags(d) + flags |= d.ModifierFlags() } } return flags & (ast.ModifierFlagsIn | ast.ModifierFlagsOut | ast.ModifierFlagsConst) @@ -1543,10 +1533,10 @@ func (c *Checker) compareSignaturesRelated(source *Signature, target *Signature, var sourceSig *Signature var targetSig *Signature if checkMode&SignatureCheckModeCallback == 0 && !c.isInstantiatedGenericParameter(source, i) { - sourceSig = c.getSingleCallSignature(c.getNonNullableType(sourceType)) + sourceSig = c.getSingleCallSignature(c.GetNonNullableType(sourceType)) } if checkMode&SignatureCheckModeCallback == 0 && !c.isInstantiatedGenericParameter(target, i) { - targetSig = c.getSingleCallSignature(c.getNonNullableType(targetType)) + targetSig = c.getSingleCallSignature(c.GetNonNullableType(targetType)) } callbacks := sourceSig != nil && targetSig != nil && c.getTypePredicateOfSignature(sourceSig) == nil && c.getTypePredicateOfSignature(targetSig) == nil && c.getTypeFacts(sourceType, TypeFactsIsUndefinedOrNull) == c.getTypeFacts(targetType, TypeFactsIsUndefinedOrNull) @@ -1937,54 +1927,56 @@ func (c *Checker) getTupleElementLabel(elementInfo TupleElementInfo, restSymbol } func (c *Checker) getTupleElementLabelFromBindingElement(node *ast.Node, index int, elementFlags ElementFlags) string { - switch node.Name().Kind { - case ast.KindIdentifier: - name := node.Name().Text() - if hasDotDotDotToken(node) { + if node.Name() != nil { + switch node.Name().Kind { + case ast.KindIdentifier: + name := node.Name().Text() + if hasDotDotDotToken(node) { + // given + // (...[x, y, ...z]: [number, number, ...number[]]) => ... + // this produces + // (x: number, y: number, ...z: number[]) => ... + // which preserves rest elements of 'z' + + // given + // (...[x, y, ...z]: [number, number, ...[...number[], number]]) => ... + // this produces + // (x: number, y: number, ...z: number[], z_1: number) => ... + // which preserves rest elements of z but gives distinct numbers to fixed elements of 'z' + if elementFlags&ElementFlagsVariable != 0 { + return name + } + return name + "_" + strconv.Itoa(index) + } // given - // (...[x, y, ...z]: [number, number, ...number[]]) => ... + // (...[x]: [number]) => ... // this produces - // (x: number, y: number, ...z: number[]) => ... - // which preserves rest elements of 'z' + // (x: number) => ... + // which preserves fixed elements of 'x' // given - // (...[x, y, ...z]: [number, number, ...[...number[], number]]) => ... + // (...[x]: ...number[]) => ... // this produces - // (x: number, y: number, ...z: number[], z_1: number) => ... - // which preserves rest elements of z but gives distinct numbers to fixed elements of 'z' - if elementFlags&ElementFlagsVariable != 0 { + // (x_0: number) => ... + // which which numbers fixed elements of 'x' whose tuple element type is variable + if elementFlags&ElementFlagsFixed != 0 { return name } - return name + "_" + strconv.Itoa(index) - } - // given - // (...[x]: [number]) => ... - // this produces - // (x: number) => ... - // which preserves fixed elements of 'x' - - // given - // (...[x]: ...number[]) => ... - // this produces - // (x_0: number) => ... - // which which numbers fixed elements of 'x' whose tuple element type is variable - if elementFlags&ElementFlagsFixed != 0 { - return name - } - return name + "_n" - case ast.KindArrayBindingPattern: - if hasDotDotDotToken(node) { - elements := node.Name().AsBindingPattern().Elements.Nodes - lastElement := core.LastOrNil(elements) - lastElementIsBindingElementRest := lastElement != nil && ast.IsBindingElement(lastElement) && hasDotDotDotToken(lastElement) - elementCount := len(elements) - core.IfElse(lastElementIsBindingElementRest, 1, 0) - if index < elementCount { - element := elements[index] - if ast.IsBindingElement(element) { - return c.getTupleElementLabelFromBindingElement(element, index, elementFlags) + return name + "_n" + case ast.KindArrayBindingPattern: + if hasDotDotDotToken(node) { + elements := node.Name().AsBindingPattern().Elements.Nodes + lastElement := core.LastOrNil(elements) + lastElementIsBindingElementRest := lastElement != nil && ast.IsBindingElement(lastElement) && hasDotDotDotToken(lastElement) + elementCount := len(elements) - core.IfElse(lastElementIsBindingElementRest, 1, 0) + if index < elementCount { + element := elements[index] + if ast.IsBindingElement(element) { + return c.getTupleElementLabelFromBindingElement(element, index, elementFlags) + } + } else if lastElementIsBindingElementRest { + return c.getTupleElementLabelFromBindingElement(lastElement, index-elementCount, elementFlags) } - } else if lastElementIsBindingElementRest { - return c.getTupleElementLabelFromBindingElement(lastElement, index-elementCount, elementFlags) } } } @@ -2274,7 +2266,7 @@ func (c *Checker) getEffectiveConstraintOfIntersection(types []*Type, targetIsUn constraints = append(constraints, t) } } - } else if t.flags&TypeFlagsDisjointDomains != 0 || c.isEmptyAnonymousObjectType(t) { + } else if t.flags&TypeFlagsDisjointDomains != 0 || c.IsEmptyAnonymousObjectType(t) { hasDisjointDomainType = true } } @@ -2285,7 +2277,7 @@ func (c *Checker) getEffectiveConstraintOfIntersection(types []*Type, targetIsUn // We add any types belong to one of the disjoint domains because they might cause the final // intersection operation to reduce the union constraints. for _, t := range types { - if t.flags&TypeFlagsDisjointDomains != 0 || c.isEmptyAnonymousObjectType(t) { + if t.flags&TypeFlagsDisjointDomains != 0 || c.IsEmptyAnonymousObjectType(t) { constraints = append(constraints, t) } } @@ -2521,6 +2513,29 @@ type Relater struct { expandingFlags ExpandingFlags overflow bool relationCount int + next *Relater +} + +func (c *Checker) getRelater() *Relater { + r := c.freeRelater + if r == nil { + r = &Relater{c: c} + } + c.freeRelater = r.next + return r +} + +func (c *Checker) putRelater(r *Relater) { + r.maybeKeysSet.Clear() + *r = Relater{ + c: c, + maybeKeys: r.maybeKeys[:0], + maybeKeysSet: r.maybeKeysSet, + sourceStack: r.sourceStack[:0], + targetStack: r.targetStack[:0], + next: c.freeRelater, + } + c.freeRelater = r } func (r *Relater) isRelatedToSimple(source *Type, target *Type) Ternary { @@ -2679,27 +2694,20 @@ func (r *Relater) hasExcessProperties(source *Type, target *Type, reportErrors b panic("No errorNode in hasExcessProperties") } if ast.IsJsxAttributes(r.errorNode) || isJsxOpeningLikeElement(r.errorNode) || isJsxOpeningLikeElement(r.errorNode.Parent) { - // !!! - // // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. - // // However, using an object-literal error message will be very confusing to the users so we give different a message. - // if prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && ast.GetSourceFileOfNode(errorNode) == ast.GetSourceFileOfNode(prop.valueDeclaration.name) { - // // Note that extraneous children (as in `<NoChild>extra</NoChild>`) don't pass this check, - // // since `children` is a Kind.PropertySignature instead of a Kind.JsxAttribute. - // errorNode = prop.valueDeclaration.name - // } - // propName := c.symbolToString(prop) - // suggestionSymbol := c.getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget) - // var suggestion *string - // if suggestionSymbol { - // suggestion = c.symbolToString(suggestionSymbol) - // } else { - // suggestion = nil - // } - // if suggestion { - // reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, c.TypeToString(errorTarget), suggestion) - // } else { - // reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, c.TypeToString(errorTarget)) - // } + // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. + // However, using an object-literal error message will be very confusing to the users so we give different a message. + if prop.ValueDeclaration != nil && ast.IsJsxAttribute(prop.ValueDeclaration) && ast.GetSourceFileOfNode(r.errorNode) == ast.GetSourceFileOfNode(prop.ValueDeclaration.Name()) { + // Note that extraneous children (as in `<NoChild>extra</NoChild>`) don't pass this check, + // since `children` is a Kind.PropertySignature instead of a Kind.JsxAttribute. + r.errorNode = prop.ValueDeclaration.Name() + } + propName := r.c.symbolToString(prop) + suggestionSymbol := r.c.getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget) + if suggestionSymbol != nil { + r.reportError(diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, r.c.TypeToString(errorTarget), r.c.symbolToString(suggestionSymbol)) + } else { + r.reportError(diagnostics.Property_0_does_not_exist_on_type_1, propName, r.c.TypeToString(errorTarget)) + } } else { // use the property's value declaration if the property is assigned inside the literal itself var objectLiteralDeclaration *ast.Node @@ -3753,7 +3761,7 @@ func (r *Relater) structuredTypeRelatedToWorker(source *Type, target *Type, repo // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. variances := r.c.getVariances(source.Target()) - // We return Ternary.Maybe for a recursive invocation of getVariances (signalled by emptyArray). This + // We return Ternary.Maybe for a recursive invocation of getVariances (signaled by emptyArray). This // effectively means we measure variance only from type parameter occurrences that aren't nested in // recursive instantiations of the generic type. if len(variances) == 0 { @@ -3847,7 +3855,7 @@ func (r *Relater) typeArgumentsRelatedTo(sources []*Type, targets []*Type, varia var related Ternary if varianceFlags&VarianceFlagsUnmeasurable != 0 { // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. - // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by + // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tainted by // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) if r.relation == r.c.identityRelation { related = r.isRelatedTo(s, t, RecursionFlagsBoth, false /*reportErrors*/) @@ -3861,7 +3869,7 @@ func (r *Relater) typeArgumentsRelatedTo(sources []*Type, targets []*Type, varia } else if variance == VarianceFlagsBivariant { // In the bivariant case we first compare contravariantly without reporting // errors. Then, if that doesn't succeed, we compare covariantly with error - // reporting. Thus, error elaboration will be based on the the covariant check, + // reporting. Thus, error elaboration will be based on the covariant check, // which is generally easier to reason about. related = r.isRelatedTo(t, s, RecursionFlagsBoth, false /*reportErrors*/) if related == TernaryFalse { @@ -4265,18 +4273,20 @@ func (r *Relater) reportUnmatchedProperty(source *Type, target *Type, unmatchedP } props := r.c.getUnmatchedProperties(source, target, requireOptionalProperties, false /*matchDiscriminantProperties*/) if len(props) == 1 { + sourceType, targetType := r.c.getTypeNamesForErrorDisplay(source, target) propName := r.c.symbolToString(unmatchedProperty) - r.reportError(diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, r.c.TypeToString(source), r.c.TypeToString(target)) + r.reportError(diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, sourceType, targetType) if len(unmatchedProperty.Declarations) != 0 { r.relatedInfo = append(r.relatedInfo, createDiagnosticForNode(unmatchedProperty.Declarations[0], diagnostics.X_0_is_declared_here, propName)) } } else if r.tryElaborateArrayLikeErrors(source, target, false /*reportErrors*/) { + sourceType, targetType := r.c.getTypeNamesForErrorDisplay(source, target) if len(props) > 5 { propNames := strings.Join(core.Map(props[:4], r.c.symbolToString), ", ") - r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, r.c.TypeToString(source), r.c.TypeToString(target), propNames, len(props)-4) + r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, sourceType, targetType, propNames, len(props)-4) } else { propNames := strings.Join(core.Map(props, r.c.symbolToString), ", ") - r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, r.c.TypeToString(source), r.c.TypeToString(target), propNames) + r.reportError(diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, sourceType, targetType, propNames) } } } @@ -4420,8 +4430,8 @@ func (r *Relater) constructorVisibilitiesAreCompatible(sourceSignature *Signatur if sourceSignature.declaration == nil || targetSignature.declaration == nil { return true } - sourceAccessibility := getEffectiveModifierFlags(sourceSignature.declaration) & ast.ModifierFlagsNonPublicAccessibilityModifier - targetAccessibility := getEffectiveModifierFlags(targetSignature.declaration) & ast.ModifierFlagsNonPublicAccessibilityModifier + sourceAccessibility := sourceSignature.declaration.ModifierFlags() & ast.ModifierFlagsNonPublicAccessibilityModifier + targetAccessibility := targetSignature.declaration.ModifierFlags() & ast.ModifierFlagsNonPublicAccessibilityModifier // A public, protected and private signature is assignable to a private signature. if targetAccessibility == ast.ModifierFlagsPrivate { return true @@ -4621,14 +4631,12 @@ func (r *Relater) reportErrorResults(originalSource *Type, originalTarget *Type, case source.symbol != nil && source.flags&TypeFlagsObject != 0 && r.c.globalObjectType == source: r.reportError(diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead) case source.objectFlags&ObjectFlagsJsxAttributes != 0 && target.flags&TypeFlagsIntersection != 0: - // !!! - // targetTypes := target.Types() - // intrinsicAttributes := c.getJsxType(JsxNames.IntrinsicAttributes, errorNode) - // intrinsicClassAttributes := c.getJsxType(JsxNames.IntrinsicClassAttributes, errorNode) - // if !c.isErrorType(intrinsicAttributes) && !c.isErrorType(intrinsicClassAttributes) && (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes)) { - // // do not report top error - // return - // } + targetTypes := target.Types() + intrinsicAttributes := r.c.getJsxType(JsxNames.IntrinsicAttributes, r.errorNode) + intrinsicClassAttributes := r.c.getJsxType(JsxNames.IntrinsicClassAttributes, r.errorNode) + if !r.c.isErrorType(intrinsicAttributes) && !r.c.isErrorType(intrinsicClassAttributes) && (slices.Contains(targetTypes, intrinsicAttributes) || slices.Contains(targetTypes, intrinsicClassAttributes)) { + return + } case originalTarget.flags&TypeFlagsIntersection != 0 && originalTarget.objectFlags&ObjectFlagsIsNeverIntersection != 0: message := diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents prop := core.Find(r.c.getPropertiesOfUnionOrIntersectionType(originalTarget), r.c.isDiscriminantWithNeverType) @@ -4677,15 +4685,26 @@ func (r *Relater) reportRelationError(message *diagnostics.Message, source *Type case constraint != nil && r.c.isTypeAssignableTo(source, constraint): r.reportError(diagnostics.X_0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, sourceType, targetType, r.c.TypeToString(constraint)) default: + r.errorChain = nil // Only report this error once r.reportError(diagnostics.X_0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, targetType, generalizedSourceType) } } if message == nil { - if r.relation == r.c.comparableRelation { + switch { + case r.relation == r.c.comparableRelation: message = diagnostics.Type_0_is_not_comparable_to_type_1 - } else if sourceType == targetType { + case sourceType == targetType: message = diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated - } else { + case r.c.exactOptionalPropertyTypes && len(r.c.getExactOptionalUnassignableProperties(source, target)) != 0: + message = diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + default: + if source.flags&TypeFlagsStringLiteral != 0 && target.flags&TypeFlagsUnion != 0 { + suggestedType := r.c.getSuggestedTypeForNonexistentStringLiteralType(source, target) + if suggestedType != nil { + r.reportError(diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, r.c.TypeToString(suggestedType)) + return + } + } message = diagnostics.Type_0_is_not_assignable_to_type_1 } } @@ -4755,12 +4774,7 @@ func (r *Relater) reportError(message *diagnostics.Message, args ...any) { diagnostics.The_types_returned_by_0_are_incompatible_between_these_types: head := getPropertyNameArg(args[0]) tail := getPropertyNameArg(r.errorChain.next.args[0]) - var arg string - if len(tail) != 0 && tail[0] == '[' { - arg = head + tail - } else { - arg = head + "." + tail - } + arg := addToDottedName(head, tail) r.errorChain = r.errorChain.next.next if message == diagnostics.Types_of_property_0_are_incompatible { message = diagnostics.The_types_of_0_are_incompatible_between_these_types @@ -4772,6 +4786,28 @@ func (r *Relater) reportError(message *diagnostics.Message, args ...any) { r.errorChain = &ErrorChain{next: r.errorChain, message: message, args: args} } +func addToDottedName(head string, tail string) string { + if strings.HasPrefix(head, "new ") { + head = "(" + head + ")" + } + pos := 0 + for { + if strings.HasPrefix(tail[pos:], "(") { + pos++ + } else if strings.HasPrefix(tail[pos:], "new ") { + pos += 4 + } else { + break + } + } + prefix := tail[:pos] + suffix := tail[pos:] + if strings.HasPrefix(suffix, "[") { + return prefix + head + suffix + } + return prefix + head + "." + suffix +} + func (r *Relater) getChainMessage(index int) *diagnostics.Message { e := r.errorChain for { @@ -4849,10 +4885,10 @@ func (c *Checker) isTypeDerivedFrom(source *Type, target *Type) bool { constraint = c.unknownType } return c.isTypeDerivedFrom(constraint, target) - case c.isEmptyAnonymousObjectType(target): + case c.IsEmptyAnonymousObjectType(target): return source.flags&(TypeFlagsObject|TypeFlagsNonPrimitive) != 0 case target == c.globalObjectType: - return source.flags&(TypeFlagsObject|TypeFlagsNonPrimitive) != 0 && !c.isEmptyAnonymousObjectType(source) + return source.flags&(TypeFlagsObject|TypeFlagsNonPrimitive) != 0 && !c.IsEmptyAnonymousObjectType(source) case target == c.globalFunctionType: return source.flags&TypeFlagsObject != 0 && c.isFunctionObjectType(source) default: diff --git a/internal/checker/services.go b/internal/checker/services.go new file mode 100644 index 0000000000..9b5863d2ae --- /dev/null +++ b/internal/checker/services.go @@ -0,0 +1,400 @@ +package checker + +import ( + "maps" + "slices" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/core" +) + +func (c *Checker) GetSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol { + return c.getSymbolsInScope(location, meaning) +} + +func (c *Checker) getSymbolsInScope(location *ast.Node, meaning ast.SymbolFlags) []*ast.Symbol { + if location.Flags&ast.NodeFlagsInWithStatement != 0 { + // We cannot answer semantic questions within a with block, do not proceed any further + return nil + } + + symbols := createSymbolTable(nil) + isStaticSymbol := false + + // Copy the given symbol into symbol tables if the symbol has the given meaning + // and it doesn't already exists in the symbol table. + copySymbol := func(symbol *ast.Symbol, meaning ast.SymbolFlags) { + if GetCombinedLocalAndExportSymbolFlags(symbol)&meaning != 0 { + id := symbol.Name + // We will copy all symbol regardless of its reserved name because + // symbolsToArray will check whether the key is a reserved name and + // it will not copy symbol with reserved name to the array + if _, ok := symbols[id]; !ok { + symbols[id] = symbol + } + } + } + + copySymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) { + if meaning != 0 { + for _, symbol := range source { + copySymbol(symbol, meaning) + } + } + } + + copyLocallyVisibleExportSymbols := func(source ast.SymbolTable, meaning ast.SymbolFlags) { + if meaning != 0 { + for _, symbol := range source { + // Similar condition as in `resolveNameHelper` + if ast.GetDeclarationOfKind(symbol, ast.KindExportSpecifier) == nil && + ast.GetDeclarationOfKind(symbol, ast.KindNamespaceExport) == nil && + symbol.Name != ast.InternalSymbolNameDefault { + copySymbol(symbol, meaning) + } + } + } + } + + populateSymbols := func() { + for location != nil { + if canHaveLocals(location) && location.Locals() != nil && !ast.IsGlobalSourceFile(location) { + copySymbols(location.Locals(), meaning) + } + + switch location.Kind { + case ast.KindSourceFile: + if !ast.IsExternalModule(location.AsSourceFile()) { + break + } + fallthrough + case ast.KindModuleDeclaration: + copyLocallyVisibleExportSymbols(c.getSymbolOfDeclaration(location).Exports, meaning&ast.SymbolFlagsModuleMember) + case ast.KindEnumDeclaration: + copySymbols(c.getSymbolOfDeclaration(location).Exports, meaning&ast.SymbolFlagsEnumMember) + case ast.KindClassExpression: + className := location.AsClassExpression().Name() + if className != nil { + copySymbol(location.Symbol(), meaning) + } + // this fall-through is necessary because we would like to handle + // type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration. + fallthrough + case ast.KindClassDeclaration, ast.KindInterfaceDeclaration: + // If we didn't come from static member of class or interface, + // add the type parameters into the symbol table + // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. + // Note: that the memberFlags come from previous iteration. + if !isStaticSymbol { + copySymbols(c.getMembersOfSymbol(c.getSymbolOfDeclaration(location)), meaning&ast.SymbolFlagsType) + } + case ast.KindFunctionExpression: + funcName := location.Name() + if funcName != nil { + copySymbol(location.Symbol(), meaning) + } + } + + if introducesArgumentsExoticObject(location) { + copySymbol(c.argumentsSymbol, meaning) + } + + isStaticSymbol = ast.IsStatic(location) + location = location.Parent + } + + copySymbols(c.globals, meaning) + } + + populateSymbols() + + delete(symbols, ast.InternalSymbolNameThis) // Not a symbol, a keyword + return symbolsToArray(symbols) +} + +func (c *Checker) GetAliasedSymbol(symbol *ast.Symbol) *ast.Symbol { + return c.resolveAlias(symbol) +} + +func (c *Checker) GetExportsOfModule(symbol *ast.Symbol) []*ast.Symbol { + return symbolsToArray(c.getExportsOfModule(symbol)) +} + +func (c *Checker) IsValidPropertyAccess(node *ast.Node, propertyName string) bool { + return c.isValidPropertyAccess(node, propertyName) +} + +func (c *Checker) isValidPropertyAccess(node *ast.Node, propertyName string) bool { + switch node.Kind { + case ast.KindPropertyAccessExpression: + return c.isValidPropertyAccessWithType(node, node.Expression().Kind == ast.KindSuperKeyword, propertyName, c.getWidenedType(c.checkExpression(node.Expression()))) + case ast.KindQualifiedName: + return c.isValidPropertyAccessWithType(node, false /*isSuper*/, propertyName, c.getWidenedType(c.checkExpression(node.AsQualifiedName().Left))) + case ast.KindImportType: + return c.isValidPropertyAccessWithType(node, false /*isSuper*/, propertyName, c.getTypeFromTypeNode(node)) + } + panic("Unexpected node kind in isValidPropertyAccess: " + node.Kind.String()) +} + +func (c *Checker) isValidPropertyAccessWithType(node *ast.Node, isSuper bool, propertyName string, t *Type) bool { + // Short-circuiting for improved performance. + if IsTypeAny(t) { + return true + } + + prop := c.getPropertyOfType(t, propertyName) + return prop != nil && c.isPropertyAccessible(node, isSuper, false /*isWrite*/, t, prop) +} + +// Checks if an existing property access is valid for completions purposes. +// node: a property access-like node where we want to check if we can access a property. +// This node does not need to be an access of the property we are checking. +// e.g. in completions, this node will often be an incomplete property access node, as in `foo.`. +// Besides providing a location (i.e. scope) used to check property accessibility, we use this node for +// computing whether this is a `super` property access. +// type: the type whose property we are checking. +// property: the accessed property's symbol. +func (c *Checker) IsValidPropertyAccessForCompletions(node *ast.Node, t *Type, property *ast.Symbol) bool { + return c.isPropertyAccessible( + node, + node.Kind == ast.KindPropertyAccessExpression && node.Expression().Kind == ast.KindSuperKeyword, + false, /*isWrite*/ + t, + property, + ) + // Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context. +} + +func (c *Checker) GetAllPossiblePropertiesOfTypes(types []*Type) []*ast.Symbol { + unionType := c.getUnionType(types) + if unionType.flags&TypeFlagsUnion == 0 { + return c.getAugmentedPropertiesOfType(unionType) + } + + props := createSymbolTable(nil) + for _, memberType := range types { + augmentedProps := c.getAugmentedPropertiesOfType(memberType) + for _, p := range augmentedProps { + if _, ok := props[p.Name]; !ok { + prop := c.createUnionOrIntersectionProperty(unionType, p.Name, false /*skipObjectFunctionPropertyAugment*/) + // May be undefined if the property is private + if prop != nil { + props[p.Name] = prop + } + } + } + } + return slices.Collect(maps.Values(props)) +} + +func (c *Checker) IsUnknownSymbol(symbol *ast.Symbol) bool { + return symbol == c.unknownSymbol +} + +func (c *Checker) IsUndefinedSymbol(symbol *ast.Symbol) bool { + return symbol == c.undefinedSymbol +} + +func (c *Checker) IsArgumentsSymbol(symbol *ast.Symbol) bool { + return symbol == c.argumentsSymbol +} + +// Originally from services.ts +func (c *Checker) GetNonOptionalType(t *Type) *Type { + return c.removeOptionalTypeMarker(t) +} + +func (c *Checker) GetStringIndexType(t *Type) *Type { + return c.getIndexTypeOfType(t, c.stringType) +} + +func (c *Checker) GetNumberIndexType(t *Type) *Type { + return c.getIndexTypeOfType(t, c.numberType) +} + +func (c *Checker) GetCallSignatures(t *Type) []*Signature { + return c.getSignaturesOfType(t, SignatureKindCall) +} + +func (c *Checker) GetConstructSignatures(t *Type) []*Signature { + return c.getSignaturesOfType(t, SignatureKindConstruct) +} + +func (c *Checker) GetApparentProperties(t *Type) []*ast.Symbol { + return c.getAugmentedPropertiesOfType(t) +} + +func (c *Checker) getAugmentedPropertiesOfType(t *Type) []*ast.Symbol { + t = c.getApparentType(t) + propsByName := createSymbolTable(c.getPropertiesOfType(t)) + var functionType *Type + if len(c.getSignaturesOfType(t, SignatureKindCall)) > 0 { + functionType = c.globalCallableFunctionType + } else if len(c.getSignaturesOfType(t, SignatureKindConstruct)) > 0 { + functionType = c.globalNewableFunctionType + } + + if functionType != nil { + for _, p := range c.getPropertiesOfType(functionType) { + if _, ok := propsByName[p.Name]; !ok { + propsByName[p.Name] = p + } + } + } + return c.getNamedMembers(propsByName) +} + +func (c *Checker) TryGetMemberInModuleExportsAndProperties(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol { + symbol := c.TryGetMemberInModuleExports(memberName, moduleSymbol) + if symbol != nil { + return symbol + } + + exportEquals := c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/) + if exportEquals == moduleSymbol { + return nil + } + + t := c.getTypeOfSymbol(exportEquals) + if c.shouldTreatPropertiesOfExternalModuleAsExports(t) { + return c.getPropertyOfType(t, memberName) + } + return nil +} + +func (c *Checker) TryGetMemberInModuleExports(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol { + symbolTable := c.getExportsOfModule(moduleSymbol) + return symbolTable[memberName] +} + +func (c *Checker) shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType *Type) bool { + return resolvedExternalModuleType.flags&TypeFlagsPrimitive == 0 || + resolvedExternalModuleType.objectFlags&ObjectFlagsClass != 0 || + // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path. + c.isArrayType(resolvedExternalModuleType) || + isTupleType(resolvedExternalModuleType) +} + +func (c *Checker) GetContextualType(node *ast.Expression, contextFlags ContextFlags) *Type { + if contextFlags&ContextFlagsCompletions != 0 { + return runWithInferenceBlockedFromSourceNode(c, node, func() *Type { return c.getContextualType(node, contextFlags) }) + } + return c.getContextualType(node, contextFlags) +} + +func runWithInferenceBlockedFromSourceNode[T any](c *Checker, node *ast.Node, fn func() T) T { + containingCall := ast.FindAncestor(node, ast.IsCallLikeExpression) + if containingCall != nil { + toMarkSkip := node + for { + c.skipDirectInferenceNodes.Add(toMarkSkip) + toMarkSkip = toMarkSkip.Parent + if toMarkSkip == nil || toMarkSkip == containingCall { + break + } + } + } + + c.isInferencePartiallyBlocked = true + result := runWithoutResolvedSignatureCaching(c, node, fn) + c.isInferencePartiallyBlocked = false + + c.skipDirectInferenceNodes.Clear() + return result +} + +func runWithoutResolvedSignatureCaching[T any](c *Checker, node *ast.Node, fn func() T) T { + ancestorNode := ast.FindAncestor(node, func(n *ast.Node) bool { + return ast.IsCallLikeOrFunctionLikeExpression(n) + }) + if ancestorNode != nil { + cachedResolvedSignatures := make(map[*SignatureLinks]*Signature) + cachedTypes := make(map[*ValueSymbolLinks]*Type) + for ancestorNode != nil { + signatureLinks := c.signatureLinks.Get(ancestorNode) + cachedResolvedSignatures[signatureLinks] = signatureLinks.resolvedSignature + signatureLinks.resolvedSignature = nil + if ast.IsFunctionExpressionOrArrowFunction(ancestorNode) { + symbolLinks := c.valueSymbolLinks.Get(c.getSymbolOfDeclaration(ancestorNode)) + resolvedType := symbolLinks.resolvedType + cachedTypes[symbolLinks] = resolvedType + symbolLinks.resolvedType = nil + } + ancestorNode = ast.FindAncestor(ancestorNode.Parent, ast.IsCallLikeOrFunctionLikeExpression) + } + result := fn() + for signatureLinks, resolvedSignature := range cachedResolvedSignatures { + signatureLinks.resolvedSignature = resolvedSignature + } + for symbolLinks, resolvedType := range cachedTypes { + symbolLinks.resolvedType = resolvedType + } + return result + } + return fn() +} + +func (c *Checker) GetRootSymbols(symbol *ast.Symbol) []*ast.Symbol { + roots := c.getImmediateRootSymbols(symbol) + if roots != nil { + var result []*ast.Symbol + for _, root := range roots { + result = append(result, c.GetRootSymbols(root)...) + } + } + return []*ast.Symbol{symbol} +} + +func (c *Checker) getImmediateRootSymbols(symbol *ast.Symbol) []*ast.Symbol { + if symbol.CheckFlags&ast.CheckFlagsSynthetic != 0 { + return core.MapNonNil( + c.valueSymbolLinks.Get(symbol).containingType.Types(), + func(t *Type) *ast.Symbol { + return c.getPropertyOfType(t, symbol.Name) + }) + } else if symbol.Flags&ast.SymbolFlagsTransient != 0 { + if c.spreadLinks.Has(symbol) { + leftSpread := c.spreadLinks.Get(symbol).leftSpread + rightSpread := c.spreadLinks.Get(symbol).rightSpread + if leftSpread != nil { + return []*ast.Symbol{leftSpread, rightSpread} + } + } + if c.mappedSymbolLinks.Has(symbol) { + syntheticOrigin := c.mappedSymbolLinks.Get(symbol).syntheticOrigin + if syntheticOrigin != nil { + return []*ast.Symbol{syntheticOrigin} + } + } + target := c.tryGetTarget(symbol) + if target != nil { + return []*ast.Symbol{target} + } + return nil + } + + return nil +} + +func (c *Checker) tryGetTarget(symbol *ast.Symbol) *ast.Symbol { + var target *ast.Symbol + next := symbol + for { + if c.valueSymbolLinks.Has(next) { + next = c.valueSymbolLinks.Get(next).target + } else if c.exportTypeLinks.Has(next) { + next = c.exportTypeLinks.Get(next).target + } else { + next = nil + } + if next == nil { + break + } + target = next + } + return target +} + +func (c *Checker) GetExportSymbolOfSymbol(symbol *ast.Symbol) *ast.Symbol { + return c.getMergedSymbol(core.IfElse(symbol.ExportSymbol != nil, symbol.ExportSymbol, symbol)) +} diff --git a/internal/checker/types.go b/internal/checker/types.go index 77be679eab..767abf2438 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -6,6 +6,7 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/evaluator" ) //go:generate go tool golang.org/x/tools/cmd/stringer -type=SignatureKind -output=stringer_generated.go @@ -125,7 +126,6 @@ type AliasSymbolLinks struct { type ModuleSymbolLinks struct { resolvedExports ast.SymbolTable // Resolved exports of module or combined early- and late-bound static members of a class. - cjsExportMerged *ast.Symbol // Version of the symbol with all non export= exports merged with the export= target typeOnlyExportStarMap map[string]*ast.Node // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration exportsChecked bool } @@ -319,16 +319,19 @@ type NodeLinks struct { hasReportedStatementInAmbientContext bool // Cache boolean if we report statements in ambient context } +type SymbolNodeLinks struct { + resolvedSymbol *ast.Symbol // Resolved symbol associated with node +} + type TypeNodeLinks struct { - resolvedType *Type // Cached type of type node - resolvedSymbol *ast.Symbol // Cached name resolution result - outerTypeParameters []*Type // Outer type parameters of anonymous object type + resolvedType *Type // Resolved type associated with node + outerTypeParameters []*Type // Outer type parameters of anonymous object type } // Links for enum members type EnumMemberLinks struct { - value EvaluatorResult // Constant value of enum member + value evaluator.Result // Constant value of enum member } // Links for assertion expressions @@ -340,9 +343,13 @@ type AssertionLinks struct { // SourceFile links type SourceFileLinks struct { - typeChecked bool - deferredNodes collections.OrderedSet[*ast.Node] - identifierCheckNodes []*ast.Node + typeChecked bool + deferredNodes collections.OrderedSet[*ast.Node] + identifierCheckNodes []*ast.Node + localJsxNamespace string + localJsxFragmentNamespace string + localJsxFactory *ast.EntityName + localJsxFragmentFactory *ast.EntityName } // Signature specific links @@ -353,57 +360,6 @@ type SignatureLinks struct { decoratorSignature *Signature // Signature for decorator as if invoked by the runtime } -// jsxFlag: JsxOpeningElement | JsxClosingElement -// resolvedJsxElementAttributesType: JsxOpeningElement | JsxClosingElement -// resolvedJsxElementAllAttributesType: JsxOpeningElement | JsxClosingElement -// jsxNamespace: Jsx* -// jsxImplicitImportContainer: Jsx* - -// resolvedJSDocType: JSDoc TypeReference | ImportType - -// switchTypes: SwitchStatement - -// contectFreeType: Expression | FunctionExpression | ArrowFunction | MethodDeclaration - -// outerTypeParameters: AnonymousType | MappedType | DeferredTypeReference - -// Only on SourceFile -// deferredNodes []Node // Set of nodes whose checking has been deferred - -// resolvedSignature Signature; // Cached signature of signature node or call expression -// effectsSignature Signature; // Signature with possible control flow effects -// enumMemberValue EvaluatorResult; // Constant value of enum member -// isVisible boolean; // Is this node visible -// containsArgumentsReference boolean; // Whether a function-like declaration contains an 'arguments' reference -// hasReportedStatementInAmbientContext boolean; // Cache boolean if we report statements in ambient context -// jsxFlag JsxFlags; // flags for knowing what kind of element/attributes we're dealing with -// resolvedJsxElementAttributesType Type; // resolved element attributes type of a JSX openinglike element -// resolvedJsxElementAllAttributesType Type; // resolved all element attributes type of a JSX openinglike element -// resolvedJSDocType Type; // Resolved type of a JSDoc type reference -// switchTypes []Type; // Cached array of switch case expression types -// jsxNamespace *Symbol; // Resolved jsx namespace symbol for this node -// jsxImplicitImportContainer *Symbol; // Resolved module symbol the implicit jsx import of this file should refer to -// contextFreeType Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive -// deferredNodes []Node // Set of nodes whose checking has been deferred -// capturedBlockScopeBindings []*Symbol; // Block-scoped bindings captured beneath this part of an IterationStatement -// outerTypeParameters []*TypeParameter; // Outer type parameters of anonymous object type -// isExhaustive boolean; // Is node an exhaustive switch statement (0 indicates in-process resolution) -// skipDirectInference true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type -// declarationRequiresScopeChange boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter. -// serializedTypes map[string]SerializedTypeEntry> // Collection of types serialized at this location -// decoratorSignature Signature; // Signature for decorator as if invoked by the runtime. -// spreadIndices { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal -// parameterInitializerContainsUndefined boolean; // True if this is a parameter declaration whose type annotation contains "undefined". -// fakeScopeForSignatureDeclaration "params" | "typeParams"; // If present, this is a fake scope injected into an enclosing declaration chain. -// assertionExpressionType Type; // Cached type of the expression of a type assertion -// potentialThisCollisions Node[]; -// potentialNewTargetCollisions Node[]; -// potentialWeakMapSetCollisions Node[]; -// potentialReflectCollisions Node[]; -// potentialUnusedRenamedBindingElementsInTypes BindingElement[]; -// externalHelpersModule Symbol; // Resolved symbol for the external helpers module -// instantiationExpressionTypes Map<number, Type>; // Cache of instantiation expression types for the node - type TypeFlags uint32 const ( @@ -581,6 +537,14 @@ type Type struct { data TypeData // Type specific data } +func (t *Type) Id() TypeId { + return t.id +} + +func (t *Type) Flags() TypeFlags { + return t.flags +} + // Casts for concrete struct types func (t *Type) AsIntrinsicType() *IntrinsicType { return t.data.(*IntrinsicType) } @@ -671,6 +635,46 @@ func (t *Type) TargetTupleType() *TupleType { return t.AsTypeReference().target.AsTupleType() } +func (t *Type) Symbol() *ast.Symbol { + return t.symbol +} + +func (t *Type) IsUnion() bool { + return t.flags&TypeFlagsUnion != 0 +} + +func (t *Type) IsString() bool { + return t.flags&TypeFlagsString != 0 +} + +func (t *Type) IsIntersection() bool { + return t.flags&TypeFlagsIntersection != 0 +} + +func (t *Type) IsStringLiteral() bool { + return t.flags&TypeFlagsStringLiteral != 0 +} + +func (t *Type) IsNumberLiteral() bool { + return t.flags&TypeFlagsNumberLiteral != 0 +} + +func (t *Type) IsBigIntLiteral() bool { + return t.flags&TypeFlagsBigIntLiteral != 0 +} + +func (t *Type) IsEnumLiteral() bool { + return t.flags&TypeFlagsEnumLiteral != 0 +} + +func (t *Type) IsBooleanLike() bool { + return t.flags&TypeFlagsBooleanLike != 0 +} + +func (t *Type) IsStringLike() bool { + return t.flags&TypeFlagsStringLike != 0 +} + // TypeData type TypeData interface { @@ -715,9 +719,8 @@ type LiteralType struct { regularType *Type // Regular version of type } -type PseudoBigInt struct { - negative bool - base10Value string +func (t *LiteralType) Value() any { + return t.value } // UniqueESSymbolTypeData diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index 4d939af194..4c22427383 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -5,14 +5,14 @@ import ( "slices" "strings" "sync" + "unicode/utf8" "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/jsnum" "github.com/microsoft/typescript-go/internal/scanner" - "github.com/microsoft/typescript-go/internal/tspath" ) func NewDiagnosticForNode(node *ast.Node, message *diagnostics.Message, args ...any) *ast.Diagnostic { @@ -33,12 +33,7 @@ func NewDiagnosticChainForNode(chain *ast.Diagnostic, node *ast.Node, message *d } func IsIntrinsicJsxName(name string) bool { - if len(name) == 0 { - return false - } - - ch := name[0] - return (ch >= 'a' && ch <= 'z') || strings.ContainsRune(name, '-') + return len(name) != 0 && (name[0] >= 'a' && name[0] <= 'z' || strings.ContainsRune(name, '-')) } func findInMap[K comparable, V any](m map[K]V, predicate func(V) bool) V { @@ -89,61 +84,16 @@ func hasDecorators(node *ast.Node) bool { return ast.HasSyntacticModifier(node, ast.ModifierFlagsDecorator) } -func getEffectiveModifierFlags(node *ast.Node) ast.ModifierFlags { - return node.ModifierFlags() // !!! Handle JSDoc -} - -func getSelectedEffectiveModifierFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags { - return getEffectiveModifierFlags(node) & flags -} - -func hasEffectiveModifier(node *ast.Node, flags ast.ModifierFlags) bool { - return getEffectiveModifierFlags(node)&flags != 0 -} - -func hasEffectiveReadonlyModifier(node *ast.Node) bool { - return hasEffectiveModifier(node, ast.ModifierFlagsReadonly) -} - -func isBindingElementOfBareOrAccessedRequire(node *ast.Node) bool { - return ast.IsBindingElement(node) && isVariableDeclarationInitializedToBareOrAccessedRequire(node.Parent.Parent) -} - -/** - * Like {@link isVariableDeclarationInitializedToRequire} but allows things like `require("...").foo.bar` or `require("...")["baz"]`. - */ -func isVariableDeclarationInitializedToBareOrAccessedRequire(node *ast.Node) bool { - return isVariableDeclarationInitializedWithRequireHelper(node, true /*allowAccessedRequire*/) -} - -func isVariableDeclarationInitializedWithRequireHelper(node *ast.Node, allowAccessedRequire bool) bool { - if node.Kind == ast.KindVariableDeclaration && node.AsVariableDeclaration().Initializer != nil { - initializer := node.AsVariableDeclaration().Initializer - if allowAccessedRequire { - initializer = getLeftmostAccessExpression(initializer) - } - return isRequireCall(initializer, true /*requireStringLiteralLikeArgument*/) - } - return false +func getSelectedModifierFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags { + return node.ModifierFlags() & flags } -func getLeftmostAccessExpression(expr *ast.Node) *ast.Node { - for ast.IsAccessExpression(expr) { - expr = expr.Expression() - } - return expr +func hasModifier(node *ast.Node, flags ast.ModifierFlags) bool { + return node.ModifierFlags()&flags != 0 } -func isRequireCall(node *ast.Node, requireStringLiteralLikeArgument bool) bool { - if ast.IsCallExpression(node) { - callExpression := node.AsCallExpression() - if len(callExpression.Arguments.Nodes) == 1 { - if ast.IsIdentifier(callExpression.Expression) && callExpression.Expression.AsIdentifier().Text == "require" { - return !requireStringLiteralLikeArgument || ast.IsStringLiteralLike(callExpression.Arguments.Nodes[0]) - } - } - } - return false +func hasReadonlyModifier(node *ast.Node) bool { + return hasModifier(node, ast.ModifierFlagsReadonly) } func isStaticPrivateIdentifierProperty(s *ast.Symbol) bool { @@ -240,7 +190,7 @@ func isTypeReferenceIdentifier(node *ast.Node) bool { return ast.IsTypeReferenceNode(node.Parent) } -func isInTypeQuery(node *ast.Node) bool { +func IsInTypeQuery(node *ast.Node) bool { // TypeScript 1.0 spec (April 2014): 3.6.3 // A type query consists of the keyword typeof followed by an expression. // The expression is restricted to a single identifier or a sequence of identifiers separated by periods @@ -255,37 +205,6 @@ func isInTypeQuery(node *ast.Node) bool { }) != nil } -func isTypeOnlyImportDeclaration(node *ast.Node) bool { - switch node.Kind { - case ast.KindImportSpecifier: - return node.AsImportSpecifier().IsTypeOnly || node.Parent.Parent.AsImportClause().IsTypeOnly - case ast.KindNamespaceImport: - return node.Parent.AsImportClause().IsTypeOnly - case ast.KindImportClause: - return node.AsImportClause().IsTypeOnly - case ast.KindImportEqualsDeclaration: - return node.AsImportEqualsDeclaration().IsTypeOnly - } - return false -} - -func isTypeOnlyExportDeclaration(node *ast.Node) bool { - switch node.Kind { - case ast.KindExportSpecifier: - return node.AsExportSpecifier().IsTypeOnly || node.Parent.Parent.AsExportDeclaration().IsTypeOnly - case ast.KindExportDeclaration: - d := node.AsExportDeclaration() - return d.IsTypeOnly && d.ModuleSpecifier != nil && d.ExportClause == nil - case ast.KindNamespaceExport: - return node.Parent.AsExportDeclaration().IsTypeOnly - } - return false -} - -func isTypeOnlyImportOrExportDeclaration(node *ast.Node) bool { - return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node) -} - func getNameFromImportDeclaration(node *ast.Node) *ast.Node { switch node.Kind { case ast.KindImportSpecifier: @@ -337,7 +256,6 @@ func nodeCanBeDecorated(useLegacyDecorators bool, node *ast.Node, parent *ast.No if useLegacyDecorators && node.Name() != nil && ast.IsPrivateIdentifier(node.Name()) { return false } - switch node.Kind { case ast.KindClassDeclaration: // class declarations are valid targets @@ -347,19 +265,21 @@ func nodeCanBeDecorated(useLegacyDecorators bool, node *ast.Node, parent *ast.No return !useLegacyDecorators case ast.KindPropertyDeclaration: // property declarations are valid if their parent is a class declaration. - return parent != nil && (ast.IsClassDeclaration(parent) || !useLegacyDecorators && ast.IsClassExpression(parent) && !hasAbstractModifier(node) && !hasAmbientModifier(node)) - case ast.KindGetAccessor, - ast.KindSetAccessor, - ast.KindMethodDeclaration: + return parent != nil && (useLegacyDecorators && ast.IsClassDeclaration(parent) || + !useLegacyDecorators && ast.IsClassLike(parent) && !hasAbstractModifier(node) && !hasAmbientModifier(node)) + case ast.KindGetAccessor, ast.KindSetAccessor, ast.KindMethodDeclaration: // if this method has a body and its parent is a class declaration, this is a valid target. - return node.BodyData() != nil && parent != nil && (ast.IsClassDeclaration(parent) || !useLegacyDecorators && ast.IsClassExpression(parent)) + return parent != nil && node.Body() != nil && (useLegacyDecorators && ast.IsClassDeclaration(parent) || + !useLegacyDecorators && ast.IsClassLike(parent)) case ast.KindParameter: // TODO(rbuckton): Parameter decorator support for ES decorators must wait until it is standardized if !useLegacyDecorators { return false } // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target. - return parent != nil && parent.BodyData() != nil && (parent.BodyData()).Body != nil && (parent.Kind == ast.KindConstructor || parent.Kind == ast.KindMethodDeclaration || parent.Kind == ast.KindSetAccessor) && getThisParameter(parent) != node && grandparent != nil && grandparent.Kind == ast.KindClassDeclaration + return parent != nil && parent.Body() != nil && + (parent.Kind == ast.KindConstructor || parent.Kind == ast.KindMethodDeclaration || parent.Kind == ast.KindSetAccessor) && + getThisParameter(parent) != node && grandparent != nil && grandparent.Kind == ast.KindClassDeclaration } return false @@ -371,7 +291,7 @@ func isShorthandPropertyNameUseSite(useSite *ast.Node) bool { func isTypeDeclaration(node *ast.Node) bool { switch node.Kind { - case ast.KindTypeParameter, ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, ast.KindEnumDeclaration: + case ast.KindTypeParameter, ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindEnumDeclaration: return true case ast.KindImportClause: return node.AsImportClause().IsTypeOnly @@ -388,17 +308,16 @@ func canHaveSymbol(node *ast.Node) bool { switch node.Kind { case ast.KindArrowFunction, ast.KindBinaryExpression, ast.KindBindingElement, ast.KindCallExpression, ast.KindCallSignature, ast.KindClassDeclaration, ast.KindClassExpression, ast.KindClassStaticBlockDeclaration, ast.KindConstructor, ast.KindConstructorType, - ast.KindConstructSignature, ast.KindElementAccessExpression, ast.KindEnumDeclaration, ast.KindEnumMember, ast.KindExportAssignment, + ast.KindConstructSignature, ast.KindElementAccessExpression, ast.KindEnumDeclaration, ast.KindEnumMember, ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindExportDeclaration, ast.KindExportSpecifier, ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindFunctionType, ast.KindGetAccessor, ast.KindIdentifier, ast.KindImportClause, ast.KindImportEqualsDeclaration, ast.KindImportSpecifier, - ast.KindIndexSignature, ast.KindInterfaceDeclaration, ast.KindJSDocCallbackTag, - ast.KindJSDocParameterTag, ast.KindJSDocPropertyTag, ast.KindJSDocSignature, ast.KindJSDocTypedefTag, ast.KindJSDocTypeLiteral, + ast.KindIndexSignature, ast.KindInterfaceDeclaration, ast.KindJSDocSignature, ast.KindJSDocTypeLiteral, ast.KindJsxAttribute, ast.KindJsxAttributes, ast.KindJsxSpreadAttribute, ast.KindMappedType, ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindModuleDeclaration, ast.KindNamedTupleMember, ast.KindNamespaceExport, ast.KindNamespaceExportDeclaration, ast.KindNamespaceImport, ast.KindNewExpression, ast.KindNoSubstitutionTemplateLiteral, ast.KindNumericLiteral, ast.KindObjectLiteralExpression, ast.KindParameter, ast.KindPropertyAccessExpression, ast.KindPropertyAssignment, ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindSetAccessor, ast.KindShorthandPropertyAssignment, ast.KindSourceFile, ast.KindSpreadAssignment, ast.KindStringLiteral, - ast.KindTypeAliasDeclaration, ast.KindTypeLiteral, ast.KindTypeParameter, ast.KindVariableDeclaration: + ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindTypeLiteral, ast.KindTypeParameter, ast.KindVariableDeclaration: return true } return false @@ -409,10 +328,10 @@ func canHaveLocals(node *ast.Node) bool { case ast.KindArrowFunction, ast.KindBlock, ast.KindCallSignature, ast.KindCaseBlock, ast.KindCatchClause, ast.KindClassStaticBlockDeclaration, ast.KindConditionalType, ast.KindConstructor, ast.KindConstructorType, ast.KindConstructSignature, ast.KindForStatement, ast.KindForInStatement, ast.KindForOfStatement, ast.KindFunctionDeclaration, - ast.KindFunctionExpression, ast.KindFunctionType, ast.KindGetAccessor, ast.KindIndexSignature, ast.KindJSDocCallbackTag, - ast.KindJSDocSignature, ast.KindJSDocTypedefTag, ast.KindMappedType, + ast.KindFunctionExpression, ast.KindFunctionType, ast.KindGetAccessor, ast.KindIndexSignature, + ast.KindJSDocSignature, ast.KindMappedType, ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindModuleDeclaration, ast.KindSetAccessor, ast.KindSourceFile, - ast.KindTypeAliasDeclaration: + ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration: return true } return false @@ -429,7 +348,7 @@ func isShorthandAmbientModule(node *ast.Node) bool { func getAliasDeclarationFromName(node *ast.Node) *ast.Node { switch node.Parent.Kind { - case ast.KindImportClause, ast.KindImportSpecifier, ast.KindNamespaceImport, ast.KindExportSpecifier, ast.KindExportAssignment, + case ast.KindImportClause, ast.KindImportSpecifier, ast.KindNamespaceImport, ast.KindExportSpecifier, ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindImportEqualsDeclaration, ast.KindNamespaceExport: return node.Parent case ast.KindQualifiedName: @@ -443,6 +362,9 @@ func entityNameToString(name *ast.Node) string { case ast.KindThisKeyword: return "this" case ast.KindIdentifier, ast.KindPrivateIdentifier: + if ast.NodeIsSynthesized(name) { + return name.Text() + } return scanner.GetTextOfNode(name) case ast.KindQualifiedName: return entityNameToString(name.AsQualifiedName().Left) + "." + entityNameToString(name.AsQualifiedName().Right) @@ -467,8 +389,8 @@ func isSideEffectImport(node *ast.Node) bool { } func getExternalModuleRequireArgument(node *ast.Node) *ast.Node { - if isVariableDeclarationInitializedToBareOrAccessedRequire(node) { - return getLeftmostAccessExpression(node.AsVariableDeclaration().Initializer).AsCallExpression().Arguments.Nodes[0] + if ast.IsVariableDeclarationInitializedToRequire(node) { + return node.AsVariableDeclaration().Initializer.AsCallExpression().Arguments.Nodes[0] } return nil } @@ -491,26 +413,8 @@ func isRightSideOfQualifiedNameOrPropertyAccess(node *ast.Node) bool { return false } -func getSourceFileOfModule(module *ast.Symbol) *ast.SourceFile { - declaration := module.ValueDeclaration - if declaration == nil { - declaration = getNonAugmentationDeclaration(module) - } - return ast.GetSourceFileOfNode(declaration) -} - -func getNonAugmentationDeclaration(symbol *ast.Symbol) *ast.Node { - return core.Find(symbol.Declarations, func(d *ast.Node) bool { - return !isExternalModuleAugmentation(d) && !(ast.IsModuleDeclaration(d) && ast.IsGlobalScopeAugmentation(d)) - }) -} - -func isExternalModuleAugmentation(node *ast.Node) bool { - return ast.IsAmbientModule(node) && ast.IsModuleAugmentationExternal(node) -} - func isTopLevelInExternalModuleAugmentation(node *ast.Node) bool { - return node != nil && node.Parent != nil && ast.IsModuleBlock(node.Parent) && isExternalModuleAugmentation(node.Parent.Parent) + return node != nil && node.Parent != nil && ast.IsModuleBlock(node.Parent) && ast.IsExternalModuleAugmentation(node.Parent.Parent) } func isSyntacticDefault(node *ast.Node) bool { @@ -524,12 +428,8 @@ func hasExportAssignmentSymbol(moduleSymbol *ast.Symbol) bool { return moduleSymbol.Exports[ast.InternalSymbolNameExportEquals] != nil } -func parsePseudoBigInt(stringValue string) string { - return stringValue // !!! -} - func isTypeAlias(node *ast.Node) bool { - return ast.IsTypeAliasDeclaration(node) + return ast.IsTypeOrJSTypeAliasDeclaration(node) } func hasOnlyExpressionInitializer(node *ast.Node) bool { @@ -600,7 +500,7 @@ func declarationBelongsToPrivateAmbientMember(declaration *ast.Node) bool { } func isPrivateWithinAmbient(node *ast.Node) bool { - return (hasEffectiveModifier(node, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(node)) && node.Flags&ast.NodeFlagsAmbient != 0 + return (hasModifier(node, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(node)) && node.Flags&ast.NodeFlagsAmbient != 0 } func isTypeAssertion(node *ast.Node) bool { @@ -659,9 +559,11 @@ func (c *Checker) compareNodes(n1, n2 *ast.Node) int { if n2 == nil { return -1 } - f1 := c.fileIndexMap[ast.GetSourceFileOfNode(n1)] - f2 := c.fileIndexMap[ast.GetSourceFileOfNode(n2)] - if f1 != f2 { + s1 := ast.GetSourceFileOfNode(n1) + s2 := ast.GetSourceFileOfNode(n2) + if s1 != s2 { + f1 := c.fileIndexMap[s1] + f2 := c.fileIndexMap[s2] // Order by index of file in the containing program return f1 - f2 } @@ -669,7 +571,7 @@ func (c *Checker) compareNodes(n1, n2 *ast.Node) int { return n1.Pos() - n2.Pos() } -func compareTypes(t1, t2 *Type) int { +func CompareTypes(t1, t2 *Type) int { if t1 == t2 { return 0 } @@ -754,7 +656,7 @@ func compareTypes(t1, t2 *Type) int { } else if o2 == nil { return -1 } else { - if c := compareTypes(o1, o2); c != 0 { + if c := CompareTypes(o1, o2); c != 0 { return c } } @@ -763,7 +665,7 @@ func compareTypes(t1, t2 *Type) int { if c := compareTypeLists(t1.Types(), t2.Types()); c != 0 { return c } - case t1.flags&(TypeFlagsEnumLiteral|TypeFlagsUniqueESSymbol) != 0: + case t1.flags&(TypeFlagsEnum|TypeFlagsEnumLiteral|TypeFlagsUniqueESSymbol) != 0: // Enum members are ordered by their symbol (and thus their declaration order). if c := t1.checker.compareSymbols(t1.symbol, t2.symbol); c != 0 { return c @@ -792,17 +694,17 @@ func compareTypes(t1, t2 *Type) int { return c } case t1.flags&TypeFlagsIndex != 0: - if c := compareTypes(t1.AsIndexType().target, t2.AsIndexType().target); c != 0 { + if c := CompareTypes(t1.AsIndexType().target, t2.AsIndexType().target); c != 0 { return c } if c := int(t1.AsIndexType().flags) - int(t2.AsIndexType().flags); c != 0 { return c } case t1.flags&TypeFlagsIndexedAccess != 0: - if c := compareTypes(t1.AsIndexedAccessType().objectType, t2.AsIndexedAccessType().objectType); c != 0 { + if c := CompareTypes(t1.AsIndexedAccessType().objectType, t2.AsIndexedAccessType().objectType); c != 0 { return c } - if c := compareTypes(t1.AsIndexedAccessType().indexType, t2.AsIndexedAccessType().indexType); c != 0 { + if c := CompareTypes(t1.AsIndexedAccessType().indexType, t2.AsIndexedAccessType().indexType); c != 0 { return c } case t1.flags&TypeFlagsConditional != 0: @@ -813,10 +715,10 @@ func compareTypes(t1, t2 *Type) int { return c } case t1.flags&TypeFlagsSubstitution != 0: - if c := compareTypes(t1.AsSubstitutionType().baseType, t2.AsSubstitutionType().baseType); c != 0 { + if c := CompareTypes(t1.AsSubstitutionType().baseType, t2.AsSubstitutionType().baseType); c != 0 { return c } - if c := compareTypes(t1.AsSubstitutionType().constraint, t2.AsSubstitutionType().constraint); c != 0 { + if c := CompareTypes(t1.AsSubstitutionType().constraint, t2.AsSubstitutionType().constraint); c != 0 { return c } case t1.flags&TypeFlagsTemplateLiteral != 0: @@ -827,7 +729,7 @@ func compareTypes(t1, t2 *Type) int { return c } case t1.flags&TypeFlagsStringMapping != 0: - if c := compareTypes(t1.AsStringMappingType().target, t2.AsStringMappingType().target); c != 0 { + if c := CompareTypes(t1.AsStringMappingType().target, t2.AsStringMappingType().target); c != 0 { return c } } @@ -836,9 +738,11 @@ func compareTypes(t1, t2 *Type) int { } func getSortOrderFlags(t *Type) int { - // We want enum literal and computed values to be ordered by their declarations, so we merge TypeFlagsEnum into - // TypeFlagsEnumLiteral and clear TypeFlagsEnum. - return int((t.flags&TypeFlagsEnum)>>1 | t.flags&^TypeFlagsEnum) + // Return TypeFlagsEnum for all enum-like unit types (they'll be sorted by their symbols) + if t.flags&(TypeFlagsEnumLiteral|TypeFlagsEnum) != 0 && t.flags&TypeFlagsUnion == 0 { + return int(TypeFlagsEnum) + } + return int(t.flags) } func compareTypeNames(t1, t2 *Type) int { @@ -917,7 +821,7 @@ func compareTypeLists(s1, s2 []*Type) int { return len(s1) - len(s2) } for i, t1 := range s1 { - if c := compareTypes(t1, s2[i]); c != 0 { + if c := CompareTypes(t1, s2[i]); c != 0 { return c } } @@ -943,10 +847,10 @@ func compareTypeMappers(m1, m2 *TypeMapper) int { case TypeMapperKindSimple: m1 := m1.data.(*SimpleTypeMapper) m2 := m2.data.(*SimpleTypeMapper) - if c := compareTypes(m1.source, m2.source); c != 0 { + if c := CompareTypes(m1.source, m2.source); c != 0 { return c } - return compareTypes(m1.target, m2.target) + return CompareTypes(m1.target, m2.target) case TypeMapperKindArray: m1 := m1.data.(*ArrayTypeMapper) m2 := m2.data.(*ArrayTypeMapper) @@ -965,20 +869,6 @@ func compareTypeMappers(m1, m2 *TypeMapper) int { return 0 } -func getClassLikeDeclarationOfSymbol(symbol *ast.Symbol) *ast.Node { - return core.Find(symbol.Declarations, ast.IsClassLike) -} - -func isThisInTypeQuery(node *ast.Node) bool { - if !ast.IsThisIdentifier(node) { - return false - } - for ast.IsQualifiedName(node.Parent) && node.Parent.AsQualifiedName().Left == node { - node = node.Parent - } - return node.Parent.Kind == ast.KindTypeQuery -} - func getDeclarationModifierFlagsFromSymbol(s *ast.Symbol) ast.ModifierFlags { return getDeclarationModifierFlagsFromSymbolEx(s, false /*isWrite*/) } @@ -1208,21 +1098,6 @@ func isThisProperty(node *ast.Node) bool { return (ast.IsPropertyAccessExpression(node) || ast.IsElementAccessExpression(node)) && node.Expression().Kind == ast.KindThisKeyword } -func anyToString(v any) string { - // !!! This function should behave identically to the expression `"" + v` in JS - switch v := v.(type) { - case string: - return v - case jsnum.Number: - return v.String() - case bool: - return core.IfElse(v, "true", "false") - case PseudoBigInt: - return "(BigInt)" // !!! - } - panic("Unhandled case in anyToString") -} - func isValidNumberString(s string, roundTripOnly bool) bool { if s == "" { return false @@ -1232,7 +1107,29 @@ func isValidNumberString(s string, roundTripOnly bool) bool { } func isValidBigIntString(s string, roundTripOnly bool) bool { - return false // !!! + if s == "" { + return false + } + scanner := scanner.NewScanner() + scanner.SetSkipTrivia(false) + success := true + scanner.SetOnError(func(diagnostic *diagnostics.Message, start, length int, args ...any) { + success = false + }) + scanner.SetText(s + "n") + result := scanner.Scan() + negative := result == ast.KindMinusToken + if negative { + result = scanner.Scan() + } + flags := scanner.TokenFlags() + // validate that + // * scanning proceeded without error + // * a bigint can be scanned, and that when it is scanned, it is + // * the full length of the input string (so the scanner is one character beyond the augmented input length) + // * it does not contain a numeric separator (the `BigInt` constructor does not accept a numeric separator in its input) + return success && result == ast.KindBigIntLiteral && scanner.TokenEnd() == len(s)+1 && flags&ast.TokenFlagsContainsSeparator == 0 && + (!roundTripOnly || s == pseudoBigIntToString(jsnum.NewPseudoBigInt(jsnum.ParsePseudoBigInt(scanner.TokenValue()), negative))) } func isValidESSymbolDeclaration(node *ast.Node) bool { @@ -1240,16 +1137,16 @@ func isValidESSymbolDeclaration(node *ast.Node) bool { return ast.IsVarConst(node) && ast.IsIdentifier(node.AsVariableDeclaration().Name()) && isVariableDeclarationInVariableStatement(node) } if ast.IsPropertyDeclaration(node) { - return hasEffectiveReadonlyModifier(node) && ast.HasStaticModifier(node) + return hasReadonlyModifier(node) && ast.HasStaticModifier(node) } - return ast.IsPropertySignatureDeclaration(node) && hasEffectiveReadonlyModifier(node) + return ast.IsPropertySignatureDeclaration(node) && hasReadonlyModifier(node) } func isVariableDeclarationInVariableStatement(node *ast.Node) bool { return ast.IsVariableDeclarationList(node.Parent) && ast.IsVariableStatement(node.Parent.Parent) } -func isKnownSymbol(symbol *ast.Symbol) bool { +func IsKnownSymbol(symbol *ast.Symbol) bool { return isLateBoundName(symbol.Name) } @@ -1261,18 +1158,13 @@ func getThisParameter(signature *ast.Node) *ast.Node { // callback tags do not currently support this parameters if len(signature.Parameters()) != 0 { thisParameter := signature.Parameters()[0] - if parameterIsThisKeyword(thisParameter) { + if ast.IsThisParameter(thisParameter) { return thisParameter } } return nil } -// Deprecated: use ast.IsThisParameter -func parameterIsThisKeyword(parameter *ast.Node) bool { - return ast.IsThisParameter(parameter) -} - func isObjectOrArrayLiteralType(t *Type) bool { return t.objectFlags&(ObjectFlagsObjectLiteral|ObjectFlagsArrayLiteral) != 0 } @@ -1300,15 +1192,6 @@ func isThisTypeParameter(t *Type) bool { return t.flags&TypeFlagsTypeParameter != 0 && t.AsTypeParameter().isThisType } -func isCallLikeExpression(node *ast.Node) bool { - switch node.Kind { - case ast.KindJsxOpeningElement, ast.KindJsxSelfClosingElement, ast.KindCallExpression, ast.KindNewExpression, - ast.KindTaggedTemplateExpression, ast.KindDecorator: - return true - } - return false -} - func isCallOrNewExpression(node *ast.Node) bool { return ast.IsCallExpression(node) || ast.IsNewExpression(node) } @@ -1421,136 +1304,6 @@ func isObjectLiteralElementLike(node *ast.Node) bool { return ast.IsObjectLiteralElement(node) } -type EvaluatorResult struct { - value any - isSyntacticallyString bool - resolvedOtherFiles bool - hasExternalReferences bool -} - -func evaluatorResult(value any, isSyntacticallyString bool, resolvedOtherFiles bool, hasExternalReferences bool) EvaluatorResult { - return EvaluatorResult{value, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences} -} - -type Evaluator func(expr *ast.Node, location *ast.Node) EvaluatorResult - -func createEvaluator(evaluateEntity Evaluator) Evaluator { - var evaluate Evaluator - evaluateTemplateExpression := func(expr *ast.Node, location *ast.Node) EvaluatorResult { - var sb strings.Builder - sb.WriteString(expr.AsTemplateExpression().Head.Text()) - resolvedOtherFiles := false - hasExternalReferences := false - for _, span := range expr.AsTemplateExpression().TemplateSpans.Nodes { - spanResult := evaluate(span.Expression(), location) - if spanResult.value == nil { - return evaluatorResult(nil, true /*isSyntacticallyString*/, false, false) - } - sb.WriteString(anyToString(spanResult.value)) - sb.WriteString(span.AsTemplateSpan().Literal.Text()) - resolvedOtherFiles = resolvedOtherFiles || spanResult.resolvedOtherFiles - hasExternalReferences = hasExternalReferences || spanResult.hasExternalReferences - } - return evaluatorResult(sb.String(), true, resolvedOtherFiles, hasExternalReferences) - } - evaluate = func(expr *ast.Node, location *ast.Node) EvaluatorResult { - isSyntacticallyString := false - resolvedOtherFiles := false - hasExternalReferences := false - // It's unclear when/whether we should consider skipping other kinds of outer expressions. - // Type assertions intentionally break evaluation when evaluating literal types, such as: - // type T = `one ${"two" as any} three`; // string - // But it's less clear whether such an assertion should break enum member evaluation: - // enum E { - // A = "one" as any - // } - // SatisfiesExpressions and non-null assertions seem to have even less reason to break - // emitting enum members as literals. However, these expressions also break Babel's - // evaluation (but not esbuild's), and the isolatedModules errors we give depend on - // our evaluation results, so we're currently being conservative so as to issue errors - // on code that might break Babel. - expr = ast.SkipParentheses(expr) - switch expr.Kind { - case ast.KindPrefixUnaryExpression: - result := evaluate(expr.AsPrefixUnaryExpression().Operand, location) - resolvedOtherFiles = result.resolvedOtherFiles - hasExternalReferences = result.hasExternalReferences - if value, ok := result.value.(jsnum.Number); ok { - switch expr.AsPrefixUnaryExpression().Operator { - case ast.KindPlusToken: - return evaluatorResult(value, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindMinusToken: - return evaluatorResult(-value, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindTildeToken: - return evaluatorResult(value.BitwiseNOT(), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - } - } - case ast.KindBinaryExpression: - left := evaluate(expr.AsBinaryExpression().Left, location) - right := evaluate(expr.AsBinaryExpression().Right, location) - operator := expr.AsBinaryExpression().OperatorToken.Kind - isSyntacticallyString = (left.isSyntacticallyString || right.isSyntacticallyString) && expr.AsBinaryExpression().OperatorToken.Kind == ast.KindPlusToken - resolvedOtherFiles = left.resolvedOtherFiles || right.resolvedOtherFiles - hasExternalReferences = left.hasExternalReferences || right.hasExternalReferences - leftNum, leftIsNum := left.value.(jsnum.Number) - rightNum, rightIsNum := right.value.(jsnum.Number) - if leftIsNum && rightIsNum { - switch operator { - case ast.KindBarToken: - return evaluatorResult(leftNum.BitwiseOR(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindAmpersandToken: - return evaluatorResult(leftNum.BitwiseAND(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindGreaterThanGreaterThanToken: - return evaluatorResult(leftNum.SignedRightShift(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindGreaterThanGreaterThanGreaterThanToken: - return evaluatorResult(leftNum.UnsignedRightShift(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindLessThanLessThanToken: - return evaluatorResult(leftNum.LeftShift(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindCaretToken: - return evaluatorResult(leftNum.BitwiseXOR(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindAsteriskToken: - return evaluatorResult(leftNum*rightNum, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindSlashToken: - return evaluatorResult(leftNum/rightNum, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindPlusToken: - return evaluatorResult(leftNum+rightNum, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindMinusToken: - return evaluatorResult(leftNum-rightNum, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindPercentToken: - return evaluatorResult(leftNum.Remainder(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - case ast.KindAsteriskAsteriskToken: - return evaluatorResult(leftNum.Exponentiate(rightNum), isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - } - } - leftStr, leftIsStr := left.value.(string) - rightStr, rightIsStr := right.value.(string) - if (leftIsStr || leftIsNum) && (rightIsStr || rightIsNum) && operator == ast.KindPlusToken { - if leftIsNum { - leftStr = leftNum.String() - } - if rightIsNum { - rightStr = rightNum.String() - } - return evaluatorResult(leftStr+rightStr, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - } - case ast.KindStringLiteral, ast.KindNoSubstitutionTemplateLiteral: - return evaluatorResult(expr.Text(), true /*isSyntacticallyString*/, false, false) - case ast.KindTemplateExpression: - return evaluateTemplateExpression(expr, location) - case ast.KindNumericLiteral: - return evaluatorResult(jsnum.FromString(expr.Text()), false, false, false) - case ast.KindIdentifier, ast.KindElementAccessExpression: - return evaluateEntity(expr, location) - case ast.KindPropertyAccessExpression: - if ast.IsEntityNameExpression(expr) { - return evaluateEntity(expr, location) - } - } - return evaluatorResult(nil, isSyntacticallyString, resolvedOtherFiles, hasExternalReferences) - } - return evaluate -} - func isInfinityOrNaNString(name string) bool { return name == "Infinity" || name == "-Infinity" || name == "NaN" } @@ -1575,7 +1328,7 @@ func (c *Checker) isMutableLocalVariableDeclaration(declaration *ast.Node) bool func isInAmbientOrTypeNode(node *ast.Node) bool { return node.Flags&ast.NodeFlagsAmbient != 0 || ast.FindAncestor(node, func(n *ast.Node) bool { - return ast.IsInterfaceDeclaration(n) || ast.IsTypeAliasDeclaration(n) || ast.IsTypeLiteralNode(n) + return ast.IsInterfaceDeclaration(n) || ast.IsTypeOrJSTypeAliasDeclaration(n) || ast.IsTypeLiteralNode(n) }) != nil } @@ -1655,7 +1408,7 @@ func hasContextSensitiveParameters(node *ast.Node) bool { // If the first parameter is not an explicit 'this' parameter, then the function has // an implicit 'this' parameter which is subject to contextual typing. parameter := core.FirstOrNil(node.Parameters()) - if parameter == nil || !parameterIsThisKeyword(parameter) { + if parameter == nil || !ast.IsThisParameter(parameter) { return true } } @@ -1736,30 +1489,13 @@ func getFunctionFlags(node *ast.Node) FunctionFlags { return flags } -func getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide *ast.EntityName) *ast.Node { - for nodeOnRightSide.Parent.Kind == ast.KindQualifiedName { - nodeOnRightSide = nodeOnRightSide.Parent - } - - if nodeOnRightSide.Parent.Kind == ast.KindImportEqualsDeclaration { - if nodeOnRightSide.Parent.AsImportEqualsDeclaration().ModuleReference == nodeOnRightSide { - return nodeOnRightSide.Parent - } - return nil - } - - if nodeOnRightSide.Parent.Kind == ast.KindExportAssignment { - if nodeOnRightSide.Parent.AsExportAssignment().Expression == nodeOnRightSide { - return nodeOnRightSide.Parent - } - return nil +func isInRightSideOfImportOrExportAssignment(node *ast.EntityName) bool { + for node.Parent.Kind == ast.KindQualifiedName { + node = node.Parent } - return nil -} - -func isInRightSideOfImportOrExportAssignment(node *ast.EntityName) bool { - return getLeftSideOfImportEqualsOrExportAssignment(node) != nil + return node.Parent.Kind == ast.KindImportEqualsDeclaration && node.Parent.AsImportEqualsDeclaration().ModuleReference == node || + (node.Parent.Kind == ast.KindExportAssignment || node.Parent.Kind == ast.KindJSExportAssignment) && node.Parent.AsExportAssignment().Expression == node } func isJsxIntrinsicTagName(tagName *ast.Node) bool { @@ -1799,12 +1535,6 @@ func isInNameOfExpressionWithTypeArguments(node *ast.Node) bool { return node.Parent.Kind == ast.KindExpressionWithTypeArguments } -func getTypeParameterFromJsDoc(node *ast.Node) *ast.Node { - name := node.Name().Text() - typeParameters := node.Parent.Parent.Parent.TypeParameters() - return core.Find(typeParameters, func(p *ast.Node) bool { return p.Name().Text() == name }) -} - func isTypeDeclarationName(name *ast.Node) bool { return name.Kind == ast.KindIdentifier && isTypeDeclaration(name.Parent) && @@ -1842,11 +1572,8 @@ func expressionResultIsUnused(node *ast.Node) bool { } } -func pseudoBigIntToString(value PseudoBigInt) string { - if value.negative && value.base10Value != "0" { - return "-" + value.base10Value - } - return value.base10Value +func pseudoBigIntToString(value jsnum.PseudoBigInt) string { + return value.String() } func getSuperContainer(node *ast.Node, stopOnFunctions bool) *ast.Node { @@ -1912,44 +1639,35 @@ func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) { traverse(body) } -func skipTypeChecking(sourceFile *ast.SourceFile, options *core.CompilerOptions) bool { +func SkipTypeChecking(sourceFile *ast.SourceFile, options *core.CompilerOptions) bool { return options.NoCheck.IsTrue() || - options.SkipLibCheck.IsTrue() && tspath.IsDeclarationFileName(sourceFile.FileName()) || + options.SkipLibCheck.IsTrue() && sourceFile.IsDeclarationFile || options.SkipDefaultLibCheck.IsTrue() && sourceFile.HasNoDefaultLib || !canIncludeBindAndCheckDiagnostics(sourceFile, options) } func canIncludeBindAndCheckDiagnostics(sourceFile *ast.SourceFile, options *core.CompilerOptions) bool { - // !!! - // if (!!sourceFile.checkJsDirective && sourceFile.checkJsDirective.enabled === false) return false; + if sourceFile.CheckJsDirective != nil && !sourceFile.CheckJsDirective.Enabled { + return false + } if sourceFile.ScriptKind == core.ScriptKindTS || sourceFile.ScriptKind == core.ScriptKindTSX || sourceFile.ScriptKind == core.ScriptKindExternal { return true } - isJs := sourceFile.ScriptKind == core.ScriptKindJS || sourceFile.ScriptKind == core.ScriptKindJSX - isCheckJs := isJs && isCheckJsEnabledForFile(sourceFile, options) - isPlainJs := isPlainJsFile(sourceFile, options.CheckJs) + isJS := sourceFile.ScriptKind == core.ScriptKindJS || sourceFile.ScriptKind == core.ScriptKindJSX + isCheckJS := isJS && ast.IsCheckJSEnabledForFile(sourceFile, options) + isPlainJS := isPlainJSFile(sourceFile, options.CheckJs) // By default, only type-check .ts, .tsx, Deferred, plain JS, checked JS and External // - plain JS: .js files with no // ts-check and checkJs: undefined // - check JS: .js files with either // ts-check or checkJs: true // - external: files that are added by plugins - return isPlainJs || isCheckJs || sourceFile.ScriptKind == core.ScriptKindDeferred -} - -func isCheckJsEnabledForFile(sourceFile *ast.SourceFile, compilerOptions *core.CompilerOptions) bool { - // !!! - // if sourceFile.CheckJsDirective != nil { - // return sourceFile.CheckJsDirective.Enabled - // } - return compilerOptions.CheckJs == core.TSTrue + return isPlainJS || isCheckJS || sourceFile.ScriptKind == core.ScriptKindDeferred } -func isPlainJsFile(file *ast.SourceFile, checkJs core.Tristate) bool { - // !!! - // return file != nil && (file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX) && file.CheckJsDirective == nil && checkJs == core.TSUnknown - return file != nil && (file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX) && checkJs == core.TSUnknown +func isPlainJSFile(file *ast.SourceFile, checkJs core.Tristate) bool { + return file != nil && (file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX) && file.CheckJsDirective == nil && checkJs == core.TSUnknown } func getEnclosingContainer(node *ast.Node) *ast.Node { @@ -1992,7 +1710,9 @@ func isModuleExportsAccessExpression(node *ast.Node) bool { func getNonModifierTokenRangeOfNode(node *ast.Node) core.TextRange { pos := node.Pos() if node.Modifiers() != nil { - pos = core.LastOrNil(node.Modifiers().Nodes).End() + if last := ast.FindLastVisibleNode(node.Modifiers().Nodes); last != nil { + pos = last.Pos() + } } return scanner.GetRangeOfTokenAtPosition(ast.GetSourceFileOfNode(node), pos) } @@ -2017,11 +1737,45 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { "AsyncIterator": { {lib: "es2015", props: []string{}}, }, + "ArrayBuffer": { + {lib: "es2024", props: []string{ + "maxByteLength", + "resizable", + "resize", + "detached", + "transfer", + "transferToFixedLength", + }}, + }, "Atomics": { - {lib: "es2017", props: []string{}}, + {lib: "es2017", props: []string{ + "add", + "and", + "compareExchange", + "exchange", + "isLockFree", + "load", + "or", + "store", + "sub", + "wait", + "notify", + "xor", + }}, + {lib: "es2024", props: []string{ + "waitAsync", + }}, }, "SharedArrayBuffer": { - {lib: "es2017", props: []string{}}, + {lib: "es2017", props: []string{ + "byteLength", + "slice", + }}, + {lib: "es2024", props: []string{ + "growable", + "maxByteLength", + "grow", + }}, }, "AsyncIterable": { {lib: "es2018", props: []string{}}, @@ -2038,6 +1792,7 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { "RegExp": { {lib: "es2015", props: []string{"flags", "sticky", "unicode"}}, {lib: "es2018", props: []string{"dotAll"}}, + {lib: "es2024", props: []string{"unicodeSets"}}, }, "Reflect": { {lib: "es2015", props: []string{"apply", "construct", "defineProperty", "deleteProperty", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"}}, @@ -2051,6 +1806,7 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { {lib: "es2017", props: []string{"values", "entries", "getOwnPropertyDescriptors"}}, {lib: "es2019", props: []string{"fromEntries"}}, {lib: "es2022", props: []string{"hasOwn"}}, + {lib: "es2024", props: []string{"groupBy"}}, }, "NumberConstructor": { {lib: "es2015", props: []string{"isFinite", "isInteger", "isNaN", "isSafeInteger", "parseFloat", "parseInt"}}, @@ -2061,13 +1817,26 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { "Map": { {lib: "es2015", props: []string{"entries", "keys", "values"}}, }, + "MapConstructor": { + {lib: "es2024", props: []string{"groupBy"}}, + }, "Set": { {lib: "es2015", props: []string{"entries", "keys", "values"}}, + {lib: "esnext", props: []string{ + "union", + "intersection", + "difference", + "symmetricDifference", + "isSubsetOf", + "isSupersetOf", + "isDisjointFrom", + }}, }, "PromiseConstructor": { {lib: "es2015", props: []string{"all", "race", "reject", "resolve"}}, {lib: "es2020", props: []string{"allSettled"}}, {lib: "es2021", props: []string{"any"}}, + {lib: "es2024", props: []string{"withResolvers"}}, }, "Symbol": { {lib: "es2015", props: []string{"for", "keyFor"}}, @@ -2086,7 +1855,7 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { {lib: "es2020", props: []string{"matchAll"}}, {lib: "es2021", props: []string{"replaceAll"}}, {lib: "es2022", props: []string{"at"}}, - {lib: "esnext", props: []string{"isWellFormed", "toWellFormed"}}, + {lib: "es2024", props: []string{"isWellFormed", "toWellFormed"}}, }, "StringConstructor": { {lib: "es2015", props: []string{"fromCodePoint", "raw"}}, @@ -2112,6 +1881,11 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { }, "SymbolConstructor": { {lib: "es2020", props: []string{"matchAll"}}, + {lib: "esnext", props: []string{ + "metadata", + "dispose", + "asyncDispose", + }}, }, "DataView": { {lib: "es2020", props: []string{"setBigInt64", "setBigUint64", "getBigInt64", "getBigUint64"}}, @@ -2175,7 +1949,7 @@ var getFeatureMap = sync.OnceValue(func() map[string][]FeatureMapEntry { }) func rangeOfTypeParameters(sourceFile *ast.SourceFile, typeParameters *ast.NodeList) core.TextRange { - return core.NewTextRange(typeParameters.Pos()-1, min(len(sourceFile.Text), scanner.SkipTrivia(sourceFile.Text, typeParameters.End())+1)) + return core.NewTextRange(typeParameters.Pos()-1, min(len(sourceFile.Text()), scanner.SkipTrivia(sourceFile.Text(), typeParameters.End())+1)) } func tryGetPropertyAccessOrIdentifierToString(expr *ast.Node) string { @@ -2242,3 +2016,50 @@ func allDeclarationsInSameSourceFile(symbol *ast.Symbol) bool { } return true } + +// A reserved member name consists of the byte 0xFE (which is an invalid UTF-8 encoding) followed by one or more +// characters where the first character is not '@' or '#'. The '@' character indicates that the name is denoted by +// a well known ES Symbol instance and the '#' character indicates that the name is a PrivateIdentifier. +func isReservedMemberName(name string) bool { + return len(name) >= 2 && name[0] == '\xFE' && name[1] != '@' && name[1] != '#' +} + +func introducesArgumentsExoticObject(node *ast.Node) bool { + switch node.Kind { + case ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindConstructor, ast.KindGetAccessor, + ast.KindSetAccessor, ast.KindFunctionDeclaration, ast.KindFunctionExpression: + return true + } + return false +} + +func symbolsToArray(symbols ast.SymbolTable) []*ast.Symbol { + var result []*ast.Symbol + for id, symbol := range symbols { + if !isReservedMemberName(id) { + result = append(result, symbol) + } + } + return result +} + +// See comment on `declareModuleMember` in `binder.go`. +func GetCombinedLocalAndExportSymbolFlags(symbol *ast.Symbol) ast.SymbolFlags { + if symbol.ExportSymbol != nil { + return symbol.Flags | symbol.ExportSymbol.Flags + } + return symbol.Flags +} + +func SkipAlias(symbol *ast.Symbol, checker *Checker) *ast.Symbol { + if symbol.Flags&ast.SymbolFlagsAlias != 0 { + return checker.GetAliasedSymbol(symbol) + } + return symbol +} + +// True if the symbol is for an external module, as opposed to a namespace. +func IsExternalModuleSymbol(moduleSymbol *ast.Symbol) bool { + firstRune, _ := utf8.DecodeRuneInString(moduleSymbol.Name) + return moduleSymbol.Flags&ast.SymbolFlagsModule != 0 && firstRune == '"' +} diff --git a/internal/collections/syncmap.go b/internal/collections/syncmap.go new file mode 100644 index 0000000000..f1101cf2bd --- /dev/null +++ b/internal/collections/syncmap.go @@ -0,0 +1,59 @@ +package collections + +import "sync" + +type SyncMap[K comparable, V any] struct { + m sync.Map +} + +func (s *SyncMap[K, V]) Load(key K) (value V, ok bool) { + val, ok := s.m.Load(key) + if !ok { + return + } + return val.(V), true +} + +func (s *SyncMap[K, V]) Store(key K, value V) { + s.m.Store(key, value) +} + +func (s *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { + actualAny, loaded := s.m.LoadOrStore(key, value) + return actualAny.(V), loaded +} + +func (s *SyncMap[K, V]) Delete(key K) { + s.m.Delete(key) +} + +func (s *SyncMap[K, V]) Clear() { + s.m.Clear() +} + +func (s *SyncMap[K, V]) Range(f func(key K, value V) bool) { + s.m.Range(func(key, value any) bool { + return f(key.(K), value.(V)) + }) +} + +// Size returns the approximate number of items in the map. +// Note that this is not a precise count, as the map may be modified +// concurrently while this method is running. +func (s *SyncMap[K, V]) Size() int { + count := 0 + s.m.Range(func(_, _ any) bool { + count++ + return true + }) + return count +} + +func (s *SyncMap[K, V]) ToMap() map[K]V { + m := make(map[K]V, s.Size()) + s.m.Range(func(key, value any) bool { + m[key.(K)] = value.(V) + return true + }) + return m +} diff --git a/internal/compiler/emitHost.go b/internal/compiler/emitHost.go index 875afd34c0..0f73ed940f 100644 --- a/internal/compiler/emitHost.go +++ b/internal/compiler/emitHost.go @@ -4,29 +4,10 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/printer" + "github.com/microsoft/typescript-go/internal/tspath" ) -type WriteFileData struct { - SourceMapUrlPos int - // BuildInfo BuildInfo - Diagnostics []*ast.Diagnostic - DiffersOnlyInMap bool - SkippedDtsWrite bool -} - -// NOTE: EmitHost operations must be thread-safe -type EmitHost interface { - Options() *core.CompilerOptions - SourceFiles() []*ast.SourceFile - UseCaseSensitiveFileNames() bool - GetCurrentDirectory() string - CommonSourceDirectory() string - IsEmitBlocked(file string) bool - WriteFile(fileName string, text string, writeByteOrderMark bool, relatedSourceFiles []*ast.SourceFile, data *WriteFileData) error - GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool) printer.EmitResolver -} - -var _ EmitHost = (*emitHost)(nil) +var _ printer.EmitHost = (*emitHost)(nil) // NOTE: emitHost operations must be thread-safe type emitHost struct { @@ -46,7 +27,7 @@ func (host *emitHost) IsEmitBlocked(file string) bool { return false } -func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool, _ []*ast.SourceFile, _ *WriteFileData) error { +func (host *emitHost) WriteFile(fileName string, text string, writeByteOrderMark bool, _ []*ast.SourceFile, _ *printer.WriteFileData) error { return host.program.host.FS().WriteFile(fileName, text, writeByteOrderMark) } @@ -54,3 +35,7 @@ func (host *emitHost) GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool checker := host.program.GetTypeCheckerForFile(file) return checker.GetEmitResolver(file, skipDiagnostics) } + +func (host *emitHost) GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData { + return host.program.GetSourceFileMetaData(path) +} diff --git a/internal/compiler/emitter.go b/internal/compiler/emitter.go index 784b3c72f7..253b42ece7 100644 --- a/internal/compiler/emitter.go +++ b/internal/compiler/emitter.go @@ -1,11 +1,15 @@ package compiler import ( + "encoding/base64" + "strings" + "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/printer" + "github.com/microsoft/typescript-go/internal/sourcemap" + "github.com/microsoft/typescript-go/internal/stringutil" "github.com/microsoft/typescript-go/internal/transformers" "github.com/microsoft/typescript-go/internal/tspath" ) @@ -20,12 +24,12 @@ const ( ) type emitter struct { - host EmitHost + host printer.EmitHost emitOnly emitOnly emittedFilesList []string emitterDiagnostics ast.DiagnosticsCollection emitSkipped bool - sourceMapDataList []*sourceMapEmitResult + sourceMapDataList []*SourceMapEmitResult writer printer.EmitTextWriter paths *outputPaths sourceFile *ast.SourceFile @@ -33,67 +37,12 @@ type emitter struct { func (e *emitter) emit() { // !!! tracing - e.emitJsFile(e.sourceFile, e.paths.jsFilePath, e.paths.sourceMapFilePath) + e.emitJSFile(e.sourceFile, e.paths.jsFilePath, e.paths.sourceMapFilePath) e.emitDeclarationFile(e.sourceFile, e.paths.declarationFilePath, e.paths.declarationMapPath) e.emitBuildInfo(e.paths.buildInfoPath) } -func (e *emitter) getModuleTransformer(emitContext *printer.EmitContext, resolver binder.ReferenceResolver) *transformers.Transformer { - options := e.host.Options() - - switch options.GetEmitModuleKind() { - case core.ModuleKindPreserve: - // `ESModuleTransformer` contains logic for preserving CJS input syntax in `--module preserve` - return transformers.NewESModuleTransformer(emitContext, options, resolver) - - case core.ModuleKindESNext, - core.ModuleKindES2022, - core.ModuleKindES2020, - core.ModuleKindES2015, - core.ModuleKindNode16, - core.ModuleKindNodeNext, - core.ModuleKindCommonJS: - return transformers.NewImpliedModuleTransformer(emitContext, options, resolver) - - default: - return transformers.NewCommonJSModuleTransformer(emitContext, options, resolver) - } -} - -func (e *emitter) getScriptTransformers(emitContext *printer.EmitContext, sourceFile *ast.SourceFile) []*transformers.Transformer { - var tx []*transformers.Transformer - options := e.host.Options() - - // JS files don't use reference calculations as they don't do import elision, no need to calculate it - importElisionEnabled := !options.VerbatimModuleSyntax.IsTrue() && !ast.IsInJSFile(sourceFile.AsNode()) - - var emitResolver printer.EmitResolver - var referenceResolver binder.ReferenceResolver - if importElisionEnabled { - emitResolver = e.host.GetEmitResolver(sourceFile, false /*skipDiagnostics*/) // !!! conditionally skip diagnostics - emitResolver.MarkLinkedReferencesRecursively(sourceFile) - referenceResolver = emitResolver - } else { - referenceResolver = binder.NewReferenceResolver(binder.ReferenceResolverHooks{}) - } - - // erase types - tx = append(tx, transformers.NewTypeEraserTransformer(emitContext, options)) - - // elide imports - if importElisionEnabled { - tx = append(tx, transformers.NewImportElisionTransformer(emitContext, options, emitResolver)) - } - - // transform `enum`, `namespace`, and parameter properties - tx = append(tx, transformers.NewRuntimeSyntaxTransformer(emitContext, options, referenceResolver)) - - // transform module syntax - tx = append(tx, e.getModuleTransformer(emitContext, referenceResolver)) - return tx -} - -func (e *emitter) emitJsFile(sourceFile *ast.SourceFile, jsFilePath string, sourceMapFilePath string) { +func (e *emitter) emitJSFile(sourceFile *ast.SourceFile, jsFilePath string, sourceMapFilePath string) { options := e.host.Options() if sourceFile == nil || e.emitOnly != emitAll && e.emitOnly != emitOnlyJs || len(jsFilePath) == 0 { @@ -105,13 +54,17 @@ func (e *emitter) emitJsFile(sourceFile *ast.SourceFile, jsFilePath string, sour } emitContext := printer.NewEmitContext() - for _, transformer := range e.getScriptTransformers(emitContext, sourceFile) { + for _, transformer := range transformers.GetScriptTransformers(emitContext, e.host, sourceFile) { sourceFile = transformer.TransformSourceFile(sourceFile) } printerOptions := printer.PrinterOptions{ - NewLine: options.NewLine, - NoEmitHelpers: options.NoEmitHelpers.IsTrue(), + RemoveComments: options.RemoveComments.IsTrue(), + NewLine: options.NewLine, + NoEmitHelpers: options.NoEmitHelpers.IsTrue(), + SourceMap: options.SourceMap.IsTrue(), + InlineSourceMap: options.InlineSourceMap.IsTrue(), + InlineSources: options.InlineSources.IsTrue(), // !!! } @@ -138,22 +91,69 @@ func (e *emitter) emitBuildInfo(buildInfoPath string) { // !!! } -func (e *emitter) printSourceFile(jsFilePath string, sourceMapFilePath string, sourceFile *ast.SourceFile, printer *printer.Printer) bool { +func (e *emitter) printSourceFile(jsFilePath string, sourceMapFilePath string, sourceFile *ast.SourceFile, printer_ *printer.Printer) bool { // !!! sourceMapGenerator + options := e.host.Options() + var sourceMapGenerator *sourcemap.Generator + if shouldEmitSourceMaps(options, sourceFile) { + sourceMapGenerator = sourcemap.NewGenerator( + tspath.GetBaseFileName(tspath.NormalizeSlashes(jsFilePath)), + getSourceRoot(options), + e.getSourceMapDirectory(options, jsFilePath, sourceFile), + tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: e.host.UseCaseSensitiveFileNames(), + CurrentDirectory: e.host.GetCurrentDirectory(), + }, + ) + } + // !!! bundles not implemented, may be deprecated sourceFiles := []*ast.SourceFile{sourceFile} - printer.Write(sourceFile.AsNode(), sourceFile, e.writer /*, sourceMapGenerator*/) + printer_.Write(sourceFile.AsNode(), sourceFile, e.writer, sourceMapGenerator) + + sourceMapUrlPos := -1 + if sourceMapGenerator != nil { + if options.SourceMap.IsTrue() || options.InlineSourceMap.IsTrue() || options.GetAreDeclarationMapsEnabled() { + e.sourceMapDataList = append(e.sourceMapDataList, &SourceMapEmitResult{ + InputSourceFileNames: sourceMapGenerator.Sources(), + SourceMap: sourceMapGenerator.RawSourceMap(), + GeneratedFile: jsFilePath, + }) + } + + sourceMappingURL := e.getSourceMappingURL( + options, + sourceMapGenerator, + jsFilePath, + sourceMapFilePath, + sourceFile, + ) + + if len(sourceMappingURL) > 0 { + if !e.writer.IsAtStartOfLine() { + e.writer.RawWrite(core.IfElse(options.NewLine == core.NewLineKindCRLF, "\r\n", "\n")) + } + sourceMapUrlPos = e.writer.GetTextPos() + e.writer.WriteComment("//# sourceMappingURL=" + sourceMappingURL) + } - // !!! add sourceMapGenerator to sourceMapDataList - // !!! append sourceMappingURL to output - // !!! write the source map - e.writer.WriteLine() + // Write the source map + if len(sourceMapFilePath) > 0 { + sourceMap := sourceMapGenerator.String() + err := e.host.WriteFile(sourceMapFilePath, sourceMap, false /*writeByteOrderMark*/, sourceFiles, nil /*data*/) + if err != nil { + e.emitterDiagnostics.Add(ast.NewCompilerDiagnostic(diagnostics.Could_not_write_file_0_Colon_1, jsFilePath, err.Error())) + } + } + } else { + e.writer.WriteLine() + } // Write the output file text := e.writer.String() - data := &WriteFileData{} // !!! - err := e.host.WriteFile(jsFilePath, text, e.host.Options().EmitBOM == core.TSTrue, sourceFiles, data) + data := &printer.WriteFileData{SourceMapUrlPos: sourceMapUrlPos} // !!! transform diagnostics + err := e.host.WriteFile(jsFilePath, text, e.host.Options().EmitBOM.IsTrue(), sourceFiles, data) if err != nil { e.emitterDiagnostics.Add(ast.NewCompilerDiagnostic(diagnostics.Could_not_write_file_0_Colon_1, jsFilePath, err.Error())) } @@ -176,7 +176,7 @@ func getSourceFilePathInNewDir(fileName string, newDirPath string, currentDirect return tspath.CombinePaths(newDirPath, sourceFilePath) } -func getOwnEmitOutputFilePath(fileName string, host EmitHost, extension string) string { +func getOwnEmitOutputFilePath(fileName string, host printer.EmitHost, extension string) string { compilerOptions := host.Options() var emitOutputFilePathWithoutExtension string if len(compilerOptions.OutDir) > 0 { @@ -195,11 +195,97 @@ func getOwnEmitOutputFilePath(fileName string, host EmitHost, extension string) } func getSourceMapFilePath(jsFilePath string, options *core.CompilerOptions) string { - // !!! + if options.SourceMap.IsTrue() && !options.InlineSourceMap.IsTrue() { + return jsFilePath + ".map" + } return "" } -func getDeclarationEmitOutputFilePath(file string, host EmitHost) string { +func shouldEmitSourceMaps(mapOptions *core.CompilerOptions, sourceFile *ast.SourceFile) bool { + return (mapOptions.SourceMap.IsTrue() || mapOptions.InlineSourceMap.IsTrue()) && + !tspath.FileExtensionIs(sourceFile.FileName(), tspath.ExtensionJson) +} + +func getSourceRoot(mapOptions *core.CompilerOptions) string { + // Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the + // relative paths of the sources list in the sourcemap + sourceRoot := tspath.NormalizeSlashes(mapOptions.SourceRoot) + if len(sourceRoot) > 0 { + sourceRoot = tspath.EnsureTrailingDirectorySeparator(sourceRoot) + } + return sourceRoot +} + +func (e *emitter) getSourceMapDirectory(mapOptions *core.CompilerOptions, filePath string, sourceFile *ast.SourceFile) string { + if len(mapOptions.SourceRoot) > 0 { + return e.host.CommonSourceDirectory() + } + if len(mapOptions.MapRoot) > 0 { + sourceMapDir := tspath.NormalizeSlashes(mapOptions.MapRoot) + if sourceFile != nil { + // For modules or multiple emit files the mapRoot will have directory structure like the sources + // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map + sourceMapDir = tspath.GetDirectoryPath(getSourceFilePathInNewDir( + sourceFile.FileName(), + sourceMapDir, + e.host.GetCurrentDirectory(), + e.host.CommonSourceDirectory(), + e.host.UseCaseSensitiveFileNames(), + )) + } + if tspath.GetRootLength(sourceMapDir) == 0 { + // The relative paths are relative to the common directory + sourceMapDir = tspath.CombinePaths(e.host.CommonSourceDirectory(), sourceMapDir) + } + return sourceMapDir + } + return tspath.GetDirectoryPath(tspath.NormalizePath(filePath)) +} + +func (e *emitter) getSourceMappingURL(mapOptions *core.CompilerOptions, sourceMapGenerator *sourcemap.Generator, filePath string, sourceMapFilePath string, sourceFile *ast.SourceFile) string { + if mapOptions.InlineSourceMap.IsTrue() { + // Encode the sourceMap into the sourceMap url + sourceMapText := sourceMapGenerator.String() + base64SourceMapText := base64.StdEncoding.EncodeToString([]byte(sourceMapText)) + return "data:application/json;base64," + base64SourceMapText + } + + sourceMapFile := tspath.GetBaseFileName(tspath.NormalizeSlashes(sourceMapFilePath)) + if len(mapOptions.MapRoot) > 0 { + sourceMapDir := tspath.NormalizeSlashes(mapOptions.MapRoot) + if sourceFile != nil { + // For modules or multiple emit files the mapRoot will have directory structure like the sources + // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map + sourceMapDir = tspath.GetDirectoryPath(getSourceFilePathInNewDir( + sourceFile.FileName(), + sourceMapDir, + e.host.GetCurrentDirectory(), + e.host.CommonSourceDirectory(), + e.host.UseCaseSensitiveFileNames(), + )) + } + if tspath.GetRootLength(sourceMapDir) == 0 { + // The relative paths are relative to the common directory + sourceMapDir = tspath.CombinePaths(e.host.CommonSourceDirectory(), sourceMapDir) + return stringutil.EncodeURI( + tspath.GetRelativePathToDirectoryOrUrl( + tspath.GetDirectoryPath(tspath.NormalizePath(filePath)), // get the relative sourceMapDir path based on jsFilePath + tspath.CombinePaths(sourceMapDir, sourceMapFile), // this is where user expects to see sourceMap + /*isAbsolutePathAnUrl*/ true, + tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: e.host.UseCaseSensitiveFileNames(), + CurrentDirectory: e.host.GetCurrentDirectory(), + }, + ), + ) + } else { + return stringutil.EncodeURI(tspath.CombinePaths(sourceMapDir, sourceMapFile)) + } + } + return stringutil.EncodeURI(sourceMapFile) +} + +func getDeclarationEmitOutputFilePath(file string, host printer.EmitHost) string { // !!! return "" } @@ -212,7 +298,7 @@ type outputPaths struct { buildInfoPath string } -func getOutputPathsFor(sourceFile *ast.SourceFile, host EmitHost, forceDtsEmit bool) *outputPaths { +func getOutputPathsFor(sourceFile *ast.SourceFile, host printer.EmitHost, forceDtsEmit bool) *outputPaths { options := host.Options() // !!! bundle not implemented, may be deprecated ownOutputFilePath := getOwnEmitOutputFilePath(sourceFile.FileName(), host, core.GetOutputExtension(sourceFile.FileName(), options.Jsx)) @@ -239,7 +325,7 @@ func getOutputPathsFor(sourceFile *ast.SourceFile, host EmitHost, forceDtsEmit b return paths } -func forEachEmittedFile(host EmitHost, action func(emitFileNames *outputPaths, sourceFile *ast.SourceFile) bool, sourceFiles []*ast.SourceFile, options *EmitOptions) bool { +func forEachEmittedFile(host printer.EmitHost, action func(emitFileNames *outputPaths, sourceFile *ast.SourceFile) bool, sourceFiles []*ast.SourceFile, options *EmitOptions) bool { // !!! outFile not yet implemented, may be deprecated for _, sourceFile := range sourceFiles { if action(getOutputPathsFor(sourceFile, host, options.forceDtsEmit), sourceFile) { @@ -249,7 +335,7 @@ func forEachEmittedFile(host EmitHost, action func(emitFileNames *outputPaths, s return false } -func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host EmitHost, forceDtsEmit bool) bool { +func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host printer.EmitHost, forceDtsEmit bool) bool { // !!! Js files are emitted only if option is enabled // Declaration files are not emitted @@ -257,7 +343,12 @@ func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host EmitHost, forceDtsE return false } - // !!! Source file from node_modules are not emitted + // !!! Source file from node_modules are not emitted. In Strada, this depends on module resolution and uses + // `sourceFilesFoundSearchingNodeModules` in `createProgram`. For now, we will just check for `/node_modules/` in + // the file name. + if strings.Contains(sourceFile.FileName(), "/node_modules/") { + return false + } // forcing dts emit => file needs to be emitted if forceDtsEmit { @@ -275,7 +366,7 @@ func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host EmitHost, forceDtsE return false } -func getSourceFilesToEmit(host EmitHost, targetSourceFile *ast.SourceFile, forceDtsEmit bool) []*ast.SourceFile { +func getSourceFilesToEmit(host printer.EmitHost, targetSourceFile *ast.SourceFile, forceDtsEmit bool) []*ast.SourceFile { // !!! outFile not yet implemented, may be deprecated var sourceFiles []*ast.SourceFile if targetSourceFile != nil { diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index 7b388c0ed0..f4fc8c1ecf 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -6,31 +6,47 @@ import ( "slices" "strings" "sync" + "sync/atomic" "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/compiler/module" + "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/module" "github.com/microsoft/typescript-go/internal/tsoptions" "github.com/microsoft/typescript-go/internal/tspath" ) type fileLoader struct { - host CompilerHost - programOptions ProgramOptions - compilerOptions *core.CompilerOptions - - resolver *module.Resolver - resolvedModulesMutex sync.Mutex - resolvedModules map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] - - mu sync.Mutex - wg core.WorkGroup - tasksByFileName map[string]*parseTask - currentNodeModulesDepth int - defaultLibraryPath string - comparePathsOptions tspath.ComparePathsOptions - rootTasks []*parseTask - supportedExtensions []string + host CompilerHost + programOptions ProgramOptions + compilerOptions *core.CompilerOptions + resolver *module.Resolver + defaultLibraryPath string + comparePathsOptions tspath.ComparePathsOptions + wg core.WorkGroup + supportedExtensions []string + + tasksByFileName collections.SyncMap[string, *parseTask] + rootTasks []*parseTask + + totalFileCount atomic.Int32 + libFileCount atomic.Int32 + + factoryMu sync.Mutex + factory ast.NodeFactory +} + +type processedFiles struct { + files []*ast.SourceFile + resolvedModules map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] + sourceFileMetaDatas map[tspath.Path]*ast.SourceFileMetaData + jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier + importHelpersImportSpecifiers map[tspath.Path]*ast.Node +} + +type jsxRuntimeImportSpecifier struct { + moduleReference string + specifier *ast.Node } func processAllProgramFiles( @@ -40,14 +56,13 @@ func processAllProgramFiles( resolver *module.Resolver, rootFiles []string, libs []string, -) (files []*ast.SourceFile, resolvedModules map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule]) { +) processedFiles { supportedExtensions := tsoptions.GetSupportedExtensions(compilerOptions, nil /*extraFileExtensions*/) loader := fileLoader{ host: host, programOptions: programOptions, compilerOptions: compilerOptions, resolver: resolver, - tasksByFileName: make(map[string]*parseTask), defaultLibraryPath: tspath.GetNormalizedAbsolutePath(host.DefaultLibraryPath(), host.GetCurrentDirectory()), comparePathsOptions: tspath.ComparePathsOptions{ UseCaseSensitiveFileNames: host.FS().UseCaseSensitiveFileNames(), @@ -66,17 +81,51 @@ func processAllProgramFiles( loader.wg.RunAndWait() - files, libFiles := []*ast.SourceFile{}, []*ast.SourceFile{} + totalFileCount := int(loader.totalFileCount.Load()) + libFileCount := int(loader.libFileCount.Load()) + + files := make([]*ast.SourceFile, 0, totalFileCount-libFileCount) + libFiles := make([]*ast.SourceFile, 0, totalFileCount) // totalFileCount here since we append files to it later to construct the final list + + resolvedModules := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule], totalFileCount) + sourceFileMetaDatas := make(map[tspath.Path]*ast.SourceFileMetaData, totalFileCount) + var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier + var importHelpersImportSpecifiers map[tspath.Path]*ast.Node + for task := range loader.collectTasks(loader.rootTasks) { + file := task.file if task.isLib { - libFiles = append(libFiles, task.file) + libFiles = append(libFiles, file) } else { - files = append(files, task.file) + files = append(files, file) + } + path := file.Path() + resolvedModules[path] = task.resolutionsInFile + sourceFileMetaDatas[path] = task.metadata + if task.jsxRuntimeImportSpecifier != nil { + if jsxRuntimeImportSpecifiers == nil { + jsxRuntimeImportSpecifiers = make(map[tspath.Path]*jsxRuntimeImportSpecifier, totalFileCount) + } + jsxRuntimeImportSpecifiers[path] = task.jsxRuntimeImportSpecifier + } + if task.importHelpersImportSpecifier != nil { + if importHelpersImportSpecifiers == nil { + importHelpersImportSpecifiers = make(map[tspath.Path]*ast.Node, totalFileCount) + } + importHelpersImportSpecifiers[path] = task.importHelpersImportSpecifier } } loader.sortLibs(libFiles) - return append(libFiles, files...), loader.resolvedModules + allFiles := append(libFiles, files...) + + return processedFiles{ + files: allFiles, + resolvedModules: resolvedModules, + sourceFileMetaDatas: sourceFileMetaDatas, + jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers, + importHelpersImportSpecifiers: importHelpersImportSpecifiers, + } } func (p *fileLoader) addRootTasks(files []string, isLib bool) { @@ -108,15 +157,13 @@ func (p *fileLoader) addAutomaticTypeDirectiveTasks() { func (p *fileLoader) startTasks(tasks []*parseTask) { if len(tasks) > 0 { - p.mu.Lock() - defer p.mu.Unlock() for i, task := range tasks { - // dedup tasks to ensure correct file order, regardless of which task would be started first - if existingTask, ok := p.tasksByFileName[task.normalizedFilePath]; ok { - tasks[i] = existingTask + loadedTask, loaded := p.tasksByFileName.LoadOrStore(task.normalizedFilePath, task) + if loaded { + // dedup tasks to ensure correct file order, regardless of which task would be started first + tasks[i] = loadedTask } else { - p.tasksByFileName[task.normalizedFilePath] = task - task.start(p) + loadedTask.start(p) } } } @@ -124,26 +171,27 @@ func (p *fileLoader) startTasks(tasks []*parseTask) { func (p *fileLoader) collectTasks(tasks []*parseTask) iter.Seq[*parseTask] { return func(yield func(*parseTask) bool) { - p.collectTasksWorker(tasks, yield) + p.collectTasksWorker(tasks, core.Set[*parseTask]{}, yield) } } -func (p *fileLoader) collectTasksWorker(tasks []*parseTask, yield func(*parseTask) bool) bool { +func (p *fileLoader) collectTasksWorker(tasks []*parseTask, seen core.Set[*parseTask], yield func(*parseTask) bool) bool { for _, task := range tasks { - if _, ok := p.tasksByFileName[task.normalizedFilePath]; ok { - // ensure we only walk each task once - delete(p.tasksByFileName, task.normalizedFilePath) + // ensure we only walk each task once + if seen.Has(task) { + continue + } + seen.Add(task) - if len(task.subTasks) > 0 { - if !p.collectTasksWorker(task.subTasks, yield) { - return false - } + if len(task.subTasks) > 0 { + if !p.collectTasksWorker(task.subTasks, seen, yield) { + return false } + } - if task.file != nil { - if !yield(task) { - return false - } + if task.file != nil { + if !yield(task) { + return false } } } @@ -181,11 +229,25 @@ type parseTask struct { file *ast.SourceFile isLib bool subTasks []*parseTask + + metadata *ast.SourceFileMetaData + resolutionsInFile module.ModeAwareCache[*module.ResolvedModule] + importHelpersImportSpecifier *ast.Node + jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier } func (t *parseTask) start(loader *fileLoader) { + loader.totalFileCount.Add(1) + if t.isLib { + loader.libFileCount.Add(1) + } + loader.wg.Queue(func() { file := loader.parseSourceFile(t.normalizedFilePath) + t.file = file + loader.wg.Queue(func() { + t.metadata = loader.loadSourceFileMetaData(file.Path()) + }) // !!! if noResolve, skip all of this t.subTasks = make([]*parseTask, 0, len(file.ReferencedFiles)+len(file.Imports)+len(file.ModuleAugmentations)) @@ -212,15 +274,28 @@ func (t *parseTask) start(loader *fileLoader) { } } - for _, imp := range loader.resolveImportsAndModuleAugmentations(file) { + toParse, resolutionsInFile, importHelpersImportSpecifier, jsxRuntimeImportSpecifier := loader.resolveImportsAndModuleAugmentations(file) + for _, imp := range toParse { t.addSubTask(imp, false) } - t.file = file + t.resolutionsInFile = resolutionsInFile + t.importHelpersImportSpecifier = importHelpersImportSpecifier + t.jsxRuntimeImportSpecifier = jsxRuntimeImportSpecifier + loader.startTasks(t.subTasks) }) } +func (p *fileLoader) loadSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData { + packageJsonType := p.resolver.GetPackageJsonTypeIfApplicable(string(path)) + impliedNodeFormat := ast.GetImpliedNodeFormatForFile(string(path), packageJsonType) + return &ast.SourceFileMetaData{ + PackageJsonType: packageJsonType, + ImpliedNodeFormat: impliedNodeFormat, + } +} + func (p *fileLoader) parseSourceFile(fileName string) *ast.SourceFile { path := tspath.ToPath(fileName, p.host.GetCurrentDirectory(), p.host.FS().UseCaseSensitiveFileNames()) sourceFile := p.host.GetSourceFile(fileName, path, p.compilerOptions.GetEmitScriptTarget()) @@ -242,20 +317,50 @@ func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containi return tspath.NormalizePath(referencedFileName) } -func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile) []string { - toParse := make([]string, 0, len(file.Imports)) - if len(file.Imports) > 0 || len(file.ModuleAugmentations) > 0 { - moduleNames := getModuleNames(file) - resolutions := p.resolveModuleNames(moduleNames, file) +const externalHelpersModuleNameText = "tslib" // TODO(jakebailey): dedupe + +func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile) ( + toParse []string, + resolutionsInFile module.ModeAwareCache[*module.ResolvedModule], + importHelpersImportSpecifier *ast.Node, + jsxRuntimeImportSpecifier_ *jsxRuntimeImportSpecifier, +) { + moduleNames := make([]*ast.Node, 0, len(file.Imports)+len(file.ModuleAugmentations)+2) + moduleNames = append(moduleNames, file.Imports...) + for _, imp := range file.ModuleAugmentations { + if imp.Kind == ast.KindStringLiteral { + moduleNames = append(moduleNames, imp) + } + // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`. + } - resolutionsInFile := make(module.ModeAwareCache[*module.ResolvedModule], len(resolutions)) + isJavaScriptFile := ast.IsSourceFileJS(file) + isExternalModuleFile := ast.IsExternalModule(file) - p.resolvedModulesMutex.Lock() - defer p.resolvedModulesMutex.Unlock() - if p.resolvedModules == nil { - p.resolvedModules = make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule]) + if isJavaScriptFile || (!file.IsDeclarationFile && (p.compilerOptions.GetIsolatedModules() || isExternalModuleFile)) { + if p.compilerOptions.ImportHelpers.IsTrue() { + specifier := p.createSyntheticImport(externalHelpersModuleNameText, file) + moduleNames = append(moduleNames, specifier) + importHelpersImportSpecifier = specifier + } + + jsxImport := ast.GetJSXRuntimeImport(ast.GetJSXImplicitImportBase(p.compilerOptions, file), p.compilerOptions) + if jsxImport != "" { + specifier := p.createSyntheticImport(jsxImport, file) + moduleNames = append(moduleNames, specifier) + jsxRuntimeImportSpecifier_ = &jsxRuntimeImportSpecifier{ + moduleReference: jsxImport, + specifier: specifier, + } } - p.resolvedModules[file.Path()] = resolutionsInFile + } + + if len(moduleNames) != 0 { + toParse = make([]string, 0, len(moduleNames)) + + resolutions := p.resolveModuleNames(moduleNames, file) + + resolutionsInFile = make(module.ModeAwareCache[*module.ResolvedModule], len(resolutions)) for i, resolution := range resolutions { resolvedFileName := resolution.ResolvedFileName @@ -270,12 +375,19 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile) // - module name comes from the list of imports // - it's not a top level JavaScript module that exceeded the search max - // const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth; + // const elideImport = isJSFileFromNodeModules && currentNodeModulesDepth > maxNodeModuleJsDepth; // Don't add the file if it has a bad extension (e.g. 'tsx' if we don't have '--allowJs') // This may still end up being an untyped module -- the file won't be included but imports will be allowed. - - shouldAddFile := resolution.IsResolved() && tspath.FileExtensionIsOneOf(resolvedFileName, []string{".ts", ".tsx", ".mts", ".cts"}) + hasAllowedExtension := false + if p.compilerOptions.ResolveJsonModule.IsTrue() { + hasAllowedExtension = tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsWithJsonFlat) + } else if p.compilerOptions.AllowJs.IsTrue() { + hasAllowedExtension = tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedJSExtensionsFlat) || tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsFlat) + } else { + hasAllowedExtension = tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsFlat) + } + shouldAddFile := resolution.IsResolved() && hasAllowedExtension // TODO(ercornel): !!!: other checks on whether or not to add the file if shouldAddFile { @@ -284,7 +396,8 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile) } } } - return toParse + + return toParse, resolutionsInFile, importHelpersImportSpecifier, jsxRuntimeImportSpecifier_ } func (p *fileLoader) resolveModuleNames(entries []*ast.Node, file *ast.SourceFile) []*module.ResolvedModule { @@ -305,3 +418,16 @@ func (p *fileLoader) resolveModuleNames(entries []*ast.Node, file *ast.SourceFil return resolvedModules } + +func (p *fileLoader) createSyntheticImport(text string, file *ast.SourceFile) *ast.Node { + p.factoryMu.Lock() + defer p.factoryMu.Unlock() + externalHelpersModuleReference := p.factory.NewStringLiteral(text) + importDecl := p.factory.NewImportDeclaration(nil, nil, externalHelpersModuleReference, nil) + // !!! addInternalEmitFlags(importDecl, InternalEmitFlags.NeverApplyImportHelper); + externalHelpersModuleReference.Parent = importDecl + importDecl.Parent = file.AsNode() + // !!! externalHelpersModuleReference.Flags &^= ast.NodeFlagsSynthesized + // !!! importDecl.Flags &^= ast.NodeFlagsSynthesized + return externalHelpersModuleReference +} diff --git a/internal/compiler/host.go b/internal/compiler/host.go index 073be18e69..3db76b350a 100644 --- a/internal/compiler/host.go +++ b/internal/compiler/host.go @@ -7,6 +7,7 @@ import ( "github.com/microsoft/typescript-go/internal/scanner" "github.com/microsoft/typescript-go/internal/tspath" "github.com/microsoft/typescript-go/internal/vfs" + "github.com/microsoft/typescript-go/internal/vfs/cachedvfs" ) type CompilerHost interface { @@ -32,6 +33,10 @@ type compilerHost struct { defaultLibraryPath string } +func NewCachedFSCompilerHost(options *core.CompilerOptions, currentDirectory string, fs vfs.FS, defaultLibraryPath string) CompilerHost { + return NewCompilerHost(options, currentDirectory, cachedvfs.From(fs), defaultLibraryPath) +} + func NewCompilerHost(options *core.CompilerOptions, currentDirectory string, fs vfs.FS, defaultLibraryPath string) CompilerHost { h := &compilerHost{} h.options = options diff --git a/internal/compiler/module/cache.go b/internal/compiler/module/cache.go deleted file mode 100644 index f826be84db..0000000000 --- a/internal/compiler/module/cache.go +++ /dev/null @@ -1,376 +0,0 @@ -package module - -import ( - "slices" - "strings" - "sync" - - "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/compiler/packagejson" - "github.com/microsoft/typescript-go/internal/core" - "github.com/microsoft/typescript-go/internal/tspath" -) - -type ModeAwareCache[T any] map[ModeAwareCacheKey]T - -type caches struct { - moduleNameCache *resolutionCache[*ResolvedModule] - typeReferenceDirectiveCache *resolutionCache[*ResolvedTypeReferenceDirective] - packageJsonInfoCache *packagejson.InfoCache - resolvedTypeReferenceDirectiveLookupLocations map[*ResolvedTypeReferenceDirective]*LookupLocations - - // Cached representation for `core.CompilerOptions.paths`. - // Doesn't handle other path patterns like in `typesVersions`. - parsedPatternsForPathsOnce sync.Once - parsedPatternsForPaths *parsedPatterns -} - -func newCaches( - currentDirectory string, - useCaseSensitiveFileNames bool, - options *core.CompilerOptions, -) caches { - optionsToRedirectsKey := make(map[*core.CompilerOptions]string) - getOriginalOrResolvedModuleFileName := func(result *ResolvedModule) tspath.Path { - if result.OriginalPath != "" { - return tspath.ToPath(result.OriginalPath, currentDirectory, useCaseSensitiveFileNames) - } - return tspath.ToPath(result.ResolvedFileName, currentDirectory, useCaseSensitiveFileNames) - } - getOriginalOrResolvedTypeReferenceFileName := func(result *ResolvedTypeReferenceDirective) tspath.Path { - if result.OriginalPath != "" { - return tspath.ToPath(result.OriginalPath, currentDirectory, useCaseSensitiveFileNames) - } - return tspath.ToPath(result.ResolvedFileName, currentDirectory, useCaseSensitiveFileNames) - } - return caches{ - moduleNameCache: newResolutionCache(currentDirectory, useCaseSensitiveFileNames, options, getOriginalOrResolvedModuleFileName, optionsToRedirectsKey, false /*isReadonly*/), - typeReferenceDirectiveCache: newResolutionCache(currentDirectory, useCaseSensitiveFileNames, options, getOriginalOrResolvedTypeReferenceFileName, optionsToRedirectsKey, false /*isReadonly*/), - packageJsonInfoCache: packagejson.NewInfoCache(currentDirectory, useCaseSensitiveFileNames), - } -} - -type resolutionCache[T comparable] struct { - perDirectoryResolutionCache[T] - nonRelativeNameResolutionCache[T] - mu sync.RWMutex - lookupLocations map[T]*LookupLocations - isReadonly bool -} - -func newResolutionCache[T comparable]( - currentDirectory string, - useCaseSensitiveFileNames bool, - options *core.CompilerOptions, - getResolvedFileName func(result T) tspath.Path, - optionsToRedirectsKey map[*core.CompilerOptions]string, - isReadonly bool, -) *resolutionCache[T] { - return &resolutionCache[T]{ - perDirectoryResolutionCache: newPerDirectoryResolutionCache[T](currentDirectory, useCaseSensitiveFileNames, options, optionsToRedirectsKey), - nonRelativeNameResolutionCache: newNonRelativeNameResolutionCache[T](currentDirectory, useCaseSensitiveFileNames, options, getResolvedFileName, optionsToRedirectsKey), - isReadonly: isReadonly, - } -} - -func (c *resolutionCache[T]) getLookupLocations(resolved T) *LookupLocations { - c.mu.RLock() - defer c.mu.RUnlock() - return c.lookupLocations[resolved] -} - -func (c *resolutionCache[T]) setLookupLocations(resolved T, failedLookupLocations []string, affectingLocations []string, resolutionDiagnostics []ast.Diagnostic) { - c.mu.Lock() - defer c.mu.Unlock() - if c.lookupLocations == nil { - c.lookupLocations = make(map[T]*LookupLocations) - } - c.lookupLocations[resolved] = &LookupLocations{ - FailedLookupLocations: failedLookupLocations, - AffectingLocations: affectingLocations, - ResolutionDiagnostics: resolutionDiagnostics, - } -} - -func (c *resolutionCache[T]) appendLookupLocations(resolved T, failedLookupLocations []string, affectingLocations []string, resolutionDiagnostics []ast.Diagnostic) { - c.mu.Lock() - defer c.mu.Unlock() - lookupLocations := c.lookupLocations[resolved] - lookupLocations.FailedLookupLocations = slices.Concat(lookupLocations.FailedLookupLocations, failedLookupLocations) - lookupLocations.AffectingLocations = slices.Concat(lookupLocations.AffectingLocations, affectingLocations) - lookupLocations.ResolutionDiagnostics = slices.Concat(lookupLocations.ResolutionDiagnostics, resolutionDiagnostics) -} - -type perDirectoryResolutionCache[T any] struct { - mu sync.RWMutex - currentDirectory string - useCaseSensitiveFileNames bool - options *core.CompilerOptions - directoryToModuleNameMap *cacheWithRedirects[tspath.Path, ModeAwareCache[T]] -} - -func newPerDirectoryResolutionCache[T any]( - currentDirectory string, - useCaseSensitiveFileNames bool, - options *core.CompilerOptions, - optionsToRedirectsKey map[*core.CompilerOptions]string, -) perDirectoryResolutionCache[T] { - return perDirectoryResolutionCache[T]{ - currentDirectory: currentDirectory, - useCaseSensitiveFileNames: useCaseSensitiveFileNames, - options: options, - directoryToModuleNameMap: newCacheWithRedirects[tspath.Path, ModeAwareCache[T]](options, optionsToRedirectsKey), - } -} - -func (c *perDirectoryResolutionCache[T]) getFromDirectoryCache(nameAndMode ModeAwareCacheKey, directory string, redirectedReference *ResolvedProjectReference) (T, bool) { - c.mu.RLock() - defer c.mu.RUnlock() - result, ok := c.directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)[tspath.ToPath(directory, c.currentDirectory, c.useCaseSensitiveFileNames)][nameAndMode] - return result, ok -} - -func (c *perDirectoryResolutionCache[T]) setInDirectoryCache(nameAndMode ModeAwareCacheKey, directory string, value T, redirectedReference *ResolvedProjectReference) { - cache := c.getOrCreateCacheForDirectory(directory, redirectedReference) - c.mu.Lock() - defer c.mu.Unlock() - cache[nameAndMode] = value -} - -func (c *perDirectoryResolutionCache[T]) getOrCreateCacheForDirectory(directory string, redirectedReference *ResolvedProjectReference) ModeAwareCache[T] { - c.mu.RLock() - cache := c.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(redirectedReference) - key := tspath.ToPath(directory, c.currentDirectory, c.useCaseSensitiveFileNames) - result, ok := cache[key] - c.mu.RUnlock() - if ok { - return result - } - - c.mu.Lock() - defer c.mu.Unlock() - result = make(ModeAwareCache[T]) - cache[key] = result - return result -} - -type nonRelativeNameResolutionCache[T any] struct { - mu sync.RWMutex - currentDirectory string - useCaseSensitiveFileNames bool - options *core.CompilerOptions - getResolvedFileName func(result T) tspath.Path - moduleNameToDirectoryMap *cacheWithRedirects[ModeAwareCacheKey, *perNonRelativeNameCache[T]] -} - -func newNonRelativeNameResolutionCache[T any]( - currentDirectory string, - useCaseSensitiveFileNames bool, - options *core.CompilerOptions, - getResolvedFileName func(result T) tspath.Path, - optionsToRedirectsKey map[*core.CompilerOptions]string, -) nonRelativeNameResolutionCache[T] { - return nonRelativeNameResolutionCache[T]{ - currentDirectory: currentDirectory, - useCaseSensitiveFileNames: useCaseSensitiveFileNames, - options: options, - getResolvedFileName: getResolvedFileName, - moduleNameToDirectoryMap: newCacheWithRedirects[ModeAwareCacheKey, *perNonRelativeNameCache[T]](options, optionsToRedirectsKey), - } -} - -func (c *nonRelativeNameResolutionCache[T]) getFromNonRelativeNameCache(nameAndMode ModeAwareCacheKey, directoryName string, redirectedReference *ResolvedProjectReference) (T, bool) { - if tspath.IsExternalModuleNameRelative(nameAndMode.Name) { - panic("module name must be non-relative") - } - c.mu.RLock() - defer c.mu.RUnlock() - return c.moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)[nameAndMode].get(tspath.ToPath(directoryName, c.currentDirectory, c.useCaseSensitiveFileNames)) -} - -func (c *nonRelativeNameResolutionCache[T]) setInNonRelativeNameCache(nameAndMode ModeAwareCacheKey, directoryName string, value T, redirectedReference *ResolvedProjectReference) { - if tspath.IsExternalModuleNameRelative(nameAndMode.Name) { - panic("module name must be non-relative") - } - cache := c.getOrCreateCacheForNonRelativeName(nameAndMode, redirectedReference) - c.mu.Lock() - defer c.mu.Unlock() - cache.set(tspath.ToPath(directoryName, c.currentDirectory, c.useCaseSensitiveFileNames), value, c.getResolvedFileName) -} - -func (c *nonRelativeNameResolutionCache[T]) getOrCreateCacheForNonRelativeName(nameAndMode ModeAwareCacheKey, redirectedReference *ResolvedProjectReference) *perNonRelativeNameCache[T] { - if tspath.IsExternalModuleNameRelative(nameAndMode.Name) { - panic("module name must be non-relative") - } - c.mu.RLock() - cache := c.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(redirectedReference) - result, ok := cache[nameAndMode] - c.mu.RUnlock() - if ok { - return result - } - - c.mu.Lock() - defer c.mu.Unlock() - result = &perNonRelativeNameCache[T]{} - cache[nameAndMode] = result - return result -} - -type perNonRelativeNameCache[T any] struct { - directoryPathMap map[tspath.Path]T -} - -func (c *perNonRelativeNameCache[T]) get(directory tspath.Path) (result T, ok bool) { - if c == nil { - return result, ok - } - result, ok = c.directoryPathMap[directory] - return result, ok -} - -// At first this function add entry directory -> module resolution result to the table. -// Then it computes the set of parent folders for 'directory' that should have the same module resolution result -// and for every parent folder in set it adds entry: parent -> module resolution. . -// Lets say we first directory name: `/a/b/c/d/e` and resolution result is: `/a/b/bar.ts`. -// Set of parent folders that should have the same result will be: -// -// [ -// /a/b/c/d, /a/b/c, /a/b -// ] -// -// this means that request for module resolution from file in any of these folder will be immediately found in cache. -func (c *perNonRelativeNameCache[T]) set(directory tspath.Path, value T, getResolvedFileName func(result T) tspath.Path) { - // if entry is already in cache do nothing - if _, ok := c.directoryPathMap[directory]; ok { - return - } - if c.directoryPathMap == nil { - c.directoryPathMap = make(map[tspath.Path]T) - } - c.directoryPathMap[directory] = value - resolvedFileName := getResolvedFileName(value) - // find common prefix between directory and resolved file name - // this common prefix should be the shortest path that has the same resolution - // directory: /a/b/c/d/e - // resolvedFileName: /a/b/foo.d.ts - // commonPrefix: /a/b - // for failed lookups cache the result for every directory up to root - commonPrefix := getCommonPrefix(directory, resolvedFileName) - current := directory - for current != commonPrefix { - parent := current.GetDirectoryPath() - if parent == current { - break - } - if _, ok := c.directoryPathMap[parent]; ok { - break - } - c.directoryPathMap[parent] = value - current = parent - } -} - -type cacheWithRedirects[K comparable, V any] struct { - redirectsMap map[*core.CompilerOptions]map[K]V - redirectsKeyToMap map[string]map[K]V - optionsToRedirectsKey map[*core.CompilerOptions]string - ownOptions *core.CompilerOptions - ownMap map[K]V -} - -func newCacheWithRedirects[K comparable, V any](ownOptions *core.CompilerOptions, optionsToRedirectsKey map[*core.CompilerOptions]string) *cacheWithRedirects[K, V] { - cache := &cacheWithRedirects[K, V]{ - redirectsMap: make(map[*core.CompilerOptions]map[K]V), - redirectsKeyToMap: make(map[string]map[K]V), - optionsToRedirectsKey: optionsToRedirectsKey, - ownOptions: ownOptions, - ownMap: make(map[K]V), - } - if ownOptions != nil { - cache.redirectsMap[ownOptions] = cache.ownMap - } - return cache -} - -func (c *cacheWithRedirects[K, V]) getMapOfCacheRedirects(redirectedReference *ResolvedProjectReference) map[K]V { - if redirectedReference == nil { - return c.ownMap - } - return c.getOrCreateMap(redirectedReference.CommandLine.CompilerOptions, false /*create*/) -} - -func (c *cacheWithRedirects[K, V]) getOrCreateMapOfCacheRedirects(redirectedReference *ResolvedProjectReference) map[K]V { - if redirectedReference == nil { - return c.ownMap - } - return c.getOrCreateMap(redirectedReference.CommandLine.CompilerOptions, true /*create*/) -} - -func (c *cacheWithRedirects[K, V]) getOrCreateMap(redirectOptions *core.CompilerOptions, create bool) map[K]V { - if result, ok := c.redirectsMap[redirectOptions]; ok { - return result - } - key := c.getRedirectsCacheKey(redirectOptions) - var result map[K]V - if result = c.redirectsKeyToMap[key]; result == nil { - if c.ownOptions != nil { - ownKey := c.getRedirectsCacheKey(c.ownOptions) - if ownKey == key { - result = c.ownMap - } else if _, ok := c.redirectsKeyToMap[ownKey]; !ok { - c.redirectsKeyToMap[ownKey] = c.ownMap - } - } - if result == nil && create { - result = make(map[K]V) - } - if result != nil { - c.redirectsKeyToMap[key] = result - } - } - if result != nil { - c.redirectsMap[redirectOptions] = result - } - return result -} - -func (c *cacheWithRedirects[K, V]) getRedirectsCacheKey(options *core.CompilerOptions) string { - if key, ok := c.optionsToRedirectsKey[options]; ok { - return key - } - result := getModuleResolutionAffectingOptionsKey(options) - c.optionsToRedirectsKey[options] = result - return result -} - -func getModuleResolutionAffectingOptionsKey(options *core.CompilerOptions) string { - // !!! TODO(andrewbranch) Real implementation depends on command line parser - return string(options.ModuleResolution) -} - -func getCommonPrefix(directory tspath.Path, resolution tspath.Path) tspath.Path { - if resolution == "" { - return resolution - } - resolutionDirectory := resolution.GetDirectoryPath() - - // find first position where directory and resolution differs - i := 0 - limit := min(len(directory), len(resolutionDirectory)) - for i < limit && directory[i] == resolutionDirectory[i] { - i++ - } - if i == len(directory) && (len(resolutionDirectory) == i || resolutionDirectory[i] == '/') { - return directory - } - rootLength := tspath.GetRootLength(string(directory)) - if i < rootLength { - return tspath.Path("") - } - sep := strings.LastIndexByte(string(directory[:i]), '/') - if sep == -1 { - return tspath.Path("") - } - return directory[:max(sep, rootLength)] -} diff --git a/internal/compiler/packagejson/cache.go b/internal/compiler/packagejson/cache.go deleted file mode 100644 index 6c93fc99c7..0000000000 --- a/internal/compiler/packagejson/cache.go +++ /dev/null @@ -1,149 +0,0 @@ -package packagejson - -import ( - "sync" - - "github.com/microsoft/typescript-go/internal/collections" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" - "github.com/microsoft/typescript-go/internal/core" - "github.com/microsoft/typescript-go/internal/semver" - "github.com/microsoft/typescript-go/internal/tspath" -) - -var typeScriptVersion = semver.MustParse(core.Version) - -type PackageJson struct { - Fields - versionPaths VersionPaths - once sync.Once -} - -func (p *PackageJson) GetVersionPaths(trace func(string)) VersionPaths { - p.once.Do(func() { - if p.Fields.TypesVersions.Type == JSONValueTypeNotPresent { - if trace != nil { - trace(diagnostics.X_package_json_does_not_have_a_0_field.Format("typesVersions")) - } - return - } - if p.Fields.TypesVersions.Type != JSONValueTypeObject { - if trace != nil { - trace(diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2.Format("typesVersions", "object", p.Fields.TypesVersions.Type.String())) - } - return - } - - if trace != nil { - trace(diagnostics.X_package_json_has_a_typesVersions_field_with_version_specific_path_mappings.Format("typesVersions")) - } - - for key, value := range p.Fields.TypesVersions.AsObject().Entries() { - keyRange, ok := semver.TryParseVersionRange(key) - if ok { - if trace != nil { - trace(diagnostics.X_package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range.Format(key)) - } - continue - } - if keyRange.Test(&typeScriptVersion) { - if value.Type != JSONValueTypeObject { - if trace != nil { - trace(diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2.Format("typesVersions['"+key+"']", "object", value.Type.String())) - } - return - } - p.versionPaths = VersionPaths{ - Version: key, - pathsJSON: value.AsObject(), - } - return - } - } - - if trace != nil { - trace(diagnostics.X_package_json_does_not_have_a_typesVersions_entry_that_matches_version_0.Format(core.VersionMajorMinor)) - } - }) - return p.versionPaths -} - -type VersionPaths struct { - Version string - pathsJSON *collections.OrderedMap[string, JSONValue] - paths *collections.OrderedMap[string, []string] -} - -func (v *VersionPaths) Exists() bool { - return v != nil && v.Version != "" && v.pathsJSON != nil -} - -func (v *VersionPaths) GetPaths() *collections.OrderedMap[string, []string] { - if !v.Exists() { - return nil - } - if v.paths != nil { - return v.paths - } - paths := collections.NewOrderedMapWithSizeHint[string, []string](v.pathsJSON.Size()) - for key, value := range v.pathsJSON.Entries() { - if value.Type != JSONValueTypeArray { - continue - } - slice := make([]string, len(value.AsArray())) - for i, path := range value.AsArray() { - if path.Type != JSONValueTypeString { - continue - } - slice[i] = path.Value.(string) - } - v.paths.Set(key, slice) - } - v.paths = paths - return v.paths -} - -type InfoCacheEntry struct { - PackageDirectory string - DirectoryExists bool - Contents *PackageJson -} - -func (p *InfoCacheEntry) Exists() bool { - return p != nil && p.Contents != nil -} - -type InfoCache struct { - mu sync.RWMutex - IsReadonly bool - cache map[tspath.Path]InfoCacheEntry - currentDirectory string - useCaseSensitiveFileNames bool -} - -func NewInfoCache(currentDirectory string, useCaseSensitiveFileNames bool) *InfoCache { - return &InfoCache{ - currentDirectory: currentDirectory, - useCaseSensitiveFileNames: useCaseSensitiveFileNames, - } -} - -func (p *InfoCache) Get(packageJsonPath string) *InfoCacheEntry { - p.mu.RLock() - defer p.mu.RUnlock() - key := tspath.ToPath(packageJsonPath, p.currentDirectory, p.useCaseSensitiveFileNames) - entry, ok := p.cache[key] - if !ok { - return nil - } - return &entry -} - -func (p *InfoCache) Set(packageJsonPath string, info *InfoCacheEntry) { - p.mu.Lock() - defer p.mu.Unlock() - key := tspath.ToPath(packageJsonPath, p.currentDirectory, p.useCaseSensitiveFileNames) - if p.cache == nil { - p.cache = make(map[tspath.Path]InfoCacheEntry) - } - p.cache[key] = *info -} diff --git a/internal/compiler/program.go b/internal/compiler/program.go index 91754a537b..07cda89bf4 100644 --- a/internal/compiler/program.go +++ b/internal/compiler/program.go @@ -8,9 +8,9 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" "github.com/microsoft/typescript-go/internal/checker" - "github.com/microsoft/typescript-go/internal/compiler/diagnostics" - "github.com/microsoft/typescript-go/internal/compiler/module" "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/diagnostics" + "github.com/microsoft/typescript-go/internal/module" "github.com/microsoft/typescript-go/internal/parser" "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/scanner" @@ -41,12 +41,15 @@ type Program struct { currentDirectory string configFilePa