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:
 
 ![LSP Prototype Screenshot](.github/ls-screenshot.png)
 
@@ -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, &params); 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