/** * Shared tsdown preset for UI plugin client bundles. Emits a closure-factory * artifact: the bundle calls window.__ModuleLoader__.load({id, factory}) * and resolves externals through the injected require (loader module table — * cordis DI entities, no globals, no import map). CSS is compiled by * lightningcss inside the bundle: `x.module.css` yields its hashed class map * and injects a tagged style at factory execution, while `x.css?inline` * exports compiled text for a plugin-owned lifecycle effect. The virtual * loaders register each real stylesheet as a watch dependency. */ import { readFile } from 'node:fs/promises' import { existsSync, globSync, readFileSync } from 'node:fs' import { isBuiltin } from 'node:module' import { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path' import { fileURLToPath } from 'node:url' import type { UserConfig } from 'tsdown' import { transform } from 'lightningcss' import { optionalStringArray } from './modules/src/client/manifest.ts' import { PLATFORM_MODULES, PRELOADED_CLIENT_EXTERNALS } from './web/src/platform.ts' import { clientBuildEnvironmentDefines } from '../../scripts/client-build-environment.ts' /** * Virtual-id wrapper keeping module CSS away from tsdown's own css pipeline * (which requires @tsdown/css). The suffix matters: tsdown's guard matches ids * ending in `.css`, so the virtual id must not. */ const CSS_VIRTUAL_PREFIX = '\0dsh-css:' const GLOBAL_CSS_VIRTUAL_PREFIX = '\0dsh-global-css:' const INLINE_CSS_VIRTUAL_PREFIX = '\0dsh-inline-css:' const CSS_VIRTUAL_SUFFIX = '.mjs' const INLINE_CSS_QUERY = '?inline' /** Emit one plugin-owned style injector and an optional CSS Modules export. */ function styleInjectionModule( id: string, fileId: string, css: string, classMap?: Readonly>, ): string { const source = [ `const css = ${JSON.stringify(css)};`, `const tagId = ${JSON.stringify(`${id}/${basename(fileId)}`)};`, 'if (typeof document !== \'undefined\' && document.querySelector(\'style[data-plugin-css=\' + JSON.stringify(tagId) + \']\') === null) {', ' const tag = document.createElement(\'style\');', ` tag.dataset.plugin = ${JSON.stringify(id)};`, ' tag.dataset.pluginCss = tagId;', ' tag.textContent = css;', ' document.head.appendChild(tag);', '}', ] source.push(classMap === undefined ? 'export {};' : `export default ${JSON.stringify(classMap)};`) return source.join('\n') } /** * Wire/type layers a client bundle may inline: browser-safe contracts * with no runtime identity to share (no Symbol/instanceof/singleton state). * Everything else under @deepseek-ai/* is either a module-table entry * (external) or a leak the purity gate rejects. */ export const INLINE_SAFE = /^@deepseek-ai\/dsh-(?:host-apiproxy|file-reference|session|llm|tools|brand|util-crypto|util-workspace-path)(?:\/|$)/ /** * Vendored framework libraries: rescoped into @deepseek-ai, so the gate below * would read them as plugin packages. They carry no cross-plugin runtime * identity to share — the framework itself is a requested module-table row * (external), while these are ordinary libraries a browser bundle inlines. */ const VENDORED_LIBRARY = /^@deepseek-ai\/(cosmokit|schemastery)(\/|$)/ /** Generated descriptor/codec contribution with no shared runtime identity. */ const GENERATED_REMOTE = /^@deepseek-ai\/dsh-[a-z0-9]+(?:-[a-z0-9]+)*\/remote$/ /** * Workspace mode replaces an empty config array with the root defaults. A * falsey entry instead removes this package before entry resolution. */ const SKIP_WORKSPACE_BUILD: UserConfig = { entry: '' } const REPOSITORY_ROOT = fileURLToPath(new URL('../..', import.meta.url)) /** Rebase a physical lib-relative source onto a browser URL that mirrors the repository directories. */ function browserSourcePath(source: string, sourcemapPath: string): string { if (!source.startsWith('.')) return source const physicalSource = resolvePath(dirname(sourcemapPath), source) const repositoryPath = relative(REPOSITORY_ROOT, physicalSource).split(sep).join('/') return repositoryPath.startsWith('packages/') ? `../../../${repositoryPath}` : source } /** * Build the tsdown config for one UI plugin package: the node-half lib build * plus the browser client bundle. Client packages emit both halves during the * Client pass by default; packages needed for Host reflection may opt into the * earlier Host pass. A package-level tsdown.config.ts REPLACES the root * workspace layout, so the lib half must be restated here — dropping it leaves * the package without lib/index.js and the host Loader cannot import its node * half. The Client build consumes `lib/types` and chains those tsc maps, with * original source content, into the standalone plugin map. * @param id - plugin id (package name), stamped into the __ModuleLoader__.load * handoff and onto the injected style tags. * @param libEntry - node-half entries, spelled at the call site so the * package-invariants gate can see `lib/types/invariant.js` in each package's * own tsdown.config.ts (a preset-side glob hides it from the mechanical check). * @param options - phase placement, lib overrides, and companion Node configs. * @returns ENV-selected tsdown config for the current build face. */ export function clientBundle( id: string, libEntry: readonly string[], options: ClientBundleOptions = {}, ): BuildFaceConfig { const lib = clientLibraryConfig(id, libEntry, options.lib) return ({ env }) => { const face = buildFace(env?.DSH_BUILD_FACE) const clientEntry = face === undefined ? 'src/client/index.ts' : 'lib/types/client/index.js' const client = clientConfig(id, clientEntry) const node = [lib, ...(options.companions ?? [])] if (face === 'host') return options.hostPhase === true ? node : [SKIP_WORKSPACE_BUILD] if (face === 'client') { return options.hostPhase === true ? [client] : [...node, client] } return [...node, client] } } /** * Build the tsdown config for a client library the compile shell links * statically (the static assembly channel: `apps/web` resolves the package * name, bundles the artifact, and owns the chunk layout and the CSS pipeline). * * Calling this preset is what puts a package in the static assembly channel, * so the call sites are the roster: gates read it through * {@link isStaticLinkedConfig} rather than a second hand-kept list. A package on * this roster must not be a module-table row as well — the browser would take * the statically linked copy and a provider's bytes would sit unused in its * bundle. * * Four artifact contracts: * 1. every bare specifier stays an import. The shell attributes chunk bytes by * `node_modules/`, so a dependency inlined into a workspace file is * attributed to no npm package and its bytes fall into the index chunk, * which collapses the vendor/index cache split. * 2. `esm` on `platform: 'browser'` — the shell is the only consumer. * 3. sourcemaps, chained through the tsc maps under `lib/types` to the sources. * 4. stylesheets ship with the package: a relative `.css` import survives as a * relative external and the sheet is emitted under `lib/` at its * `src`-relative path, so vite stays the only owner of class hashing. * @param id - package name, used in tsdown diagnostics. * @param libEntry - emitted JavaScript entries consumed from `lib/types`, one * bundle each: a multi-entry build would emit a hash-named shared chunk that * the exact `files` list cannot publish. * @returns ENV-selected tsdown config for the Client build face. */ export function staticLinked(id: string, libEntry: readonly string[]): BuildFaceConfig { // Each entry names its own output file, so two entries with the same basename // would overwrite one artifact instead of emitting two. const names = new Set(libEntry.map(entry => basename(entry, '.js'))) if (names.size !== libEntry.length) { throw new Error(`tsdown: ${id} entries collide on an output name: ${libEntry.join(', ')}`) } return clientOnly(libEntry.map(entry => staticLinkedConfig(id, entry))) } /** * Whether a package's tsdown configs put it in the static assembly channel. * The roster has no separate list: gates load each package's own * `tsdown.config.ts`, call it for the Client face, and ask this. * @param configs - configs a package's build-face function returned. * @returns true when at least one config was built by {@link staticLinked}. */ export function isStaticLinkedConfig(configs: readonly UserConfig[]): boolean { return configs.some(config => (config.plugins as readonly { name?: string }[] | undefined ?? []) .some(plugin => plugin.name === STATIC_LINKED_PLUGIN)) } /** * Build a Client-only Node library during the Client pass. * @param id - Package name used in tsdown diagnostics. * @param libEntry - Emitted JavaScript entries consumed from `lib/types`. * @returns ENV-selected tsdown config for the Client build face. */ export function clientLibrary(id: string, libEntry: readonly string[]): BuildFaceConfig { const lib = clientLibraryConfig(id, libEntry) return clientOnly([lib]) } /** * Select arbitrary package-local configs only during the Client pass. * @param configs - Node-side configs emitted after Client tsc. * @returns ENV-selected tsdown config for the Client build face. */ export function clientOnly(configs: readonly UserConfig[]): BuildFaceConfig { return ({ env }) => buildFace(env?.DSH_BUILD_FACE) === 'host' ? [SKIP_WORKSPACE_BUILD] : [...configs] } interface ClientBundleOptions { /** Emit the Node-side artifacts during the Host pass instead of the Client pass. */ readonly hostPhase?: boolean /** Additional Node-side configs emitted alongside the package library. */ readonly companions?: readonly UserConfig[] /** Overrides for the package's primary Node-side library config. */ readonly lib?: UserConfig } type BuildFace = 'host' | 'client' | undefined type BuildFaceConfig = (inlineConfig: Pick) => UserConfig[] function buildFace(value: unknown): BuildFace { if (value === undefined || value === 'host' || value === 'client') return value throw new Error(`tsdown: --env.DSH_BUILD_FACE must be host or client, received ${String(value)}`) } function clientLibraryConfig( id: string, libEntry: readonly string[], overrides: UserConfig = {}, ): UserConfig { const isProductionDependency = (specifier: string): boolean => matchesSpecifier(productionExternals(id), specifier) return { name: id, entry: [...libEntry], outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024', fixedExtension: false, dts: false, clean: false, deps: { // The Node half runs from a real install: a production dependency is on // disk there and stays an import, everything else inlines. Stating both // halves takes the artifact off tsdown's getProductionDeps fallback, where // moving a dependency between npm sections silently re-bundles it. // Builtins keep tsdown's own handling (neither side claims them). neverBundle: isProductionDependency, alwaysBundle: (specifier: string) => !isBuiltin(specifier) && !isProductionDependency(specifier), }, ...overrides, } } /** The slice of the rolldown plugin context the stylesheet plugin uses. */ interface AssetEmitter { emitFile(file: { type: 'asset' fileName: string source: Uint8Array originalFileName: string }): string } function staticLinkedConfig(id: string, entry: string, outputName = basename(entry, '.js')): UserConfig { const emitted = new Set() return { name: id, entry: { [outputName]: entry }, outDir: 'lib', format: ['esm'], platform: 'browser', target: 'es2024', fixedExtension: false, dts: false, clean: false, // The shell compiles this artifact, so its map is the only path from a // browser stack frame back to the TSX (tsc emits the lib/types half). sourcemap: true, outputOptions: { sourcemapExcludeSources: false }, plugins: [{ // Contract 1. `pre` because tsdown's own deps plugin would otherwise // resolve and inline every specifier missing from the npm production // sections, which is the coupling this preset exists to remove. The name // is also the roster marker {@link isStaticLinkedConfig} reads. name: STATIC_LINKED_PLUGIN, resolveId: { order: 'pre' as const, handler(source: string, importer: string | undefined) { // An entry arrives without an importer and must stay internal. if (importer === undefined) return null return isBareSpecifier(source) ? { id: source, external: true } : null }, }, }, tscSourceMapPlugin(), { // Contract 4. The import survives verbatim and the sheet lands beside the // JavaScript, so the shell's CSS Modules pipeline sees a real stylesheet. name: 'dsh-css-asset', async resolveId(this: AssetEmitter, source: string, importer: string | undefined) { if (!source.endsWith('.css') || importer === undefined) return null const { file, fileName } = stylesheetAsset(source, importer) if (!emitted.has(fileName)) { emitted.add(fileName) // originalFileName also puts the physical sheet in the watch graph. this.emitFile({ type: 'asset', fileName, source: await readFile(file), originalFileName: file }) } // Every emitted chunk sits at the lib/ root, so the src-relative name // is what resolves from there. Rolldown keeps relative externals as // written instead of re-normalizing them. return { id: `./${fileName}`, external: true } }, }], } } /** Whether a specifier names a package rather than a file next to its importer. */ function isBareSpecifier(specifier: string): boolean { return !specifier.startsWith('.') && !specifier.startsWith('\0') && !isAbsolute(specifier) } /** * Locate a stylesheet import against the package sources and name its emitted position. * @param source - relative import specifier as written in the source. * @param importer - absolute path of the importing module, emitted or source. * @returns the stylesheet on disk plus its `src`-relative name under `lib/`. */ function stylesheetAsset(source: string, importer: string): { readonly file: string, readonly fileName: string } { const file = sourceAssetPath(source, importer) const boundary = file.lastIndexOf(SOURCE_MARKER) if (boundary < 0) throw new Error(`tsdown: stylesheet ${file} is outside the package sources`) return { file, fileName: file.slice(boundary + SOURCE_MARKER.length).split(sep).join('/') } } /** The manifest fields the build faces read to state their own module edges. */ interface WorkspaceManifest { readonly name?: string /** Sections a real install materializes on disk next to the built package. */ readonly dependencies?: Record readonly peerDependencies?: Record readonly optionalDependencies?: Record readonly dsh?: { readonly client?: { readonly external?: unknown } } } const manifestCache = new Map() const productionExternalCache = new Map() const clientExternalCache = new Map>() /** * Read one workspace package's manifest. Located by package name rather than by * cwd, because tsdown evaluates every package config with the repository root as * `process.cwd()` during a workspace build. Callers read it on the first * resolveId of a build, not while a config is built, so selecting a build face * never touches a manifest. * @param id - package name, as spelled at the preset call site. * @returns the parsed manifest. * @throws {Error} when no workspace package declares that name. */ function workspaceManifest(id: string): WorkspaceManifest { const cached = manifestCache.get(id) if (cached !== undefined) return cached for (const manifestPath of globSync('packages/*/*/package.json', { cwd: REPOSITORY_ROOT })) { const manifest = JSON.parse( readFileSync(resolvePath(REPOSITORY_ROOT, manifestPath), 'utf8'), ) as WorkspaceManifest if (manifest.name !== id) continue manifestCache.set(id, manifest) return manifest } throw new Error(`tsdown: no packages/*/*/package.json declares the name ${id}`) } /** * External patterns for one package's Node half: its own production sections, * subpaths included. * @param id - package name, as spelled at the preset call site. * @returns one `^name(/|$)` pattern per production dependency, name-sorted. */ function productionExternals(id: string): readonly RegExp[] { const cached = productionExternalCache.get(id) if (cached !== undefined) return cached const manifest = workspaceManifest(id) const names = new Set([ ...Object.keys(manifest.dependencies ?? {}), ...Object.keys(manifest.peerDependencies ?? {}), ...Object.keys(manifest.optionalDependencies ?? {}), ]) const patterns = [...names].sort().map(name => new RegExp(`^${escapeSpecifier(name)}(/|$)`)) productionExternalCache.set(id, patterns) return patterns } /** * Module-table specifiers one `dsh.client` declaration requests. Matching is * exact, never normalized: a package declares the specifier its own code * imports, and the loader keys static entries the same way. * @param subject - package name, used in diagnostics. * @param declaration - the package's `dsh.client` object. * @returns the requested specifiers, empty when the package declares none. * @throws {Error} when `external` is not a string array. */ export function requestedExternals( subject: string, declaration: { readonly external?: unknown }, ): ReadonlySet { return new Set(optionalStringArray(subject, 'dsh.client.external', declaration.external) ?? []) } /** * Module-table specifiers one package requests. The shell baseline is implicit * for every dynamic bundle; `dsh.client.external` only adds package-specific * dynamic rows or subpaths. * @param id - package name, as spelled at the preset call site. * @returns the baseline plus the package's explicit requests. */ function clientExternals(id: string): ReadonlySet { const cached = clientExternalCache.get(id) if (cached !== undefined) return cached const externals = new Set([ ...PLATFORM_MODULES, ...PRELOADED_CLIENT_EXTERNALS, ...requestedExternals(id, workspaceManifest(id).dsh?.client ?? {}), ]) clientExternalCache.set(id, externals) return externals } /** Escape a package name for literal use inside a RegExp source. */ function escapeSpecifier(name: string): string { return name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } /** Whether an import specifier is the package a pattern names, or one of its subpaths. */ function matchesSpecifier(patterns: readonly RegExp[], specifier: string): boolean { return patterns.some(pattern => pattern.test(specifier)) } function clientConfig(id: string, entry: string): UserConfig { const isRequested = (specifier: string): boolean => clientExternals(id).has(specifier) return { name: `${id}/client`, entry: { client: entry }, // Browser bundle lands next to the node half (single lib/ artifact dir; // the entryFileNames pin keeps it exactly lib/client.js). clean must stay // off — a default clean would wipe the node-half output emitted above. outDir: 'lib', format: 'cjs', platform: 'browser', // Types ship from lib/types (tsc); dts here would wrap the banner/footer into .d.cts and break parsing. dts: false, // Plugin code is fetched outside Vite's module graph, so its own bundle // must carry the TS/TSX mapping consumed by browser profiling tools. sourcemap: true, clean: false, deps: { neverBundle: isRequested, // Anything NOT requested from the loader module table must inline // (wire/type layers, zod, clsx — every non-shared dep). A require() the // table cannot answer is a guaranteed runtime throw, so the rule is the // package's own request list: requested specifiers stay imports, // everything else is bundled. alwaysBundle: (specifier: string) => !isRequested(specifier), }, // Browser bundles inline node-idiom deps (zustand/immer read // process.env.NODE_ENV; zustand's esm build also probes // import.meta.env.MODE, which a CJS output cannot carry — rolldown flags // EMPTY_IMPORT_META). vite defined both on the seed path; tsdown inlining // needs the substitutions here or the factory throws ReferenceError at // boot / the build gate reds. Both keys honor the build's NODE_ENV so a // dev build keeps the dev-branch semantics; artifacts default to production. // The bare `import.meta.env` key is required alongside the precise MODE // key: zustand probes `import.meta.env ? import.meta.env.MODE : ...`, and // the truthiness probe would otherwise survive as an empty import.meta. define: { ...clientBuildEnvironmentDefines(process.env), 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV ?? 'production'), 'import.meta.env.MODE': JSON.stringify(process.env.NODE_ENV ?? 'production'), 'import.meta.env': JSON.stringify({ MODE: process.env.NODE_ENV ?? 'production' }), }, plugins: [{ // Bundle purity gate (build-time mirror of the module-edge rules): the // baseline and package-specific requests stay external, inline-safe wire layers // inline, and every other @deepseek-ai value import is a build error — a // cross-plugin value import either inlines a duplicate runtime instance // or requires a specifier the module table cannot answer for this package. // Cross-plugin collaboration goes through cordis services instead. name: 'dsh-client-bundle-purity', resolveId(source: string) { if (!source.startsWith('@deepseek-ai/')) return null if (isRequested(source)) return null // requested module-table row: external wins if (VENDORED_LIBRARY.test(source)) return null // vendored library: inline, no shared identity if (INLINE_SAFE.test(source) || GENERATED_REMOTE.test(source)) return null // wire contribution: inline is the point throw new Error( `client bundle purity: "${source}" is not in the default client externals or ${id}'s dsh.client.external, an inline-safe wire layer, or a generated /remote contribution — ` + 'cross-plugin value imports are forbidden; declare a non-default module request or collaborate through cordis services ' + '(type-only imports are erased and never reach this gate)', ) }, }, tscSourceMapPlugin(), { name: 'dsh-css-modules-inline', resolveId(source: string, importer: string | undefined) { if (!source.endsWith('.module.css')) return null const abs = importer !== undefined ? sourceAssetPath(source, importer) : source return CSS_VIRTUAL_PREFIX + abs + CSS_VIRTUAL_SUFFIX }, async load(virtualId: string) { if (!virtualId.startsWith(CSS_VIRTUAL_PREFIX)) return null const fileId = virtualId.slice(CSS_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length) // The virtual id otherwise hides the physical stylesheet from Rolldown's watch graph. this.addWatchFile(fileId) const source = await readFile(fileId) const { code, exports: cssExports } = transform({ filename: fileId, code: source, cssModules: { pattern: '[hash]_[local]' }, minify: true, }) const classMap: Record = {} const exportEntries = Object.entries(cssExports ?? {}) .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)) for (const [local, exp] of exportEntries) classMap[local] = exp.name return styleInjectionModule(id, fileId, code.toString(), classMap) }, }, { name: 'dsh-css-text-inline', resolveId(source: string, importer: string | undefined) { if (!source.endsWith(`.css${INLINE_CSS_QUERY}`)) return null const stylesheet = source.slice(0, -INLINE_CSS_QUERY.length) const abs = importer !== undefined ? sourceAssetPath(stylesheet, importer) : stylesheet return INLINE_CSS_VIRTUAL_PREFIX + abs + CSS_VIRTUAL_SUFFIX }, async load(virtualId: string) { if (!virtualId.startsWith(INLINE_CSS_VIRTUAL_PREFIX)) return null const fileId = virtualId.slice(INLINE_CSS_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length) this.addWatchFile(fileId) const source = await readFile(fileId) const { code } = transform({ filename: fileId, code: source, minify: true }) return `export default ${JSON.stringify(code.toString())};` }, }, { name: 'dsh-css-global-inline', resolveId(source: string, importer: string | undefined) { if (!source.endsWith('.css') || source.endsWith('.module.css')) return null const abs = importer !== undefined ? sourceAssetPath(source, importer) : source return GLOBAL_CSS_VIRTUAL_PREFIX + abs + CSS_VIRTUAL_SUFFIX }, async load(virtualId: string) { if (!virtualId.startsWith(GLOBAL_CSS_VIRTUAL_PREFIX)) return null const fileId = virtualId.slice(GLOBAL_CSS_VIRTUAL_PREFIX.length, -CSS_VIRTUAL_SUFFIX.length) this.addWatchFile(fileId) const source = await readFile(fileId) const { code } = transform({ filename: fileId, code: source, minify: true }) return styleInjectionModule(id, fileId, code.toString()) }, }], outputOptions: { entryFileNames: 'client.js', sourcemapExcludeSources: false, // The map is served from /plugins//client.js.map. The // browser resolves its local sources back into URLs that mirror the // /packages///src directories; sourcesContent keeps them usable // without exposing that tree as an HTTP route. sourcemapPathTransform: browserSourcePath, banner: `window.__ModuleLoader__.load({ id: ${JSON.stringify(id)}, factory: (require) => {`, footer: 'return module.exports; } });', intro: 'var module = { exports: {} }; var exports = module.exports;', }, } } /** Chain tsc's emitted maps into any Client bundle that consumes `lib/types`. */ function tscSourceMapPlugin() { return { name: 'dsh-tsc-sourcemap', async load(id: string) { if (!id.includes(TYPES_MARKER) || !id.endsWith('.js') || !existsSync(`${id}.map`)) return null const code = await readFile(id, 'utf8') const mapPath = `${id}.map` const map = JSON.parse(await readFile(mapPath, 'utf8')) as { sourceRoot?: unknown sources?: unknown sourcesContent?: unknown [key: string]: unknown } if (!Array.isArray(map.sources) || map.sources.some(source => typeof source !== 'string')) { throw new Error(`client sourcemap: ${mapPath} has invalid sources`) } const sources = map.sources as string[] if ( !Array.isArray(map.sourcesContent) || map.sourcesContent.length !== sources.length || map.sourcesContent.some(source => typeof source !== 'string') ) { const sourceRoot = typeof map.sourceRoot === 'string' ? map.sourceRoot : '' map.sourcesContent = await Promise.all(sources.map(async source => await readFile(resolvePath(dirname(mapPath), sourceRoot, source), 'utf8'))) } return { code: code.replace(SOURCEMAP_COMMENT, ''), map } }, } } /** Path segment separating a package's tsc output from the sources it was emitted from. */ const TYPES_MARKER = `${sep}lib${sep}types${sep}` /** Plugin name carrying contract 1, and the marker that identifies a statically linked config. */ const STATIC_LINKED_PLUGIN = 'dsh-static-linked-external' /** Path segment a package's sources hang under, and the root emitted assets mirror. */ const SOURCE_MARKER = `${sep}src${sep}` /** Trailing sourcemap reference tsc appends to every emitted module. */ const SOURCEMAP_COMMENT = /\n\/\/# sourceMappingURL=.*\s*$/ /** Resolve an emitted JS asset import against its source-tree counterpart. */ function sourceAssetPath(source: string, importer: string): string { const emitted = resolvePath(dirname(importer), source) if (existsSync(emitted)) return emitted const boundary = emitted.indexOf(TYPES_MARKER) if (boundary < 0) return emitted return resolvePath(emitted.slice(0, boundary), 'src', emitted.slice(boundary + TYPES_MARKER.length)) }