@seanhogg/builderforce-webcontainers-core 2026.10.2 → 2026.10.3
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/dist/build.d.ts +42 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +65 -0
- package/dist/build.js.map +1 -0
- package/dist/buildHost.d.ts +31 -0
- package/dist/buildHost.d.ts.map +1 -0
- package/dist/buildHost.js +125 -0
- package/dist/buildHost.js.map +1 -0
- package/dist/buildHtml.d.ts +28 -0
- package/dist/buildHtml.d.ts.map +1 -0
- package/dist/buildHtml.js +74 -0
- package/dist/buildHtml.js.map +1 -0
- package/dist/bundler.d.ts +129 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +79 -0
- package/dist/bundler.js.map +1 -0
- package/dist/check/acquire.d.ts +46 -0
- package/dist/check/acquire.d.ts.map +1 -0
- package/dist/check/acquire.js +179 -0
- package/dist/check/acquire.js.map +1 -0
- package/dist/check/compilerHost.d.ts +22 -0
- package/dist/check/compilerHost.d.ts.map +1 -0
- package/dist/check/compilerHost.js +128 -0
- package/dist/check/compilerHost.js.map +1 -0
- package/dist/check/diagnostics.d.ts +23 -0
- package/dist/check/diagnostics.d.ts.map +1 -0
- package/dist/check/diagnostics.js +28 -0
- package/dist/check/diagnostics.js.map +1 -0
- package/dist/check/index.d.ts +19 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +13 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/projects.d.ts +26 -0
- package/dist/check/projects.d.ts.map +1 -0
- package/dist/check/projects.js +124 -0
- package/dist/check/projects.js.map +1 -0
- package/dist/check/shims.d.ts +29 -0
- package/dist/check/shims.d.ts.map +1 -0
- package/dist/check/shims.js +76 -0
- package/dist/check/shims.js.map +1 -0
- package/dist/check/typeStore.d.ts +57 -0
- package/dist/check/typeStore.d.ts.map +1 -0
- package/dist/check/typeStore.js +89 -0
- package/dist/check/typeStore.js.map +1 -0
- package/dist/check/typecheck.d.ts +29 -0
- package/dist/check/typecheck.d.ts.map +1 -0
- package/dist/check/typecheck.js +91 -0
- package/dist/check/typecheck.js.map +1 -0
- package/dist/compileComponent.d.ts +8 -0
- package/dist/compileComponent.d.ts.map +1 -0
- package/dist/compileComponent.js +22 -0
- package/dist/compileComponent.js.map +1 -0
- package/dist/compileScript.d.ts +19 -4
- package/dist/compileScript.d.ts.map +1 -1
- package/dist/compileScript.js +37 -12
- package/dist/compileScript.js.map +1 -1
- package/dist/components.d.ts +41 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +14 -0
- package/dist/components.js.map +1 -0
- package/dist/detectProject.d.ts +3 -0
- package/dist/detectProject.d.ts.map +1 -1
- package/dist/detectProject.js +16 -6
- package/dist/detectProject.js.map +1 -1
- package/dist/devServer.d.ts +5 -2
- package/dist/devServer.d.ts.map +1 -1
- package/dist/devServer.js +10 -6
- package/dist/devServer.js.map +1 -1
- package/dist/hash.d.ts +2 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +22 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +24 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/installer/bins.d.ts +24 -0
- package/dist/installer/bins.d.ts.map +1 -0
- package/dist/installer/bins.js +56 -0
- package/dist/installer/bins.js.map +1 -0
- package/dist/installer/index.d.ts +14 -0
- package/dist/installer/index.d.ts.map +1 -0
- package/dist/installer/index.js +9 -0
- package/dist/installer/index.js.map +1 -0
- package/dist/installer/install.d.ts +46 -0
- package/dist/installer/install.d.ts.map +1 -0
- package/dist/installer/install.js +245 -0
- package/dist/installer/install.js.map +1 -0
- package/dist/installer/lockfile.d.ts +49 -0
- package/dist/installer/lockfile.d.ts.map +1 -0
- package/dist/installer/lockfile.js +110 -0
- package/dist/installer/lockfile.js.map +1 -0
- package/dist/installer/registry.d.ts +84 -0
- package/dist/installer/registry.d.ts.map +1 -0
- package/dist/installer/registry.js +130 -0
- package/dist/installer/registry.js.map +1 -0
- package/dist/installer/semver.d.ts +38 -0
- package/dist/installer/semver.d.ts.map +1 -0
- package/dist/installer/semver.js +187 -0
- package/dist/installer/semver.js.map +1 -0
- package/dist/installer/spec.d.ts +30 -0
- package/dist/installer/spec.d.ts.map +1 -0
- package/dist/installer/spec.js +30 -0
- package/dist/installer/spec.js.map +1 -0
- package/dist/installer/tar.d.ts +17 -0
- package/dist/installer/tar.d.ts.map +1 -0
- package/dist/installer/tar.js +150 -0
- package/dist/installer/tar.js.map +1 -0
- package/dist/installer/tree.d.ts +48 -0
- package/dist/installer/tree.d.ts.map +1 -0
- package/dist/installer/tree.js +179 -0
- package/dist/installer/tree.js.map +1 -0
- package/dist/node/assert.d.ts +15 -0
- package/dist/node/assert.d.ts.map +1 -0
- package/dist/node/assert.js +137 -0
- package/dist/node/assert.js.map +1 -0
- package/dist/node/buffer.d.ts +84 -0
- package/dist/node/buffer.d.ts.map +1 -0
- package/dist/node/buffer.js +304 -0
- package/dist/node/buffer.js.map +1 -0
- package/dist/node/builtins.d.ts +25 -0
- package/dist/node/builtins.d.ts.map +1 -0
- package/dist/node/builtins.js +101 -0
- package/dist/node/builtins.js.map +1 -0
- package/dist/node/callable.d.ts +13 -0
- package/dist/node/callable.d.ts.map +1 -0
- package/dist/node/callable.js +26 -0
- package/dist/node/callable.js.map +1 -0
- package/dist/node/childProcess.d.ts +13 -0
- package/dist/node/childProcess.d.ts.map +1 -0
- package/dist/node/childProcess.js +143 -0
- package/dist/node/childProcess.js.map +1 -0
- package/dist/node/crypto.d.ts +3 -0
- package/dist/node/crypto.d.ts.map +1 -0
- package/dist/node/crypto.js +180 -0
- package/dist/node/crypto.js.map +1 -0
- package/dist/node/esm.d.ts +9 -0
- package/dist/node/esm.d.ts.map +1 -0
- package/dist/node/esm.js +202 -0
- package/dist/node/esm.js.map +1 -0
- package/dist/node/events.d.ts +40 -0
- package/dist/node/events.d.ts.map +1 -0
- package/dist/node/events.js +160 -0
- package/dist/node/events.js.map +1 -0
- package/dist/node/fs/index.d.ts +7 -0
- package/dist/node/fs/index.d.ts.map +1 -0
- package/dist/node/fs/index.js +270 -0
- package/dist/node/fs/index.js.map +1 -0
- package/dist/node/fs/stats.d.ts +93 -0
- package/dist/node/fs/stats.d.ts.map +1 -0
- package/dist/node/fs/stats.js +104 -0
- package/dist/node/fs/stats.js.map +1 -0
- package/dist/node/fs/sync.d.ts +98 -0
- package/dist/node/fs/sync.d.ts.map +1 -0
- package/dist/node/fs/sync.js +348 -0
- package/dist/node/fs/sync.js.map +1 -0
- package/dist/node/hashes.d.ts +15 -0
- package/dist/node/hashes.d.ts.map +1 -0
- package/dist/node/hashes.js +195 -0
- package/dist/node/hashes.js.map +1 -0
- package/dist/node/http/client.d.ts +35 -0
- package/dist/node/http/client.d.ts.map +1 -0
- package/dist/node/http/client.js +161 -0
- package/dist/node/http/client.js.map +1 -0
- package/dist/node/http/index.d.ts +5 -0
- package/dist/node/http/index.d.ts.map +1 -0
- package/dist/node/http/index.js +125 -0
- package/dist/node/http/index.js.map +1 -0
- package/dist/node/http/server.d.ts +135 -0
- package/dist/node/http/server.d.ts.map +1 -0
- package/dist/node/http/server.js +308 -0
- package/dist/node/http/server.js.map +1 -0
- package/dist/node/http/status.d.ts +3 -0
- package/dist/node/http/status.d.ts.map +1 -0
- package/dist/node/http/status.js +13 -0
- package/dist/node/http/status.js.map +1 -0
- package/dist/node/inspect.d.ts +22 -0
- package/dist/node/inspect.d.ts.map +1 -0
- package/dist/node/inspect.js +172 -0
- package/dist/node/inspect.js.map +1 -0
- package/dist/node/loader.d.ts +91 -0
- package/dist/node/loader.d.ts.map +1 -0
- package/dist/node/loader.js +265 -0
- package/dist/node/loader.js.map +1 -0
- package/dist/node/loop.d.ts +71 -0
- package/dist/node/loop.d.ts.map +1 -0
- package/dist/node/loop.js +189 -0
- package/dist/node/loop.js.map +1 -0
- package/dist/node/misc.d.ts +10 -0
- package/dist/node/misc.d.ts.map +1 -0
- package/dist/node/misc.js +256 -0
- package/dist/node/misc.js.map +1 -0
- package/dist/node/path.d.ts +14 -0
- package/dist/node/path.d.ts.map +1 -0
- package/dist/node/path.js +128 -0
- package/dist/node/path.js.map +1 -0
- package/dist/node/process.d.ts +31 -0
- package/dist/node/process.d.ts.map +1 -0
- package/dist/node/process.js +309 -0
- package/dist/node/process.js.map +1 -0
- package/dist/node/program.d.ts +19 -0
- package/dist/node/program.d.ts.map +1 -0
- package/dist/node/program.js +165 -0
- package/dist/node/program.js.map +1 -0
- package/dist/node/readline.d.ts +2 -0
- package/dist/node/readline.d.ts.map +1 -0
- package/dist/node/readline.js +155 -0
- package/dist/node/readline.js.map +1 -0
- package/dist/node/resolve.d.ts +45 -0
- package/dist/node/resolve.d.ts.map +1 -0
- package/dist/node/resolve.js +206 -0
- package/dist/node/resolve.js.map +1 -0
- package/dist/node/runtime.d.ts +40 -0
- package/dist/node/runtime.d.ts.map +1 -0
- package/dist/node/runtime.js +149 -0
- package/dist/node/runtime.js.map +1 -0
- package/dist/node/stream/index.d.ts +52 -0
- package/dist/node/stream/index.d.ts.map +1 -0
- package/dist/node/stream/index.js +184 -0
- package/dist/node/stream/index.js.map +1 -0
- package/dist/node/stream/readable.d.ts +83 -0
- package/dist/node/stream/readable.d.ts.map +1 -0
- package/dist/node/stream/readable.js +325 -0
- package/dist/node/stream/readable.js.map +1 -0
- package/dist/node/stream/writable.d.ts +80 -0
- package/dist/node/stream/writable.d.ts.map +1 -0
- package/dist/node/stream/writable.js +224 -0
- package/dist/node/stream/writable.js.map +1 -0
- package/dist/node/urlqs.d.ts +22 -0
- package/dist/node/urlqs.d.ts.map +1 -0
- package/dist/node/urlqs.js +165 -0
- package/dist/node/urlqs.js.map +1 -0
- package/dist/node/util.d.ts +37 -0
- package/dist/node/util.d.ts.map +1 -0
- package/dist/node/util.js +160 -0
- package/dist/node/util.js.map +1 -0
- package/dist/node/zlib.d.ts +2 -0
- package/dist/node/zlib.d.ts.map +1 -0
- package/dist/node/zlib.js +133 -0
- package/dist/node/zlib.js.map +1 -0
- package/dist/packageCdn.d.ts +12 -0
- package/dist/packageCdn.d.ts.map +1 -1
- package/dist/packageCdn.js +3 -1
- package/dist/packageCdn.js.map +1 -1
- package/dist/projectConfig.d.ts +6 -2
- package/dist/projectConfig.d.ts.map +1 -1
- package/dist/projectConfig.js +32 -8
- package/dist/projectConfig.js.map +1 -1
- package/dist/shell/builtins.d.ts +23 -0
- package/dist/shell/builtins.d.ts.map +1 -0
- package/dist/shell/builtins.js +131 -0
- package/dist/shell/builtins.js.map +1 -0
- package/dist/shell/context.d.ts +41 -0
- package/dist/shell/context.d.ts.map +1 -0
- package/dist/shell/context.js +65 -0
- package/dist/shell/context.js.map +1 -0
- package/dist/shell/devHandoff.d.ts +18 -0
- package/dist/shell/devHandoff.d.ts.map +1 -0
- package/dist/shell/devHandoff.js +36 -0
- package/dist/shell/devHandoff.js.map +1 -0
- package/dist/shell/exec.d.ts +67 -0
- package/dist/shell/exec.d.ts.map +1 -0
- package/dist/shell/exec.js +247 -0
- package/dist/shell/exec.js.map +1 -0
- package/dist/shell/expand.d.ts +28 -0
- package/dist/shell/expand.d.ts.map +1 -0
- package/dist/shell/expand.js +149 -0
- package/dist/shell/expand.js.map +1 -0
- package/dist/shell/fileCommands.d.ts +10 -0
- package/dist/shell/fileCommands.d.ts.map +1 -0
- package/dist/shell/fileCommands.js +208 -0
- package/dist/shell/fileCommands.js.map +1 -0
- package/dist/shell/lineEditor.d.ts +43 -0
- package/dist/shell/lineEditor.d.ts.map +1 -0
- package/dist/shell/lineEditor.js +234 -0
- package/dist/shell/lineEditor.js.map +1 -0
- package/dist/shell/npm.d.ts +6 -0
- package/dist/shell/npm.d.ts.map +1 -0
- package/dist/shell/npm.js +234 -0
- package/dist/shell/npm.js.map +1 -0
- package/dist/shell/parse.d.ts +73 -0
- package/dist/shell/parse.d.ts.map +1 -0
- package/dist/shell/parse.js +300 -0
- package/dist/shell/parse.js.map +1 -0
- package/dist/shell/program.d.ts +12 -0
- package/dist/shell/program.d.ts.map +1 -0
- package/dist/shell/program.js +219 -0
- package/dist/shell/program.js.map +1 -0
- package/dist/shell/textCommands.d.ts +15 -0
- package/dist/shell/textCommands.d.ts.map +1 -0
- package/dist/shell/textCommands.js +185 -0
- package/dist/shell/textCommands.js.map +1 -0
- package/dist/styleModules.d.ts +6 -0
- package/dist/styleModules.d.ts.map +1 -1
- package/dist/styleModules.js +14 -4
- package/dist/styleModules.js.map +1 -1
- package/dist/svelteCompiler.d.ts +28 -0
- package/dist/svelteCompiler.d.ts.map +1 -0
- package/dist/svelteCompiler.js +13 -0
- package/dist/svelteCompiler.js.map +1 -0
- package/dist/system/commands.d.ts +26 -0
- package/dist/system/commands.d.ts.map +1 -0
- package/dist/system/commands.js +53 -0
- package/dist/system/commands.js.map +1 -0
- package/dist/system/index.d.ts +23 -0
- package/dist/system/index.d.ts.map +1 -0
- package/dist/system/index.js +16 -0
- package/dist/system/index.js.map +1 -0
- package/dist/system/kernel.d.ts +54 -0
- package/dist/system/kernel.d.ts.map +1 -0
- package/dist/system/kernel.js +81 -0
- package/dist/system/kernel.js.map +1 -0
- package/dist/system/ports.d.ts +32 -0
- package/dist/system/ports.d.ts.map +1 -0
- package/dist/system/ports.js +57 -0
- package/dist/system/ports.js.map +1 -0
- package/dist/system/process.d.ts +32 -0
- package/dist/system/process.d.ts.map +1 -0
- package/dist/system/process.js +130 -0
- package/dist/system/process.js.map +1 -0
- package/dist/system/programs.d.ts +10 -0
- package/dist/system/programs.d.ts.map +1 -0
- package/dist/system/programs.js +22 -0
- package/dist/system/programs.js.map +1 -0
- package/dist/system/terminal.d.ts +45 -0
- package/dist/system/terminal.d.ts.map +1 -0
- package/dist/system/terminal.js +127 -0
- package/dist/system/terminal.js.map +1 -0
- package/dist/system/types.d.ts +100 -0
- package/dist/system/types.d.ts.map +1 -0
- package/dist/system/types.js +2 -0
- package/dist/system/types.js.map +1 -0
- package/dist/vfs.d.ts +28 -4
- package/dist/vfs.d.ts.map +1 -1
- package/dist/vfs.js +95 -32
- package/dist/vfs.js.map +1 -1
- package/dist/vueCompiler.d.ts +75 -0
- package/dist/vueCompiler.d.ts.map +1 -0
- package/dist/vueCompiler.js +67 -0
- package/dist/vueCompiler.js.map +1 -0
- package/package.json +18 -2
- package/src/build.ts +105 -0
- package/src/buildHost.ts +154 -0
- package/src/buildHtml.ts +101 -0
- package/src/bundler.ts +190 -0
- package/src/check/acquire.ts +212 -0
- package/src/check/compilerHost.ts +138 -0
- package/src/check/diagnostics.ts +48 -0
- package/src/check/index.ts +28 -0
- package/src/check/projects.ts +149 -0
- package/src/check/shims.ts +88 -0
- package/src/check/typeStore.ts +103 -0
- package/src/check/typecheck.ts +134 -0
- package/src/compileComponent.ts +21 -0
- package/src/compileScript.ts +42 -13
- package/src/components.ts +59 -0
- package/src/detectProject.ts +18 -6
- package/src/devServer.ts +13 -8
- package/src/hash.ts +22 -0
- package/src/index.ts +35 -6
- package/src/installer/bins.ts +64 -0
- package/src/installer/index.ts +13 -0
- package/src/installer/install.ts +275 -0
- package/src/installer/lockfile.ts +146 -0
- package/src/installer/registry.ts +175 -0
- package/src/installer/semver.ts +190 -0
- package/src/installer/spec.ts +53 -0
- package/src/installer/tar.ts +155 -0
- package/src/installer/tree.ts +236 -0
- package/src/node/assert.ts +127 -0
- package/src/node/buffer.ts +304 -0
- package/src/node/builtins.ts +123 -0
- package/src/node/callable.ts +25 -0
- package/src/node/childProcess.ts +164 -0
- package/src/node/crypto.ts +187 -0
- package/src/node/esm.ts +196 -0
- package/src/node/events.ts +176 -0
- package/src/node/fs/index.ts +277 -0
- package/src/node/fs/stats.ts +110 -0
- package/src/node/fs/sync.ts +335 -0
- package/src/node/hashes.ts +171 -0
- package/src/node/http/client.ts +173 -0
- package/src/node/http/index.ts +122 -0
- package/src/node/http/server.ts +308 -0
- package/src/node/http/status.ts +13 -0
- package/src/node/inspect.ts +166 -0
- package/src/node/loader.ts +293 -0
- package/src/node/loop.ts +193 -0
- package/src/node/misc.ts +250 -0
- package/src/node/path.ts +135 -0
- package/src/node/process.ts +324 -0
- package/src/node/program.ts +170 -0
- package/src/node/readline.ts +157 -0
- package/src/node/resolve.ts +216 -0
- package/src/node/runtime.ts +184 -0
- package/src/node/stream/index.ts +196 -0
- package/src/node/stream/readable.ts +345 -0
- package/src/node/stream/writable.ts +244 -0
- package/src/node/urlqs.ts +162 -0
- package/src/node/util.ts +145 -0
- package/src/node/zlib.ts +145 -0
- package/src/packageCdn.ts +11 -1
- package/src/projectConfig.ts +34 -7
- package/src/shell/builtins.ts +141 -0
- package/src/shell/context.ts +89 -0
- package/src/shell/devHandoff.ts +49 -0
- package/src/shell/exec.ts +268 -0
- package/src/shell/expand.ts +145 -0
- package/src/shell/fileCommands.ts +206 -0
- package/src/shell/lineEditor.ts +233 -0
- package/src/shell/npm.ts +229 -0
- package/src/shell/parse.ts +295 -0
- package/src/shell/program.ts +223 -0
- package/src/shell/textCommands.ts +177 -0
- package/src/styleModules.ts +15 -4
- package/src/svelteCompiler.ts +31 -0
- package/src/system/commands.ts +72 -0
- package/src/system/index.ts +22 -0
- package/src/system/kernel.ts +106 -0
- package/src/system/ports.ts +73 -0
- package/src/system/process.ts +158 -0
- package/src/system/programs.ts +31 -0
- package/src/system/terminal.ts +135 -0
- package/src/system/types.ts +103 -0
- package/src/vfs.ts +92 -28
- package/src/vueCompiler.ts +121 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type * as TS from 'typescript';
|
|
2
|
+
import type { VirtualFileSystem } from '../vfs.js';
|
|
3
|
+
import type { PathAlias } from '../projectConfig.js';
|
|
4
|
+
import { dirname, extname, join, normalizePath } from '../paths.js';
|
|
5
|
+
import { isBareSpecifier } from '../resolve.js';
|
|
6
|
+
import { AMBIENT_SHIM_PATH, EMPTY_TYPES_PATH, SHIMMED_TYPE_REFERENCES, SHIM_DIR } from './shims.js';
|
|
7
|
+
import { dtsCandidates, LIB_DIR, packageRequestUrl, TYPES_DIR, type TypeStore } from './typeStore.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A synchronous TypeScript CompilerHost over the project's VFS and a filled
|
|
11
|
+
* {@link TypeStore}. Module resolution is done here rather than by TypeScript's
|
|
12
|
+
* node resolver: project imports follow the runtime's own rules (resolve.ts
|
|
13
|
+
* probing, tsconfig aliases), bare imports go to the types the CDN named, and
|
|
14
|
+
* references inside fetched declaration files resolve as URLs.
|
|
15
|
+
*/
|
|
16
|
+
export interface VirtualHostOptions {
|
|
17
|
+
fs: VirtualFileSystem;
|
|
18
|
+
store: TypeStore;
|
|
19
|
+
typesOrigin: string;
|
|
20
|
+
dependencies: Readonly<Record<string, string>>;
|
|
21
|
+
aliases: readonly PathAlias[];
|
|
22
|
+
/** The ambient shim's text (see shims.ts). */
|
|
23
|
+
shim: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const TS_PROBE = ['.ts', '.tsx', '.d.ts', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
27
|
+
|
|
28
|
+
function extensionOf(ts: typeof TS, path: string): TS.Extension {
|
|
29
|
+
if (path.endsWith('.d.ts')) return ts.Extension.Dts;
|
|
30
|
+
if (path.endsWith('.d.mts')) return ts.Extension.Dmts;
|
|
31
|
+
if (path.endsWith('.d.cts')) return ts.Extension.Dcts;
|
|
32
|
+
const map: Record<string, TS.Extension> = {
|
|
33
|
+
'.ts': ts.Extension.Ts, '.tsx': ts.Extension.Tsx, '.mts': ts.Extension.Mts, '.cts': ts.Extension.Cts,
|
|
34
|
+
'.js': ts.Extension.Js, '.jsx': ts.Extension.Jsx, '.mjs': ts.Extension.Mjs, '.cjs': ts.Extension.Cjs, '.json': ts.Extension.Json,
|
|
35
|
+
};
|
|
36
|
+
return map[extname(path)] ?? ts.Extension.Ts;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** TypeScript's probing for a project-relative path: extensions, `.js` → `.ts`, `index`. */
|
|
40
|
+
function probeProject(fs: VirtualFileSystem, base: string): string | undefined {
|
|
41
|
+
const ext = extname(base);
|
|
42
|
+
if (fs.isFile(base) && TS_PROBE.includes(ext)) return base;
|
|
43
|
+
for (const candidate of TS_PROBE) if (fs.isFile(base + candidate)) return base + candidate;
|
|
44
|
+
if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs') {
|
|
45
|
+
const stem = base.slice(0, -ext.length);
|
|
46
|
+
for (const alt of ['.ts', '.tsx', '.d.ts', '.mts', '.cts']) if (fs.isFile(stem + alt)) return stem + alt;
|
|
47
|
+
}
|
|
48
|
+
for (const candidate of TS_PROBE) if (fs.isFile(join(base, `index${candidate}`))) return join(base, `index${candidate}`);
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createVirtualHost(ts: typeof TS, options: VirtualHostOptions): TS.CompilerHost {
|
|
53
|
+
const { fs, store } = options;
|
|
54
|
+
|
|
55
|
+
const readFile = (path: string): string | undefined => {
|
|
56
|
+
if (path === AMBIENT_SHIM_PATH) return options.shim;
|
|
57
|
+
if (path === EMPTY_TYPES_PATH) return 'export {};\n';
|
|
58
|
+
return fs.readText(path) ?? store.read(path);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function typesFor(url: string | undefined | null): string | undefined {
|
|
62
|
+
return url ? store.virtualPath(url) : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveInTypes(specifier: string, containingUrl: string): string | undefined {
|
|
66
|
+
if (isBareSpecifier(specifier)) return typesFor(store.packages.get(packageRequestUrl(options.typesOrigin, specifier, {})));
|
|
67
|
+
for (const candidate of dtsCandidates(specifier, containingUrl)) {
|
|
68
|
+
const final = store.finalUrl(candidate);
|
|
69
|
+
if (final) return typesFor(final);
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resolveInProject(specifier: string, containingFile: string): string | undefined {
|
|
75
|
+
if (specifier.includes('?')) return undefined; // `?raw`/`?url`: the ambient shim declares them
|
|
76
|
+
if (!isBareSpecifier(specifier)) {
|
|
77
|
+
const base = specifier.startsWith('/') ? normalizePath(specifier) : join(dirname(containingFile), specifier);
|
|
78
|
+
return probeProject(fs, base);
|
|
79
|
+
}
|
|
80
|
+
for (const alias of options.aliases) {
|
|
81
|
+
const matches = alias.wildcard ? specifier.startsWith(alias.prefix) : specifier === alias.prefix;
|
|
82
|
+
if (!matches) continue;
|
|
83
|
+
const rest = alias.wildcard ? specifier.slice(alias.prefix.length) : '';
|
|
84
|
+
for (const target of alias.targets) {
|
|
85
|
+
const hit = probeProject(fs, normalizePath(target + rest));
|
|
86
|
+
if (hit) return hit;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return typesFor(store.packages.get(packageRequestUrl(options.typesOrigin, specifier, options.dependencies)));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveModule(specifier: string, containingFile: string): TS.ResolvedModuleFull | undefined {
|
|
93
|
+
const containingUrl = store.urlOf(containingFile);
|
|
94
|
+
const resolved = containingUrl ? resolveInTypes(specifier, containingUrl) : resolveInProject(specifier, containingFile);
|
|
95
|
+
if (!resolved) return undefined;
|
|
96
|
+
return { resolvedFileName: resolved, extension: extensionOf(ts, resolved), isExternalLibraryImport: resolved.startsWith(`${TYPES_DIR}/`) };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** `/// <reference types>` resolves the same from anywhere: acquisition keyed it by name. */
|
|
100
|
+
function resolveTypeReference(name: string): string | undefined {
|
|
101
|
+
if (SHIMMED_TYPE_REFERENCES.has(name)) return EMPTY_TYPES_PATH;
|
|
102
|
+
return typesFor(store.packages.get(`types:${name}`));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
getSourceFile(fileName, languageVersion) {
|
|
107
|
+
const shared = !fs.isFile(fileName);
|
|
108
|
+
const cached = shared ? store.sourceFiles.get(fileName) : undefined;
|
|
109
|
+
if (cached) return cached;
|
|
110
|
+
const text = readFile(fileName);
|
|
111
|
+
if (text === undefined) return undefined;
|
|
112
|
+
const file = ts.createSourceFile(fileName, text, languageVersion, true);
|
|
113
|
+
// Lib and package files never change for a URL: parse once per store.
|
|
114
|
+
if (shared && fileName !== AMBIENT_SHIM_PATH) store.sourceFiles.set(fileName, file);
|
|
115
|
+
return file;
|
|
116
|
+
},
|
|
117
|
+
getDefaultLibFileName: (compilerOptions) => `${LIB_DIR}/${ts.getDefaultLibFileName(compilerOptions)}`,
|
|
118
|
+
getDefaultLibLocation: () => LIB_DIR,
|
|
119
|
+
writeFile: () => undefined,
|
|
120
|
+
getCurrentDirectory: () => '/',
|
|
121
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
122
|
+
useCaseSensitiveFileNames: () => true,
|
|
123
|
+
getNewLine: () => '\n',
|
|
124
|
+
fileExists: (fileName) => readFile(fileName) !== undefined,
|
|
125
|
+
readFile,
|
|
126
|
+
directoryExists: (dir) => fs.isDirectory(dir) || dir.startsWith(TYPES_DIR) || dir === LIB_DIR || dir === SHIM_DIR,
|
|
127
|
+
getDirectories: () => [],
|
|
128
|
+
resolveModuleNameLiterals: (literals, containingFile) =>
|
|
129
|
+
literals.map((literal) => ({ resolvedModule: resolveModule(literal.text, containingFile) })),
|
|
130
|
+
resolveTypeReferenceDirectiveReferences: (references) =>
|
|
131
|
+
references.map((reference) => {
|
|
132
|
+
const resolved = resolveTypeReference(typeof reference === 'string' ? reference : reference.fileName);
|
|
133
|
+
return {
|
|
134
|
+
resolvedTypeReferenceDirective: resolved ? { primary: true, resolvedFileName: resolved, isExternalLibraryImport: true } : undefined,
|
|
135
|
+
};
|
|
136
|
+
}),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type * as TS from 'typescript';
|
|
2
|
+
|
|
3
|
+
export type DiagnosticCategory = 'error' | 'warning' | 'suggestion' | 'message';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One problem, in a shape an editor (or an agent) can act on without the
|
|
7
|
+
* TypeScript API: positions are 1-based like an editor's gutter, and `file` is
|
|
8
|
+
* the project-relative path (`src/App.tsx`), the same key `FlatFiles` uses.
|
|
9
|
+
*/
|
|
10
|
+
export interface CheckDiagnostic {
|
|
11
|
+
/** Project-relative path; absent for global problems (compiler options, a missing lib). */
|
|
12
|
+
file?: string;
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
message: string;
|
|
16
|
+
/** TypeScript's code (2322 for TS2322). */
|
|
17
|
+
code: number;
|
|
18
|
+
category: DiagnosticCategory;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const CATEGORIES: Record<number, DiagnosticCategory> = { 0: 'warning', 1: 'error', 2: 'suggestion', 3: 'message' };
|
|
22
|
+
|
|
23
|
+
export function toCheckDiagnostic(ts: typeof TS, diagnostic: TS.Diagnostic): CheckDiagnostic {
|
|
24
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
25
|
+
const category = CATEGORIES[diagnostic.category] ?? 'error';
|
|
26
|
+
if (!diagnostic.file || diagnostic.start === undefined) return { line: 1, column: 1, message, code: diagnostic.code, category };
|
|
27
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
28
|
+
return { file: diagnostic.file.fileName.replace(/^\//, ''), line: line + 1, column: character + 1, message, code: diagnostic.code, category };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** `src/App.tsx(3,7): error TS2322: Type 'number' is not assignable to type 'string'.` — tsc's own format. */
|
|
32
|
+
export function formatDiagnostic(diagnostic: CheckDiagnostic): string {
|
|
33
|
+
const where = diagnostic.file ? `${diagnostic.file}(${diagnostic.line},${diagnostic.column}): ` : '';
|
|
34
|
+
return `${where}${diagnostic.category} TS${diagnostic.code}: ${diagnostic.message}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Stable order (file, then position) and no duplicates — a file in two tsconfig projects reports once. */
|
|
38
|
+
export function sortDiagnostics(diagnostics: CheckDiagnostic[]): CheckDiagnostic[] {
|
|
39
|
+
const seen = new Set<string>();
|
|
40
|
+
return diagnostics
|
|
41
|
+
.filter((d) => {
|
|
42
|
+
const key = `${d.file ?? ''}:${d.line}:${d.column}:${d.code}:${d.message}`;
|
|
43
|
+
if (seen.has(key)) return false;
|
|
44
|
+
seen.add(key);
|
|
45
|
+
return true;
|
|
46
|
+
})
|
|
47
|
+
.sort((a, b) => (a.file ?? '').localeCompare(b.file ?? '') || a.line - b.line || a.column - b.column);
|
|
48
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@seanhogg/builderforce-webcontainers-core/check` — type-checking a project in
|
|
3
|
+
* memory. A separate entry point because it is typed against the `typescript`
|
|
4
|
+
* package (an optional peer dependency), which the rest of the core never needs.
|
|
5
|
+
*/
|
|
6
|
+
export { typecheckProject } from './typecheck.js';
|
|
7
|
+
export type { TypecheckOptions, TypecheckResult } from './typecheck.js';
|
|
8
|
+
export { toCheckDiagnostic, formatDiagnostic, sortDiagnostics } from './diagnostics.js';
|
|
9
|
+
export type { CheckDiagnostic, DiagnosticCategory } from './diagnostics.js';
|
|
10
|
+
export { acquireTypes, acquireExtendedConfigs } from './acquire.js';
|
|
11
|
+
export type { FetchLike, FetchResponseLike, AcquireRequest, AcquireOptions } from './acquire.js';
|
|
12
|
+
export { resolveCheckProjects, defaultCompilerOptions, createParseConfigHost } from './projects.js';
|
|
13
|
+
export type { CheckProject } from './projects.js';
|
|
14
|
+
export { createVirtualHost } from './compilerHost.js';
|
|
15
|
+
export type { VirtualHostOptions } from './compilerHost.js';
|
|
16
|
+
export { ambientShim, declaresModule, AMBIENT_SHIM_PATH, SHIMMED_TYPE_REFERENCES } from './shims.js';
|
|
17
|
+
export {
|
|
18
|
+
TypeStore,
|
|
19
|
+
libBaseUrlFor,
|
|
20
|
+
typesPackageName,
|
|
21
|
+
dtsCandidates,
|
|
22
|
+
packageRequestUrl,
|
|
23
|
+
DEFAULT_TYPES_ORIGIN,
|
|
24
|
+
DEFAULT_NPM_BASE_URL,
|
|
25
|
+
TYPES_DIR,
|
|
26
|
+
LIB_DIR,
|
|
27
|
+
} from './typeStore.js';
|
|
28
|
+
export type { TypeSources } from './typeStore.js';
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type * as TS from 'typescript';
|
|
2
|
+
import type { VirtualFileSystem } from '../vfs.js';
|
|
3
|
+
import { dirname, extname, join } from '../paths.js';
|
|
4
|
+
import type { TypeStore } from './typeStore.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Which programs to build, with which options, over which files — what `tsc -b`
|
|
8
|
+
* would derive from the project's tsconfig files.
|
|
9
|
+
*
|
|
10
|
+
* Vite's templates keep a root `tsconfig.json` holding only `references` (to
|
|
11
|
+
* `tsconfig.app.json` and `tsconfig.node.json`); each reference is its own
|
|
12
|
+
* program. With no tsconfig at all, the checker synthesises Vite's defaults for
|
|
13
|
+
* a React + TS app, so a generated project with no config still gets checked.
|
|
14
|
+
*/
|
|
15
|
+
export interface CheckProject {
|
|
16
|
+
/** The tsconfig this came from; undefined when synthesised. */
|
|
17
|
+
configPath?: string;
|
|
18
|
+
options: TS.CompilerOptions;
|
|
19
|
+
rootNames: string[];
|
|
20
|
+
/** Problems parsing the config itself. */
|
|
21
|
+
errors: readonly TS.Diagnostic[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Tool configs (`vite.config.ts`…) describe the build, which runs elsewhere: not checked. */
|
|
25
|
+
const TOOL_CONFIG = /(^|\/)(vite|vitest|svelte|tailwind|postcss|eslint|prettier|playwright)\.config\.[cm]?[jt]s$/;
|
|
26
|
+
const SOURCE_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts'];
|
|
27
|
+
/** "No inputs were found in config file" — a reference covering only tool configs. */
|
|
28
|
+
const NO_INPUTS = 18003;
|
|
29
|
+
|
|
30
|
+
/** Vite's React + TS template, made strict-ish; what a project with no tsconfig gets. */
|
|
31
|
+
export function defaultCompilerOptions(ts: typeof TS, jsxImportSource?: string): TS.CompilerOptions {
|
|
32
|
+
return {
|
|
33
|
+
target: ts.ScriptTarget.ES2020,
|
|
34
|
+
lib: ['lib.es2020.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts'],
|
|
35
|
+
module: ts.ModuleKind.ESNext,
|
|
36
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
37
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
38
|
+
...(jsxImportSource ? { jsxImportSource } : {}),
|
|
39
|
+
strict: true,
|
|
40
|
+
noFallthroughCasesInSwitch: true,
|
|
41
|
+
isolatedModules: true,
|
|
42
|
+
resolveJsonModule: true,
|
|
43
|
+
allowImportingTsExtensions: true,
|
|
44
|
+
esModuleInterop: true,
|
|
45
|
+
skipLibCheck: true,
|
|
46
|
+
noEmit: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Options no in-browser check wants, whatever the config says: nothing is emitted. */
|
|
51
|
+
function forCheck(options: TS.CompilerOptions): TS.CompilerOptions {
|
|
52
|
+
return {
|
|
53
|
+
...options,
|
|
54
|
+
noEmit: true,
|
|
55
|
+
skipLibCheck: true,
|
|
56
|
+
composite: false,
|
|
57
|
+
incremental: false,
|
|
58
|
+
declaration: false,
|
|
59
|
+
declarationMap: false,
|
|
60
|
+
emitDeclarationOnly: false,
|
|
61
|
+
tsBuildInfoFile: undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function globToRegExp(pattern: string): RegExp {
|
|
66
|
+
let source = '';
|
|
67
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
68
|
+
const ch = pattern[i]!;
|
|
69
|
+
if (ch === '*' && pattern[i + 1] === '*' && pattern[i + 2] === '/') {
|
|
70
|
+
source += '(?:[^/]+/)*';
|
|
71
|
+
i += 2;
|
|
72
|
+
} else if (ch === '*') source += '[^/]*';
|
|
73
|
+
else if (ch === '?') source += '[^/]';
|
|
74
|
+
else source += ch.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
75
|
+
}
|
|
76
|
+
return new RegExp(`^${source}$`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A tsconfig `include`/`exclude` spec as a matcher; a bare directory means everything under it. */
|
|
80
|
+
function specMatcher(root: string, spec: string): RegExp {
|
|
81
|
+
let abs = join(root, spec);
|
|
82
|
+
const last = abs.slice(abs.lastIndexOf('/') + 1);
|
|
83
|
+
if (!/[*?]/.test(last) && !extname(last)) abs = `${abs === '/' ? '' : abs}/**/*`;
|
|
84
|
+
return globToRegExp(abs);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The ParseConfigHost the config parser reads through: the VFS plus fetched `extends` packages. */
|
|
88
|
+
export function createParseConfigHost(fs: VirtualFileSystem, store: TypeStore): TS.ParseConfigHost {
|
|
89
|
+
return {
|
|
90
|
+
useCaseSensitiveFileNames: true,
|
|
91
|
+
fileExists: (path) => fs.isFile(path) || store.read(path) !== undefined,
|
|
92
|
+
readFile: (path) => fs.readText(path) ?? store.read(path),
|
|
93
|
+
readDirectory(rootDir, extensions, excludes, includes) {
|
|
94
|
+
const include = (includes ?? ['**/*']).map((spec) => specMatcher(rootDir, spec));
|
|
95
|
+
const exclude = (excludes ?? []).map((spec) => specMatcher(rootDir, spec));
|
|
96
|
+
return fs.list().filter((path) =>
|
|
97
|
+
extensions.some((ext) => path.endsWith(ext)) &&
|
|
98
|
+
!path.includes('/node_modules/') &&
|
|
99
|
+
include.some((re) => re.test(path)) &&
|
|
100
|
+
!exclude.some((re) => re.test(path)),
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function parseConfig(ts: typeof TS, host: TS.ParseConfigHost, configPath: string): TS.ParsedCommandLine | { errors: TS.Diagnostic[] } {
|
|
107
|
+
const text = host.readFile(configPath) ?? '';
|
|
108
|
+
const json = ts.parseConfigFileTextToJson(configPath, text);
|
|
109
|
+
if (json.error) return { errors: [json.error] };
|
|
110
|
+
return ts.parseJsonConfigFileContent(json.config, host, dirname(configPath), undefined, configPath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function referencedConfigs(ts: typeof TS, host: TS.ParseConfigHost, configPath: string): string[] {
|
|
114
|
+
const json = ts.parseConfigFileTextToJson(configPath, host.readFile(configPath) ?? '').config as { references?: Array<{ path?: unknown }>; files?: unknown[]; include?: unknown[] } | undefined;
|
|
115
|
+
const references = json?.references ?? [];
|
|
116
|
+
// A "solution" config — references and nothing of its own — is checked through its references.
|
|
117
|
+
const ownsFiles = (json?.files?.length ?? 0) > 0 || json?.include !== undefined;
|
|
118
|
+
if (!references.length || ownsFiles) return [];
|
|
119
|
+
return references
|
|
120
|
+
.map((ref) => (typeof ref.path === 'string' ? join(dirname(configPath), ref.path) : undefined))
|
|
121
|
+
.filter((path): path is string => !!path)
|
|
122
|
+
.map((path) => (path.endsWith('.json') ? path : join(path, 'tsconfig.json')))
|
|
123
|
+
.filter((path) => host.fileExists(path));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function resolveCheckProjects(ts: typeof TS, fs: VirtualFileSystem, store: TypeStore, jsxImportSource?: string): CheckProject[] {
|
|
127
|
+
const host = createParseConfigHost(fs, store);
|
|
128
|
+
const root = ['/tsconfig.json', '/jsconfig.json'].find((path) => fs.isFile(path));
|
|
129
|
+
|
|
130
|
+
if (!root) {
|
|
131
|
+
const rootNames = fs.list().filter((path) => SOURCE_EXTENSIONS.some((ext) => path.endsWith(ext)) && !path.includes('/node_modules/') && !TOOL_CONFIG.test(path));
|
|
132
|
+
return rootNames.length ? [{ options: defaultCompilerOptions(ts, jsxImportSource), rootNames, errors: [] }] : [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const configs = referencedConfigs(ts, host, root);
|
|
136
|
+
const projects: CheckProject[] = [];
|
|
137
|
+
for (const configPath of configs.length ? configs : [root]) {
|
|
138
|
+
const parsed = parseConfig(ts, host, configPath);
|
|
139
|
+
const errors = parsed.errors.filter((d) => d.code !== NO_INPUTS);
|
|
140
|
+
if (!('options' in parsed)) {
|
|
141
|
+
projects.push({ configPath, options: {}, rootNames: [], errors });
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const rootNames = parsed.fileNames.filter((path) => !TOOL_CONFIG.test(path));
|
|
145
|
+
if (!rootNames.length && !errors.length) continue;
|
|
146
|
+
projects.push({ configPath, options: forCheck(parsed.options), rootNames, errors });
|
|
147
|
+
}
|
|
148
|
+
return projects;
|
|
149
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient declarations the checker adds, standing in for what a local install
|
|
3
|
+
* would provide:
|
|
4
|
+
* • Vite's `vite/client` (`import.meta.env`, CSS/asset/`?raw` imports) and CRA's
|
|
5
|
+
* `react-scripts` types. Shimmed rather than fetched: they are what every
|
|
6
|
+
* generated app references, and a small local copy never fails to load;
|
|
7
|
+
* • `.vue` / `.svelte` imports. Component internals are not type-checked yet;
|
|
8
|
+
* importing one must not be an error;
|
|
9
|
+
* • packages whose types could not be found, declared as `any` — a CDN miss is
|
|
10
|
+
* not the user's type error.
|
|
11
|
+
*
|
|
12
|
+
* A pattern the project (or a fetched package) already declares is skipped: two
|
|
13
|
+
* declarations of `*.vue` with a default export each would be an error of ours.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const SHIM_DIR = '/__bfwc_shims__';
|
|
17
|
+
export const AMBIENT_SHIM_PATH = `${SHIM_DIR}/ambient.d.ts`;
|
|
18
|
+
/** What a shimmed type reference (`/// <reference types="vite/client" />`) resolves to. */
|
|
19
|
+
export const EMPTY_TYPES_PATH = `${SHIM_DIR}/empty.d.ts`;
|
|
20
|
+
export const SHIMMED_TYPE_REFERENCES: ReadonlySet<string> = new Set(['vite/client', 'react-scripts']);
|
|
21
|
+
|
|
22
|
+
const STRING_DEFAULT = '{ const src: string; export default src; }';
|
|
23
|
+
const ANY_DEFAULT = '{ const value: any; export default value; }';
|
|
24
|
+
|
|
25
|
+
const MODULE_SHIMS: ReadonlyArray<[pattern: string, body: string]> = [
|
|
26
|
+
['*.module.css', '{ const classes: { readonly [key: string]: string }; export default classes; }'],
|
|
27
|
+
['*.module.scss', '{ const classes: { readonly [key: string]: string }; export default classes; }'],
|
|
28
|
+
['*.css', '{}'],
|
|
29
|
+
['*.scss', '{}'],
|
|
30
|
+
['*.sass', '{}'],
|
|
31
|
+
['*.less', '{}'],
|
|
32
|
+
...['svg', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'avif', 'ico', 'bmp', 'woff', 'woff2', 'ttf', 'otf', 'eot', 'mp4', 'webm', 'mp3', 'wav', 'ogg', 'pdf', 'txt', 'md', 'wasm'].map(
|
|
33
|
+
(ext): [string, string] => [`*.${ext}`, STRING_DEFAULT],
|
|
34
|
+
),
|
|
35
|
+
['*?raw', STRING_DEFAULT],
|
|
36
|
+
['*?url', STRING_DEFAULT],
|
|
37
|
+
['*?inline', STRING_DEFAULT],
|
|
38
|
+
['*.vue', ANY_DEFAULT],
|
|
39
|
+
['*.svelte', ANY_DEFAULT],
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const IMPORT_META = `interface ImportMetaEnv {
|
|
43
|
+
readonly [key: string]: any;
|
|
44
|
+
readonly MODE: string;
|
|
45
|
+
readonly BASE_URL: string;
|
|
46
|
+
readonly PROD: boolean;
|
|
47
|
+
readonly DEV: boolean;
|
|
48
|
+
readonly SSR: boolean;
|
|
49
|
+
}
|
|
50
|
+
interface ImportMeta {
|
|
51
|
+
readonly env: ImportMetaEnv;
|
|
52
|
+
readonly hot?: any;
|
|
53
|
+
readonly glob: any;
|
|
54
|
+
}`;
|
|
55
|
+
|
|
56
|
+
function escapeRegExp(text: string): string {
|
|
57
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** True when any of `texts` declares `declare module '<pattern>'`. */
|
|
61
|
+
export function declaresModule(texts: Iterable<string>, pattern: string): boolean {
|
|
62
|
+
const re = new RegExp(`declare\\s+module\\s+['"]${escapeRegExp(pattern)}['"]`);
|
|
63
|
+
for (const text of texts) if (re.test(text)) return true;
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface AmbientShimOptions {
|
|
68
|
+
/** Declarations already loaded: the project's own `.d.ts` files and fetched package types. */
|
|
69
|
+
existing: string[];
|
|
70
|
+
/** Packages with no types found — declared as `any`. */
|
|
71
|
+
untyped: string[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function ambientShim(options: AmbientShimOptions): string {
|
|
75
|
+
const lines = [IMPORT_META];
|
|
76
|
+
// CRA reads `process.env.REACT_APP_*`; @types/node, when loaded, declares it properly.
|
|
77
|
+
if (!options.existing.some((text) => /declare\s+var\s+process\b/.test(text))) {
|
|
78
|
+
lines.push('declare var process: { env: { readonly [key: string]: string | undefined; readonly NODE_ENV: string } };');
|
|
79
|
+
}
|
|
80
|
+
for (const [pattern, body] of MODULE_SHIMS) {
|
|
81
|
+
if (!declaresModule(options.existing, pattern)) lines.push(`declare module ${JSON.stringify(pattern)} ${body}`);
|
|
82
|
+
}
|
|
83
|
+
for (const name of options.untyped) {
|
|
84
|
+
lines.push(`declare module ${JSON.stringify(name)};`);
|
|
85
|
+
lines.push(`declare module ${JSON.stringify(`${name}/*`)};`);
|
|
86
|
+
}
|
|
87
|
+
return lines.join('\n') + '\n';
|
|
88
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type * as TS from 'typescript';
|
|
2
|
+
import { isRegistryRange } from '../packageCdn.js';
|
|
3
|
+
import { splitPackageSpecifier } from '../resolve.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Where the checker's non-project files live, and the cache that holds them.
|
|
7
|
+
*
|
|
8
|
+
* A TypeScript program is synchronous, but type definitions come from the
|
|
9
|
+
* network. So checking is two phases: acquisition fetches everything the project
|
|
10
|
+
* can reach into a {@link TypeStore}; the program then reads only the store. The
|
|
11
|
+
* store outlives one check (a worker keeps it), so a second check of the same
|
|
12
|
+
* project makes no requests and reuses parsed lib files.
|
|
13
|
+
*
|
|
14
|
+
* Fetched files are addressed by URL and exposed to TypeScript under virtual
|
|
15
|
+
* paths; libs and `extends`-ed tsconfig packages likewise.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export const TYPES_DIR = '/__bfwc_types__';
|
|
19
|
+
export const LIB_DIR = '/__bfwc_lib__';
|
|
20
|
+
/** tsconfig `extends: "@vue/tsconfig/..."` resolves through node_modules, so fetched configs live there. */
|
|
21
|
+
export const CONFIG_MODULES_DIR = '/node_modules';
|
|
22
|
+
|
|
23
|
+
export interface TypeSources {
|
|
24
|
+
/** An esm.sh-compatible CDN: answers `X-TypeScript-Types` for a package URL. */
|
|
25
|
+
typesOrigin: string;
|
|
26
|
+
/** Directory holding `lib.*.d.ts` for the TypeScript version in use. */
|
|
27
|
+
libBaseUrl: string;
|
|
28
|
+
/** Raw npm files (for tsconfig `extends` packages), jsDelivr's `/npm` layout. */
|
|
29
|
+
npmBaseUrl: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const DEFAULT_TYPES_ORIGIN = 'https://esm.sh';
|
|
33
|
+
export const DEFAULT_NPM_BASE_URL = 'https://cdn.jsdelivr.net/npm';
|
|
34
|
+
|
|
35
|
+
export function libBaseUrlFor(typescriptVersion: string): string {
|
|
36
|
+
return `${DEFAULT_NPM_BASE_URL}/typescript@${typescriptVersion}/lib`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** `@scope/name` → `@types/scope__name`, DefinitelyTyped's naming. */
|
|
40
|
+
export function typesPackageName(name: string): string {
|
|
41
|
+
return `@types/${name.startsWith('@') ? name.slice(1).replace('/', '__') : name}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** `name@range` when the project declares a registry range for it, else `name`. */
|
|
45
|
+
export function versioned(name: string, dependencies: Readonly<Record<string, string>>): string {
|
|
46
|
+
const range = dependencies[name];
|
|
47
|
+
return range && isRegistryRange(range) ? `${name}@${range}` : name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The CDN module URL whose `X-TypeScript-Types` names a specifier's types. */
|
|
51
|
+
export function packageRequestUrl(origin: string, specifier: string, dependencies: Readonly<Record<string, string>>): string {
|
|
52
|
+
const { name, subpath } = splitPackageSpecifier(specifier);
|
|
53
|
+
return `${origin}/${versioned(name, dependencies)}${subpath}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** URLs to try, in order, for a relative or absolute reference inside a fetched `.d.ts`. */
|
|
57
|
+
export function dtsCandidates(specifier: string, fromUrl: string): string[] {
|
|
58
|
+
const url = new URL(specifier, fromUrl).href.replace(/[?#].*$/, '');
|
|
59
|
+
if (/\.d\.[mc]?ts$/.test(url)) return [url];
|
|
60
|
+
if (/\.[mc]?js$/.test(url)) return [url.replace(/\.([mc]?)js$/, '.d.$1ts')];
|
|
61
|
+
if (/\.[mc]?ts$/.test(url)) return [url];
|
|
62
|
+
return [`${url}.d.ts`, `${url}/index.d.ts`];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class TypeStore {
|
|
66
|
+
/** Final (post-redirect) URL → text. */
|
|
67
|
+
readonly files = new Map<string, string>();
|
|
68
|
+
/** Requested URL → final URL; `''` records a failure so it is not retried. */
|
|
69
|
+
readonly redirects = new Map<string, string>();
|
|
70
|
+
/** Package request URL (or `types:<name>`) → final types URL, or null when it has none. */
|
|
71
|
+
readonly packages = new Map<string, string | null>();
|
|
72
|
+
/** `lib.dom.d.ts` → text, or null when missing. */
|
|
73
|
+
readonly libs = new Map<string, string | null>();
|
|
74
|
+
/** `/node_modules/@vue/tsconfig/tsconfig.json` → text, or null when missing. */
|
|
75
|
+
readonly configs = new Map<string, string | null>();
|
|
76
|
+
/** Parsed lib and package files, reused by every program built over this store. */
|
|
77
|
+
readonly sourceFiles = new Map<string, TS.SourceFile>();
|
|
78
|
+
|
|
79
|
+
/** The final URL for a requested one, when it was fetched. */
|
|
80
|
+
finalUrl(url: string): string | undefined {
|
|
81
|
+
const final = this.redirects.get(url) ?? (this.files.has(url) ? url : undefined);
|
|
82
|
+
return final || undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
virtualPath(url: string): string {
|
|
86
|
+
return `${TYPES_DIR}/${url.replace(/^[a-z]+:\/\//i, '')}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
urlOf(virtualPath: string): string | undefined {
|
|
90
|
+
if (!virtualPath.startsWith(`${TYPES_DIR}/`)) return undefined;
|
|
91
|
+
const rest = virtualPath.slice(TYPES_DIR.length + 1);
|
|
92
|
+
for (const scheme of ['https://', 'http://']) if (this.files.has(scheme + rest)) return scheme + rest;
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Text for any virtual non-project path, or undefined. */
|
|
97
|
+
read(path: string): string | undefined {
|
|
98
|
+
if (path.startsWith(`${LIB_DIR}/`)) return this.libs.get(path.slice(LIB_DIR.length + 1)) ?? undefined;
|
|
99
|
+
if (path.startsWith(`${CONFIG_MODULES_DIR}/`)) return this.configs.get(path) ?? undefined;
|
|
100
|
+
const url = this.urlOf(path);
|
|
101
|
+
return url ? this.files.get(url) : undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|