@nifrajs/cli 3.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -3
- package/dist/app-files.d.ts +11 -0
- package/dist/app-files.d.ts.map +1 -0
- package/dist/app-files.js +34 -0
- package/dist/app-files.js.map +1 -0
- package/dist/assure-hydration.d.ts +7 -1
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +128 -43
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +16 -2
- package/dist/assure.js.map +1 -1
- package/dist/capabilities-tool.d.ts +5 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +32 -10
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/cdn-check.d.ts +41 -0
- package/dist/cdn-check.d.ts.map +1 -0
- package/dist/cdn-check.js +207 -0
- package/dist/cdn-check.js.map +1 -0
- package/dist/check-diagnostics.d.ts +7 -15
- package/dist/check-diagnostics.d.ts.map +1 -1
- package/dist/check-diagnostics.js +162 -713
- package/dist/check-diagnostics.js.map +1 -1
- package/dist/check-scan.d.ts +58 -7
- package/dist/check-scan.d.ts.map +1 -1
- package/dist/check-scan.js +323 -62
- package/dist/check-scan.js.map +1 -1
- package/dist/check.d.ts +1 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +145 -54
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +42 -16
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +306 -87
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +60 -5
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +298 -33
- package/dist/command-catalog.js.map +1 -1
- package/dist/config-target.d.ts +8 -0
- package/dist/config-target.d.ts.map +1 -0
- package/dist/config-target.js +45 -0
- package/dist/config-target.js.map +1 -0
- package/dist/contracts.d.ts +3 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +56 -16
- package/dist/contracts.js.map +1 -1
- package/dist/db-audit.d.ts +37 -0
- package/dist/db-audit.d.ts.map +1 -0
- package/dist/db-audit.js +99 -0
- package/dist/db-audit.js.map +1 -0
- package/dist/db-child.d.ts +64 -0
- package/dist/db-child.d.ts.map +1 -0
- package/dist/db-child.js +213 -0
- package/dist/db-child.js.map +1 -0
- package/dist/db-config.d.ts +60 -0
- package/dist/db-config.d.ts.map +1 -0
- package/dist/db-config.js +176 -0
- package/dist/db-config.js.map +1 -0
- package/dist/db-tool.d.ts +84 -0
- package/dist/db-tool.d.ts.map +1 -0
- package/dist/db-tool.js +537 -0
- package/dist/db-tool.js.map +1 -0
- package/dist/dev-bun-config.d.ts +20 -13
- package/dist/dev-bun-config.d.ts.map +1 -1
- package/dist/dev-bun-config.js +98 -41
- package/dist/dev-bun-config.js.map +1 -1
- package/dist/dev-feed-tool.d.ts +106 -0
- package/dist/dev-feed-tool.d.ts.map +1 -0
- package/dist/dev-feed-tool.js +713 -0
- package/dist/dev-feed-tool.js.map +1 -0
- package/dist/dev-server-client.d.ts +67 -0
- package/dist/dev-server-client.d.ts.map +1 -0
- package/dist/dev-server-client.js +195 -0
- package/dist/dev-server-client.js.map +1 -0
- package/dist/diagnostics.d.ts +86 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +85 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/diff-tool.d.ts +3 -3
- package/dist/diff-tool.d.ts.map +1 -1
- package/dist/diff-tool.js +6 -5
- package/dist/diff-tool.js.map +1 -1
- package/dist/docs-search.d.ts.map +1 -1
- package/dist/docs-search.js +12 -4
- package/dist/docs-search.js.map +1 -1
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +76 -15
- package/dist/doctor.js.map +1 -1
- package/dist/env-file.d.ts +15 -0
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +73 -1
- package/dist/env-file.js.map +1 -1
- package/dist/fix-recipes.d.ts.map +1 -1
- package/dist/fix-recipes.js +41 -21
- package/dist/fix-recipes.js.map +1 -1
- package/dist/frontend-guidance.js +5 -5
- package/dist/frontend-guidance.js.map +1 -1
- package/dist/i18n-check.d.ts +16 -0
- package/dist/i18n-check.d.ts.map +1 -0
- package/dist/i18n-check.js +154 -0
- package/dist/i18n-check.js.map +1 -0
- package/dist/init-agents.d.ts +49 -13
- package/dist/init-agents.d.ts.map +1 -1
- package/dist/init-agents.js +239 -34
- package/dist/init-agents.js.map +1 -1
- package/dist/internal/code-unit-order.d.ts +4 -0
- package/dist/internal/code-unit-order.d.ts.map +1 -0
- package/dist/internal/code-unit-order.js +6 -0
- package/dist/internal/code-unit-order.js.map +1 -0
- package/dist/internal/script-kind.d.ts +7 -0
- package/dist/internal/script-kind.d.ts.map +1 -0
- package/dist/internal/script-kind.js +12 -0
- package/dist/internal/script-kind.js.map +1 -0
- package/dist/internal/source-facts.d.ts +5 -0
- package/dist/internal/source-facts.d.ts.map +1 -1
- package/dist/internal/source-facts.js +61 -5
- package/dist/internal/source-facts.js.map +1 -1
- package/dist/internal/typescript-import.d.ts +49 -24
- package/dist/internal/typescript-import.d.ts.map +1 -1
- package/dist/internal/typescript-import.js +507 -67
- package/dist/internal/typescript-import.js.map +1 -1
- package/dist/introspect.d.ts +6 -4
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +93 -74
- package/dist/introspect.js.map +1 -1
- package/dist/learn.js +3 -3
- package/dist/learn.js.map +1 -1
- package/dist/levels-tool.d.ts +10 -0
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +33 -3
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts +71 -16
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +78 -18
- package/dist/load.js.map +1 -1
- package/dist/manifest-tool.d.ts.map +1 -1
- package/dist/manifest-tool.js +3 -2
- package/dist/manifest-tool.js.map +1 -1
- package/dist/mcp-app-tool.d.ts.map +1 -1
- package/dist/mcp-app-tool.js +2 -0
- package/dist/mcp-app-tool.js.map +1 -1
- package/dist/mcp-context.d.ts.map +1 -1
- package/dist/mcp-context.js +5 -6
- package/dist/mcp-context.js.map +1 -1
- package/dist/mcp-delegate.d.ts +57 -0
- package/dist/mcp-delegate.d.ts.map +1 -0
- package/dist/mcp-delegate.js +130 -0
- package/dist/mcp-delegate.js.map +1 -0
- package/dist/mcp-docs-tools.d.ts.map +1 -1
- package/dist/mcp-docs-tools.js +23 -5
- package/dist/mcp-docs-tools.js.map +1 -1
- package/dist/mcp-exec.d.ts +3 -0
- package/dist/mcp-exec.d.ts.map +1 -1
- package/dist/mcp-exec.js +263 -131
- package/dist/mcp-exec.js.map +1 -1
- package/dist/mcp-http.d.ts.map +1 -1
- package/dist/mcp-http.js +20 -5
- package/dist/mcp-http.js.map +1 -1
- package/dist/mcp-io.d.ts +26 -0
- package/dist/mcp-io.d.ts.map +1 -1
- package/dist/mcp-io.js +113 -0
- package/dist/mcp-io.js.map +1 -1
- package/dist/mcp-isolate.d.ts +48 -0
- package/dist/mcp-isolate.d.ts.map +1 -0
- package/dist/mcp-isolate.js +222 -0
- package/dist/mcp-isolate.js.map +1 -0
- package/dist/mcp-path.d.ts +10 -0
- package/dist/mcp-path.d.ts.map +1 -0
- package/dist/mcp-path.js +51 -0
- package/dist/mcp-path.js.map +1 -0
- package/dist/mcp-project-child.d.ts +74 -0
- package/dist/mcp-project-child.d.ts.map +1 -0
- package/dist/mcp-project-child.js +130 -0
- package/dist/mcp-project-child.js.map +1 -0
- package/dist/mcp-reflect.d.ts.map +1 -1
- package/dist/mcp-reflect.js +2 -2
- package/dist/mcp-reflect.js.map +1 -1
- package/dist/mcp-render.d.ts.map +1 -1
- package/dist/mcp-render.js +64 -45
- package/dist/mcp-render.js.map +1 -1
- package/dist/mcp-root.d.ts +37 -9
- package/dist/mcp-root.d.ts.map +1 -1
- package/dist/mcp-root.js +124 -25
- package/dist/mcp-root.js.map +1 -1
- package/dist/mcp-run.d.ts +18 -1
- package/dist/mcp-run.d.ts.map +1 -1
- package/dist/mcp-run.js +159 -55
- package/dist/mcp-run.js.map +1 -1
- package/dist/mcp-ws.js +4 -1
- package/dist/mcp-ws.js.map +1 -1
- package/dist/mcp.d.ts +18 -5
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +165 -82
- package/dist/mcp.js.map +1 -1
- package/dist/migrate-layout.d.ts +44 -0
- package/dist/migrate-layout.d.ts.map +1 -0
- package/dist/migrate-layout.js +982 -0
- package/dist/migrate-layout.js.map +1 -0
- package/dist/openapi-tool.d.ts +2 -2
- package/dist/openapi-tool.d.ts.map +1 -1
- package/dist/openapi-tool.js.map +1 -1
- package/dist/openapi-types.d.ts +2 -1
- package/dist/openapi-types.d.ts.map +1 -1
- package/dist/openapi-types.js +240 -12
- package/dist/openapi-types.js.map +1 -1
- package/dist/pipeline-report.d.ts +3 -2
- package/dist/pipeline-report.d.ts.map +1 -1
- package/dist/pipeline-report.js +19 -16
- package/dist/pipeline-report.js.map +1 -1
- package/dist/port.d.ts +5 -4
- package/dist/port.d.ts.map +1 -1
- package/dist/port.js +46 -29
- package/dist/port.js.map +1 -1
- package/dist/project-facts.d.ts +28 -4
- package/dist/project-facts.d.ts.map +1 -1
- package/dist/project-facts.js +12 -2
- package/dist/project-facts.js.map +1 -1
- package/dist/recipes/4.0.0.d.ts +9 -0
- package/dist/recipes/4.0.0.d.ts.map +1 -0
- package/dist/recipes/4.0.0.js +34 -0
- package/dist/recipes/4.0.0.js.map +1 -0
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +2 -0
- package/dist/recipes/index.js.map +1 -1
- package/dist/release-verification.d.ts +11 -1
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +47 -4
- package/dist/release-verification.js.map +1 -1
- package/dist/review.d.ts +21 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +823 -0
- package/dist/review.js.map +1 -0
- package/dist/route-types.d.ts +28 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +106 -0
- package/dist/route-types.js.map +1 -0
- package/dist/rules/codes.d.ts +9 -0
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +9 -0
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/data-guard.d.ts +12 -0
- package/dist/rules/data-guard.d.ts.map +1 -0
- package/dist/rules/data-guard.js +213 -0
- package/dist/rules/data-guard.js.map +1 -0
- package/dist/rules/index.d.ts +3 -0
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +17 -5
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/islands.d.ts.map +1 -1
- package/dist/rules/islands.js +7 -4
- package/dist/rules/islands.js.map +1 -1
- package/dist/rules/legacy.d.ts +3 -1
- package/dist/rules/legacy.d.ts.map +1 -1
- package/dist/rules/legacy.js +829 -34
- package/dist/rules/legacy.js.map +1 -1
- package/dist/rules/nano.d.ts.map +1 -1
- package/dist/rules/nano.js +15 -6
- package/dist/rules/nano.js.map +1 -1
- package/dist/rules/pages.d.ts +15 -0
- package/dist/rules/pages.d.ts.map +1 -0
- package/dist/rules/pages.js +88 -0
- package/dist/rules/pages.js.map +1 -0
- package/dist/rules/routes.d.ts +11 -0
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +180 -2
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/secrets.d.ts +10 -0
- package/dist/rules/secrets.d.ts.map +1 -0
- package/dist/rules/secrets.js +169 -0
- package/dist/rules/secrets.js.map +1 -0
- package/dist/rules/security.d.ts +7 -0
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +171 -65
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/typescript.d.ts +16 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +59 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/rules/zones.d.ts +17 -0
- package/dist/rules/zones.d.ts.map +1 -0
- package/dist/rules/zones.js +174 -0
- package/dist/rules/zones.js.map +1 -0
- package/dist/scaffold.d.ts +25 -12
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +154 -90
- package/dist/scaffold.js.map +1 -1
- package/dist/sdk.d.ts +17 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +941 -153
- package/dist/sdk.js.map +1 -1
- package/dist/search-terms.d.ts +2 -0
- package/dist/search-terms.d.ts.map +1 -1
- package/dist/search-terms.js +23 -8
- package/dist/search-terms.js.map +1 -1
- package/dist/smoke.d.ts +79 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +494 -0
- package/dist/smoke.js.map +1 -0
- package/dist/sync-manifest.d.ts.map +1 -1
- package/dist/sync-manifest.js +2 -1
- package/dist/sync-manifest.js.map +1 -1
- package/dist/sync-routes.d.ts +4 -3
- package/dist/sync-routes.d.ts.map +1 -1
- package/dist/sync-routes.js +4 -3
- package/dist/sync-routes.js.map +1 -1
- package/dist/test-tool.d.ts.map +1 -1
- package/dist/test-tool.js +30 -11
- package/dist/test-tool.js.map +1 -1
- package/dist/types-search.d.ts.map +1 -1
- package/dist/types-search.js +11 -5
- package/dist/types-search.js.map +1 -1
- package/dist/upgrade.d.ts +36 -6
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +167 -29
- package/dist/upgrade.js.map +1 -1
- package/dist/verification-plan.d.ts.map +1 -1
- package/dist/verification-plan.js +8 -0
- package/dist/verification-plan.js.map +1 -1
- package/dist/verification.d.ts.map +1 -1
- package/dist/verification.js +45 -12
- package/dist/verification.js.map +1 -1
- package/dist/web-app-options.d.ts +19 -0
- package/dist/web-app-options.d.ts.map +1 -0
- package/dist/web-app-options.js +49 -0
- package/dist/web-app-options.js.map +1 -0
- package/dist/work-graph.d.ts +3 -0
- package/dist/work-graph.d.ts.map +1 -1
- package/dist/work-graph.js +33 -16
- package/dist/work-graph.js.map +1 -1
- package/docs/examples.json +185 -29
- package/docs/llms-full.txt +4123 -548
- package/docs/types.json +14391 -10060
- package/package.json +19 -11
- package/src/app-files.ts +40 -0
- package/src/assure-hydration.ts +139 -46
- package/src/assure.ts +17 -2
- package/src/capabilities-tool.ts +35 -9
- package/src/cdn-check.ts +268 -0
- package/src/check-diagnostics.ts +199 -797
- package/src/check-scan.ts +394 -63
- package/src/check.ts +146 -58
- package/src/cli.ts +347 -92
- package/src/command-catalog.ts +407 -45
- package/src/config-target.ts +47 -0
- package/src/contracts.ts +66 -15
- package/src/db-audit.ts +128 -0
- package/src/db-child.ts +285 -0
- package/src/db-config.ts +224 -0
- package/src/db-tool.ts +690 -0
- package/src/dev-bun-config.ts +116 -40
- package/src/dev-feed-tool.ts +912 -0
- package/src/dev-server-client.ts +267 -0
- package/src/diagnostics.ts +179 -0
- package/src/diff-tool.ts +6 -5
- package/src/docs-search.ts +10 -3
- package/src/doctor.ts +98 -15
- package/src/env-file.ts +78 -1
- package/src/fix-recipes.ts +44 -31
- package/src/frontend-guidance.ts +5 -5
- package/src/i18n-check.ts +179 -0
- package/src/init-agents.ts +301 -38
- package/src/internal/code-unit-order.ts +5 -0
- package/src/internal/script-kind.ts +11 -0
- package/src/internal/source-facts.ts +96 -22
- package/src/internal/typescript-import.ts +663 -68
- package/src/introspect.ts +93 -82
- package/src/learn.ts +3 -3
- package/src/levels-tool.ts +47 -2
- package/src/load.ts +144 -32
- package/src/manifest-tool.ts +3 -2
- package/src/mcp-app-tool.ts +2 -0
- package/src/mcp-context.ts +5 -7
- package/src/mcp-delegate.ts +162 -0
- package/src/mcp-docs-tools.ts +23 -5
- package/src/mcp-exec.ts +301 -161
- package/src/mcp-http.ts +22 -5
- package/src/mcp-io.ts +130 -0
- package/src/mcp-isolate.ts +287 -0
- package/src/mcp-path.ts +50 -0
- package/src/mcp-project-child.ts +182 -0
- package/src/mcp-reflect.ts +3 -2
- package/src/mcp-render.ts +72 -42
- package/src/mcp-root.ts +130 -24
- package/src/mcp-run.ts +190 -56
- package/src/mcp-ws.ts +4 -1
- package/src/mcp.ts +193 -91
- package/src/migrate-layout.ts +1121 -0
- package/src/openapi-tool.ts +7 -3
- package/src/openapi-types.ts +315 -13
- package/src/pipeline-report.ts +22 -18
- package/src/port.ts +53 -30
- package/src/project-facts.ts +42 -8
- package/src/recipes/4.0.0.ts +35 -0
- package/src/recipes/index.ts +2 -0
- package/src/release-verification.ts +74 -5
- package/src/review.ts +988 -0
- package/src/route-types.ts +133 -0
- package/src/rules/codes.ts +9 -0
- package/src/rules/data-guard.ts +230 -0
- package/src/rules/index.ts +18 -5
- package/src/rules/islands.ts +12 -4
- package/src/rules/legacy.ts +947 -35
- package/src/rules/nano.ts +18 -6
- package/src/rules/pages.ts +99 -0
- package/src/rules/routes.ts +181 -2
- package/src/rules/secrets.ts +174 -0
- package/src/rules/security.ts +198 -70
- package/src/rules/typescript.ts +77 -0
- package/src/rules/zones.ts +195 -0
- package/src/scaffold.ts +175 -98
- package/src/sdk.ts +1215 -158
- package/src/search-terms.ts +24 -7
- package/src/smoke.ts +607 -0
- package/src/sync-manifest.ts +2 -1
- package/src/sync-routes.ts +4 -3
- package/src/test-tool.ts +32 -11
- package/src/types-search.ts +11 -4
- package/src/upgrade.ts +205 -25
- package/src/verification-plan.ts +27 -0
- package/src/verification.ts +50 -12
- package/src/web-app-options.ts +57 -0
- package/src/work-graph.ts +40 -16
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The one place the CLI imports TypeScript from.
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* CLI ships. Making it a hard dependency would have contradicted that for every install.
|
|
9
|
-
*
|
|
10
|
-
* So it is an optional peer, resolved at the moment the rule runs. Every Nifra project has TypeScript
|
|
11
|
-
* - the templates all ship a `typecheck` script - so this resolves in practice; the point is that an
|
|
12
|
-
* install does not pay for it.
|
|
4
|
+
* The CLI supports the legacy compiler API shipped by TypeScript 5 and 6 and the
|
|
5
|
+
* split API shipped by TypeScript 7. The scanners only need a small AST surface,
|
|
6
|
+
* so TypeScript 7 is presented through a compatibility facade rather than leaking
|
|
7
|
+
* either compiler's concrete types through the rule registry.
|
|
13
8
|
*/
|
|
14
9
|
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
15
10
|
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
@@ -19,23 +14,57 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
19
14
|
}
|
|
20
15
|
return path;
|
|
21
16
|
};
|
|
22
|
-
import { existsSync } from "node:fs";
|
|
23
|
-
import { dirname, join } from "node:path";
|
|
17
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
18
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
19
|
+
import { pathToFileURL } from "node:url";
|
|
20
|
+
import { diagnostic } from "../diagnostics.js";
|
|
21
|
+
export const NIFRA_TS_UNSUPPORTED = "NIFRA_TS_UNSUPPORTED";
|
|
22
|
+
/** A project compiler was found, but its API is outside the scanner adapter's supported range. */
|
|
23
|
+
export class UnsupportedTypeScriptError extends Error {
|
|
24
|
+
code = NIFRA_TS_UNSUPPORTED;
|
|
25
|
+
version;
|
|
26
|
+
constructor(version) {
|
|
27
|
+
super(unsupportedTypeScriptMessage(version));
|
|
28
|
+
this.name = "UnsupportedTypeScriptError";
|
|
29
|
+
this.version = version;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function isUnsupportedTypeScriptError(error) {
|
|
33
|
+
if (error instanceof UnsupportedTypeScriptError)
|
|
34
|
+
return true;
|
|
35
|
+
if (typeof error !== "object" || error === null)
|
|
36
|
+
return false;
|
|
37
|
+
const candidate = error;
|
|
38
|
+
return (candidate.code === NIFRA_TS_UNSUPPORTED &&
|
|
39
|
+
typeof candidate.version === "string" &&
|
|
40
|
+
typeof candidate.message === "string");
|
|
41
|
+
}
|
|
42
|
+
export function unsupportedTypeScriptMessage(version) {
|
|
43
|
+
return `${NIFRA_TS_UNSUPPORTED}: TypeScript ${version} is outside the compiler API versions supported by Nifra scanners. Use TypeScript 5, 6, or 7, or pin the project to TypeScript 6 (for example, \`bun add -d typescript@^6\`).`;
|
|
44
|
+
}
|
|
45
|
+
export function unsupportedTypeScriptDiagnostic(version) {
|
|
46
|
+
return diagnostic({
|
|
47
|
+
code: NIFRA_TS_UNSUPPORTED,
|
|
48
|
+
severity: "error",
|
|
49
|
+
message: unsupportedTypeScriptMessage(version),
|
|
50
|
+
fix: {
|
|
51
|
+
recipe: "toolchain.install-typescript",
|
|
52
|
+
command: "bun add -d typescript@^6",
|
|
53
|
+
},
|
|
54
|
+
verify: "nifra check --lints-only",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
24
57
|
/**
|
|
25
|
-
* Is this module actually the compiler, rather than
|
|
26
|
-
*
|
|
27
|
-
* The `typescript` package name also carries small non-compiler entry points (a version stub, for
|
|
28
|
-
* one), and a resolver that falls back to a global download cache can hand one of those back. They
|
|
29
|
-
* import cleanly and then explode on first use - `undefined is not an object (evaluating
|
|
30
|
-
* 'ts.ScriptKind.TSX')` deep inside a scan - which reads as a Nifra bug rather than as "the compiler
|
|
31
|
-
* we loaded is not a compiler". Checking the two members every caller needs turns that into a
|
|
32
|
-
* resolution miss, which the fallbacks below already know how to handle.
|
|
58
|
+
* Is this module actually the legacy compiler, rather than TypeScript 7's version
|
|
59
|
+
* entry point or another package published under the same name?
|
|
33
60
|
*/
|
|
34
61
|
function isCompiler(module) {
|
|
35
62
|
if (typeof module !== "object" || module === null)
|
|
36
63
|
return false;
|
|
37
64
|
const api = module;
|
|
38
|
-
return typeof api.createSourceFile === "function" &&
|
|
65
|
+
return (typeof api.createSourceFile === "function" &&
|
|
66
|
+
api.ScriptKind !== undefined &&
|
|
67
|
+
typeof api.forEachChild === "function");
|
|
39
68
|
}
|
|
40
69
|
/** Unwrap the CJS default interop wrapper, so both `import * as ts` shapes look the same. */
|
|
41
70
|
function compilerOf(module) {
|
|
@@ -44,16 +73,41 @@ function compilerOf(module) {
|
|
|
44
73
|
const wrapped = module?.default;
|
|
45
74
|
return isCompiler(wrapped) ? wrapped : undefined;
|
|
46
75
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
76
|
+
function versionOf(module) {
|
|
77
|
+
if (typeof module !== "object" || module === null)
|
|
78
|
+
return undefined;
|
|
79
|
+
const version = module.version;
|
|
80
|
+
if (typeof version === "string")
|
|
81
|
+
return version;
|
|
82
|
+
const wrapped = module.default;
|
|
83
|
+
if (typeof wrapped !== "object" || wrapped === null)
|
|
84
|
+
return undefined;
|
|
85
|
+
const wrappedVersion = wrapped.version;
|
|
86
|
+
return typeof wrappedVersion === "string" ? wrappedVersion : undefined;
|
|
87
|
+
}
|
|
88
|
+
function majorVersion(version) {
|
|
89
|
+
const match = /^(\d+)(?:\.|$)/.exec(version.trim());
|
|
90
|
+
if (match === null)
|
|
91
|
+
return undefined;
|
|
92
|
+
const major = Number.parseInt(match[1], 10);
|
|
93
|
+
return Number.isSafeInteger(major) ? major : undefined;
|
|
94
|
+
}
|
|
95
|
+
/** Keep unknown fixture versions usable, but reject known compiler majors outside 5/6/7. */
|
|
96
|
+
function isUnsupportedVersion(version) {
|
|
97
|
+
const major = majorVersion(version);
|
|
98
|
+
return major !== undefined && major > 0 && major !== 5 && major !== 6 && major !== 7;
|
|
99
|
+
}
|
|
100
|
+
function packageVersion(packageRoot) {
|
|
101
|
+
const parsed = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
102
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
103
|
+
return undefined;
|
|
104
|
+
const version = parsed.version;
|
|
105
|
+
return typeof version === "string" ? version : undefined;
|
|
106
|
+
}
|
|
107
|
+
/** Import TypeScript from the CLI's own dependency tree, or `undefined` when it is not installed. */
|
|
108
|
+
async function importTypeScriptModule() {
|
|
55
109
|
try {
|
|
56
|
-
return
|
|
110
|
+
return await import("typescript");
|
|
57
111
|
}
|
|
58
112
|
catch (cause) {
|
|
59
113
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -62,60 +116,446 @@ export async function importTypeScript() {
|
|
|
62
116
|
throw cause;
|
|
63
117
|
}
|
|
64
118
|
}
|
|
119
|
+
/** Import the CLI's own TypeScript only for legacy callers. Project loads use the adapter below. */
|
|
120
|
+
export async function importTypeScript() {
|
|
121
|
+
const module = await importTypeScriptModule();
|
|
122
|
+
if (module === undefined)
|
|
123
|
+
return undefined;
|
|
124
|
+
const version = versionOf(module);
|
|
125
|
+
if (version !== undefined && isUnsupportedVersion(version))
|
|
126
|
+
throw new UnsupportedTypeScriptError(version);
|
|
127
|
+
return compilerOf(module);
|
|
128
|
+
}
|
|
129
|
+
function packageRootForResolvedEntry(entry) {
|
|
130
|
+
return dirname(dirname(entry));
|
|
131
|
+
}
|
|
65
132
|
/**
|
|
66
|
-
* Find the project's compiler the way module resolution would: `node_modules/typescript` in
|
|
67
|
-
* then each parent directory up to the filesystem root
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* The walk is deliberate, not a fallback for a missing resolver. `Bun.resolveSync` memoizes a
|
|
71
|
-
* specifier for the life of the process AND auto-installs from the global download cache when the
|
|
72
|
-
* project has none, so a long-lived process (the MCP server) that first resolved `typescript` before
|
|
73
|
-
* `bun install` kept handing back that cache entry afterwards - the typecheck went phantom until the
|
|
74
|
-
* server was restarted. A filesystem probe is re-answered every call, so an install that lands
|
|
75
|
-
* mid-session is picked up on the next scan.
|
|
133
|
+
* Find the project's compiler the way module resolution would: `node_modules/typescript` in
|
|
134
|
+
* `root`, then each parent directory up to the filesystem root. This filesystem probe is
|
|
135
|
+
* deliberate: Bun's resolver can memoize a missing package for a long-lived MCP process.
|
|
76
136
|
*/
|
|
77
137
|
function resolveProjectTypeScript(root) {
|
|
78
138
|
let dir = root;
|
|
79
139
|
while (true) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
// (rather than importing the directory) keeps a package whose main entry is a stub out of play.
|
|
83
|
-
const entry = join(pkg, "lib", "typescript.js");
|
|
140
|
+
const packageRoot = join(dir, "node_modules", "typescript");
|
|
141
|
+
const entry = join(packageRoot, "lib", "typescript.js");
|
|
84
142
|
if (existsSync(entry))
|
|
85
|
-
return entry;
|
|
86
|
-
if (existsSync(join(
|
|
87
|
-
return
|
|
143
|
+
return { packageRoot, entry, version: packageVersion(packageRoot) };
|
|
144
|
+
if (existsSync(join(packageRoot, "package.json"))) {
|
|
145
|
+
return { packageRoot, entry: packageRoot, version: packageVersion(packageRoot) };
|
|
146
|
+
}
|
|
88
147
|
const parent = dirname(dir);
|
|
89
148
|
if (parent === dir)
|
|
90
149
|
return undefined;
|
|
91
150
|
dir = parent;
|
|
92
151
|
}
|
|
93
152
|
}
|
|
153
|
+
function normalizedPath(path) {
|
|
154
|
+
return resolve(path).replaceAll("\\", "/");
|
|
155
|
+
}
|
|
156
|
+
// TypeScript 7 canonicalizes Windows paths case-insensitively before virtual-FS callbacks.
|
|
157
|
+
function pathIdentity(path) {
|
|
158
|
+
const normalized = normalizedPath(path);
|
|
159
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
160
|
+
}
|
|
161
|
+
function realPath(path) {
|
|
162
|
+
try {
|
|
163
|
+
// Bun's portable realpath can preserve an 8.3 spelling on Windows; the native
|
|
164
|
+
// implementation resolves the same spelling used by the TypeScript 7 service.
|
|
165
|
+
return normalizedPath(realpathSync.native(path));
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return normalizedPath(realpathSync(path));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function canonicalRoot(root) {
|
|
172
|
+
try {
|
|
173
|
+
return realPath(root);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Virtual project roots may not exist yet; the resolved spelling is still the best identity.
|
|
177
|
+
return normalizedPath(root);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function pathVariants(path) {
|
|
181
|
+
const variants = new Set();
|
|
182
|
+
const add = (candidate) => {
|
|
183
|
+
const normalized = normalizedPath(candidate);
|
|
184
|
+
variants.add(normalized);
|
|
185
|
+
if (process.platform === "win32")
|
|
186
|
+
variants.add(normalized.toLowerCase());
|
|
187
|
+
};
|
|
188
|
+
add(path);
|
|
189
|
+
try {
|
|
190
|
+
add(realPath(path));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Virtual fixture files do not exist on disk; their normalized path is sufficient.
|
|
194
|
+
}
|
|
195
|
+
return [...variants];
|
|
196
|
+
}
|
|
197
|
+
function requiredRecord(value, label) {
|
|
198
|
+
if (typeof value !== "object" || value === null)
|
|
199
|
+
throw new Error(`TypeScript 7 ${label} export is invalid`);
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
function requiredConstructor(value, label) {
|
|
203
|
+
if (typeof value !== "function")
|
|
204
|
+
throw new Error(`TypeScript 7 ${label} export is invalid`);
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
function requiredNumberMap(module, name) {
|
|
208
|
+
return requiredRecord(module[name], name);
|
|
209
|
+
}
|
|
210
|
+
function hasNodeKind(node, kinds) {
|
|
211
|
+
if (typeof node !== "object" || node === null)
|
|
212
|
+
return false;
|
|
213
|
+
const kind = node.kind;
|
|
214
|
+
return typeof kind === "number" && kinds.has(kind);
|
|
215
|
+
}
|
|
216
|
+
function syntaxKinds(module, names) {
|
|
217
|
+
const syntaxKind = requiredNumberMap(module, "SyntaxKind");
|
|
218
|
+
const values = names.flatMap((name) => {
|
|
219
|
+
const value = syntaxKind[name];
|
|
220
|
+
return typeof value === "number" ? [value] : [];
|
|
221
|
+
});
|
|
222
|
+
return new Set(values);
|
|
223
|
+
}
|
|
224
|
+
function createVirtualFileSystem(sourceFiles, root) {
|
|
225
|
+
const rootPaths = pathVariants(root);
|
|
226
|
+
const virtualFiles = [];
|
|
227
|
+
const seenFiles = new Set();
|
|
228
|
+
for (const file of sourceFiles.keys()) {
|
|
229
|
+
const identity = pathIdentity(file);
|
|
230
|
+
if (seenFiles.has(identity))
|
|
231
|
+
continue;
|
|
232
|
+
seenFiles.add(identity);
|
|
233
|
+
virtualFiles.push(normalizedPath(file));
|
|
234
|
+
}
|
|
235
|
+
const virtualDirectories = new Set();
|
|
236
|
+
let hasVirtualFileInRoot = false;
|
|
237
|
+
for (const file of virtualFiles) {
|
|
238
|
+
const normalized = normalizedPath(file);
|
|
239
|
+
const rootPath = rootPaths.find((candidate) => normalized === candidate || normalized.startsWith(`${candidate}/`));
|
|
240
|
+
if (rootPath === undefined)
|
|
241
|
+
continue;
|
|
242
|
+
if (!hasVirtualFileInRoot) {
|
|
243
|
+
// Leave an empty overlay transparent so real project files remain discoverable.
|
|
244
|
+
for (const candidate of rootPaths)
|
|
245
|
+
virtualDirectories.add(candidate);
|
|
246
|
+
hasVirtualFileInRoot = true;
|
|
247
|
+
}
|
|
248
|
+
let directory = normalizedPath(dirname(normalized));
|
|
249
|
+
while (directory === rootPath || directory.startsWith(`${rootPath}/`)) {
|
|
250
|
+
for (const variant of pathVariants(directory))
|
|
251
|
+
virtualDirectories.add(variant);
|
|
252
|
+
if (directory === rootPath)
|
|
253
|
+
break;
|
|
254
|
+
directory = normalizedPath(dirname(directory));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const lookup = (fileName) => {
|
|
258
|
+
for (const variant of pathVariants(fileName)) {
|
|
259
|
+
const content = sourceFiles.get(variant);
|
|
260
|
+
if (content !== undefined)
|
|
261
|
+
return content;
|
|
262
|
+
}
|
|
263
|
+
return undefined;
|
|
264
|
+
};
|
|
265
|
+
return {
|
|
266
|
+
readFile: (fileName) => lookup(fileName),
|
|
267
|
+
fileExists: (fileName) => lookup(fileName) !== undefined || undefined,
|
|
268
|
+
directoryExists: (directoryName) => {
|
|
269
|
+
const normalized = pathVariants(directoryName).find((variant) => virtualDirectories.has(variant));
|
|
270
|
+
return normalized === undefined ? undefined : true;
|
|
271
|
+
},
|
|
272
|
+
getAccessibleEntries: (directoryName) => {
|
|
273
|
+
const directory = pathVariants(directoryName).find((variant) => virtualDirectories.has(variant));
|
|
274
|
+
if (directory === undefined)
|
|
275
|
+
return undefined;
|
|
276
|
+
const directoryIdentity = pathIdentity(directory);
|
|
277
|
+
const prefix = directoryIdentity.endsWith("/") ? directoryIdentity : `${directoryIdentity}/`;
|
|
278
|
+
const files = new Set();
|
|
279
|
+
const directories = new Set();
|
|
280
|
+
for (const file of virtualFiles) {
|
|
281
|
+
const normalized = normalizedPath(file);
|
|
282
|
+
const identity = pathIdentity(normalized);
|
|
283
|
+
if (!identity.startsWith(prefix))
|
|
284
|
+
continue;
|
|
285
|
+
const remainder = normalized.slice(prefix.length);
|
|
286
|
+
const slash = remainder.indexOf("/");
|
|
287
|
+
if (slash === -1)
|
|
288
|
+
files.add(remainder);
|
|
289
|
+
else
|
|
290
|
+
directories.add(remainder.slice(0, slash));
|
|
291
|
+
}
|
|
292
|
+
return { files: [...files], directories: [...directories] };
|
|
293
|
+
},
|
|
294
|
+
realpath: (path) => {
|
|
295
|
+
const normalized = pathVariants(path).find((variant) => sourceFiles.has(variant) || virtualDirectories.has(variant));
|
|
296
|
+
return normalized;
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function sourceEntries(root, sourceIndex) {
|
|
301
|
+
const files = new Map();
|
|
302
|
+
if (sourceIndex === undefined)
|
|
303
|
+
return { files, paths: [] };
|
|
304
|
+
const paths = [];
|
|
305
|
+
for (const file of sourceIndex.files) {
|
|
306
|
+
const content = sourceIndex.read(file);
|
|
307
|
+
if (content === undefined)
|
|
308
|
+
continue;
|
|
309
|
+
const absolute = isAbsolute(file) ? file : resolve(root, file);
|
|
310
|
+
const normalized = normalizedPath(absolute);
|
|
311
|
+
paths.push(normalized);
|
|
312
|
+
for (const variant of pathVariants(normalized))
|
|
313
|
+
files.set(variant, content);
|
|
314
|
+
}
|
|
315
|
+
return { files, paths: [...new Set(paths)] };
|
|
316
|
+
}
|
|
317
|
+
/** Build a TypeScript 7 facade over unstable/ast and the async project API. */
|
|
318
|
+
async function createTypeScript7Session(root, packageRoot, version, sourceIndex) {
|
|
319
|
+
// Resolve subpaths from the exact package installation selected above. Resolving from `root`
|
|
320
|
+
// alone can select a different hoisted TypeScript copy when this loader is used from a CLI that
|
|
321
|
+
// has its own peer installation.
|
|
322
|
+
const packageResolveRoot = dirname(packageRoot);
|
|
323
|
+
const astPath = Bun.resolveSync("typescript/unstable/ast", packageResolveRoot);
|
|
324
|
+
const asyncPath = Bun.resolveSync("typescript/unstable/async", packageResolveRoot);
|
|
325
|
+
const astModule = requiredRecord(await import(__rewriteRelativeImportExtension(pathToFileURL(astPath).href)), "ast");
|
|
326
|
+
const asyncModule = requiredRecord(await import(__rewriteRelativeImportExtension(pathToFileURL(asyncPath).href)), "async");
|
|
327
|
+
const API = requiredConstructor(asyncModule.API, "async.API");
|
|
328
|
+
// Windows can return a DOS 8.3 spelling from os.tmpdir() (for example RUNNER~1), while the
|
|
329
|
+
// TypeScript 7 project service resolves the same directory to its long spelling. Keep cwd,
|
|
330
|
+
// virtual files, and open files on one canonical path identity so project discovery is stable.
|
|
331
|
+
const sessionRoot = canonicalRoot(root);
|
|
332
|
+
const { files, paths } = sourceEntries(sessionRoot, sourceIndex);
|
|
333
|
+
const projectConfig = sourceIndex?.projectConfig ?? join(sessionRoot, "tsconfig.json");
|
|
334
|
+
const sourceCache = new Map();
|
|
335
|
+
const sourceByContent = new Map();
|
|
336
|
+
const projects = new Map();
|
|
337
|
+
const api = new API({
|
|
338
|
+
cwd: sessionRoot,
|
|
339
|
+
fs: createVirtualFileSystem(files, sessionRoot),
|
|
340
|
+
});
|
|
341
|
+
let snapshot;
|
|
342
|
+
let configuredProject;
|
|
343
|
+
let closed = false;
|
|
344
|
+
try {
|
|
345
|
+
snapshot = await api.updateSnapshot({
|
|
346
|
+
openFiles: paths,
|
|
347
|
+
...(existsSync(projectConfig) ? { openProject: projectConfig } : {}),
|
|
348
|
+
});
|
|
349
|
+
configuredProject =
|
|
350
|
+
sourceIndex?.projectConfig === undefined ? undefined : snapshot.getProject(projectConfig);
|
|
351
|
+
if (sourceIndex?.projectConfig !== undefined && configuredProject === undefined) {
|
|
352
|
+
throw new Error(`TypeScript 7 could not open project config ${projectConfig}`);
|
|
353
|
+
}
|
|
354
|
+
for (const path of paths) {
|
|
355
|
+
const project = configuredProject ?? (await snapshot.getDefaultProjectForFile(path));
|
|
356
|
+
if (project === undefined) {
|
|
357
|
+
throw new Error(`TypeScript 7 could not create a project for source file ${path}`);
|
|
358
|
+
}
|
|
359
|
+
projects.set(pathIdentity(path), project);
|
|
360
|
+
const source = await project.program.getSourceFile(path);
|
|
361
|
+
if (source === undefined) {
|
|
362
|
+
throw new Error(`TypeScript 7 could not load project source file ${path}`);
|
|
363
|
+
}
|
|
364
|
+
for (const variant of pathVariants(path))
|
|
365
|
+
sourceCache.set(variant, source);
|
|
366
|
+
for (const variant of pathVariants(source.fileName))
|
|
367
|
+
sourceCache.set(variant, source);
|
|
368
|
+
sourceByContent.set(source.text, source);
|
|
369
|
+
const diagnostics = await project.program.getSyntacticDiagnostics(path);
|
|
370
|
+
// Legacy scanners use parseDiagnostics to avoid interpreting recovery nodes. The remote
|
|
371
|
+
// TypeScript 7 source object is extensible in current releases; define the same optional
|
|
372
|
+
// property without copying source text or changing node identities.
|
|
373
|
+
try {
|
|
374
|
+
Object.defineProperty(source, "parseDiagnostics", {
|
|
375
|
+
configurable: true,
|
|
376
|
+
enumerable: false,
|
|
377
|
+
value: diagnostics,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
// A future remote source implementation may be sealed. The scanner remains conservative
|
|
382
|
+
// for files whose syntax diagnostics are not observable through the compatibility object.
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
await snapshot?.dispose();
|
|
388
|
+
await api.close();
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
const functionLikeKinds = syntaxKinds(astModule, [
|
|
392
|
+
"FunctionDeclaration",
|
|
393
|
+
"FunctionExpression",
|
|
394
|
+
"ArrowFunction",
|
|
395
|
+
"MethodDeclaration",
|
|
396
|
+
"GetAccessor",
|
|
397
|
+
"SetAccessor",
|
|
398
|
+
"Constructor",
|
|
399
|
+
"MethodSignature",
|
|
400
|
+
"CallSignature",
|
|
401
|
+
"ConstructSignature",
|
|
402
|
+
"IndexSignature",
|
|
403
|
+
"FunctionType",
|
|
404
|
+
"ConstructorType",
|
|
405
|
+
"JSDocFunctionType",
|
|
406
|
+
"JSDocSignature",
|
|
407
|
+
]);
|
|
408
|
+
const parameterKinds = syntaxKinds(astModule, ["Parameter"]);
|
|
409
|
+
const stringLiteralKinds = syntaxKinds(astModule, [
|
|
410
|
+
"StringLiteral",
|
|
411
|
+
"NoSubstitutionTemplateLiteral",
|
|
412
|
+
]);
|
|
413
|
+
const createSourceFile = (_fileName, sourceText) => {
|
|
414
|
+
if (typeof _fileName !== "string" || typeof sourceText !== "string") {
|
|
415
|
+
throw new TypeError("TypeScript 7 createSourceFile received invalid arguments");
|
|
416
|
+
}
|
|
417
|
+
const absolute = isAbsolute(_fileName) ? _fileName : resolve(sessionRoot, _fileName);
|
|
418
|
+
const cached = pathVariants(absolute)
|
|
419
|
+
.map((variant) => sourceCache.get(variant))
|
|
420
|
+
.find((source) => source !== undefined);
|
|
421
|
+
if (cached !== undefined && cached.text === sourceText)
|
|
422
|
+
return cached;
|
|
423
|
+
const byContent = sourceByContent.get(sourceText);
|
|
424
|
+
if (byContent !== undefined)
|
|
425
|
+
return byContent;
|
|
426
|
+
throw new Error(`TypeScript 7 source file was not preloaded: ${_fileName}`);
|
|
427
|
+
};
|
|
428
|
+
const forEachChild = (node, visit) => {
|
|
429
|
+
if (typeof visit !== "function")
|
|
430
|
+
throw new TypeError("TypeScript 7 forEachChild visitor is invalid");
|
|
431
|
+
if (typeof node !== "object" || node === null)
|
|
432
|
+
throw new TypeError("TypeScript 7 node is invalid");
|
|
433
|
+
const childVisitor = visit;
|
|
434
|
+
return node.forEachChild(childVisitor);
|
|
435
|
+
};
|
|
436
|
+
const isFunctionLike = (node) => hasNodeKind(node, functionLikeKinds);
|
|
437
|
+
const isParameter = (node) => hasNodeKind(node, parameterKinds);
|
|
438
|
+
const isStringLiteralLike = (node) => hasNodeKind(node, stringLiteralKinds);
|
|
439
|
+
const facade = {
|
|
440
|
+
...astModule,
|
|
441
|
+
version,
|
|
442
|
+
createSourceFile,
|
|
443
|
+
forEachChild,
|
|
444
|
+
isFunctionLike,
|
|
445
|
+
isParameter,
|
|
446
|
+
isStringLiteralLike,
|
|
447
|
+
};
|
|
448
|
+
const compiler = Object.freeze(facade);
|
|
449
|
+
const firstProject = projects.values().next().value;
|
|
450
|
+
const semantic = firstProject === undefined
|
|
451
|
+
? undefined
|
|
452
|
+
: {
|
|
453
|
+
checker: firstProject.checker,
|
|
454
|
+
getCheckerForFile: async (file) => {
|
|
455
|
+
const project = projects.get(pathIdentity(file)) ??
|
|
456
|
+
configuredProject ??
|
|
457
|
+
(await snapshot.getDefaultProjectForFile(file));
|
|
458
|
+
return project?.checker;
|
|
459
|
+
},
|
|
460
|
+
getSourceFile: async (file) => {
|
|
461
|
+
const project = projects.get(pathIdentity(file)) ??
|
|
462
|
+
configuredProject ??
|
|
463
|
+
(await snapshot.getDefaultProjectForFile(file));
|
|
464
|
+
return project?.program.getSourceFile(file);
|
|
465
|
+
},
|
|
466
|
+
typeFlags: requiredNumberMap(asyncModule, "TypeFlags"),
|
|
467
|
+
symbolFlags: requiredNumberMap(asyncModule, "SymbolFlags"),
|
|
468
|
+
signatureKind: requiredNumberMap(asyncModule, "SignatureKind"),
|
|
469
|
+
};
|
|
470
|
+
const close = async () => {
|
|
471
|
+
if (closed)
|
|
472
|
+
return;
|
|
473
|
+
closed = true;
|
|
474
|
+
await snapshot?.dispose();
|
|
475
|
+
await api.close();
|
|
476
|
+
};
|
|
477
|
+
return {
|
|
478
|
+
compiler,
|
|
479
|
+
...(semantic === undefined ? {} : { semantic }),
|
|
480
|
+
close,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function legacySession(compiler) {
|
|
484
|
+
return { compiler, close: async () => { } };
|
|
485
|
+
}
|
|
486
|
+
async function resolveProjectSession(root, sourceIndex) {
|
|
487
|
+
const resolved = resolveProjectTypeScript(root);
|
|
488
|
+
if (resolved === undefined) {
|
|
489
|
+
const module = await importTypeScriptModule();
|
|
490
|
+
if (module === undefined)
|
|
491
|
+
return { session: undefined, unsupported: undefined };
|
|
492
|
+
const version = versionOf(module);
|
|
493
|
+
if (version !== undefined && isUnsupportedVersion(version))
|
|
494
|
+
throw new UnsupportedTypeScriptError(version);
|
|
495
|
+
if (majorVersion(version ?? "") === 7) {
|
|
496
|
+
const entry = Bun.resolveSync("typescript", import.meta.dir);
|
|
497
|
+
return {
|
|
498
|
+
session: await createTypeScript7Session(root, packageRootForResolvedEntry(entry), version ?? "7", sourceIndex),
|
|
499
|
+
unsupported: undefined,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
const compiler = compilerOf(module);
|
|
503
|
+
return {
|
|
504
|
+
session: compiler === undefined ? undefined : legacySession(compiler),
|
|
505
|
+
unsupported: undefined,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (resolved.version !== undefined && isUnsupportedVersion(resolved.version)) {
|
|
509
|
+
throw new UnsupportedTypeScriptError(resolved.version);
|
|
510
|
+
}
|
|
511
|
+
const major = resolved.version === undefined ? undefined : majorVersion(resolved.version);
|
|
512
|
+
if (major === 7) {
|
|
513
|
+
return {
|
|
514
|
+
session: await createTypeScript7Session(root, resolved.packageRoot, resolved.version ?? "7", sourceIndex),
|
|
515
|
+
unsupported: undefined,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
const module = await import(__rewriteRelativeImportExtension(pathToFileURL(resolved.entry).href));
|
|
519
|
+
const version = resolved.version ?? versionOf(module);
|
|
520
|
+
if (version !== undefined && isUnsupportedVersion(version))
|
|
521
|
+
throw new UnsupportedTypeScriptError(version);
|
|
522
|
+
const compiler = compilerOf(module);
|
|
523
|
+
if (compiler === undefined) {
|
|
524
|
+
throw new Error(`TypeScript package at ${resolved.packageRoot} does not expose the legacy compiler API`);
|
|
525
|
+
}
|
|
526
|
+
return { session: legacySession(compiler), unsupported: undefined };
|
|
527
|
+
}
|
|
94
528
|
/**
|
|
95
|
-
* Import TypeScript resolved from the PROJECT root first,
|
|
96
|
-
*
|
|
97
|
-
* globally-installed or bunx-run CLI could miss the project's compiler (or load a different major)
|
|
98
|
-
* depending on where the CLI happened to live, while the project's own `typescript` sat unused in
|
|
99
|
-
* its node_modules. Resolving from `root` makes the verdicts a function of the project, not of how
|
|
100
|
-
* the CLI was installed - the same cwd-invariance the typecheck gate's tsc resolution has.
|
|
529
|
+
* Import TypeScript resolved from the PROJECT root first, with TypeScript 7's package exports
|
|
530
|
+
* selected explicitly. A project TypeScript 7 install never falls back to the CLI's compiler.
|
|
101
531
|
*/
|
|
102
|
-
export async function importProjectTypeScript(root) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
532
|
+
export async function importProjectTypeScript(root, sourceIndex) {
|
|
533
|
+
const loaded = await resolveProjectSession(root, sourceIndex);
|
|
534
|
+
return loaded.session?.compiler;
|
|
535
|
+
}
|
|
536
|
+
/** Load a project compiler for scanners while preserving a structured unsupported-toolchain result. */
|
|
537
|
+
export async function loadProjectTypeScript(root, load, sourceIndex) {
|
|
108
538
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
539
|
+
if (load !== undefined) {
|
|
540
|
+
const compiler = await load();
|
|
541
|
+
return {
|
|
542
|
+
compiler,
|
|
543
|
+
session: compiler === undefined ? undefined : legacySession(compiler),
|
|
544
|
+
unsupported: undefined,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const resolved = await resolveProjectSession(root, sourceIndex);
|
|
548
|
+
return {
|
|
549
|
+
compiler: resolved.session?.compiler,
|
|
550
|
+
session: resolved.session,
|
|
551
|
+
unsupported: resolved.unsupported,
|
|
552
|
+
};
|
|
111
553
|
}
|
|
112
|
-
catch (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return importTypeScript();
|
|
118
|
-
throw cause;
|
|
554
|
+
catch (error) {
|
|
555
|
+
if (isUnsupportedTypeScriptError(error)) {
|
|
556
|
+
return { compiler: undefined, session: undefined, unsupported: error };
|
|
557
|
+
}
|
|
558
|
+
throw error;
|
|
119
559
|
}
|
|
120
560
|
}
|
|
121
561
|
//# sourceMappingURL=typescript-import.js.map
|