import { writeFile } from 'node:fs/promises' import path from 'node:path' import esbuild from 'esbuild' /** * The in-WebView terminal document, bundled from its modules. * * The document is a string the native WebView loads inside its HTML, so it cannot be an ES module * there — and it is ordinary TypeScript everywhere else, which the page imports directly. So this * is one esbuild bundle of the entry that calls `createTerminalDocument()` with no host, written * out as a string exactly as the xterm engine beside it is. * * `iife`, so the bundle's module scope is its own and nothing it declares reaches the page it is * pasted into. Not minified: the document is read in crash reports and in the WebView's own * console, and the size it saves is small beside the engine it sits next to. */ const mobileRoot = path.join(import.meta.dirname, '..') /** The oldest WebView Orca supports, matching the engine bundle's own floor (#7030). */ const TARGET = 'chrome74' const ENTRY = path.join(mobileRoot, 'src', 'terminal', 'document', 'native-document-entry.ts') export const TERMINAL_DOCUMENT_SCRIPT_PATH = path.join( mobileRoot, 'src', 'terminal', 'terminal-webview-document-script.generated.ts' ) const GENERATED_HEADER = `// Generated by scripts/build-terminal-document-script.mjs. Do not edit.\n` + `// The source is mobile/src/terminal/document/, bundled from native-document-entry.ts.\n` + `// Target: ${TARGET}. Regenerate via pnpm postinstall.` /** * One options object, so a census of what the bundle contains measures the bundle that ships. * * `minify: false` is load-bearing beyond readability: the engine-error overlay reports the line and * column `window.onerror` hands it, and a minified document makes both useless. * * So is `absWorkingDir`: esbuild writes each module's path into the bundle as a comment, relative * to the working directory, so without it the artifact's bytes depend on where the generator was * run from — and from outside the repo the comments carry an absolute path with the builder's home * directory in it. */ export function terminalDocumentBuildOptions(extra = {}) { return { absWorkingDir: mobileRoot, entryPoints: [ENTRY], bundle: true, format: 'iife', minify: false, platform: 'browser', target: TARGET, legalComments: 'none', write: false, logLevel: 'silent', ...extra } } /** * One bundle, and everything a reader asks about it. * * The text and the module list come from the same build because they are two readings of one * thing: a census that built its own would answer about a bundle nobody ships, and the pair is * what lets a test compare the committed artifact with what the sources say it should be. */ export async function terminalDocumentBundle() { const result = await esbuild.build(terminalDocumentBuildOptions({ metafile: true })) const [output] = result.outputFiles if (!output) { throw new Error('[build-terminal-document-script] esbuild emitted no document bundle') } return { script: output.text.trimEnd(), inputs: Object.keys(result.metafile.inputs) } } export async function buildTerminalDocumentScript() { return (await terminalDocumentBundle()).script } async function main() { const script = await buildTerminalDocumentScript() await writeFile( TERMINAL_DOCUMENT_SCRIPT_PATH, `${GENERATED_HEADER}\nexport const TERMINAL_DOCUMENT_SCRIPT = ${JSON.stringify(script)}\n` ) } if (process.argv[1] && import.meta.url.endsWith(path.basename(process.argv[1]))) { await main() }