@remotex-labs/xbuild 3.0.0 → 3.0.2

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["src/modules/server/server.module.ts","src/modules/server/html/server.html","src/services/framework.service.ts","src/models/files.model.ts","src/services/watch.service.ts","src/components/glob.component.ts","src/constants/glob.constant.ts","src/providers/stack.provider.ts","src/modules/typescript/services/typescript.service.ts","src/modules/typescript/models/declaration.model.ts","src/components/transformer.component.ts","src/modules/typescript/constants/typescript.constant.ts","src/modules/typescript/services/host.service.ts"],"sourceRoot":"https://github.com/remotex-labs/xBuild/tree/v3.0.0/","sourcesContent":["/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { ServerAddressInterface, ServerConfigurationInterface, ServerEventsType } from '@server/interfaces/server.interface';\n\n/**\n * Imports\n */\n\nimport * as http from 'http';\nimport * as https from 'https';\nimport { extname } from 'path';\nimport { readFileSync } from 'fs';\nimport html from './html/server.html';\nimport { join } from '@remotex-labs/xmap';\nimport { inject } from '@remotex-labs/xinject';\nimport { Subject } from '@remotex-labs/xobservable';\nimport { readdir, stat, readFile } from 'fs/promises';\nimport { FrameworkService } from '@services/framework.service';\n\n/**\n * Serves one directory over HTTP or HTTPS, files and listings alike.\n *\n * @remarks\n * Meant for looking at build output while developing:\n * a request maps to a path under the root, a file is sent with a content type guessed from its extension,\n * and a directory is rendered as a browsable listing.\n * A configuration can take a request over before any of that happens,\n * which is the hook to reach for when the output needs an API beside it or a single-page fallback.\n * Nothing here writes to a terminal: what it does is reported on a stream, so a run decides what to say about it.\n * Constructed rather than injected, so a build can run several of them over different roots at once.\n *\n * @example\n * ```ts\n * const server = new ServerModule({ port: 0, verbose: true }, 'dist');\n *\n * await server.start(); // resolves once listening, after onStart has run\n * server.config.port; // 54321 - the port the system picked, written back\n * await server.stop();\n * ```\n *\n * @see ServerConfigurationInterface\n * @since 2.0.0\n */\n\nexport class ServerModule {\n /**\n * Node server currently listening, absent until {@link start} and again after {@link stop}.\n *\n * @remarks\n * Holds either an HTTP or an HTTPS server,\n * since the HTTPS type extends the HTTP one and the two are interchangeable here.\n * Its presence is what {@link stop} treats as whether anything is running.\n *\n * @since 2.0.0\n */\n\n private server?: http.Server;\n\n /**\n * The stream everything this server does is reported on.\n *\n * @remarks\n * The server says what happened and writes none of it,\n * so a run decides for itself what reaches a terminal, and one that wants none of it subscribes to nothing.\n * Kept private and reached through {@link pipe} and {@link subscribe},\n * which is what keeps a reader from reporting an event of its own.\n *\n * @see ServerEventsType\n * @since 3.0.0\n */\n\n private readonly events$ = new Subject<ServerEventsType>();\n\n /**\n * Absolute directory every request is resolved inside.\n *\n * @remarks\n * Resolved once in the constructor, so a later change to the working directory cannot move what is being served.\n *\n * @since 2.0.0\n */\n\n private readonly rootDir: string;\n\n /**\n * Framework service, consulted for the directory the bundled certificates ship in.\n *\n * @remarks\n * Only reached when HTTPS is started without a key and certificate of its own.\n *\n * @see FrameworkService\n * @since 2.0.0\n */\n\n private readonly framework = inject(FrameworkService);\n\n /**\n * Creates a server over one directory.\n *\n * @param config - How to listen and what to do with requests\n * @param dir - Directory to serve, resolved to an absolute path immediately\n *\n * @remarks\n * The configuration is kept by reference rather than copied: the host and port defaults land on it here,\n * and the port the system assigns lands on it once listening.\n * The object the caller passed is therefore also how the caller learns what was bound.\n * A port of `0`, which is also the default, leaves the choice to the operating system.\n *\n * @example\n * ```ts\n * const config = { port: 8080, https: true, onRequest: (req, res, next) => next() };\n * const server = new ServerModule(config, './public');\n *\n * config.host; // 'localhost' - defaulted here, on the caller's own object\n * ```\n *\n * @see ServerConfigurationInterface\n * @since 2.0.0\n */\n\n constructor(readonly config: ServerConfigurationInterface, dir: string) {\n this.rootDir = FrameworkService.resolve(dir);\n this.config.port ||= 0;\n this.config.host ||= 'localhost';\n }\n\n /**\n * The event stream's `pipe`, bound to the stream.\n *\n * @remarks\n * Hands out the operator chain without handing out the subject,\n * so a reader composes on what the server reports and cannot report anything itself.\n *\n * @example\n * ```ts\n * server.pipe(filter(event => event.type === 'request')).subscribe(report);\n * ```\n *\n * @see subscribe\n * @since 3.0.0\n */\n\n get pipe(): typeof this.events$.pipe {\n return this.events$.pipe.bind(this.events$);\n }\n\n /**\n * The event stream's `subscribe`, bound to the stream.\n *\n * @remarks\n * How a run learns what the server is doing, since the server itself writes nothing.\n * Answers with the handle that ends the subscription, as the stream's own `subscribe` does.\n *\n * @example\n * ```ts\n * const unsubscribe = server.subscribe(event => event.type); // 'start', then 'request'\n * unsubscribe();\n * ```\n *\n * @see pipe\n * @since 3.0.0\n */\n\n get subscribe(): typeof this.events$.subscribe {\n return this.events$.subscribe.bind(this.events$);\n }\n\n /**\n * Starts listening over HTTPS when the configuration asks for it and over HTTP otherwise.\n *\n * @returns A promise settling once the server is listening\n *\n * @remarks\n * The `onStart` hook runs from the listen callback,\n * so it has already been called - and the assigned port already written back - by the time this resolves.\n * Nothing guards against starting twice:\n * a second call replaces the reference and leaves the first server listening with no way left to close it,\n * so reach for {@link restart} rather than starting again.\n *\n * @example\n * ```ts\n * const server = new ServerModule({ port: 3000, onStart: ({ url }) => console.log(url) }, 'dist');\n * await server.start(); // logs 'http://localhost:3000'\n * ```\n *\n * @see stop\n * @see restart\n *\n * @since 2.0.0\n */\n\n async start(): Promise<void> {\n if (this.config.https)\n return await this.startHttpsServer();\n\n await this.startHttpServer();\n }\n\n /**\n * Closes the server and waits for it to finish.\n *\n * @returns A promise settling once every connection has ended\n *\n * @throws Error - Reported by Node when the server was already closed underneath\n *\n * @remarks\n * Closing refuses new connections and waits on the ones in flight,\n * so a request already in progress delays this rather than ending mid-flight.\n * Stopping when nothing is running is not an error - it reports as much and returns.\n *\n * @example\n * ```ts\n * await server.stop(); // 'Server stopped.'\n * await server.stop(); // 'No server is currently running.'\n * ```\n *\n * @see start\n * @since 2.0.0\n */\n\n async stop(): Promise<void> {\n if (!this.server) return this.events$.next({ type: 'stop', running: false });\n\n await new Promise<void>((resolve, reject) => {\n this.server!.close(err => {\n if (err) reject(err);\n else resolve();\n });\n });\n\n this.server = undefined;\n this.events$.next({ type: 'stop', running: true });\n }\n\n /**\n * Stops the server and starts it again.\n *\n * @returns A promise settling once the new server is listening\n *\n * @remarks\n * Reads the configuration afresh on the way back up, so an edit made while it was running takes effect.\n * A port left at `0` is no longer `0` by then, since the previous run wrote the assigned one back,\n * so a restart keeps the port it was given rather than asking for another.\n *\n * @example\n * ```ts\n * server.config.verbose = true;\n * await server.restart(); // 'Restarting server...' then listening again, now logging requests\n * ```\n *\n * @see stop\n * @see start\n *\n * @since 2.0.0\n */\n\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Writes the port the system assigned back onto the configuration.\n *\n * @remarks\n * Only a configured `0` is replaced, since `0` is the value that leaves the choice to the operating system.\n * A port asked for by number is already what was bound.\n * Called from the listen callback, before `onStart`, so the hook and every later reader see the real port.\n *\n * @since 2.0.0\n */\n\n private setActualPort(): void {\n if (this.config.port === 0) {\n const address = this.server!.address();\n if(address && typeof address === 'object' && address.port)\n this.config.port = address.port;\n }\n }\n\n /**\n * Creates and starts the plain HTTP server.\n *\n * @returns A promise settling once the server is listening\n *\n * @remarks\n * Every request goes through {@link handleRequest},\n * which is handed the default handling as a callback,\n * so a configuration hook can decide whether to run it.\n *\n * @since 2.0.0\n */\n\n private startHttpServer(): Promise<void> {\n return new Promise<void>((resolve) => {\n this.server = http.createServer((req, res) => {\n this.handleRequest(req, res, () => this.defaultResponse(req, res));\n });\n\n this.server.listen(this.config.port, this.config.host, () => {\n this.setActualPort();\n const address: ServerAddressInterface = {\n host: this.config.host!,\n port: this.config.port!,\n url: `http://${ this.config.host }:${ this.config.port }`\n };\n\n this.config.onStart?.(address);\n this.events$.next({ ...address, type: 'start' });\n resolve();\n });\n });\n }\n\n /**\n * Creates and starts the HTTPS server.\n *\n * @returns A promise settling once the server is listening\n *\n * @throws Error - Raised when a key or certificate cannot be read\n *\n * @remarks\n * A configuration naming neither key nor certificate falls back to the pair shipped with the framework,\n * so HTTPS can be switched on without producing one first.\n * That pair is self-signed, so a browser will warn about it, which is what a development server can live with.\n * Both files are read synchronously, before anything is listening,\n * so a missing one fails the start rather than the first request.\n *\n * @since 2.0.0\n */\n\n private startHttpsServer(): Promise<void> {\n return new Promise((resolve) => {\n const options = {\n key: readFileSync(this.config.key ?? join(this.framework.frameworkRoot, '..', 'certs', 'server.key')),\n cert: readFileSync(this.config.cert ?? join(this.framework.frameworkRoot, '..', 'certs', 'server.crt'))\n };\n\n this.server = https.createServer(options, (req, res) => {\n this.handleRequest(req, res, () => this.defaultResponse(req, res));\n });\n\n this.server.listen(this.config.port, this.config.host, () => {\n this.setActualPort();\n const address: ServerAddressInterface = {\n host: this.config.host!,\n port: this.config.port!,\n url: `https://${ this.config.host }:${ this.config.port }`\n };\n\n this.config.onStart?.(address);\n this.events$.next({ ...address, type: 'start' });\n resolve();\n });\n });\n }\n\n /**\n * Passes a request to the configuration's hook or to the default handling when there is none.\n *\n * @param req - Request as it arrived\n * @param res - Response to write to\n * @param defaultHandler - The static-file handling, for the hook to call or to skip\n *\n * @remarks\n * A hook that never calls the handler owns the response entirely,\n * which is what makes an API route or a single-page fallback possible.\n * Only what throws synchronously reaches the error response here:\n * the default handling is asynchronous and catches its own failures,\n * and a hook that rejects a promise of its own is beyond this.\n *\n * @see sendError\n * @since 2.0.0\n */\n\n private handleRequest(req: IncomingMessage, res: ServerResponse, defaultHandler: () => void): void {\n try {\n this.events$.next({ type: 'request', url: req.url ?? '' });\n\n if (this.config.onRequest) {\n this.config.onRequest(req, res, defaultHandler);\n } else {\n defaultHandler();\n }\n } catch (error) {\n this.sendError(res, <Error> error);\n }\n }\n\n /**\n * Maps a file extension to the content type it is served as.\n *\n * @param ext - Extension without its dot\n * @returns The matching content type, or the binary fallback for an extension not listed\n *\n * @remarks\n * Covers what a build emits rather than the web at large.\n * TypeScript is served as plain text, so a browser shows a source file instead of downloading it,\n * and an unlisted extension downloads under the binary fallback rather than under a guess.\n *\n * @since 2.0.0\n */\n\n private getContentType(ext: string): string {\n const contentTypes: Record<string, string> = {\n html: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n cjs: 'application/javascript',\n mjs: 'application/javascript',\n ts: 'text/plain',\n map: 'application/json',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n gif: 'image/gif',\n txt: 'text/plain'\n };\n\n return contentTypes[ext] || 'application/octet-stream';\n }\n\n /**\n * Resolves a request to a path under the root and serves whatever is there.\n *\n * @param req - Request as it arrived\n * @param res - Response to write to\n *\n * @remarks\n * The request path is joined onto the root and the result checked for the root prefix,\n * so a path climbing out with `..` is refused with a 403.\n * The check is by prefix rather than true containment,\n * so a sibling directory whose name starts with the root's own would pass it.\n * A directory is listed and a file is sent.\n * Anything else on disk - a socket or a device - matches neither, and the request ends unanswered.\n * A path that cannot be reached at all is reported as missing,\n * and a failed `favicon.ico` is passed over in the log, since browsers ask for one unprompted on every visit.\n *\n * @see handleFile\n * @see handleDirectory\n *\n * @since 2.0.0\n */\n\n private async defaultResponse(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const requestPath = req.url === '/' ? '' : req.url?.replace(/^\\/+/, '') || '';\n const fullPath = join(this.rootDir, requestPath);\n\n if (!fullPath.startsWith(this.rootDir)) {\n res.statusCode = 403;\n res.end();\n\n return;\n }\n\n try {\n const stats = await stat(fullPath);\n\n if (stats.isDirectory()) {\n await this.handleDirectory(fullPath, requestPath, res);\n } else if (stats.isFile()) {\n await this.handleFile(fullPath, res);\n }\n } catch (error) {\n this.events$.next({ type: 'error', error: <Error> error, url: req.url });\n this.sendNotFound(res);\n }\n }\n\n /**\n * Renders a directory as a browsable listing.\n *\n * @param fullPath - Absolute path of the directory to list\n * @param requestPath - The same directory as the request spelled it, relative to the root\n * @param res - Response to write to\n *\n * @remarks\n * Entries are told apart by whether they have an extension,\n * so a directory carrying a dot in its name is drawn as a file,\n * since a listing is navigation rather than a report.\n * The request path is also split into a trail of links, one per directory it names,\n * which is what lets a visitor climb back out.\n * Names are put into the template as they are, so a filename containing markup reaches the page intact.\n *\n * @since 2.0.0\n */\n\n private async handleDirectory(fullPath: string, requestPath: string, res: ServerResponse): Promise<void> {\n const files = await readdir(fullPath);\n let fileList = files.map(file => {\n const fullPath = join(requestPath, file);\n const ext = extname(file).slice(1) || 'folder';\n\n if(ext === 'folder') {\n return `\n <a href=\"/${ fullPath }\" class=\"folder-row\">\n <div class=\"icon\"><i class=\"fa-solid fa-folder\"></i></div>\n <div class=\"meta\"><div class=\"name\">${ file }</div><div class=\"sub\">Folder</div></div>\n </a>\n `;\n }\n\n return `\n <a href=\"/${ fullPath }\" class=\"file-row\">\n <div class=\"icon\"><i class=\"fa-solid fa-file-code\"></i></div>\n <div class=\"meta\"><div class=\"name\">${ file }</div><div class=\"sub\">${ ext }</div></div>\n </a>\n `;\n }).join('');\n\n if(!fileList) {\n fileList = '<div class=\"empty\">No files or folders here.</div>';\n } else {\n fileList = `<div class=\"list\">${ fileList }</div>`;\n }\n\n let activePath = '/';\n const segments = requestPath.split('/').map(path => {\n activePath += `${ path }/`;\n\n return `<li><a href=\"${ activePath }\">${ path }</a></li>`;\n }).join('');\n\n const htmlResult = html.replace('${ fileList }', fileList)\n .replace('${ paths }', '<li><a href=\"/\">root</a></li>' + segments)\n .replace('${ up }', '/' + requestPath.split('/').slice(0, -1).join('/'));\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(htmlResult);\n }\n\n /**\n * Sends one file.\n *\n * @param fullPath - Absolute path of the file to send\n * @param res - Response to write to\n *\n * @remarks\n * Read whole before anything is written,\n * so the response carries no length and a large file is held in memory rather than streamed,\n * which a development server over its own build output can afford.\n * A file with no extension is treated as text.\n *\n * @see getContentType\n * @since 2.0.0\n */\n\n private async handleFile(fullPath: string, res: ServerResponse): Promise<void> {\n const ext = extname(fullPath).slice(1) || 'txt';\n const contentType = this.getContentType(ext);\n\n const data = await readFile(fullPath);\n res.writeHead(200, { 'Content-Type': contentType });\n res.end(data);\n }\n\n /**\n * Answers a request that reached nothing.\n *\n * @param res - Response to write to\n *\n * @remarks\n * Plain text rather than the listing template, since the answer is for whatever asked rather than for a reader.\n *\n * @since 2.0.0\n */\n\n private sendNotFound(res: ServerResponse): void {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n\n /**\n * Answers a request that failed and reports why.\n *\n * @param res - Response to write to\n * @param error - The failure to report\n *\n * @remarks\n * The reason is logged rather than sent,\n * so a stack trace reaches the developer running the server and not whoever is connected to it.\n *\n * @since 2.0.0\n */\n\n private sendError(res: ServerResponse, error: Error): void {\n this.events$.next({ type: 'error', error });\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end('Internal Server Error');\n }\n}\n","<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"/><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/><title>Dark File Browser — FTP-like</title><link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css\" integrity=\"sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw==\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" /><style>:root{--bg:#0b0f14;--panel:#0f1720;--muted:#9aa4b2;--accent:#E5C07B;--glass:rgba(255,255,255,0.03);--card:#0c1116;--radius:12px;--gap:12px;--shadow:0 6px 18px rgba(0,0,0,0.4);--file-icon-size:40px;font-family:Inter,ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial}*{box-sizing:border-box;font-style:normal !important}html,body{height:100%;margin:0;font-size:14px;color:#dce7ef;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:radial-gradient(1200px 600px at 10% 10%,rgba(110,231,183,0.04),transparent 8%),linear-gradient(180deg,rgba(255,255,255,0.01),transparent 20%),var(--bg);padding:28px;display:flex;gap:20px;align-items:flex-start;justify-content:center}.app{width:1100px;max-width:98vw;display:flex;gap:18px;padding:18px;border-radius:16px;box-shadow:var(--shadow);border:1px solid rgba(255,255,255,0.03);background:linear-gradient(180deg,rgba(255,255,255,0.02),rgba(255,255,255,0));overflow:hidden}.sidebar{width:260px;background:linear-gradient(180deg,rgba(255,255,255,0.01),transparent);border-radius:var(--radius);padding:14px}.brand{display:flex;gap:12px;align-items:center;margin-bottom:10px}.logo{width:46px;height:46px;border-radius:10px;background:linear-gradient(135deg,#b65b9f 0%,#804b8f 100%);display:flex;align-items:center;justify-content:center;font-weight:700}.brand h1{font-size:16px;margin:0}.muted{color:var(--muted);font-size:13px}.search{margin:12px 0}.search input{width:100%;padding:10px 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.03);background:var(--glass);color:inherit}.quick-list{margin-top:12px}.quick-list a{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;background:transparent;color:var(--muted);text-decoration:none;cursor:pointer;transition:color 0.15s ease}.quick-list a:hover{color:var(--accent)}.main{flex:1;display:flex;flex-direction:column}.topbar{display:flex;align-items:center;gap:12px;padding-bottom:12px}.breadcrumbs{list-style:none;display:flex;gap:8px;align-items:center;background:var(--glass);padding:8px 12px;border-radius:var(--radius);margin:0}.breadcrumbs li{display:flex;align-items:center}.breadcrumbs li:not(:last-child)::after{content:'>';margin-left:8px;color:var(--muted)}.breadcrumbs a{color:var(--muted);text-decoration:none;transition:color 0.15s ease}.breadcrumbs a:hover{color:var(--accent)}.list{margin-top:14px;display:grid;grid-template-columns:1fr;gap:10px}.list a{display:flex;text-decoration:none;color:inherit}.folder-row,.file-row{display:flex;gap:12px;align-items:center;padding:10px;border-radius:10px;background:linear-gradient(180deg,rgba(255,255,255,0.01),transparent);border:1px solid rgba(255,255,255,0.02);transition:color 0.25s ease}.icon{width:var(--file-icon-size);height:var(--file-icon-size);border-radius:10px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.02);flex-shrink:0;transition:background 0.25s ease,color 0.25s ease}.folder-row:hover,.file-row:hover{color:var(--accent)}.folder-row:hover .icon{background:rgba(152,195,121,0.2)}.file-row:hover .icon{background:rgba(224,108,117,0.2)}.folder-row:hover .icon i{color:#98C379}.file-row:hover .icon i{color:#e09c6c}.meta{display:flex;flex-direction:column}.name{font-weight:600}.sub{color:var(--muted);font-size:13px}.empty{padding:40px;text-align:center;color:var(--muted)}@media (max-width:880px){.app{flex-direction:column;padding:12px}.sidebar,.main{width:100%}}</style></head><body><div class=\"app\"><aside class=\"sidebar\"><div class=\"brand\"><div class=\"logo\">F</div><div><h1>xBuildFTP</h1><div class=\"muted\">Browse & serve files</div></div></div><div class=\"search\"><input placeholder=\"Search files & folders...\"/></div><div class=\"quick-list\"><a href=\"/\">🏠 Home</a><a href=\"${ up }\">⬆️ Up</a></div></aside><main class=\"main\"><div class=\"topbar\"><div class=\"topbar\"><ul class=\"breadcrumbs\"> ${ paths } </ul></div></div> ${ fileList } </main></div></body><script> const searchInput = document.querySelector('.search input'); const listItems = document.querySelectorAll('.list > .folder-row, .list > .file-row'); const emptyMessage = document.querySelector('.empty'); searchInput.addEventListener('input', () => { const query = searchInput.value.toLowerCase(); let anyVisible = false; listItems.forEach(item => { const name = item.querySelector('.name').textContent.toLowerCase(); if (name.includes(query)) { item.style.display = 'flex'; anyVisible = true; } else { item.style.display = 'none'; } }); emptyMessage.style.display = anyVisible ? 'none' : 'block'; }); </script></html>","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { PositionInterface, FormatStackFrameInterface } from '@remotex-labs/xmap';\n\n/**\n * Imports\n */\n\nimport { cwd } from 'process';\nimport { readFileSync } from 'fs';\nimport { FilesModel } from '@models/files.model';\nimport { inject, Injectable } from '@remotex-labs/xinject';\nimport { normalize, SourceService } from '@remotex-labs/xmap';\n\n/**\n * Matches a path that belongs to the framework rather than to the project being built.\n *\n * @remarks\n * Case-insensitive, since the same file surfaces as `xBuild` from a checkout and as `xbuild` from `node_modules`.\n * The lookahead spares a project's own `xbuild.config`, which names the framework without being part of it.\n *\n * @since 3.0.0\n */\n\nconst FRAMEWORK_PATH_REGEX = /xbuild(?!\\.config)/i;\n\n/**\n * Matches a source map whose `mappings` field is empty.\n *\n * @remarks\n * Such a map resolves nothing,\n * so keeping it would cost a lookup on every frame and answer with the generated position anyway.\n * Kept at module level so the pattern is compiled once rather than on every registration.\n *\n * @since 3.0.0\n */\n\nconst EMPTY_MAPPINGS_REGEX = /\"mappings\"\\s*:\\s*\"\"/;\n\n/**\n * Holds the framework's own paths and the source maps a stack trace is resolved through.\n *\n * @remarks\n * Two jobs in service of one thing - reporting an error against the source a reader recognizes.\n * It tells framework frames apart from a project's own,\n * and it hands out the {@link SourceService} that maps a generated position back to its source.\n * Maps arrive either as text through {@link addSourceMap} or read from a `.map` companion through\n * {@link loadSourceMap}, and both are keyed by resolved path, so the same file registered under a relative and an\n * absolute path is parsed once.\n * The framework's own map is loaded on construction, which is what lets an error thrown inside the build be reported\n * against its source.\n * Registered as a singleton, so every consumer shares one registry.\n *\n * @example\n * ```ts\n * const framework = inject(FrameworkService);\n *\n * framework.projectRoot; // 'D:/app' - where the build was started\n * framework.getSourceMap(framework.frameworkFile); // the framework's own SourceService\n * framework.isFrameworkFile({ source: 'D:/app/src/index.ts' }); // false - a project file\n * ```\n *\n * @see SourceService\n * @since 2.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class FrameworkService {\n /**\n * Absolute path of the framework file this service was loaded from.\n *\n * @remarks\n * Normalized like {@link frameworkRoot} and {@link projectRoot},\n * so all three compare and join the same way whatever the platform.\n *\n * @example\n * ```ts\n * framework.frameworkFile; // 'D:/app/node_modules/@remotex-labs/xbuild/dist/index.js'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly frameworkFile: string;\n\n /**\n * Absolute path of the directory the framework was distributed in.\n *\n * @remarks\n * Where anything shipped beside the build is found, the server's certificates among them.\n *\n * @example\n * ```ts\n * framework.frameworkRoot; // 'D:/app/node_modules/@remotex-labs/xbuild/dist'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly frameworkRoot: string;\n\n /**\n * Absolute path of the directory the build was started from.\n *\n * @remarks\n * The user's project root rather than the framework's,\n * so it is what a path is made relative to when a frame is printed.\n *\n * @example\n * ```ts\n * framework.projectRoot; // 'D:/app'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly projectRoot: string;\n\n /**\n * Shared file cache, held on the class so {@link resolve} needs no instance.\n *\n * @remarks\n * What is wanted here is the memo it keeps rather than the snapshots: resolving through it is what keeps this\n * registry, the file cache, and everything else keyed by path agreeing on what one path is.\n * Claimed by the first {@link resolve} rather than by a static initializer, since an initializer would run while\n * this module is being imported, and importing it must not reach the container.\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n private static files?: FilesModel;\n\n /**\n * Source maps keyed by the resolved path of the file each one describes.\n *\n * @since 2.0.0\n */\n\n private readonly sourceMaps = new Map<string, SourceService>();\n\n /**\n * Captures the framework's paths and loads its own source map.\n *\n * @throws Error - When the framework ships without a readable `.map` companion\n *\n * @remarks\n * A framework shipped without its map is a broken build rather than a supported one,\n * so the read failure surfaces here instead of being swallowed.\n *\n * @example\n * ```ts\n * const framework = new FrameworkService();\n * framework.getSourceMap(framework.frameworkFile); // SourceService\n * ```\n *\n * @see loadSourceMap\n * @since 2.0.0\n */\n\n constructor() {\n this.projectRoot = normalize(cwd());\n this.frameworkFile = normalize(import.meta.filename);\n this.frameworkRoot = normalize(import.meta.dirname);\n\n this.loadSourceMap(this.frameworkFile);\n }\n\n /**\n * Normalizes a path to the absolute form every cache here is keyed by.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns Absolute path with forward slashes\n *\n * @remarks\n * Static so that a caller with no framework service in hand can still key a path the way this package does, which\n * is what keeps entry-point names, source-map keys, and file entries from disagreeing about one file.\n * The first call claims the file cache, and every later call finds it already claimed, so the container is reached\n * only once something asks for a path rather than when this module is imported.\n * Resolution is memoized by the cache behind it, so resolving the same path again costs a lookup.\n *\n * @example\n * ```ts\n * FrameworkService.resolve('src/index.ts'); // 'D:/app/src/index.ts'\n * ```\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n static resolve(path: string): string {\n return (FrameworkService.files ??= inject(FilesModel)).resolve(path);\n }\n\n /**\n * Reports whether a position belongs to the framework rather than to the project being built.\n *\n * @param position - Position or stack frame to judge, as the source map resolver reports it\n * @returns `true` when the position comes from framework code\n *\n * @remarks\n * The judgment is made on the path, matched case-insensitively, since the same file surfaces as `xBuild` from a\n * checkout and as `xbuild` from `node_modules`.\n * A project's own `xbuild.config` names the framework without being part of it, so it is excluded by name.\n * The source root is consulted only when the source itself does not settle the question.\n *\n * @example\n * ```ts\n * framework.isFrameworkFile({ source: 'D:/app/node_modules/xbuild/dist/index.js' }); // true\n * framework.isFrameworkFile({ source: 'D:/app/xbuild.config.ts' }); // false\n * framework.isFrameworkFile({ source: 'D:/app/src/index.ts' }); // false\n * ```\n *\n * @see PositionInterface\n * @see FormatStackFrameInterface\n *\n * @since 2.2.5\n */\n\n isFrameworkFile(position: PositionInterface | FormatStackFrameInterface): boolean {\n return FRAMEWORK_PATH_REGEX.test(position.source ?? '') || FRAMEWORK_PATH_REGEX.test(position.sourceRoot ?? '');\n }\n\n /**\n * Returns the source map registered for a file.\n *\n * @param path - Path of the file, relative or absolute\n * @returns The source map of that file, or `undefined` when none was registered\n *\n * @remarks\n * A pure registry read: a file that was never registered stays unregistered, since nothing here reaches the disk.\n * Use {@link loadSourceMap} to register one.\n *\n * @example\n * ```ts\n * framework.getSourceMap('dist/index.js'); // undefined - never registered\n * framework.loadSourceMap('dist/index.js');\n * framework.getSourceMap('dist/index.js'); // SourceService\n * ```\n *\n * @see SourceService\n * @since 2.0.0\n */\n\n getSourceMap(path: string): SourceService | undefined {\n return this.sourceMaps.get(FrameworkService.resolve(path));\n }\n\n /**\n * Registers a source map from its text.\n *\n * @param path - Path of the file the map describes, relative or absolute\n * @param source - Raw source map content\n * @param force - Whether a map the file already carries is replaced rather than kept\n *\n * @throws Error - When the content is not a source map the resolver can parse\n *\n * @remarks\n * A file that already carries a map keeps it, so the first registration wins, and a later call costs only a lookup.\n * A caller that knows the file was written again says so with `force`, which parses the map it was handed and puts\n * it in place of the one registered before: a watch rebuilding a file leaves the map registered for it describing\n * text that is no longer there, and a stale map resolves a frame to the wrong line rather than to none.\n * A map with empty mappings is dropped rather than registered, resolving through such a map being the same as not\n * resolving at all, and it leaves what was registered before it in place rather than clearing it.\n *\n * @example\n * ```ts\n * framework.addSourceMap('dist/index.js', readFileSync('dist/index.js.map', 'utf-8'));\n * framework.getSourceMap('dist/index.js'); // SourceService\n *\n * framework.addSourceMap('dist/index.js', rebuilt); // kept - the first registration wins\n * framework.addSourceMap('dist/index.js', rebuilt, true); // replaced - the file was written again\n * ```\n *\n * @see loadSourceMap\n * @since 3.0.0\n */\n\n addSourceMap(path: string, source: string, force: boolean = false): void {\n const key = FrameworkService.resolve(path);\n if (!force && this.sourceMaps.has(key)) return;\n\n this.register(key, source);\n }\n\n /**\n * Registers the source map a file's `.map` companion carries.\n *\n * @param path - Path of the generated file, relative or absolute\n *\n * @throws Error - When the companion cannot be read or does not parse\n *\n * @remarks\n * The companion is looked for beside the file, as `<path>.map`, which is where every file this toolchain emits\n * carries its map.\n * A file that already carries a map is left alone before the disk is touched,\n * so repeating the call on a tracked file costs only a lookup.\n * An empty path is ignored outright,\n * and a companion that parses but maps nothing registers no map and raises nothing.\n *\n * @example\n * ```ts\n * framework.loadSourceMap('dist/index.js'); // reads dist/index.js.map\n * framework.loadSourceMap('dist/index.js'); // cached - no read\n * ```\n *\n * @see addSourceMap\n * @since 3.0.0\n */\n\n loadSourceMap(path: string): void {\n if (!path) return;\n\n const key = FrameworkService.resolve(path);\n if (this.sourceMaps.has(key)) return;\n\n let source: string;\n try {\n source = readFileSync(`${ key }.map`, 'utf-8');\n } catch (error) {\n throw FrameworkService.failure(key, error);\n }\n\n this.register(key, source);\n }\n\n /**\n * Builds the error reported when a source map cannot be registered.\n *\n * @param key - Resolved path of the file the map describes\n * @param error - Failure raised while reading or parsing it\n * @returns The error to throw, naming the file and carrying the original reason\n *\n * @remarks\n * The reading and the parsing halves fail in the same way as far as a caller is concerned,\n * so both report the file first and the reason after it.\n *\n * @since 3.0.0\n */\n\n private static failure(key: string, error: unknown): Error {\n return new Error(\n `Failed to load source map for: ${ key }\\n${ error instanceof Error ? error.message : String(error) }`\n );\n }\n\n /**\n * Parses a source map and files it under a resolved path.\n *\n * @param key - Resolved path of the file the map describes\n * @param source - Raw source map content\n *\n * @throws Error - When the content is not a source map the resolver can parse\n *\n * @remarks\n * The single point where a map enters the registry,\n * so both entry points resolve their path once and skip an already registered file before reaching here.\n * A map with empty mappings is dropped rather than registered, since resolving through such a map answers with\n * the position it was given.\n *\n * @since 3.0.0\n */\n\n private register(key: string, source: string): void {\n if (EMPTY_MAPPINGS_REGEX.test(source)) return;\n\n try {\n this.sourceMaps.set(key, new SourceService(source, key));\n } catch (error) {\n throw FrameworkService.failure(key, error);\n }\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { Stats } from 'fs';\nimport type { TextChangeRange } from 'typescript';\nimport type { FileSnapshotInterface, ScriptSnapshotType } from './interfaces/files-model.interface';\n\n/**\n * Imports\n */\n\nimport { readFileSync, statSync } from 'fs';\nimport { resolve } from '@remotex-labs/xmap';\nimport { Injectable } from '@remotex-labs/xinject';\n\n/**\n * In-memory cache of file contents keyed by resolved absolute path.\n *\n * @remarks\n * Backs the TypeScript language service, which asks for a script version on every request and only reparses when\n * that version changes.\n * Content is read once and re-read only when the modification time moves,\n * so repeated lookups of an unchanged file cost a map read.\n * Reach for {@link touch} when any cached content will do,\n * {@link refresh} when the file may have changed on disk or when a watcher already carries its `Stats`,\n * and {@link refreshAll} to catch what the watcher failed to report.\n *\n * @example\n * ```ts\n * const model = inject(FilesModel);\n *\n * model.touch('src/index.ts').version; // 1 - read from disk\n * model.touch('src/index.ts').version; // 1 - served from the cache\n * model.refresh('src/index.ts').version; // 2 - the file changed on disk\n * model.clear(); // every entry dropped\n * ```\n *\n * @see FileSnapshotInterface\n * @since 2.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class FilesModel {\n /**\n * Memoized mapping from an input path to its resolved absolute form.\n *\n * @remarks\n * Kept apart from {@link cache} because several input paths can resolve to the same absolute path,\n * and resolution is repeated far more often than content changes.\n *\n * @since 3.0.0\n */\n\n private readonly resolved = new Map<string, string>();\n\n /**\n * Entries keyed by resolved absolute path.\n *\n * @remarks\n * Holds one {@link FileSnapshotInterface} per tracked path, including paths that carry no readable file.\n *\n * @since 3.0.0\n */\n\n private readonly cache = new Map<string, FileSnapshotInterface>();\n\n /**\n * Drops every cached entry and every memoized path.\n *\n * @remarks\n * Leaves the model in its initial state, so the next request re-reads from disk and restarts versions at `1`.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts');\n * model.clear();\n * model.getSnapshot('src/index.ts'); // undefined\n * ```\n *\n * @since 2.0.0\n */\n\n clear(): void {\n this.cache.clear();\n this.resolved.clear();\n }\n\n /**\n * Returns the cached entry for a path without touching the filesystem.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns The cached entry, or `undefined` when the path was never tracked\n *\n * @remarks\n * A pure cache read: it never reads or stats the file, so an untracked path stays untracked.\n * Use {@link touch} to track the path instead.\n *\n * @example\n * ```ts\n * model.getSnapshot('src/index.ts'); // undefined - never tracked\n * model.touch('src/index.ts');\n * model.getSnapshot('src/index.ts'); // { mtimeMs: 1754000000000, version: 1, snapshot: { ... } }\n * ```\n *\n * @see touch\n * @since 2.0.0\n */\n\n getSnapshot(path: string): FileSnapshotInterface | undefined {\n return this.cache.get(this.resolve(path));\n }\n\n /**\n * Returns the entry for a path, reading the file when it is not tracked yet.\n *\n * @param path - Filesystem path, relative or absolute\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, cached or newly created\n *\n * @remarks\n * A tracked path is returned as it stands, without a `stat` call, however stale it may be.\n * Use {@link refresh} when the file may have changed since it was cached.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts').version; // 1 - read from disk\n * model.touch('src/index.ts').version; // 1 - served from the cache, no stat\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n touch(path: string, encoding?: BufferEncoding): FileSnapshotInterface {\n const target = this.resolve(path);\n\n return this.cache.get(target) ?? this.sync(target, this.stat(target), encoding);\n }\n\n /**\n * Synchronizes a path with the filesystem and returns its entry.\n *\n * @param path - Filesystem path, relative or absolute\n * @param stats - Already obtained `Stats` for the path, sparing a `stat` call\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, rebuilt only when the file actually changed\n *\n * @remarks\n * The content is re-read when the modification time differs from the cached one,\n * so calling this on an unchanged file leaves its version intact.\n * A path that is missing or is not a regular file yields an entry with an `undefined` snapshot.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts').version; // 1\n * model.refresh('src/index.ts').version; // 1 - mtime unchanged\n * model.refresh('src/index.ts').version; // 2 - the file was written to\n * ```\n *\n * @see touch\n * @since 3.0.0\n */\n\n refresh(path: string, stats?: Stats, encoding?: BufferEncoding): FileSnapshotInterface {\n const target = this.resolve(path);\n\n return this.sync(target, stats ?? this.stat(target), encoding);\n }\n\n /**\n * Synchronizes a set of paths, or every path already tracked.\n *\n * @param paths - Paths to synchronize, defaulting to everything in the cache\n *\n * @remarks\n * The safety net under file watching: a change that goes unreported leaves an entry stale with nothing to\n * announce it - the version never moves,\n * so the language service is never told to reparse, and the build keeps compiling text that is no longer on disk.\n * Sweeping asks the filesystem rather than the watcher,\n * so a missed event costs a needless rebuild at worst rather than a wrong one.\n * Every path gets a `stat`, and only the ones whose time moved are read again.\n * The keys it walks are already resolved,\n * so re-synchronizing them writes back over the same keys and cannot extend the walk.\n * A tracked path that is still missing keeps the entry and the version it had,\n * so repeated sweeps do not inflate the versions of files that were deleted.\n *\n * @example\n * ```ts\n * model.refreshAll([ 'src/index.ts' ]); // that one path\n * model.refreshAll(); // every tracked path, re-read where it changed\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n refreshAll(paths?: Array<string>): void {\n const pathList = paths ?? this.cache.keys();\n for (const path of pathList) {\n this.refresh(path);\n }\n }\n\n /**\n * Normalizes a path to its absolute form.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns Absolute path with forward slashes\n *\n * @remarks\n * The result is memoized per input string, since the same paths are resolved on every cache lookup.\n *\n * @example\n * ```ts\n * model.resolve('src/index.ts'); // 'D:/project/src/index.ts'\n * ```\n *\n * @since 2.0.0\n */\n\n resolve(path: string): string {\n let target = this.resolved.get(path);\n if (target === undefined) this.resolved.set(path, target = resolve(path));\n\n return target;\n }\n\n /**\n * Brings the entry for a resolved path in line with the given filesystem state.\n *\n * @param target - Resolved absolute path\n * @param info - `Stats` for the path, or `undefined` when it does not exist\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, reused when nothing changed\n *\n * @remarks\n * A path that is not a regular file keeps its already empty entry untouched,\n * so repeated events for a missing path do not inflate its version.\n * A file whose modification time matches the cached one is left as is, and the content is not read.\n *\n * @since 3.0.0\n */\n\n private sync(target: string, info: Stats | undefined, encoding: BufferEncoding = 'utf-8'): FileSnapshotInterface {\n const entry = this.cache.get(target);\n\n if (!info?.isFile()) {\n if (entry && !entry.snapshot) return entry;\n\n return this.store(target, { mtimeMs: 0, snapshot: undefined, version: (entry?.version ?? 0) + 1 });\n }\n\n if (entry?.mtimeMs === info.mtimeMs) return entry;\n\n return this.store(target, {\n mtimeMs: info.mtimeMs,\n version: (entry?.version ?? 0) + 1,\n snapshot: this.snapshot(readFileSync(target, encoding))\n });\n }\n\n /**\n * Computes the span that differs between two versions of a text.\n *\n * @param oldText - Text the language service last parsed\n * @param newText - Text that replaces it\n * @returns The replaced span in `oldText` together with the length of its replacement\n *\n * @remarks\n * Narrows the change by trimming the shared prefix and the shared suffix,\n * which lets the language service reuse the untouched parts of the syntax tree.\n * The suffix scan stops at the prefix boundary, so the two never overlap on a text that shrank.\n *\n * @since 3.0.0\n */\n\n private changeRange(oldText: string, newText: string): TextChangeRange {\n const oldLength = oldText.length;\n const newLength = newText.length;\n const max = Math.min(oldLength, newLength);\n\n let prefix = 0;\n while (prefix < max && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix)) prefix++;\n\n let suffix = 0;\n while (suffix < max - prefix && oldText.charCodeAt(oldLength - 1 - suffix) === newText.charCodeAt(newLength - 1 - suffix)) suffix++;\n\n return {\n span: { start: prefix, length: oldLength - prefix - suffix },\n newLength: newLength - prefix - suffix\n };\n }\n\n /**\n * Wraps file content in a script snapshot.\n *\n * @param text - Content read from disk\n * @returns A snapshot exposing the content both as `text` and through the `IScriptSnapshot` methods\n *\n * @remarks\n * `getChangeRange` closes over this text as the new version and delegates to {@link changeRange},\n * so the language service can diff against any earlier snapshot it still holds.\n *\n * @since 3.0.0\n */\n\n private snapshot(text: string): ScriptSnapshotType {\n return {\n text,\n getText: (start, end): string => text.slice(start, end),\n getLength: (): number => text.length,\n getChangeRange: (previous):\n TextChangeRange => this.changeRange(previous.getText(0, previous.getLength()), text)\n };\n }\n\n /**\n * Writes an entry to the cache and hands it back.\n *\n * @param target - Resolved absolute path\n * @param entry - Entry to store under that path\n * @returns The stored entry\n *\n * @remarks\n * Exists so {@link sync} can store and return in a single expression.\n *\n * @since 3.0.0\n */\n\n private store(target: string, entry: FileSnapshotInterface): FileSnapshotInterface {\n this.cache.set(target, entry);\n\n return entry;\n }\n\n /**\n * Reads the filesystem state of a path.\n *\n * @param path - Resolved absolute path\n * @returns The `Stats` for the path, or `undefined` when it does not exist\n *\n * @remarks\n * A missing path is an ordinary outcome here rather than a failure, so the throwing form is disabled.\n *\n * @since 3.0.0\n */\n\n private stat(path: string): Stats | undefined {\n return statSync(path, { throwIfNoEntry: false });\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { FSWatcher, Dirent } from 'fs';\nimport type { ErrorType, CompleteType, UnsubscribeType } from '@remotex-labs/xobservable';\nimport type { WatchEventType, ChangeType, ObserverType } from './interfaces/watch-service.interface';\nimport type { WatchChangeInterface, WatchOptionsInterface } from './interfaces/watch-service.interface';\n\n/**\n * Imports\n */\n\nimport { Injectable } from '@remotex-labs/xinject';\nimport { Subject } from '@remotex-labs/xobservable';\nimport { ChangeCode } from '@constants/watch.constant';\nimport { createMatcher } from '@components/glob.component';\nimport { resolve, join, relative } from '@remotex-labs/xmap';\nimport { watch, realpathSync, readdirSync, lstatSync, statSync } from 'fs';\n\n/**\n * A filesystem watcher that multicasts debounced batches of path changes to every subscriber.\n *\n * @remarks\n * Extends a multicast {@link Subject}: the underlying `fs.watch` handles are opened on the **first** subscription and\n * torn down only when the **last** subscription ends, while every active subscriber receives each emitted batch.\n * Events are filtered by a glob matcher, coalesced within a debounced window, and delivered as a single\n * {@link WatchEventType} keyed by path relative to the base.\n * Because `fs.watch` never follows symbolic links,\n * {@link WatchOptionsInterface.followSymlinks} places explicit watchers on the links it finds.\n * As a {@link Subject}, the emitted stream can be reshaped with `pipe` and operators before subscribing.\n *\n * @example\n * <caption>Multiple independent subscribers - each receives every batch</caption>\n * ```ts\n * const watcher = new WatchService('src', { recursive: true, filter: [ '**\\/*.{ts,js}' ], debounce: 100 });\n *\n * const stopA = watcher.subscribe((changes) => rebuild(changes)); // opens the fs watchers\n * const stopB = watcher.subscribe((changes) => reloadTypes(changes)); // reuses them\n *\n * stopB(); // watchers stay open - `stopA` is still subscribed\n * stopA(); // last subscriber leaves - every handle is closed\n * ```\n *\n * @example\n * <caption>Scoped teardown - the subscription disposes automatically at the end of the block</caption>\n * ```ts\n * const watcher = new WatchService(cwd(), { followSymlinks: true, filter: [ '**\\/*.{ts,js}' ] });\n * using sub = watcher.subscribe((changes) => console.log(Object.keys(changes)));\n * ```\n *\n * @see Subject.pipe\n * @see WatchEventType\n * @see WatchOptionsInterface\n *\n * @since 3.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class WatchService extends Subject<WatchEventType> {\n /**\n * The absolute root path being watched.\n *\n * @since 3.0.0\n */\n\n private readonly base: string;\n\n /**\n * Predicate deciding whether a path passes the configured filter.\n *\n * @since 3.0.0\n */\n\n private readonly matcher: ReturnType<typeof createMatcher>;\n\n /**\n * Active `fs.watch` handles, keyed by the path each was opened on.\n *\n * @since 3.0.0\n */\n\n private readonly watchers = new Map<string, FSWatcher>();\n\n /**\n * Changes accumulated in the current debounced window, keyed by path relative to the base.\n *\n * @since 3.0.0\n */\n\n private readonly pending = new Map<string, WatchChangeInterface>();\n\n /**\n * Count of currently active subscriptions, used to start watchers on the first and stop them on the last.\n *\n * @since 3.0.0\n */\n\n private subscriptions = 0;\n\n /**\n * Handle for the scheduled debounced flush, or `undefined` while idle.\n *\n * @since 3.0.0\n */\n\n private timer?: ReturnType<typeof setTimeout>;\n\n /**\n * Creates a watcher rooted at a base path.\n *\n * @param base - Directory to watch, resolved to an absolute path\n * @param options - Filtering, debounce, recursion, and symlink behavior\n *\n * @remarks\n * No watcher is opened until the first subscriber attaches, so constructing one costs a resolve and a matcher.\n *\n * @example\n * ```ts\n * const watcher = new WatchService('src', { filter: [ '**\\/*.ts' ] }); // nothing is watched yet\n * ```\n *\n * @see WatchOptionsInterface\n * @since 3.0.0\n */\n\n constructor(base: string, private options?: WatchOptionsInterface) {\n super();\n\n this.base = resolve(base);\n this.matcher = createMatcher(this.options?.filter ?? [], {\n dot: this.options?.dot ?? false\n });\n }\n\n /**\n * Subscribes to the debounced change stream, starting the watchers on the first subscriber.\n *\n * @param observerOrNext - A full observer object, or a `next` callback\n * @param error - Error handler, used when the first argument is a `next` callback\n * @param complete - Completion handler, used when the first argument is a `next` callback\n * @returns Idempotent, disposable unsubscribe function that detaches this subscriber and,\n * once it is the last one, closes every open watcher\n *\n * @remarks\n * The first subscription opens the `fs.watch` handles, and each later subscription reuses them.\n * Unsubscribing runs at most once.\n * The handles, the pending batch, and the flush timer are released only when the final subscriber leaves,\n * so a watcher shared by several consumers stays alive until all of them detach.\n *\n * @example\n * ```ts\n * const stop = watcher.subscribe((changes) => rebuild(changes));\n * stop(); // detaches, and closes the handles when no other subscriber is left\n * ```\n *\n * @see ObserverType\n * @see Subject.subscribe\n *\n * @since 3.0.0\n */\n\n override subscribe(observerOrNext?: ObserverType, error?: ErrorType, complete?: CompleteType): UnsubscribeType {\n const unsubscribe = super.subscribe(observerOrNext, error, complete);\n if (++this.subscriptions === 1) this.start();\n\n return this.toUnsubscribe(() => {\n unsubscribe();\n if (--this.subscriptions === 0) this.stop();\n });\n }\n\n /**\n * The debounced window in milliseconds, defaulting to 150.\n *\n * @since 3.0.0\n */\n\n private get debounce(): number {\n return this.options?.debounce ?? 150;\n }\n\n /**\n * Opens the base watcher and the symlink watchers when configured.\n *\n * @remarks\n * Invoked once when the subscriber count rises from zero to one.\n *\n * @since 3.0.0\n */\n\n private start(): void {\n this.watch(this.base, this.ignored.bind(this), this.options?.recursive);\n if (this.options?.followSymlinks) this.watchSymlinks(this.base);\n }\n\n /**\n * Clears the pending timer and closes every open watcher.\n *\n * @remarks\n * Invoked once when the subscriber count falls back to zero, returning the service to its pre-subscription state so\n * a later subscription can start clean.\n *\n * @since 3.0.0\n */\n\n private stop(): void {\n if (this.timer) clearTimeout(this.timer);\n for (const watcher of this.watchers.values()) watcher.close();\n\n this.timer = undefined;\n this.pending.clear();\n this.watchers.clear();\n }\n\n /**\n * Emits the accumulated batch to every subscriber and clears the window.\n *\n * @remarks\n * A no-op when nothing is pending, so an expired timer with no changes emits nothing.\n * A `next` that throws is reported to that subscriber's own `error` handler by the {@link Subject},\n * which then rethrows the failures as one aggregate.\n * That aggregate is swallowed here, so one faulty consumer cannot stop the watcher for the others.\n *\n * @since 3.0.0\n */\n\n private flush(): void {\n this.timer = undefined;\n if (this.pending.size === 0) return;\n\n const batch = Object.fromEntries(this.pending) as WatchEventType;\n this.pending.clear();\n\n try {\n this.next(batch);\n } catch {\n /* handled per-observer by the Subject */\n }\n }\n\n /**\n * Closes and forgets the watcher registered on a path, if any.\n *\n * @param path - Path whose watcher should be released\n *\n * @since 3.0.0\n */\n\n private watcherClose(path: string): void {\n const watcher = this.watchers.get(path);\n if (!watcher) return;\n\n watcher.close();\n this.watchers.delete(path);\n }\n\n /**\n * Classifies a raw watch event and queues it for the next flush.\n *\n * @param event - The `fs.watch` event name, either `rename` or `change`\n * @param path - Absolute path the event refers to\n *\n * @remarks\n * A symlink is stat-followed: when it resolves to a matching file, it is watched directly,\n * and when it resolves to a directory under a recursive watch, it is watched recursively.\n * A broken link is dropped.\n * The change type is read from that followed `stat` - a missing entry is {@link ChangeCode.Deleted} and closes its\n * watcher, an entry whose `birthtime` equals its `mtime` is {@link ChangeCode.Added},\n * and anything else is {@link ChangeCode.Change}.\n * Only paths that pass the filter arm the debounced timer and enter the pending batch.\n *\n * @since 3.0.0\n */\n\n private watcherEvent(event: string, path: string): void {\n const relativePath = relative(this.base, path);\n const link = lstatSync(path, { throwIfNoEntry: false });\n const stats = link?.isSymbolicLink() ? statSync(path, { throwIfNoEntry: false }) : link;\n\n if (link?.isSymbolicLink()) {\n if (!stats) return;\n if (event === 'rename') this.watcherClose(path);\n\n if (stats.isFile() && this.matcher(path)) this.watch(path);\n else if (stats.isDirectory() && this.options?.recursive)\n this.watch(path, this.ignored.bind(this), true);\n }\n\n if (!this.matcher(relativePath)) return;\n if (this.timer) this.timer.refresh();\n else this.timer = setTimeout(this.flush.bind(this), this.debounce);\n\n let type: ChangeType;\n if (!stats) {\n this.watcherClose(path);\n type = ChangeCode.Deleted;\n } else {\n type = stats.birthtimeMs === stats.mtimeMs ? ChangeCode.Added : ChangeCode.Change;\n }\n\n this.pending.set(relativePath, { type, stats });\n }\n\n /**\n * Opens an `fs.watch` on a path and registers its change and error handlers.\n *\n * @param path - Path to watch, ignored if already watched or filtered out by {@link ignored}\n * @param ignore - Optional per-entry ignore predicate forwarded to `fs.watch`\n * @param recursive - Whether the watch should cover nested entries\n *\n * @remarks\n * The watch is opened on the real (symlink-resolved) path, while events are reported against the original `path`.\n * A watcher error closes the watcher and forwards the error to every subscriber.\n *\n * @since 3.0.0\n */\n\n private watch(path: string, ignore?: (filename: string) => boolean, recursive: boolean = false): void {\n if (this.watchers.has(path) || this.ignored(path)) return;\n const watcher = watch(realpathSync(path), { recursive, ignore }, (event, filename) => {\n if (!filename) return;\n const target = path.includes(filename) ? path : join(path, filename);\n this.watcherEvent(event, target);\n });\n\n watcher.on('error', (error: Error) => {\n this.watcherClose(path);\n this.error(error);\n });\n\n this.watchers.set(path, watcher);\n }\n\n /**\n * Whether a path should be skipped by the watcher.\n *\n * @param target - Path to test\n * @returns `true` for an empty path, a `~` backup file, or - unless `dot` is set - any dot-prefixed segment\n *\n * @since 3.0.0\n */\n\n private ignored(target: string): boolean {\n if (!target || target.endsWith('~')) return true;\n if (!this.options?.dot) {\n if (target && target.split(/[/\\\\]/).some(\n seg => seg.startsWith('.'))\n ) return true;\n }\n\n return false;\n }\n\n /**\n * Walks the tree under a root and watches every symbolic link found.\n *\n * @param root - Directory to scan for links\n *\n * @remarks\n * Iterative and single-level per read, so ignored directories are pruned before entry and never fully materialized.\n * Descends into real subdirectories only when recursion is enabled.\n * Unreadable directories are skipped silently.\n *\n * @since 3.0.0\n */\n\n private watchSymlinks(root: string): void {\n const stack: Array<string> = [ root ];\n\n while (stack.length) {\n const dir = stack.pop()!;\n\n let entries: Array<Dirent>;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n const full = join(entry.parentPath ?? dir, entry.name);\n if (this.ignored(full)) continue;\n\n if (entry.isSymbolicLink()) {\n this.watch(full, this.ignored.bind(this), this.options?.recursive);\n } else if (this.options?.recursive && entry.isDirectory()) {\n stack.push(full);\n }\n }\n }\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { Dirent } from 'fs';\nimport type { GlobOptionsInterface } from './interfaces/glob-component.interface';\n\n/**\n * Imports\n */\n\nimport { readdirSync } from 'fs';\nimport { join } from '@remotex-labs/xmap';\nimport { Char } from '@constants/char.constant';\nimport { FrameworkService } from '@services/framework.service';\nimport { RegexElement, RegexCloser } from '@constants/glob.constant';\n\n/**\n * Escapes a single character for literal use inside a regular expression.\n *\n * @param char - The character to escape\n * @returns The character prefixed with a backslash when it carries special meaning in a regular expression,\n * or the character unchanged otherwise\n *\n * @remarks\n * A backslash is prepended when `char` is one of the regex metacharacters `.+^$()|\\{}[]*?`.\n * Any other character is returned as-is.\n * Intended for building patterns from user-supplied glob fragments where each source character must match itself.\n *\n * @example\n * ```ts\n * lit('.'); // '\\\\.'\n * lit('a'); // 'a'\n * ```\n *\n * @since 3.0.0\n */\n\nexport function lit(char: string): string {\n return '.+^$()|\\\\{}[]*?'.includes(char) ? '\\\\' + char : char;\n}\n\n/**\n * Returns the UTF-16 code unit of a glob string at a given index.\n *\n * @param glob - The glob string to read from\n * @param index - The zero-based position of the character to read\n * @returns The code unit at `index`, or `NaN` when `index` is out of range\n *\n * @remarks\n * A thin wrapper over {@link String.charCodeAt} used while scanning a glob pattern character by character.\n * Comparing code units avoids allocating single-character substrings on the hot path.\n *\n * @example\n * ```ts\n * at('a*b', 1); // 42 - Char.Star\n * at('a*b', 9); // NaN - past the end\n * ```\n *\n * @see Char\n * @since 3.0.0\n */\n\nexport function at(glob: string, index: number): number {\n return glob.charCodeAt(index);\n}\n\n/**\n * Determines whether the `**` at a given index forms a globstar segment.\n *\n * @param glob - The glob string being scanned\n * @param index - The zero-based position of the first `*` of the candidate `**`\n * @returns `true` when the `**` occupies a whole path segment, `false` otherwise\n *\n * @remarks\n * A globstar is a `**` that spans an entire path segment,\n * so it must be bounded on both sides by a slash or by the start or end of the string.\n * The character before `index` must be the start of the string or a slash,\n * and the character after the `**` must be the end of the string or a slash.\n * A `**` embedded within a segment, such as in `a**b`, matches as two consecutive single stars rather than a globstar.\n * The caller is responsible for confirming that both characters at `index` and `index + 1` are `*`.\n *\n * @example\n * ```ts\n * isGlobstar('**', 0); // true - the whole string\n * isGlobstar('a/**', 2); // true - preceded by a slash, ends the string\n * isGlobstar('a**b', 1); // false - embedded in a segment\n * ```\n *\n * @see Char\n * @since 3.0.0\n */\n\nexport function isGlobstar(glob: string, index: number): boolean {\n return (index === 0 || at(glob, index - 1) === Char.Slash)\n && (index + 2 === glob.length || at(glob, index + 2) === Char.Slash);\n}\n\n/**\n * Wraps a regex fragment in a non-capturing group.\n *\n * @param body - The regex source to enclose\n * @returns The body wrapped as `(?:body)`\n *\n * @remarks\n * Groups a fragment so a following quantifier or alternation applies to the whole fragment rather than its last token.\n *\n * @example\n * ```ts\n * group('a|b'); // '(?:a|b)'\n * group('a|b') + '?'; // '(?:a|b)?' - the quantifier covers both alternatives\n * ```\n *\n * @since 3.0.0\n */\n\nexport function group(body: string): string {\n return `(?:${ body })`;\n}\n\n/**\n * Finds the index of the `]` that closes a character class.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `[`\n * @returns The index of the closing `]`, or the length of the string when the class is unterminated\n *\n * @remarks\n * Applies POSIX-style character-class rules while scanning.\n * A leading `!` or `^` negates the class and is skipped, and a `]` immediately after the opening bracket\n * (or after the negation) is treated as a literal member rather than a close.\n * A backslash escapes the next character, so an escaped `]` does not close the class.\n *\n * @example\n * ```ts\n * classEnd('[abc]def', 0); // 4\n * classEnd('[]abc]', 0); // 5 - the leading ] is a member\n * classEnd('[abc', 0); // 4 - unterminated, so the length\n * ```\n *\n * @see compileClass\n * @since 3.0.0\n */\n\nexport function classEnd(glob: string, openIndex: number): number {\n let scan = openIndex + 1;\n const lead = at(glob, scan);\n\n if (lead === Char.Bang || lead === Char.Caret) scan++;\n if (at(glob, scan) === Char.RBracket) scan++; // leading ] is literal\n\n while (scan < glob.length && at(glob, scan) !== Char.RBracket)\n scan += at(glob, scan) === Char.Backslash ? 2 : 1;\n\n return scan;\n}\n\n/**\n * Finds the index of the `)` that closes an extglob group.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `(`\n * @returns The index of the matching `)`, or `-1` when the group is unterminated\n *\n * @remarks\n * Tracks nesting depth so an inner `( ... )` does not end the outer group.\n * A backslash escapes the next character, and a `[ ... ]` character class is skipped via {@link classEnd},\n * so parentheses inside it are not counted.\n *\n * @example\n * ```ts\n * findClose('@(a|b)c', 1); // 5\n * findClose('@(a|(b))', 1); // 7 - the inner group does not end it\n * findClose('@(a', 1); // -1 - unterminated\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function findClose(glob: string, openIndex: number): number {\n for (let cursor = openIndex, depth = 0; cursor < glob.length; cursor++) {\n const char = at(glob, cursor);\n\n if (char === Char.Backslash) cursor++;\n else if (char === Char.LParen) depth++;\n else if (char === Char.RParen && --depth === 0) return cursor;\n else if (char === Char.LBracket) cursor = classEnd(glob, cursor);\n }\n\n return -1;\n}\n\n/**\n * Finds the index of the `}` that closes an expandable brace group.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `{`\n * @returns The index of the matching `}` when the group contains a top-level comma, `-1` otherwise\n *\n * @remarks\n * A brace group is expandable only when it holds at least one top-level comma, so `{a,b}` closes but `{a}` does not.\n * Tracks nesting depth so an inner `{ ... }` does not end the outer group,\n * skips a `[ ... ]` character class via {@link classEnd}, and treats a backslash as escaping the next character.\n * Returning `-1` signals the caller to emit the `{` as a literal.\n *\n * @example\n * ```ts\n * braceClose('{a,b}c', 0); // 4\n * braceClose('{a,{b,c}}', 0); // 8 - the inner group does not end it\n * braceClose('{abc}', 0); // -1 - no top-level comma, so a literal\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function braceClose(glob: string, openIndex: number): number {\n let comma = false;\n\n for (let cursor = openIndex + 1, depth = 0; cursor < glob.length; cursor++) {\n const char = at(glob, cursor);\n\n if (char === Char.Backslash) cursor++;\n else if (char === Char.LBrace) depth++;\n else if (char === Char.RBrace) {\n if (depth === 0) return comma ? cursor : -1; // expandable only with a comma\n depth--;\n }\n else if (char === Char.Comma && depth === 0) comma = true;\n else if (char === Char.LBracket) cursor = classEnd(glob, cursor);\n }\n\n return -1;\n}\n\n/**\n * Compiles a glob character class into its regex equivalent.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `[`\n * @returns A tuple of the compiled regex source and the index just past the class\n *\n * @remarks\n * Translates glob character-class syntax into a regex class.\n * A leading `!` or `^` becomes a negation that also excludes the path separator, emitted as `[^/`.\n * A `]` immediately after the opening (or after the negation) is escaped as a literal member,\n * and a `^` inside the class is escaped so it is not read as a negation.\n * An unterminated class is not a class at all - the function returns the literal `\\[` and advances past the `[`.\n *\n * @example\n * ```ts\n * compileClass('[a-z]x', 0); // [ '[a-z]', 5 ]\n * compileClass('[!a]', 0); // [ '[^/a]', 4 ] - negated, and the separator excluded with it\n * compileClass('[abc', 0); // [ '\\\\[', 1 ] - unterminated, so a literal bracket\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function compileClass(glob: string, openIndex: number): [string, number] {\n const end = classEnd(glob, openIndex);\n if (end >= glob.length) return [ '\\\\[', openIndex + 1 ]; // unterminated → literal\n\n let cursor = openIndex + 1, out = '[';\n const lead = at(glob, cursor);\n\n if (lead === Char.Bang || lead === Char.Caret) { out += '^/'; cursor++; }\n if (at(glob, cursor) === Char.RBracket) { out += '\\\\]'; cursor++; }\n\n for (; cursor < end; cursor++) {\n if (at(glob, cursor) === Char.Backslash) out += '\\\\' + glob[++cursor];\n else if (at(glob, cursor) === Char.Caret) out += '\\\\^';\n else out += glob[cursor];\n }\n\n return [ out + ']', end + 1 ];\n}\n\n/**\n * Finds the index of the next path separator at or after a position.\n *\n * @param glob - The glob string being scanned\n * @param from - The zero-based position to start scanning from\n * @returns The index of the next unescaped `/`, or the length of the string when none remains\n *\n * @remarks\n * Marks the end of the current path segment.\n * A backslash escapes the next character, so an escaped `/` does not end the segment.\n *\n * @example\n * ```ts\n * segmentEnd('src/index.ts', 0); // 3\n * segmentEnd('index.ts', 0); // 8 - no separator left, so the length\n * ```\n *\n * @since 3.0.0\n */\n\nexport function segmentEnd(glob: string, from: number): number {\n for (let cursor = from; cursor < glob.length; cursor++) {\n if (at(glob, cursor) === Char.Slash) return cursor;\n if (at(glob, cursor) === Char.Backslash) cursor++;\n }\n\n return glob.length;\n}\n\n/**\n * Compiles a glob fragment into a regular-expression source.\n *\n * @param glob - The glob fragment to compile\n * @param isSegmentStart - Whether the fragment begins at the start of a path segment\n * @param alt - The code unit that separates alternatives, or `0` when the fragment is not an alternation body\n * @param options - Compilation options, of which only {@link GlobOptionsInterface.dot} is read, defaulting to `false`\n * @returns The regex source for the fragment, without the anchoring `^` and `$`\n *\n * @remarks\n * The core of the compiler, invoked recursively for the bodies of extglob, brace, and negation groups.\n * It walks the fragment one character at a time and emits the matching regex, handling wildcards (`*`, `**`, `?`),\n * character classes, brace expansion, extglob prefixes (`?( )`, `*( )`, `+( )`, `@( )`, `!( )`), and escapes.\n *\n * Segment-start tracking drives the leading-dot guard: at the start of a segment a wildcard must not match a dotfile,\n * so a {@link RegexElement.NotDot} guard is emitted.\n * `isSegmentStart` seeds this state for the fragment, and it is re-armed after every `/` and at each alternative.\n * When `options.dot` is `true`, the guard is suppressed everywhere, so wildcards match dotfiles as ordinary names,\n * and `**` descends into dot directories.\n *\n * The `alt` parameter marks the fragment as the body of an alternation.\n * When set to {@link Char.Pipe} or {@link Char.Comma}, an unescaped separator of that kind becomes a regex `|`,\n * and `**` is treated as two single stars rather than a globstar.\n * Any other occurrence of `|` or `,` is emitted literally.\n *\n * @example\n * ```ts\n * compileFragment('*.ts', true); // (?!\\.)[^/]*\\.ts\n * compileFragment('a,b', false, Char.Comma); // a|b\n * compileFragment('*.ts', true, 0, { dot: true }); // [^/]*\\.ts\n * ```\n *\n * @see globToRegExp\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function compileFragment(glob: string, isSegmentStart: boolean = false, alt: number = 0, options: GlobOptionsInterface = {}): string {\n const { dot = false } = options;\n\n let out = '';\n let index = 0;\n let wasStart = isSegmentStart;\n\n const guard = dot ? '' : RegexElement.NotDot;\n const DS = guard + RegexElement.NotSlash + '+';\n const GLOBSTAR = group(DS + '(?:/' + DS + ')*') + '?';\n\n while (index < glob.length) {\n const char = at(glob, index);\n const nChar = at(glob, index + 1);\n\n if (nChar === Char.LParen && (char === Char.Bang || RegexCloser[char])) {\n const close = findClose(glob, index + 1);\n\n if (char !== Char.Bang) { // ?*+@( ... )\n const end = close === -1 ? glob.length : close; // unclosed → group runs to the end\n const inner = compileFragment(glob.slice(index + 2, end), wasStart, Char.Pipe, options);\n\n out += RegexElement.Open + inner + RegexCloser[char];\n index = end + 1;\n continue;\n }\n\n if (close !== -1) {\n const inner = compileFragment(glob.slice(index + 2, close), wasStart, Char.Pipe, options);\n const tailEnd = segmentEnd(glob, close + 1);\n const tail = compileFragment(glob.slice(close + 1, tailEnd), false, 0, options);\n\n out += group(\n (wasStart ? guard : '') +\n `(?!${ group(inner) + tail + RegexElement.SegBreak })` +\n RegexElement.NotSlashLazy + tail\n );\n\n index = tailEnd;\n continue;\n }\n }\n\n switch (char) {\n case Char.Slash:\n out += RegexElement.Slash;\n index++;\n wasStart = true;\n break;\n\n case Char.Backslash:\n out += index + 1 < glob.length ? lit(glob[index + 1]) : '\\\\\\\\';\n index += 2;\n break;\n\n case Char.Question:\n out += wasStart && !dot ? RegexElement.NotDotSlash : RegexElement.NotSlash;\n index++;\n break;\n\n case Char.Star:\n if (nChar === Char.Star && alt !== Char.Pipe && (index > 0 || isSegmentStart) && isGlobstar(glob, index)) {\n const root = index === 0 && alt === 0 ? RegexElement.AbsRoot : '';\n if (at(glob, index + 2) === Char.Slash) {\n out += root + group(DS + RegexElement.Slash) + '*'; index += 3; wasStart = true;\n } else {\n out += root + GLOBSTAR; index += 2;\n }\n } else {\n out += (wasStart ? guard : '') + RegexElement.NotSlashRun;\n index++;\n }\n break;\n\n case Char.LBrace: {\n const close = braceClose(glob, index);\n\n if (close === -1) {\n out += '\\\\{'; index++;\n } else {\n out += group(compileFragment(glob.slice(index + 1, close), wasStart, Char.Comma, options));\n index = close + 1;\n }\n break;\n }\n\n case Char.LBracket: {\n const [ src, next ] = compileClass(glob, index);\n out += (wasStart && !dot && src !== '\\\\[' ? RegexElement.NotDot : '') + src;\n index = next;\n break;\n }\n\n case Char.Pipe:\n case Char.Comma:\n if (alt === char) { out += RegexElement.Alt; wasStart = isSegmentStart; }\n else out += lit(glob[index]);\n index++;\n break;\n\n default:\n out += lit(glob[index]); index++;\n }\n }\n\n return out;\n}\n\n/**\n * Compiles a glob pattern into an anchored regular expression.\n *\n * @param glob - The glob pattern to compile\n * @param options - Compilation options carrying the regex flags and the dotfile setting\n * @returns A {@link RegExp} anchored with `^` and `$` that matches exactly the paths described by the glob\n *\n * @remarks\n * The entry point of the compiler.\n * It compiles the pattern with {@link compileFragment} starting at a segment boundary, then wraps the result\n * in `^ ... $` so the expression matches a whole path rather than a substring.\n *\n * Supported glob syntax:\n * - `*` - matches any run of characters within a single path segment, never crossing a `/`.\n * - `?` - matches exactly one character within a segment.\n * - `**` - globstar, matching across segment boundaries, spanning any number of intermediate segments.\n * - `[abc]`, `[a-z]`, `[a-zA-Z0-9]` - a character class matching exactly one listed character or range.\n * Multiple ranges combine, and it never matches more than one character.\n * - `[!abc]`, `[^abc]` - a negated character class matching exactly one character not listed.\n * - `{a,b}`, `{a,{b,c}}` - brace alternation, matching any one of the comma-separated alternatives.\n * A brace group with no top-level comma, such as `{abc}`, is treated as the literal text `{abc}`.\n * - `@( ... )` - extglob group matching its `|`-separated alternatives exactly once.\n * - `?( ... )` - extglob group matching zero or one of its alternatives.\n * - `*( ... )` - extglob group matching zero or more of its alternatives.\n * - `+( ... )` - extglob group matching one or more of its alternatives.\n * - `!( ... )` - extglob negation matching anything the alternatives do not.\n * - `\\` - escapes the next character so it is matched literally, so `\\*.js` matches the literal name `*.js`.\n * - `/` - the literal path separator, which segment-relative wildcards never cross.\n *\n * Character classes and `?` always consume exactly one character.\n * To constrain a run of characters, follow the class with `*` (`[ab]*c` allows any run before `c`)\n * or repeat it with an extglob (`+([ab])c` requires every character before `c` to be `a` or `b`).\n *\n * The `!( ... )` negation is single-segment: its body never crosses a `/`, and the guarantee holds when\n * the negation is the last thing in its segment or is followed by a literal tail such as `.ts`.\n * It is not whole-pattern negation - a leading `!` not followed by `(` is matched as a literal `!`.\n *\n * Leading dots are guarded: at the start of a segment,\n * `*`, `?`, `[ ... ]`, and `**` do not match a name that begins with `.` unless the pattern spells the dot out.\n * So `*` matches `env` but not `.env`.\n * To include dotfiles, name the dot explicitly:\n * - `.*` - matches only dotfiles, such as `.env`.\n * - `{.,}*` - matches every name, dotfiles included.\n *\n * Passing {@link GlobOptionsInterface.dot} as `true` lifts the guard for the whole pattern,\n * so plain wildcards match dotfiles, and `**` descends into dot directories - `**\\/*` then matches `.git/config`.\n *\n * @example\n * <caption>Common patterns and what they match</caption>\n * ```text\n * *.{ts,js} x.ts, x.js\n * @(a|b) a, b\n * +(ab) ab, abab (not: '')\n * !(a).js ab.js, x.js (not: a.js)\n * !(*.spec).ts app.ts, index.ts (not: app.spec.ts)\n * !(*.spec|*.test).ts app.ts (not: app.spec.ts, app.test.ts)\n * ```\n *\n * @example\n * <caption>Every file except a spec, recursively - the two most useful forms</caption>\n * ```ts\n * globToRegExp('**\\/!(*.spec).{ts,js}'); // any .ts or .js file whose name does not end in .spec\n * globToRegExp('**\\/!(*.spec.ts)'); // any file at all except those ending in .spec.ts\n * ```\n *\n * @see compileFragment\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function globToRegExp(glob: string, options: GlobOptionsInterface = {}): RegExp {\n return new RegExp('^' + compileFragment(glob, true, 0, options) + '$', options.flags);\n}\n\n/**\n * Builds a predicate that tests a path against a set of include and exclude globs.\n *\n * @param globs - The glob patterns to match against, where a leading `!` marks an exclusion\n * @param options - Compilation options applied to every compiled pattern\n * @returns A predicate returning `true` when `path` is included by the set and excluded by none of it\n *\n * @remarks\n * Each glob is compiled once with {@link globToRegExp} and sorted into an include or exclude list.\n * A leading `!` marks the pattern as an exclusion and is stripped before compilation.\n * A repeated `!` toggles, so `!!pattern` is an inclusion again.\n * A `!` immediately followed by `(` is left in place - it is the extglob negation {@link globToRegExp} handles,\n * not a whole-pattern exclusion.\n *\n * The predicate accepts a path when it is matched by at least one include pattern and by no exclude pattern.\n * When the set contains no include patterns, every path is considered included,\n * so a set of only exclusions matches everything except what it excludes.\n *\n * @example\n * ```ts\n * const isSource = createMatcher([ '**\\/*.ts', '!**\\/*.spec.ts' ]);\n * isSource('src/app.ts'); // true\n * isSource('src/app.spec.ts'); // false - excluded\n * isSource('src/app.js'); // false - not included\n * ```\n *\n * @see globToRegExp\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function createMatcher(globs: Array<string>, options: GlobOptionsInterface = {}): (path: string) => boolean {\n const include: Array<RegExp> = [];\n const exclude: Array<RegExp> = [];\n\n for (let glob of globs) {\n let neg = false;\n while (at(glob, 0) === Char.Bang && at(glob, 1) !== Char.LParen) {\n neg = !neg;\n glob = glob.slice(1);\n }\n\n (neg ? exclude : include).push(globToRegExp(glob, options));\n }\n\n return (path) =>\n (include.length === 0 || include.some(r => r.test(path))) &&\n !exclude.some(r => r.test(path));\n}\n\n/**\n * Walks a directory tree and collects every file the globs match.\n *\n * @param base - The directory the walk starts from and the patterns are matched against\n * @param globs - The glob patterns to match, where a leading `!` marks an exclusion\n * @param options - Compilation options applied to every compiled pattern\n * @returns The matched files as paths relative to `base`, with forward slashes, in the order the walk reaches them\n *\n * @remarks\n * The base is resolved through the shared path cache,\n * and every path below it is built by appending a name to its directory's path.\n * A file therefore costs one string and one {@link createMatcher} test rather than a resolve of its own.\n * The walk is iterative, so a deep tree cannot overflow the stack,\n * and a directory that cannot be read is skipped rather than thrown from.\n * Unless `dot` is set, a name beginning with `.` is skipped before it is tested, which prunes whole trees such as `.git`.\n * A pattern that spells a leading dot, as `.github/**` or `**\\/.cache/*` does, disarms this and lets the walk descend.\n * Symbolic links are not followed, since a link never reports itself as a directory, which is what keeps a link cycle\n * from being walked.\n *\n * @example\n * ```ts\n * collectFiles(cwd(), [ 'src/**\\/*.ts', '!**\\/*.spec.ts' ]);\n * // [ 'src/index.ts', 'src/models/files.model.ts' ]\n * ```\n *\n * @see createMatcher\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function collectFiles(base: string, globs: Array<string>, options: GlobOptionsInterface = {}): Array<string> {\n const root = FrameworkService.resolve(base);\n const matcher = createMatcher(globs, options);\n const dotted = options.dot || globs.some(glob => at(glob, 0) === Char.Dot || glob.includes('/.'));\n\n const files: Array<string> = [];\n const stack: Array<string> = [ '' ];\n\n while (stack.length > 0) {\n const directory = stack.pop()!;\n\n let entries: Array<Dirent>;\n try {\n entries = readdirSync(directory ? join(root, directory) : root, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n if (!dotted && at(entry.name, 0) === Char.Dot) continue;\n const path = directory ? `${ directory }/${ entry.name }` : entry.name;\n\n if (entry.isDirectory()) stack.push(path);\n else if (matcher(path)) files.push(path);\n }\n }\n\n return files;\n}\n","/**\n * Imports\n */\n\nimport { Char } from '@constants/char.constant';\n\n/**\n * Regular-expression fragments emitted while compiling a glob into a {@link RegExp} source.\n *\n * @remarks\n * Each member is a reusable snippet of regex syntax with a fixed meaning in the compiled output,\n * so the compiler can assemble a pattern by concatenating members rather than repeating string literals.\n * Declared as a `const enum` so references inline to their literal value at compile time.\n *\n * @example\n * ```ts\n * RegexElement.NotDot + RegexElement.NotSlashRun; // '(?!\\\\.)[^/]*' - the source for a leading `*`\n * ```\n *\n * @see RegexCloser\n * @since 3.0.0\n */\n\nexport const enum RegexElement {\n /**\n * The alternation separator `|`.\n *\n * @since 3.0.0\n */\n\n Alt = '|',\n\n /**\n * The opening of a non-capturing group `(?:`.\n *\n * @since 3.0.0\n */\n\n Open = '(?:',\n\n /**\n * The literal path separator `/`.\n *\n * @since 3.0.0\n */\n\n Slash = '/',\n\n /**\n * A zero-width guard `(?!\\.)` that forbids a leading dot at the start of a segment.\n *\n * @remarks\n * Prevents a wildcard from matching a dotfile unless the pattern names the dot explicitly.\n *\n * @since 3.0.0\n */\n\n NotDot = '(?!\\\\.)',\n\n /**\n * A single character class `[^/]` matching any one character except the path separator.\n *\n * @since 3.0.0\n */\n\n NotSlash = '[^/]',\n\n /**\n * A segment boundary `(?:$|/)` matching either the end of the string or a slash.\n *\n * @since 3.0.0\n */\n\n SegBreak = '(?:$|/)',\n\n /**\n * A greedy run `[^/]*` of characters that are not the path separator.\n *\n * @since 3.0.0\n */\n\n NotSlashRun = '[^/]*',\n\n /**\n * A single character class `[^./]` matching any one character except `.` or `/`.\n *\n * @remarks\n * Emitted for `?` at the start of a segment, where a leading dot must not match.\n *\n * @since 3.0.0\n */\n\n NotDotSlash = '[^./]',\n\n /**\n * A lazy run `[^/]*?` of characters that are not the path separator.\n *\n * @remarks\n * Used as the body of a negation so the negative lookahead governs how much the segment consumes.\n *\n * @since 3.0.0\n */\n\n NotSlashLazy = '[^/]*?',\n\n /**\n * An optional absolute-path root `(?:[A-Za-z]:)?/?` matching a Windows drive prefix and/or a leading slash.\n *\n * @remarks\n * Emitted before a leading globstar so a relative pattern such as `**\\/*.ts` also matches an absolute path\n * like `/a/b/c.ts` or `C:/a/b/c.ts`.\n * Both parts are optional, so a purely relative path still matches.\n * Path separators are assumed to be forward slashes, so normalize Windows backslashes before testing.\n *\n * @since 3.0.0\n */\n\n AbsRoot = '(?:[A-Za-z]:)?/?',\n}\n\n/**\n * Maps an extglob prefix character to the regex closer that ends its non-capturing group.\n *\n * @remarks\n * Keyed by the {@link Char} code unit that precedes a `(` in an extglob construct,\n * the value carries the group-closing parenthesis together with the quantifier that reproduces the prefix semantics.\n * - `@( ... )` matches the group exactly once.\n * - `+( ... )` matches the group one or more times.\n * - `*( ... )` matches the group zero or more times.\n * - `?( ... )` matches the group zero or one time.\n * The presence of a key also signals that the prefix opens an extglob group,\n * so the compiler tests membership before treating the character as extglob syntax.\n *\n * @example\n * ```ts\n * RegexCloser[Char.Plus]; // ')+' - so `+(ab)` compiles to `(?:ab)+`\n * RegexCloser[Char.Bang]; // undefined - `!(` is a negation, handled apart\n * ```\n *\n * @see Char\n * @see RegexElement\n *\n * @since 3.0.0\n */\n\nexport const RegexCloser: Record<number, string> = {\n [Char.At]: ')',\n [Char.Plus]: ')+',\n [Char.Star]: ')*',\n [Char.Question]: ')?'\n} as const;\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { PartialMessage } from 'esbuild';\nimport type { SourceService } from '@remotex-labs/xmap';\nimport type { ParsedStackTraceInterface } from '@remotex-labs/xmap/parser.component';\nimport type { StackTraceInterface, ResolveMetadataInterface } from '@providers/interfaces/stack-provider.interface';\n\n/**\n * Imports\n */\n\nimport { inject } from '@remotex-labs/xinject';\nimport { FilesModel } from '@models/files.model';\nimport { resolveError } from '@remotex-labs/xmap';\nimport { xterm } from '@remotex-labs/xansi/xterm.component';\nimport { FrameworkService } from '@services/framework.service';\nimport { parseErrorStack } from '@remotex-labs/xmap/parser.component';\nimport { formatErrorCode } from '@remotex-labs/xmap/formatter.component';\nimport { highlightCode } from '@remotex-labs/xmap/highlighter.component';\n\n/**\n * Returns a source resolver for a file, from its source map when one is registered and from its cached text otherwise.\n *\n * @param fileName - Path of the file a stack frame points at, relative or absolute\n * @returns The resolver for that file, or `null` when the file has neither a map nor cached text\n *\n * @remarks\n * A registered map wins since it resolves back to the authored file rather than to the emitted one.\n * Without a map the cached text stands in through a minimal resolver that slices the surrounding lines as its\n * code window, so an unmapped file still prints a snippet.\n * That window spans three lines either side unless the caller asks for a different span and is clamped to the\n * bounds of the file.\n * `startLine` and `endLine` come back as 1-based line numbers rather than as indexes into the text,\n * which is how {@link formatErrorCode} reads them, so a printed number labels the line it belongs to.\n * The line passes through as it arrived, while the column comes back one higher than it was given.\n *\n * @example\n * ```ts\n * getSource('dist/index.js'); // SourceService - the registered map\n * getSource('src/index.ts')?.getPositionWithCode(10, 4); // line 10, column 5, lines 7-13 as code\n * getSource('missing.ts'); // null\n * ```\n *\n * @see SourceService\n * @see FilesModel.touch\n * @see FrameworkService.getSourceMap\n *\n * @since 2.0.0\n */\n\nexport function getSource(fileName: string = ''): SourceService | null {\n const framework = inject(FrameworkService);\n const mapped = framework.getSourceMap(fileName);\n if (mapped) return mapped;\n\n const snapshot = inject(FilesModel).touch(fileName);\n const code = snapshot.snapshot?.text;\n\n if (!snapshot || !code) return null;\n const lines = code.split('\\n');\n\n return {\n getPositionWithCode: (line, column, _bias, options) => {\n const after = options?.linesAfter ?? 3;\n const before = options?.linesBefore ?? 3;\n\n // both bounds are 1-based line numbers, so only the slice start converts to an index\n const startLine = Math.max(line - before, 1);\n const endLine = Math.min(line + after, lines.length);\n\n return {\n line,\n name: null,\n code: lines.slice(startLine - 1, endLine).join('\\n'),\n source: fileName,\n column: column,\n endLine,\n startLine,\n sourceRoot: null,\n sourceIndex: -1,\n generatedLine: -1,\n generatedColumn: -1\n };\n }\n } as SourceService;\n}\n\n/**\n * Brings an error and an esbuild message to the same shape - a name, a message, and a list of frames.\n *\n * @param raw - Thrown error, or the message esbuild reported for a failed build\n * @returns The parsed trace, with an empty frame list when there is nothing to point at\n *\n * @remarks\n * An `Error` is parsed from its own stack text, whether it arrives on its own or wrapped as the `detail` of an\n * esbuild message.\n * A plain esbuild message carries no stack, so its location becomes the single frame of the trace, flagged as\n * ordinary code: not eval, not async, not native, and not a constructor call.\n * A message without a location resolves to no frames at all, which leaves the caller with the text alone.\n *\n * @example\n * ```ts\n * getErrorStack(new Error('boom')).stack.length; // 12 - frames parsed from error.stack\n *\n * getErrorStack({ text: 'Unexpected token', location: { file: 'src/index.ts', line: 4, column: 2 } }).stack;\n * // [ { source: '@src/index.ts', fileName: 'src/index.ts', line: 4, column: 2, ... } ]\n *\n * getErrorStack({ text: 'Could not resolve module' }).stack; // []\n * ```\n *\n * @see parseErrorStack\n * @see ParsedStackTraceInterface\n *\n * @since 2.0.0\n */\n\nexport function getErrorStack(raw: Partial<PartialMessage> | Error): ParsedStackTraceInterface {\n if (raw instanceof Error) return parseErrorStack(raw);\n if (raw.detail instanceof Error) return parseErrorStack(raw.detail);\n\n if (!raw.location) {\n return { stack: [], name: 'esBuildMessage', message: raw.text ?? '', rawStack: '' };\n }\n\n return {\n name: 'esBuildMessage',\n message: raw.text ?? '',\n rawStack: '',\n stack: [\n {\n source: `@${ raw.location.file }`,\n line: raw.location.line,\n column: raw.location.column || 1,\n fileName: raw.location.file,\n eval: false,\n async: false,\n native: false,\n constructor: false\n }\n ]\n };\n}\n\n/**\n * Resolves an error back to its authored sources and picks the code window to print with it.\n *\n * @param raw - Thrown error, or the message esbuild reported for a failed build\n * @param options - Frame selection and code window size, as {@link resolveError} takes them\n * @param verbose - Whether native frames stay in the resolved stack\n * @returns The resolved trace, carrying `formatCode` when a frame supplied a code window\n *\n * @remarks\n * Every frame resolves through {@link getSource}, so a mapped frame points at the authored file and an unmapped\n * one falls back to the cached text of the emitted file.\n * `verbose` and `withFrameworkFrames` each admit native frames to the stack, while `withFrameworkFrames` alone\n * decides whether a framework frame may supply the code window.\n * The window is taken from the first frame that carries code, highlighted and marked at that position, and is\n * left unset when no frame carries any - a resolve against sources that are gone prints as a bare trace.\n *\n * @example\n * ```ts\n * const metadata = getErrorMetadata(error, { linesBefore: 2, linesAfter: 2 });\n * metadata.stack[0].format; // 'at run src/index.ts:12:8'\n * metadata.formatCode; // lines 10-14, highlighted, with column 8 marked in bright pink\n * ```\n *\n * @see resolveError\n * @see getErrorStack\n * @see StackTraceInterface\n * @see ResolveMetadataInterface\n *\n * @since 3.0.0\n */\n\nexport function getErrorMetadata(raw: PartialMessage | Error, options?: StackTraceInterface, verbose: boolean = false): ResolveMetadataInterface {\n const framework = inject(FrameworkService);\n const parsed = getErrorStack(raw);\n const resolved: ResolveMetadataInterface = resolveError(parsed, {\n ...options,\n withNativeFrames: verbose || (options?.withFrameworkFrames ?? false),\n getSource(path: string): SourceService | null {\n return getSource(path);\n }\n });\n\n resolved.stack.filter(frame => {\n if (!(options?.withFrameworkFrames ?? false) && framework.isFrameworkFile(frame)) return false;\n if(!resolved.formatCode && frame.code) {\n resolved.formatCode = formatErrorCode(\n {\n code: highlightCode(frame.code),\n line: frame.line ?? 1,\n column: frame.column ?? 1,\n startLine: frame.stratLine ?? 1\n },\n { color: xterm.brightPink }\n );\n }\n });\n\n return resolved;\n}\n\n/**\n * Renders resolved metadata as the block that gets printed to the terminal.\n *\n * @param metadata - Resolved trace, as {@link getErrorMetadata} returns it\n * @param name - Name to head the block with, such as `TypeError` or `esBuildMessage`\n * @param message - Message to head the block with\n * @param notes - Extra lines esbuild attached to the message, printed in gray under the heading\n * @returns The block, ready to write as-is\n *\n * @remarks\n * The heading is always written, the code window and the trace only when the metadata holds them, so an error\n * resolved against missing sources still prints as a single readable line.\n * Coloring of the window and of each frame is left as {@link getErrorMetadata} produced it - nothing here is\n * highlighted a second time.\n *\n * @example\n * ```ts\n * formatStack(metadata, 'TypeError', 'x is not a function');\n * //\n * // TypeError: x is not a function\n * //\n * // 11 | x();\n * // | ^\n * //\n * // Enhanced Stack Trace:\n * // at run src/index.ts:11:2\n * ```\n *\n * @see xterm\n * @see getErrorMetadata\n * @see ResolveMetadataInterface\n *\n * @since 2.0.0\n */\n\nexport function formatStack(metadata: ResolveMetadataInterface, name: string, message: string, notes: PartialMessage['notes'] = []): string {\n const parts = [ `\\n${ name }: ${ xterm.lightCoral(message) }` ];\n for (const note of notes ?? []) {\n if(note.text) parts.push('\\n ' + xterm.gray(note.text));\n }\n\n if (metadata.formatCode) parts.push(`\\n\\n${ metadata.formatCode }`);\n if (metadata.stack.length) {\n parts.push(`\\n\\nEnhanced Stack Trace:\\n ${ metadata.stack.map(stack => stack.format).join('\\n ') }\\n`);\n }\n\n return parts.join('');\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { ModuleResolutionCache, SourceFile } from 'typescript';\nimport type { LanguageService, Diagnostic, Program } from 'typescript';\nimport type { EmitAndSemanticDiagnosticsBuilderProgram } from 'typescript';\nimport type { CacheEntryInterface } from './interfaces/typescript-service.interface';\nimport type { ParsedCommandLine, BuilderProgramHost, ReadBuildProgramHost } from 'typescript';\nimport type { DiagnosticInterface, ResolvedModuleInterface } from './interfaces/typescript-service.interface';\n\n/**\n * Imports\n */\n\nimport ts from 'typescript';\nimport { Injectable } from '@remotex-labs/xinject';\nimport { normalize, relative, dirname } from '@remotex-labs/xmap';\nimport { DeclarationModel } from '@typescript/models/declaration.model';\nimport { LanguageHostService } from '@typescript/services/host.service';\n\n/**\n * One TypeScript project, wrapping its language service, module resolution, and declaration emit.\n *\n * @remarks\n * Everything a build needs from TypeScript comes through here:\n *\n * - **Diagnostics** - {@link check}\n * - **Declaration files** - {@link emit} and {@link emitBundle}\n * - **Specifier resolution** - {@link resolve}\n *\n * Each configuration file gets one shared instance, reference counted,\n * so several consumers naming the same `tsconfig.json` share one language service,\n * and the last {@link dispose} tears it down.\n * The parse forces `emitDeclarationOnly` on,\n * since this asks the compiler for types alone while the bundler produces the JavaScript.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService, 'tsconfig.json');\n *\n * service.check(); // [] - the project type-checks\n * await service.emit({ index: 'src/index.ts' }); // [ 'D:/app/dist/index.d.ts' ]\n * service.dispose(); // released - torn down once nothing else holds it\n * ```\n *\n * @see DeclarationModel\n * @see LanguageHostService\n *\n * @since 2.0.0\n */\n\n@Injectable({\n factory(path?: string): TypescriptService {\n return TypescriptService.acquire(path);\n }\n})\nexport class TypescriptService {\n /**\n * The language service this project's queries run against.\n *\n * @remarks\n * Backed by {@link languageHostService} and a document registry,\n * so the syntax trees of shared files survive between requests.\n *\n * @example\n * ```ts\n * service.languageService.getProgram()?.getSourceFiles().length; // 214\n * ```\n *\n * @since 2.0.0\n */\n\n readonly languageService: LanguageService;\n\n /**\n * The host the language service reads files and versions through.\n *\n * @remarks\n * Exposed because it owns the tracked file set, which is what decides the program's file list.\n *\n * @example\n * ```ts\n * service.languageHostService.tracked.size; // grows as the language service resolves imports\n * ```\n *\n * @see LanguageHostService\n * @since 2.0.0\n */\n\n readonly languageHostService: LanguageHostService;\n\n /**\n * The live instances, keyed by their normalized configuration path.\n *\n * @remarks\n * Static, so sharing spans the whole process rather than one injector,\n * and each entry carries the reference count that decides when its language service is torn down.\n *\n * @see acquire\n * @since 3.0.0\n */\n\n private static readonly cache = new Map<string, CacheEntryInterface>();\n\n /**\n * The diagnostics of every file checked so far, keyed by the file name the compiler reported.\n *\n * @remarks\n * Only the affected files are recomputed on a {@link check},\n * so the untouched entries here are what makes the result whole-project rather than only-what-changed.\n * The key is the absolute path the compiler reported,\n * so a caller's own names are resolved before they are read back.\n *\n * @see reconcileDiagnostics\n * @since 3.0.0\n */\n\n private readonly diagnosticsCache = new Map<string, Array<DiagnosticInterface>>();\n\n /**\n * The host the builder program reads through.\n *\n * @remarks\n * Routes every read to {@link languageHostService},\n * so the builder sees the same cached content the language service does\n * rather than reaching the disk a second time and disagreeing with it.\n *\n * @since 3.0.0\n */\n\n private readonly builderHost: ReadBuildProgramHost & BuilderProgramHost = {\n createHash: ts.sys.createHash,\n readFile: (file: string, encoding?: BufferEncoding): string | undefined =>\n this.languageHostService.readFile(file, encoding),\n getCurrentDirectory: (): string => ts.sys.getCurrentDirectory(),\n useCaseSensitiveFileNames: (): boolean => ts.sys.useCaseSensitiveFileNames\n };\n\n /**\n * The declaration cache and emitter bound to this project.\n *\n * @remarks\n * Constructed with this service, whose {@link resolve} is what decides which specifiers name project files.\n *\n * @see DeclarationModel\n * @since 3.0.0\n */\n\n private readonly declaration: DeclarationModel;\n\n /**\n * The configuration currently in force, replaced whenever the file behind it is reparsed.\n *\n * @see parseConfig\n * @since 3.0.0\n */\n\n private parsedConfig: ParsedCommandLine;\n\n /**\n * The snapshot version of the configuration file behind the current parse.\n *\n * @remarks\n * Taken from the shared file model, which advances a version whenever the watcher re-reads a file that changed,\n * so comparing it against the version the model now holds tells {@link reload} whether anything needs reparsing.\n *\n * @see reload\n * @since 3.0.0\n */\n\n private configVersion: number;\n\n /**\n * The cache backing {@link resolve}, rebuilt whenever the compiler options change.\n *\n * @see createResolutionCache\n * @since 3.0.0\n */\n\n private resolutionCache: ModuleResolutionCache;\n\n /**\n * The builder program of the last {@link check}, carried forward, so the next check only revisits what changed.\n *\n * @remarks\n * Absent before the first check and after a {@link reload}, either of which makes the next check a full pass.\n *\n * @since 3.0.0\n */\n\n private builder?: EmitAndSemanticDiagnosticsBuilderProgram;\n\n /**\n * Creates a service for one configuration file.\n *\n * @param configPath - Path of the `tsconfig.json` to run against\n *\n * @remarks\n * Prefer injecting the service, which shares and reference counts instances per configuration path.\n * An instance built here stays outside the shared cache, so nothing else can reach it,\n * and {@link dispose} has no hold of its own to release.\n * A configuration that cannot be read does not throw - {@link parseConfig} falls back to a built-in default.\n *\n * @example\n * ```ts\n * const service = new TypescriptService('tsconfig.build.json');\n * service.config.options.emitDeclarationOnly; // true - forced on regardless of the file\n * ```\n *\n * @see acquire\n * @since 3.0.0\n */\n\n constructor(readonly configPath: string = 'tsconfig.json') {\n this.parsedConfig = this.parseConfig();\n this.languageHostService = new LanguageHostService(this.parsedConfig);\n this.configVersion = this.languageHostService.filesCache.touch(this.configPath).version;\n this.resolutionCache = this.createResolutionCache();\n this.languageService = ts.createLanguageService(\n this.languageHostService, ts.createDocumentRegistry(true)\n );\n\n this.declaration = new DeclarationModel(this);\n }\n\n /**\n * Reparses the configuration of every shared instance whose file has changed.\n *\n * @param force - Whether every instance reparses regardless of whether its configuration file has moved\n * @returns The configuration paths reparsed by this call, in the order their instances were acquired\n *\n * @remarks\n * This walks the whole shared cache rather than reaching one instance through a holder.\n * A single call after a watch event covers every project in the process,\n * and a configuration several consumers share is reparsed once rather than once per consumer.\n *\n * Each version comes from the shared file model as it stands rather than from disk,\n * since re-reading a changed file is the watcher's part,\n * so an instance whose configuration has not moved costs a map lookup and nothing more.\n *\n * Forcing skips that comparison and reparses every instance\n * that catches a change the configuration file's own version misses, such as an edit to a file it extends.\n * The cost is the state of every project in the process rather than the state of what moved.\n *\n * A change discards everything the old options fed:\n * the file set, the resolution cache, the cached declarations, the cached diagnostics, and the builder program,\n * so the next {@link check} runs as a full pass.\n * An instance the constructor built rather than the cache is never reached here.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService, 'tsconfig.json');\n *\n * TypescriptService.reload(); // [] - nothing has been written since the configuration was read\n * TypescriptService.reload(); // [ 'tsconfig.json' ] - reparsed, and service.config describes the edit\n * TypescriptService.reload(true); // [ 'tsconfig.json' ] - reparsed with nothing written since\n * ```\n *\n * @see check\n * @see acquire\n *\n * @since 3.0.0\n */\n\n static reload(force: boolean = false): Array<string> {\n const reloaded: Array<string> = [];\n for (const [ path, entry ] of TypescriptService.cache) {\n if (entry.instance.refresh(force)) reloaded.push(path);\n }\n\n return reloaded;\n }\n\n /**\n * The parsed configuration this service is running against.\n *\n * @returns The compiler options, file names, and raw configuration currently in force\n *\n * @remarks\n * {@link reload} replaces it wholesale,\n * so a reference taken from here describes the configuration as it stood when it was read.\n *\n * @example\n * ```ts\n * service.config.options.rootDir; // 'D:/app' - defaulted to the working directory when the file omits it\n * service.config.fileNames.length; // 42\n * ```\n *\n * @since 3.0.0\n */\n\n get config(): ParsedCommandLine {\n return this.parsedConfig;\n }\n\n /**\n * Type-checks the project and returns the diagnostics of the files named.\n *\n * @param reachable - Files to report on, as the build reaches them, reporting everything checked when omitted\n * @returns Diagnostics of those files, formatted for reporting\n *\n * @remarks\n * Only the files the builder reports as affected are rechecked,\n * their semantic, syntactic, and suggestion diagnostics replacing what was cached for them,\n * while untouched files keep the diagnostics they already had.\n * That is what makes the result whole-project without rechecking it whole.\n * A file matched by the configuration's `exclude` globs is skipped,\n * and a file that has left the program loses its cached diagnostics\n * rather than reporting them against a file that is no longer there.\n *\n * The check covers the program while the report covers `reachable`,\n * which is what lets several variants share one service:\n * the diagnostics are computed once for whatever changed,\n * and each variant reads back the files its own build reaches at the cost of a lookup per file.\n * Narrowing the check instead would consume a file for the variant that saw it first\n * and leave the next one with nothing to report.\n * Each name is resolved as it is read, so a build's own paths serve as they are, relative or absolute.\n *\n * @example\n * ```ts\n * service.check(); // [ { file: 'src/index.ts', line: 3, column: 7, code: 2322, category: 1, message: '...' } ]\n * service.check(); // [] once the file is fixed and the watcher has refreshed it\n *\n * service.check(context.stage.reachableFiles); // only what this variant's build reaches\n * ```\n *\n * @see DiagnosticInterface\n * @see reconcileDiagnostics\n *\n * @since 3.0.0\n */\n\n check(reachable?: Iterable<string>): Array<DiagnosticInterface> {\n const program = this.languageService.getProgram();\n if (!program) return [];\n\n const ignore = this.languageHostService.ignoreSourceFile;\n const skip = (file: SourceFile): boolean => {\n if(file.fileName.includes('node_modules')) return true;\n\n return ignore(file);\n };\n\n let affected;\n this.builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(program, this.builderHost, this.builder);\n while (affected = this.builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, skip)) {\n if ('fileName' in affected.affected) {\n const file = affected.affected;\n this.diagnosticsCache.set(file.fileName, [\n ...affected.result,\n ...this.builder!.getSyntacticDiagnostics(file),\n ...this.languageService.getSuggestionDiagnostics(file.fileName)\n ].map(diagnostic => this.formatDiagnostic(diagnostic)));\n }\n }\n\n return this.reconcileDiagnostics(program, reachable ?? this.diagnosticsCache.keys());\n }\n\n /**\n * Writes one declaration file per project file the entry points reach.\n *\n * @param entryPoints - Entry files to walk, keyed by the output name each entry itself is written under\n * @param outdir - Directory to write into, defaulting to the configuration's `outDir` and then to `dist`\n * @returns The output paths written by this call, empty when everything was already current\n *\n * @remarks\n * This path always passes a directory on, so `declarationDir` is never consulted.\n * Name it explicitly to write somewhere other than `outDir`.\n * The keys name the entries alone, while the files reached through them keep the layout of the source tree.\n * Nothing is type-checked here: declarations are produced by an isolated-declarations pass,\n * and a declaration the compiler cannot infer surfaces through {@link check} rather than as a failure to write.\n *\n * @example\n * ```ts\n * await service.emit({ index: 'src/index.ts' }); // [ 'dist/index.d.ts', 'dist/builder.d.ts' ] - absolute\n * await service.emit({ index: 'src/index.ts' }); // [] - nothing changed since\n * await service.emit({ index: 'src/index.ts' }, 'types'); // the same files, written under ./types\n * ```\n *\n * @see emitBundle\n * @since 3.0.0\n */\n\n async emit(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n outdir ??= this.config.options.outDir ?? 'dist';\n\n return this.declaration.emit(entryPoints, outdir);\n }\n\n /**\n * Writes one bundled declaration file per entry point.\n *\n * @param entryPoints - Entry files to bundle, keyed by the output name each is written under\n * @param outdir - Directory to write into, defaulting to the configuration's `outDir` and then to `dist`\n * @returns The output paths written, in the order the entry points were given\n *\n * @remarks\n * Each entry becomes one file carrying the declarations of everything it reaches,\n * so a package ships a single `.d.ts` instead of a tree mirroring its source.\n * The keys name the outputs, with `.d.ts` appended to each,\n * which is the shape the bundler's own entry points take and what keeps two entries of one name apart.\n * Every call rebuilds its bundles rather than reading a cache, so unlike {@link emit} this always writes.\n *\n * @example\n * ```ts\n * await service.emitBundle({ index: 'src/index.ts' }, 'dist'); // [ 'D:/app/dist/index.d.ts' ]\n * ```\n *\n * @see emit\n * @since 3.0.0\n */\n\n async emitBundle(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n outdir ??= this.config.options.outDir ?? 'dist';\n\n return this.declaration.emitBundle(entryPoints, outdir);\n }\n\n /**\n * Re-reads a batch of files so the language service sees their current content.\n *\n * @param files - Paths to refresh, relative or absolute\n *\n * @remarks\n * Each path is tracked as it is refreshed,\n * so naming a file the program has not reached yet adds it rather than passing over it.\n *\n * @example\n * ```ts\n * service.touchFiles([ 'src/index.ts' ]);\n * service.check(); // now reflects what is on disk\n * ```\n *\n * @see LanguageHostService.refreshFiles\n * @since 2.0.0\n */\n\n touchFiles(files: Array<string>): void {\n this.languageHostService.refreshFiles(files);\n }\n\n /**\n * Resolves a specifier the way the type checker resolves it.\n *\n * @param specifier - Module specifier as written in the source\n * @param containingFile - File the specifier was written in, since resolution is relative to its directory\n * @returns The resolved module, or `undefined` when the specifier resolves to nothing\n *\n * @remarks\n * An alias or a `paths` mapping resolves the way the compiler sees it rather than the way Node would,\n * which is what lets the declarations rewrite an alias into a path that still resolves.\n * The result carries two fields beyond what the compiler returns:\n * the directory the specifier resolved against, and the path from that directory to the target.\n * The first resolution attaches both, and the cached entry serves them back.\n * With no containing file, the working directory stands in for it.\n *\n * @example\n * ```ts\n * const module = service.resolve('@components/builder', 'D:/app/src/index.ts');\n *\n * module?.resolvedFileName; // 'D:/app/src/components/builder.ts'\n * module?.relativeFileName; // './components/builder.ts'\n * module?.isExternalLibraryImport; // false - a project file, not a package\n * ```\n *\n * @see ResolvedModuleInterface\n * @since 3.0.0\n */\n\n resolve(specifier: string, containingFile?: string): ResolvedModuleInterface | undefined {\n const container = containingFile ? this.languageHostService.filesCache.resolve(dirname(containingFile)) : process.cwd();\n const dirCache = this.resolutionCache.getOrCreateCacheForDirectory(container);\n const cached = dirCache.get(specifier, undefined)?.resolvedModule;\n if(cached) return cached as ResolvedModuleInterface;\n\n const result = <ResolvedModuleInterface> ts.resolveModuleName(\n specifier, containingFile ?? '', this.parsedConfig.options, this.languageHostService, this.resolutionCache\n ).resolvedModule;\n\n if (result) {\n const path = relative(container, result.resolvedFileName);\n\n result.container = container;\n result.relativeFileName = path.startsWith('.') ? path : `./${ path }`;\n }\n\n return result;\n }\n\n /**\n * Releases this consumer's hold on the shared instance.\n *\n * @remarks\n * The language service is torn down and the instance dropped from the shared cache\n * only once the last holder has released it,\n * so a service several consumers share outlives any one of them.\n * The hold released is the one the shared cache keeps under this service's configuration path,\n * so a release takes effect only on an instance the shared cache holds.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService);\n *\n * service.dispose(); // released - torn down only if nothing else holds it\n * ```\n *\n * @see acquire\n * @since 3.0.0\n */\n\n dispose(): void {\n const entry = TypescriptService.cache.get(this.configPath);\n if (!entry) return;\n\n entry.refCount--;\n if (entry.refCount > 0) return;\n\n this.languageService.dispose();\n TypescriptService.cache.delete(this.configPath);\n }\n\n /**\n * Releases the service when it leaves a `using` scope.\n *\n * @remarks\n * Delegates to {@link dispose}, so scope-bound and explicit release share one reference count.\n *\n * @example\n * ```ts\n * {\n * using service = inject(TypescriptService);\n * service.check();\n * } // released here\n * ```\n *\n * @see dispose\n * @since 3.0.0\n */\n\n [Symbol.dispose ?? Symbol.for('Symbol.dispose')](): void {\n this.dispose();\n }\n\n /**\n * Returns the shared instance for a configuration path, creating it on the first request.\n *\n * @param path - Path of the `tsconfig.json` the instance runs against\n * @returns The instance for that path, with its reference count raised\n *\n * @remarks\n * The path is normalized before it serves as the key,\n * so the same configuration reached by two spellings is one instance.\n * The instance is constructed with that normalized key,\n * which is what lets a release find its own entry.\n * Reached through the injectable factory rather than called directly.\n *\n * @see dispose\n * @since 3.0.0\n */\n\n private static acquire(path: string = 'tsconfig.json'): TypescriptService {\n const key = normalize(path);\n const entry = TypescriptService.cache.get(key);\n\n if (entry) {\n entry.refCount++;\n\n return entry.instance;\n }\n\n const instance = new TypescriptService(key);\n TypescriptService.cache.set(key, { instance, refCount: 1 });\n\n return instance;\n }\n\n /**\n * Rebuilds everything this instance derives from its compiler options once its configuration file has moved.\n *\n * @param force - Whether the rebuild runs even though the configuration file's version has not moved\n * @returns Whether the configuration was reparsed\n *\n * @remarks\n * Split out of {@link reload}, so the shared cache decides which instance reloads,\n * while the state it rebuilds stays with the instance holding it.\n * The version is the one the shared file model already holds,\n * since re-reading a file that changed is the watcher's part,\n * so this observes a change rather than going looking for one.\n * Forcing drops that guard and rebuilds regardless,\n * which is the only way through for a change the version leaves out.\n * The version is taken and stored either way,\n * so a forced rebuild leaves nothing behind for the next call to mistake for a change.\n *\n * @see reload\n * @since 3.0.0\n */\n\n private refresh(force: boolean = false): boolean {\n const { version } = this.languageHostService.filesCache.touch(this.configPath);\n if (!force && version === this.configVersion) return false;\n\n this.configVersion = version;\n this.parsedConfig = this.parseConfig();\n this.languageHostService.options = this.parsedConfig;\n this.resolutionCache = this.createResolutionCache();\n this.declaration.clear();\n this.diagnosticsCache.clear();\n this.builder = undefined;\n\n return true;\n }\n\n /**\n * Builds the module resolution cache for the current options.\n *\n * @returns A cache keyed the way the language host normalizes paths\n *\n * @remarks\n * Real paths go through the host,\n * so a symlinked file is keyed the same here as in the file cache,\n * and the two cannot disagree about which file a specifier reached.\n *\n * @since 3.0.0\n */\n\n private createResolutionCache(): ModuleResolutionCache {\n return ts.createModuleResolutionCache(\n ts.sys.getCurrentDirectory(),\n path => this.languageHostService.realpath(path),\n this.parsedConfig.options\n );\n }\n\n /**\n * Reads the diagnostics of a set of files out of the cache, dropping whatever no longer belongs to the program.\n *\n * @param program - Program the files are looked up in\n * @param reachable - Files to read, named as the caller has them, relative or absolute\n * @returns The cached diagnostics of those files, in the order they were named\n *\n * @remarks\n * The walk covers the files asked for rather than the cache,\n * so reporting one variant's inputs costs what that variant reaches rather than what the project holds.\n * Each name is resolved before the lookup,\n * since the cache is keyed by the absolute path the compiler reported,\n * while a build names its inputs relative to its own working directory.\n * A file that leaves the program - deleted, excluded, or no longer reached -\n * would otherwise keep reporting the diagnostics it had when it left,\n * since nothing marks it affected once it is gone,\n * so a name the program no longer carries is dropped from the cache as it is read.\n *\n * @since 3.0.0\n */\n\n private reconcileDiagnostics(program: Program, reachable: Iterable<string>): Array<DiagnosticInterface> {\n const files = this.languageHostService.filesCache;\n const result: Array<DiagnosticInterface> = [];\n\n for (const name of reachable) {\n const path = files.resolve(name);\n const diagnostics = this.diagnosticsCache.get(path);\n\n if (!diagnostics) continue;\n if (program.getSourceFile(path)) result.push(...diagnostics);\n else this.diagnosticsCache.delete(path);\n }\n\n return result;\n }\n\n /**\n * Reduces a compiler diagnostic to the shape that reporting consumes.\n *\n * @param diagnostic - Diagnostic as the compiler produced it\n * @returns The message and category, with the position and code when the diagnostic has a location\n *\n * @remarks\n * Chained messages are flattened into one string, and line and column are counted from one rather than from zero,\n * since the compiler counts from zero while every editor and terminal reports from one.\n * A diagnostic with no file - a configuration error, say - carries the message and category alone.\n *\n * @see DiagnosticInterface\n * @since 2.0.0\n */\n\n private formatDiagnostic(diagnostic: Diagnostic): DiagnosticInterface {\n const result: DiagnosticInterface = {\n message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n'),\n category: diagnostic.category\n };\n\n if (diagnostic.file && diagnostic.start !== undefined) {\n const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n result.file = diagnostic.file.fileName;\n result.line = line + 1;\n result.column = character + 1;\n result.code = diagnostic.code;\n }\n\n return result;\n }\n\n /**\n * Reads the configuration file and forces the options this build depends on.\n *\n * @returns The parsed configuration, with the forced options applied\n *\n * @remarks\n * Declaration emit is forced on and source maps off,\n * since this asks the compiler for types alone while the bundler produces the JavaScript.\n * `stripInternal` and `skipLibCheck` follow from that.\n * A configuration that cannot be read yields a built-in default rather than an error,\n * so a project without a `tsconfig.json` still type-checks under sensible settings.\n * `rootDir` falls back to the working directory,\n * without which output paths would follow whichever directory the sources happen to share.\n *\n * @since 2.0.0\n */\n\n private parseConfig(): ParsedCommandLine {\n let config = ts.getParsedCommandLineOfConfigFile(\n this.configPath,\n {\n sourceMap: false,\n skipLibCheck: true,\n stripInternal: true,\n declarationMap: false,\n emitDeclarationOnly: true\n },\n {\n ...ts.sys,\n onUnRecoverableConfigFileDiagnostic: () => {}\n }\n );\n\n if (!config) {\n config = {\n options: {\n strict: true,\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.NodeNext,\n sourceMap: false,\n skipLibCheck: true,\n stripInternal: true,\n declarationMap: false,\n emitDeclarationOnly: true,\n moduleResolution: ts.ModuleResolutionKind.NodeNext\n },\n errors: [],\n fileNames: [],\n projectReferences: undefined\n };\n }\n\n config.options = {\n ...config.options,\n noEmit: true,\n rootDir: config.options?.rootDir ?? process.cwd(),\n isolatedModules: false,\n useCaseSensitiveFileNames: true\n };\n\n return config;\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { TypescriptService } from '@typescript/services/typescript.service';\nimport type { DeclarationEntryInterface } from './interfaces/declaration-model.interface';\nimport type { NamedBindingInterface, ParseContextInterface } from './interfaces/declaration-model.interface';\nimport type { Declaration, Directive, ModuleExportName, Statement, StringLiteral } from '@oxc-project/types';\nimport type { BundleSurfaceInterface, MergedImportInterface } from './interfaces/declaration-model.interface';\nimport type { ExportNamedDeclaration, ImportDeclaration, TSImportEqualsDeclaration } from '@oxc-project/types';\nimport type { ExportAllDeclaration, ExportDefaultDeclaration, ExportDefaultDeclarationKind } from '@oxc-project/types';\n\n/**\n * Imports\n */\n\nimport { existsSync } from 'fs';\nimport { parseSync } from 'oxc-parser';\nimport { inject } from '@remotex-labs/xinject';\nimport { mkdir, writeFile } from 'fs/promises';\nimport { Char } from '@constants/char.constant';\nimport { FilesModel } from '@models/files.model';\nimport { isolatedDeclarationSync } from 'oxc-transform';\nimport { join, dirname, relative } from '@remotex-labs/xmap';\nimport { applyEdits, removeNode } from '@components/transformer.component';\nimport { HeaderDeclarationBundle } from '@typescript/constants/typescript.constant';\n\n/**\n * Builds and caches the declaration of every file a build touches, in both the forms it needs.\n *\n * @remarks\n * Each file is reduced to a {@link DeclarationEntryInterface}: the standalone declaration with its project specifiers\n * resolved, the same text stripped down to inlinable declarations, and the dependency, import, and export records that\n * stripping produced.\n * Declarations are produced by oxc's isolated-declarations pass, which needs no type checker,\n * so an entry costs one such pass and one parse.\n * Both forms and every record come out of that single parse.\n * Entries are held against the snapshot version of their file,\n * so a file is rebuilt only once the file model has observed the change,\n * and {@link clear} drops the cache when the compiler options behind the entries move.\n * One instance owns one cache,\n * so a build that wants entries shared across its steps passes the model around rather than constructing a second one.\n *\n * @example\n * ```ts\n * const declarations = new DeclarationModel(inject(TypescriptService));\n * const entry = declarations.touch('src/index.ts');\n *\n * entry.content; // 'declare const version: string;\\n'\n * entry.declaration; // the same text, prefixed with its imports\n * entry.projectDependencies; // Set { 'D:/app/src/builder.ts' }\n * declarations.touch('src/index.ts') === entry; // true - unchanged file, cached entry\n * ```\n *\n * @see DeclarationEntryInterface\n * @since 3.0.0\n */\n\nexport class DeclarationModel {\n /**\n * Entries keyed by the resolved absolute path of the file they describe.\n *\n * @remarks\n * Exposed for consumers that walk an already-built graph.\n * Use {@link touch} to build or refresh an entry.\n *\n * @example\n * ```ts\n * declarations.touch('src/index.ts');\n * declarations.cache.size; // 1\n * ```\n *\n * @see DeclarationEntryInterface\n * @since 3.0.0\n */\n\n readonly cache = new Map<string, DeclarationEntryInterface>();\n\n /**\n * Shared file snapshot cache the entries are versioned against.\n *\n * @since 3.0.0\n */\n\n private readonly filesCache = inject(FilesModel);\n\n /**\n * Entry version last written to each output path.\n *\n * @remarks\n * Keyed by output path rather than source path,\n * so emitting into a different directory writes every file again instead of reporting them as already current.\n * What it records is what was written rather than what is on disk,\n * so {@link emit} checks the file is still there before it passes over one,\n * which is what makes an output that something else removed come back on the next run.\n *\n * @since 3.0.0\n */\n\n private readonly emitted = new Map<string, number>();\n\n /**\n * Creates a declaration cache bound to one TypeScript service.\n *\n * @param ts - Service whose module resolution decides which specifiers are project files\n *\n * @example\n * ```ts\n * const declarations = new DeclarationModel(inject(TypescriptService));\n * declarations.cache.size; // 0\n * ```\n *\n * @see TypescriptService\n * @since 3.0.0\n */\n\n constructor(private readonly ts: TypescriptService) {}\n\n /**\n * Drops every cached entry.\n *\n * @remarks\n * Needed when something the declarations depend on has changed without the snapshot versions reflecting it -\n * the compiler options, or the resolution cache behind them.\n * A file whose content changed does not need this, since its entry is rebuilt on the next {@link touch}.\n * The record of what already reached the disk goes with them,\n * so the next call to {@link emit} writes every file again,\n * which is also what a cleaned output directory calls for.\n *\n * @example\n * ```ts\n * declarations.touch('src/index.ts');\n * declarations.clear();\n * declarations.cache.size; // 0\n * ```\n *\n * @see touch\n * @since 3.0.0\n */\n\n clear(): void {\n this.cache.clear();\n this.emitted.clear();\n }\n\n /**\n * Returns the declaration entry of a file, building it only when the cached one is stale.\n *\n * @param path - Filesystem path of the file, relative or absolute\n * @returns The entry describing the file's declarations, dependencies, and exports\n *\n * @remarks\n * The file is tracked through the file model, so a path never seen before is read from the disk once,\n * and a tracked path costs a map lookup.\n * The cached entry is returned whenever its version still matches the file's snapshot version, which only advances\n * when the file model observes a change on disk.\n * A file that is missing or unreadable yields an entry built from empty content rather than throwing.\n *\n * @example\n * ```ts\n * const entry = declarations.touch('src/index.ts');\n * entry.version; // 1\n * declarations.touch('src/index.ts') === entry; // true\n * ```\n *\n * @see clear\n * @see DeclarationEntryInterface\n *\n * @since 3.0.0\n */\n\n touch(path: string): DeclarationEntryInterface {\n const target = this.filesCache.resolve(path);\n const file = this.filesCache.touch(target);\n const cached = this.cache.get(target);\n\n if (cached?.version === file.version) return cached;\n\n const entry = this.build(target, file.snapshot?.text ?? '', file.version);\n this.cache.set(target, entry);\n\n return entry;\n }\n\n /**\n * Writes one declaration file per project file the entry points reach, skipping what has not changed.\n *\n * @param entryPoints - Entry files to walk, keyed by the output name each entry itself is written under\n * @param outdir - Directory to write into, overriding the configuration's `declarationDir` and `outDir`\n * @returns The output paths written by this call, empty when everything was already current\n *\n * @remarks\n * The walk follows the dependency edges out of each entry, so a project whose `tsconfig.json` lists only its entry\n * points still emits every file those entries reach.\n * Nothing outside the project is emitted, since only project files are edges,\n * and a `.d.ts` input is skipped along with everything only it reaches - it is already a declaration.\n * A key names the output of the entry it is keyed to and of nothing else.\n * The files reached through it keep mirroring the source tree the way `tsc` lays them out:\n * `declarationDir` wins over `outDir`, and the per-file path is taken relative to `rootDir`.\n * A file whose entry was written unchanged since the last call is left alone, so a watch cycle rewrites only what\n * moved.\n *\n * @example\n * ```ts\n * await declarations.emit({ main: 'src/index.ts' }); // [ 'dist/main.d.ts', 'dist/builder.d.ts' ]\n * await declarations.emit({ main: 'src/index.ts' }); // [] - nothing changed\n * await declarations.emit({ main: 'src/index.ts' }, './types'); // the same files, written under ./types\n * ```\n *\n * @see clear\n * @see emitBundle\n *\n * @since 3.0.0\n */\n\n async emit(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n const outputs: Array<string> = [];\n const contents: Array<string> = [];\n const visited = new Set<string>();\n const names = new Map<string, string>();\n\n for (const [ name, entry ] of Object.entries(entryPoints))\n names.set(this.filesCache.resolve(entry), name);\n\n const pending = [ ...names.keys() ];\n while (pending.length > 0) {\n const target = pending.pop()!;\n if (visited.has(target) || target.endsWith('.d.ts')) continue;\n visited.add(target);\n\n const entry = this.touch(target);\n for (const dependency of entry.projectDependencies)\n if (!visited.has(dependency)) pending.push(dependency);\n\n const output = this.outputPath(target, outdir, names.get(target));\n if (this.emitted.get(output) === entry.version && existsSync(output)) continue;\n\n this.emitted.set(output, entry.version);\n outputs.push(output);\n contents.push(entry.declaration);\n }\n\n return this.write(outputs, contents);\n }\n\n /**\n * Bundles every entry point and writes each one to a declaration file of its own.\n *\n * @param entryPoints - Entry files to bundle, keyed by the output name each is written under\n * @param outdir - Directory to write into, overriding the configuration's `declarationDir` and `outDir`\n * @returns The output paths written, in the order the entry points were given\n *\n * @remarks\n * The key names the output rather than the source doing so, `.d.ts` being appended to it, so two entries both\n * called `index.ts` are told apart by the names they were keyed under.\n * A key carrying a directory writes into it, and the directory is created if it is not there.\n * Bundles are always rebuilt, since assembling one from cached entries costs little,\n * and they open with {@link HeaderDeclarationBundle} so a generated file is recognizable as one.\n * With no output directory configured or passed, they land in the working directory.\n *\n * @example\n * ```ts\n * await declarations.emitBundle({ index: 'src/index.ts', 'utils/index': 'src/utils/index.ts' }, 'dist/types');\n * // [ 'D:/app/dist/types/index.d.ts', 'D:/app/dist/types/utils/index.d.ts' ]\n * ```\n *\n * @see emit\n * @since 3.0.0\n */\n\n async emitBundle(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n const options = this.ts.config.options;\n const base = this.filesCache.resolve(outdir ?? options.declarationDir ?? options.outDir ?? '.');\n\n return this.write(\n Object.keys(entryPoints).map(name => join(base, `${ name }.d.ts`)),\n Object.values(entryPoints).map(entry => this.bundle(entry))\n );\n }\n\n /**\n * Builds the bundled declaration text of one entry point.\n *\n * @param entry - Filesystem path of the entry file, relative or absolute\n * @returns The complete declaration file content, header included\n *\n * @remarks\n * Nothing is written and nothing is cached beyond the entries themselves, so the same entry can be bundled\n * repeatedly, and each call reflects the files as the cache currently sees them.\n * Declarations are inlined once per file even when several files depend on it, and a dependency cycle is walked\n * once rather than followed around.\n *\n * @see render\n * @since 3.0.0\n */\n\n private bundle(entry: string): string {\n const target = this.filesCache.resolve(entry);\n const node = this.touch(target);\n\n return this.render(this.collectClosure(target, node), this.collectSurface(target, node));\n }\n\n /**\n * Creates the directories of a batch and writes its files concurrently.\n *\n * @param outputs - Absolute output paths to write\n * @param contents - Content of each output, in the same order\n * @returns The written paths, for direct return by callers\n *\n * @remarks\n * Each directory is created once for the whole batch rather than once per file, and an empty batch touches the disk\n * not at all.\n *\n * @since 3.0.0\n */\n\n private async write(outputs: Array<string>, contents: Array<string>): Promise<Array<string>> {\n if (outputs.length < 1) return outputs;\n\n const directories = new Set(outputs.map(output => dirname(output)));\n await Promise.all([ ...directories ].map(directory => mkdir(directory, { recursive: true })));\n await Promise.all(outputs.map((output, index) => writeFile(output, contents[index], 'utf-8')));\n\n return outputs;\n }\n\n /**\n * Maps a source path to the declaration path it is written to.\n *\n * @param source - Resolved absolute path of the source file\n * @param outdir - Directory overriding both configured output directories\n * @param name - Output name to use instead of the one the source implies, carrying no extension\n * @returns The absolute output path\n *\n * @remarks\n * The directory is the first of `outdir`, `declarationDir`, and `outDir` that is set,\n * and the source's own directory only when none of them is.\n * A name replaces everything the source would have decided, `.d.ts` being appended to it, and a name carrying a\n * directory nests the output inside the base.\n * Without one the path mirrors the source tree relative to `rootDir` - the source directory standing in when no\n * `rootDir` is set, which flattens the output the way `tsc` does - and the extension follows the input, so `.ts`\n * and `.tsx` become `.d.ts` while `.mts` and `.cts` keep their module flavor as `.d.mts` and `.d.cts`.\n *\n * @since 3.0.0\n */\n\n private outputPath(source: string, outdir?: string, name?: string): string {\n const { declarationDir, outDir, rootDir } = this.ts.config.options;\n const base = outdir ?? declarationDir ?? outDir;\n const target = base ? this.filesCache.resolve(base) : dirname(source);\n if (name) return join(target, `${ name }.d.ts`);\n\n const root = rootDir ? this.filesCache.resolve(rootDir) : dirname(source);\n\n return join(target, relative(root, source).replace(/\\.([cm]?)tsx?$/, '.d.$1ts'));\n }\n\n /**\n * Collects every project file the entry reaches, dependencies first.\n *\n * @param target - Resolved absolute path of the entry file\n * @param entry - Cache entry of the entry file\n * @returns The entries to inline, in the order their content is concatenated\n *\n * @remarks\n * A depth-first walk over the dependency edges with an explicit stack, so a deep dependency chain cannot overflow\n * the stack, and a visited set, so a cycle terminates, and a shared dependency is inlined once.\n * The entry counts as visited from the start, so a dependency cycling back to it does not inline it twice, and it\n * lands last regardless, which keeps the file the bundle describes at the bottom.\n *\n * @since 3.0.0\n */\n\n private collectClosure(target: string, entry: DeclarationEntryInterface): Array<DeclarationEntryInterface> {\n const visited = new Set<string>([ target ]);\n const closure: Array<DeclarationEntryInterface> = [];\n const pending = [ ...entry.projectDependencies ];\n\n while (pending.length > 0) {\n const dependency = pending.pop()!;\n if (visited.has(dependency)) continue;\n visited.add(dependency);\n\n const node = this.touch(dependency);\n closure.push(node);\n\n for (const nested of node.projectDependencies)\n if (!visited.has(nested)) pending.push(nested);\n }\n\n closure.push(entry);\n\n return closure;\n }\n\n /**\n * Collects the names and re-export statements the bundle exposes.\n *\n * @param target - Resolved absolute path of the entry file\n * @param entry - Cache entry of the entry file\n * @returns The entry's surface, merged with the surface of every project file it star re-exports\n *\n * @remarks\n * Star re-exports of project files are followed transitively, their names becoming the entry's own, while package\n * re-exports are kept as statements and passed straight through.\n * The entry counts as visited from the start, so a star re-export cycling back to it is not walked again.\n * Namespace re-exports of project files are left out: flattening one would mean synthesizing a `declare namespace`\n * around the target's exports, which the inlined fragments do not describe well enough.\n *\n * @see BundleSurfaceInterface\n * @since 3.0.0\n */\n\n private collectSurface(target: string, entry: DeclarationEntryInterface): BundleSurfaceInterface {\n const exports = new Set<string>();\n const statements = new Set<string>();\n const visited = new Set<string>([ target ]);\n const pending = [ entry ];\n\n while (pending.length > 0) {\n const node = pending.pop()!;\n for (const binding of node.projectExports.exports) exports.add(this.clause(binding));\n\n for (const [ module, bindings ] of Object.entries(node.packageExports)) {\n if (bindings.star) statements.add(`export * from '${ module }';`);\n if (bindings.named?.length)\n statements.add(`export { ${ bindings.named.map(binding => this.clause(binding)).join(', ') } } from '${ module }';`);\n\n for (const name of bindings.namespaces ?? []) statements.add(`export * as ${ name } from '${ module }';`);\n }\n\n for (const star of node.projectExports.star) {\n if (visited.has(star)) continue;\n visited.add(star);\n pending.push(this.touch(star));\n }\n }\n\n return { exports, statements };\n }\n\n /**\n * Merges the package imports of every inlined file into one record per module.\n *\n * @param closure - Entries whose content the bundle carries\n * @returns The merged bindings, keyed by module specifier in first-seen order\n *\n * @remarks\n * One pass over the files and their modules folds each module's side effect flag, default binding, namespaces,\n * and named bindings into a single record the bundle can write back as statements.\n *\n * @see MergedImportInterface\n * @since 3.0.0\n */\n\n private mergeImports(closure: Array<DeclarationEntryInterface>): Map<string, MergedImportInterface> {\n const merged = new Map<string, MergedImportInterface>();\n\n for (const node of closure) {\n for (const [ module, bindings ] of Object.entries(node.packageImports)) {\n let entry = merged.get(module);\n if (!entry) merged.set(module, entry = { side: false, named: new Set(), namespaces: new Set() });\n\n if (bindings.side) entry.side = true;\n entry.default ??= bindings.default;\n for (const name of bindings.namespaces ?? []) entry.namespaces.add(name);\n for (const binding of bindings.named ?? []) entry.named.add(this.clause(binding));\n }\n }\n\n return merged;\n }\n\n /**\n * Writes the merged imports back out as import statements.\n *\n * @param merged - Bindings collected per module\n * @returns One statement per import form a module was used with\n *\n * @remarks\n * A module can need several statements: a side effect import, one for each namespace binding,\n * and one carrying its default and named bindings together.\n * Named bindings are sorted, so the same set of files always produces the same bundle.\n *\n * @since 3.0.0\n */\n\n private renderImports(merged: Map<string, MergedImportInterface>): Array<string> {\n const statements: Array<string> = [];\n\n for (const [ module, entry ] of merged) {\n if (entry.side) statements.push(`import '${ module }';`);\n for (const name of entry.namespaces) statements.push(`import * as ${ name } from '${ module }';`);\n\n const clauses: Array<string> = [];\n if (entry.default) clauses.push(entry.default);\n if (entry.named.size > 0) clauses.push(`{ ${ [ ...entry.named ].sort().join(', ') } }`);\n if (clauses.length > 0) statements.push(`import ${ clauses.join(', ') } from '${ module }';`);\n }\n\n return statements;\n }\n\n /**\n * Assembles the finished bundle from its header, imports, inlined content, and exports.\n *\n * @param closure - Entries to inline, dependencies first\n * @param surface - Names and statements the bundle exposes\n * @returns The complete declaration file content\n *\n * @remarks\n * Imports are merged over the whole closure rather than the surface, since every inlined declaration is free to\n * reference them, while the exports come from the surface alone.\n * A bundle that exposes nothing still closes with an empty export clause, without which its declarations would be\n * read as globals rather than as a module.\n *\n * @see HeaderDeclarationBundle\n * @since 3.0.0\n */\n\n private render(closure: Array<DeclarationEntryInterface>, surface: BundleSurfaceInterface): string {\n const parts: Array<string> = [ HeaderDeclarationBundle ];\n const imports = this.renderImports(this.mergeImports(closure));\n if (imports.length > 0) parts.push(...imports, '');\n\n for (const node of closure) {\n const content = node.content.trim();\n if (content) parts.push(content, '');\n }\n\n if (surface.exports.size > 0) parts.push(`export {\\n\\t${ [ ...surface.exports ].sort().join(',\\n\\t') }\\n};`);\n parts.push(...surface.statements);\n if (surface.exports.size < 1 && surface.statements.size < 1) parts.push('export {};');\n\n return `${ parts.join('\\n') }\\n`;\n }\n\n /**\n * Writes a binding the way an import or export clause spells it.\n *\n * @param binding - Name and the alias it was renamed to, if any\n * @returns The bare name, or `name as alias` when the clause renamed it\n *\n * @see NamedBindingInterface\n * @since 3.0.0\n */\n\n private clause(binding: NamedBindingInterface): string {\n return binding.alias ? `${ binding.name } as ${ binding.alias }` : binding.name;\n }\n\n /**\n * Emits the declarations of one file and reduces them to a cache entry.\n *\n * @param target - Resolved absolute path of the file\n * @param source - Current text of the file\n * @param version - Snapshot version the entry is recorded against\n * @returns The freshly built entry\n *\n * @remarks\n * The emitted text is parsed once, and that parse drives everything: the statement walk queues both edit lists and\n * records the graph, and the comment walk that follows it queues the doc comments the stripping orphaned.\n * Emit diagnostics are not surfaced here - a declaration oxc cannot infer is reported by the type checker as an\n * isolated-declarations error against the source file itself.\n *\n * @see strip\n * @see pruneComments\n * @since 3.0.0\n */\n\n private build(target: string, source: string, version: number): DeclarationEntryInterface {\n const declaration = isolatedDeclarationSync(target, source, { stripInternal: true }).code;\n const context: ParseContextInterface = {\n edits: [],\n target,\n parsed: parseSync(target, declaration, { sourceType: 'module' }),\n content: declaration,\n bundleEdits: [],\n packageImports: Object.create(null),\n packageExports: Object.create(null),\n projectExports: { star: new Set(), exports: [], namespace: Object.create(null) },\n projectDependencies: new Set()\n };\n\n const kept: Array<number> = [];\n const { body } = context.parsed.program;\n\n for (const statement of body)\n if (this.strip(statement, context)) kept.push(statement.start);\n\n this.pruneComments(context, body, kept);\n\n return {\n version,\n content: applyEdits(declaration, context.bundleEdits),\n declaration: applyEdits(declaration, context.edits),\n packageImports: context.packageImports,\n packageExports: context.packageExports,\n projectExports: context.projectExports,\n projectDependencies: context.projectDependencies\n };\n }\n\n /**\n * Dispatches one top-level statement to the handler for its module syntax.\n *\n * @param statement - Statement to strip\n * @param context - Pass the edits are queued against and the bindings recorded on\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * Only top-level statements are visited, since only those can carry module syntax.\n * `export =` and `export as namespace` are dropped without a record: both describe how a module is consumed whole,\n * which a fragment inlined into a bundle can no longer express.\n * Anything that is not module syntax is kept untouched.\n *\n * @since 3.0.0\n */\n\n private strip(statement: Directive | Statement, context: ParseContextInterface): boolean {\n switch (statement.type) {\n case 'ImportDeclaration':\n this.stripImport(statement, context);\n\n return false;\n\n case 'ExportAllDeclaration':\n this.stripStarExport(statement, context);\n\n return false;\n\n case 'ExportNamedDeclaration':\n return this.stripNamedExport(statement, context);\n\n case 'ExportDefaultDeclaration':\n return this.stripDefaultExport(statement, context);\n\n case 'TSImportEqualsDeclaration':\n return this.stripImportEquals(statement, context);\n\n case 'TSExportAssignment':\n case 'TSNamespaceExportDeclaration':\n removeNode(statement, context.content, context.bundleEdits);\n\n return false;\n\n default:\n return true;\n }\n }\n\n /**\n * Removes an `import` statement, recording either a dependency or the package bindings it pulled in.\n *\n * @param statement - Import statement to strip\n * @param context - Pass the deletion is queued against\n *\n * @remarks\n * An import of a project file only contributes an edge, since the target's declarations are inlined,\n * and its bindings are already in scope in the bundle.\n * Everything else is recorded per module, so the bundle can reissue one import statement for it.\n *\n * @see link\n * @since 3.0.0\n */\n\n private stripImport(statement: ImportDeclaration, context: ParseContextInterface): void {\n removeNode(statement, context.content, context.bundleEdits);\n if (this.link(statement.source, context)) return;\n\n const module = context.packageImports[statement.source.value] ??= {};\n if (statement.specifiers.length < 1) {\n module.side = true;\n\n return;\n }\n\n for (const entry of statement.specifiers) {\n switch (entry.type) {\n case 'ImportDefaultSpecifier':\n module.default ??= entry.local.name;\n break;\n\n case 'ImportNamespaceSpecifier':\n (module.namespaces ??= []).push(entry.local.name);\n break;\n\n default:\n (module.named ??= []).push(this.binding(this.nameOf(entry.imported), entry.local.name));\n }\n }\n }\n\n /**\n * Removes an `import x = require('module')` statement the way its ESM equivalent is removed.\n *\n * @param statement - Import-equals statement to strip\n * @param context - Pass the deletion is queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * Only the external-module form names a module.\n * `import A = B.C` aliases a local name and is kept as it stands, since the namespace it reaches into is inlined\n * with the rest of the fragment.\n * A package binding is recorded as a namespace import, which is what `require` binds in type space.\n *\n * @see stripImport\n * @since 3.0.0\n */\n\n private stripImportEquals(statement: TSImportEqualsDeclaration, context: ParseContextInterface): boolean {\n const { moduleReference } = statement;\n if (moduleReference.type !== 'TSExternalModuleReference') return true;\n\n removeNode(statement, context.content, context.bundleEdits);\n const source = moduleReference.expression;\n\n if (!this.link(source, context))\n ((context.packageImports[source.value] ??= {}).namespaces ??= []).push(statement.id.name);\n\n return false;\n }\n\n /**\n * Strips an `export` that carries a declaration, a specifier list, or a re-export clause.\n *\n * @param statement - Named export statement to strip\n * @param context - Pass the edits are queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * A declaration keeps its body and loses only the `export` keyword, so `export declare const x` becomes\n * `declare const x` and stays valid where the fragment lands.\n * A specifier list is removed outright: names re-exported from a project file, or from nothing at all, are recorded\n * as this file's own surface, since the declarations behind them are inlined.\n * Only a clause pointing at a package is recorded as a re-export the bundle has to emit again.\n *\n * @see collectDeclared\n * @since 3.0.0\n */\n\n private stripNamedExport(statement: ExportNamedDeclaration, context: ParseContextInterface): boolean {\n const { exports } = context.projectExports;\n\n if (statement.declaration) {\n this.collectDeclared(statement.declaration, exports);\n context.bundleEdits.push({ start: statement.start, end: statement.declaration.start });\n\n return true;\n }\n\n removeNode(statement, context.content, context.bundleEdits);\n const named = statement.source && !this.link(statement.source, context)\n ? (context.packageExports[statement.source.value] ??= {}).named ??= []\n : exports;\n\n for (const entry of statement.specifiers)\n named.push(this.binding(this.nameOf(entry.local), this.nameOf(entry.exported)));\n\n return false;\n }\n\n /**\n * Removes an `export *` statement, recording the module or project file behind it.\n *\n * @param statement - Star export statement to strip\n * @param context - Pass the deletion is queued against\n *\n * @remarks\n * A star export of a project file becomes an edge plus an entry the bundler follows to collect the names it\n * exposes, whereas a namespace form records the name it is exposed under instead.\n *\n * @see link\n * @since 3.0.0\n */\n\n private stripStarExport(statement: ExportAllDeclaration, context: ParseContextInterface): void {\n removeNode(statement, context.content, context.bundleEdits);\n\n const target = this.link(statement.source, context);\n const exposed = statement.exported ? this.nameOf(statement.exported) : null;\n\n if (target) {\n if (exposed) context.projectExports.namespace[exposed] = target;\n else context.projectExports.star.add(target);\n\n return;\n }\n\n const module = context.packageExports[statement.source.value] ??= {};\n if (exposed) (module.namespaces ??= []).push(exposed);\n else module.star = true;\n }\n\n /**\n * Strips an `export default`, keeping the declaration behind it whenever there is one to keep.\n *\n * @param statement - Default export statement to strip\n * @param context - Pass the edits are queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * A named class, function, or interface keeps its body and is recorded as `Name as default`,\n * with `export default` rewritten to `declare` so the fragment stays a valid ambient declaration.\n * A default export of an identifier is dropped, since the declaration it names is a statement of its own that\n * the fragment already carries.\n * An anonymous default has no binding a bundle could re-export, so it is dropped without a record.\n *\n * @see defaultBinding\n * @since 3.0.0\n */\n\n private stripDefaultExport(statement: ExportDefaultDeclaration, context: ParseContextInterface): boolean {\n const { declaration } = statement;\n const local = this.defaultBinding(declaration);\n if (local) context.projectExports.exports.push({ name: local, alias: 'default' });\n\n if (local && declaration.type !== 'Identifier') {\n context.bundleEdits.push({ start: statement.start, end: declaration.start, text: 'declare ' });\n\n return true;\n }\n\n removeNode(statement, context.content, context.bundleEdits);\n\n return false;\n }\n\n /**\n * Queues the removal of every doc comment the stripping left attached to nothing.\n *\n * @param context - Pass the deletions are queued against\n * @param body - Top-level statements of the file, in source order\n * @param kept - Start offsets of the surviving statements, in source order\n *\n * @remarks\n * Only comments that sit between two top-level statements are judged, so the documentation a surviving declaration\n * carries on its own members is never touched.\n * Such a comment is kept when nothing but whitespace separates it from the next surviving statement.\n * Anything else - a stripped statement between the two, another comment, or a trailing position with no statement\n * after it at all - makes it an orphan.\n * Only `/**` comments are considered, so line comments and plain block comments stay put.\n * Comments and statements are both in source order, so all three are walked together in one pass,\n * and a file with many comments does not cost a scan per comment.\n *\n * @see build\n * @since 3.0.0\n */\n\n private pruneComments(context: ParseContextInterface, body: Array<Directive | Statement>, kept: Array<number>): void {\n const { content, bundleEdits } = context;\n let inner = 0;\n let index = 0;\n\n for (const comment of context.parsed.comments) {\n if (comment.type !== 'Block' || comment.value.charCodeAt(0) !== Char.Star) continue;\n\n while (inner < body.length && body[inner].end <= comment.start) inner++;\n if (inner < body.length && body[inner].start < comment.start) continue;\n\n while (index < kept.length && kept[index] < comment.end) index++;\n if (index < kept.length && this.blank(content, comment.end, kept[index])) continue;\n\n removeNode(comment, content, bundleEdits);\n }\n }\n\n /**\n * Resolves a specifier, recording it as a dependency and rewriting it when it names a project file.\n *\n * @param source - Specifier literal as written in the declaration\n * @param context - Pass the specifier was read from\n * @returns The resolved absolute path, or `null` when the specifier names a package or does not resolve\n *\n * @remarks\n * The one place a specifier is looked at, so the two outputs cannot disagree on which files are inlined.\n * An internal target leaves an edge behind for the bundle and a relative rewrite for the standalone declaration,\n * while a package leaves both untouched.\n * The rewrite names the declaration rather than the source, the resolved extension giving way to `.d.ts`, so an\n * emitted file points at the file emitted beside it rather than at a source that was never shipped.\n * Resolution goes through the TypeScript service, so aliases and `paths` mappings resolve the way the type checker\n * sees them rather than the way Node would, and the path it reports is normalized the way the file cache keys are.\n *\n * @since 3.0.0\n */\n\n private link(source: StringLiteral, context: ParseContextInterface): string | null {\n const resolved = this.ts.resolve(source.value, context.target);\n if (!resolved || resolved.isExternalLibraryImport) return null;\n\n const { extension, relativeFileName, resolvedFileName } = resolved;\n const target = this.filesCache.resolve(resolvedFileName);\n\n context.projectDependencies.add(target);\n context.edits.push({\n end: source.end,\n start: source.start,\n text: `'${ extension ? relativeFileName.slice(0, -extension.length) : relativeFileName }.d.ts'`\n });\n\n return target;\n }\n\n /**\n * Appends the names a declaration binds to the exported surface.\n *\n * @param declaration - Declaration carried by an `export` statement\n * @param names - Bindings the declared names are appended to\n *\n * @remarks\n * A variable statement can bind several names at once, while every other declaration binds at most one.\n * Bindings that are not plain identifiers - a destructured variable, or an ambient module declared by its quoted\n * path - contribute nothing, having no name a bundle could re-export.\n *\n * @since 3.0.0\n */\n\n private collectDeclared(declaration: Declaration, names: Array<NamedBindingInterface>): void {\n if (declaration.type === 'VariableDeclaration') {\n for (const entry of declaration.declarations)\n if (entry.id.type === 'Identifier') names.push({ name: entry.id.name });\n\n return;\n }\n\n if ('id' in declaration && declaration.id && 'name' in declaration.id) names.push({ name: declaration.id.name });\n }\n\n /**\n * Returns the local name a default export binds, when it binds one.\n *\n * @param declaration - Declaration or expression behind `export default`\n * @returns The bound name, or `undefined` for an anonymous or non-binding default\n *\n * @since 3.0.0\n */\n\n private defaultBinding(declaration: ExportDefaultDeclarationKind): string | undefined {\n if (declaration.type === 'Identifier') return declaration.name;\n\n return 'id' in declaration ? declaration.id?.name : undefined;\n }\n\n /**\n * Reads the name out of an import or export clause entry.\n *\n * @param name - Identifier or string literal naming a binding\n * @returns The identifier, or the literal re-quoted so it can be emitted back into a clause\n *\n * @since 3.0.0\n */\n\n private nameOf(name: ModuleExportName): string {\n return 'name' in name ? name.name : JSON.stringify(name.value);\n }\n\n /**\n * Pairs the name a binding carries on the module with its local name.\n *\n * @param name - Name the binding is known by on the other side of the clause\n * @param alias - Local name the clause binds it under\n * @returns The bare name when the two match, and the pair when the clause renamed it\n *\n * @see NamedBindingInterface\n * @since 3.0.0\n */\n\n private binding(name: string, alias: string): NamedBindingInterface {\n return name === alias ? { name } : { name, alias };\n }\n\n /**\n * Reports whether a range of the content holds nothing but whitespace.\n *\n * @param content - Text the range points into\n * @param start - Inclusive start offset of the range\n * @param end - Exclusive end offset of the range\n * @returns `true` when every character in the range is a space, tab, or line break\n *\n * @remarks\n * Scans in place and stops at the first other character, so it costs nothing on the long ranges left behind by\n * stripped statements and allocates no substring on the short ones.\n *\n * @since 3.0.0\n */\n\n private blank(content: string, start: number, end: number): boolean {\n for (let index = start; index < end; index++) {\n const code = content.charCodeAt(index);\n if (code !== Char.Space && code !== Char.Tab && code !== Char.Lf && code !== Char.Cr) return false;\n }\n\n return true;\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { ParseResult } from 'oxc-parser';\nimport type { Span, StringLiteral } from '@oxc-project/types';\nimport type { TypescriptService } from '@typescript/services/typescript.service';\nimport type { SourceEditInterface } from './interfaces/transformer-component.interface';\n\n/**\n * Imports\n */\n\nimport { Char } from '@constants/char.constant';\n\n/**\n * Records an edit that deletes a node along with the rest of its line.\n *\n * @param node - Span of the node to delete, as the parser reported it\n * @param content - Source text the span points into\n * @param edits - Collector the deletion is appended to\n *\n * @remarks\n * The deleted range runs from the start of the node through the spaces and tabs that follow it and one line terminator,\n * so a statement that sat alone on its line does not leave a blank line behind.\n * Anything before the node on that line is kept, since the scan only moves forward from the node's end.\n *\n * @example\n * ```ts\n * const content = \"import 'a';\\nconst x = 1;\";\n * const edits: Array<SourceEditInterface> = [];\n *\n * removeNode({ start: 0, end: 11 }, content, edits);\n * edits; // [ { start: 0, end: 12 } ]\n * applyEdits(content, edits); // 'const x = 1;'\n * ```\n *\n * @see applyEdits\n * @since 3.0.0\n */\n\nexport function removeNode(node: Span, content: string, edits: Array<SourceEditInterface>): void {\n let cursor = node.end;\n\n while (cursor < content.length) {\n const code = content.charCodeAt(cursor);\n if (code !== Char.Space && code !== Char.Tab) break;\n cursor++;\n }\n if (content.charCodeAt(cursor) === Char.Cr) cursor++;\n if (content.charCodeAt(cursor) === Char.Lf) cursor++;\n\n edits.push({ start: node.start, end: cursor });\n}\n\n/**\n * Rewrites the source text with a set of edits applied.\n *\n * @param content - Source text the edits point into\n * @param edits - Edits to apply, sorted in place by start offset\n * @returns The rewritten text, or `content` itself when there is nothing to apply\n *\n * @remarks\n * The edits are ordered by start offset and applied left to right,\n * so a transform can collect them in whatever order it walks the tree.\n * An edit starting inside a range an earlier edit already replaced is dropped rather than merged,\n * which keeps the output well-formed when two passes claim overlapping spans.\n * An edit carrying no `text` deletes its span.\n * The array is sorted in place, so a caller that depends on its original order should pass a copy.\n *\n * @example\n * ```ts\n * applyEdits('const a = 1;', [ { start: 0, end: 5, text: 'let' } ]); // 'let a = 1';\n * applyEdits('const a = 1;', [ { start: 0, end: 6 } ]); // 'a = 1;' - deleted\n * applyEdits('const a = 1;', []); // 'const a = 1;' - returned untouched\n * ```\n *\n * @see SourceEditInterface\n * @since 3.0.0\n */\n\nexport function applyEdits(content: string, edits: Array<SourceEditInterface>): string {\n if (edits.length < 1) return content;\n edits.sort((left, right) => left.start - right.start);\n\n const parts: Array<string> = new Array(edits.length * 2 + 1);\n let index = 0;\n let cursor = 0;\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n if (edit.start < cursor) continue;\n parts[index++] = content.slice(cursor, edit.start);\n parts[index++] = edit.text ?? '';\n cursor = edit.end;\n }\n\n parts[index++] = content.slice(cursor);\n parts.length = index;\n\n return parts.join('');\n}\n\n/**\n * Queues an edit rewriting a specifier to the relative path of the project file it resolves to.\n *\n * @param source - Specifier literal to rewrite, or `null` when the statement carries none\n * @param target - Resolved absolute path of the file the specifier was written in\n * @param edits - Collector the rewrite is appended to\n * @param ts - Service whose module resolution decides what the specifier names\n *\n * @remarks\n * Only a project file is rewritten, so a specifier naming a package or resolving nowhere is left as it was written.\n * So is a statement with no specifier at all, which is what `export { a }` without a `from` clause looks like.\n * The replacement is measured from the importing file's own directory and carries no extension,\n * so an alias or a `paths` mapping becomes a specifier that still resolves once the file no longer sits in the source\n * tree.\n *\n * @example\n * ```ts\n * const edits: Array<SourceEditInterface> = [];\n *\n * rewrite(statement.source, 'D:/app/src/index.ts', edits, ts);\n * edits; // [ { start: 21, end: 43, text: \"'./components/builder.js'\" } ]\n * ```\n *\n * @see resolveSource\n * @since 3.0.0\n */\n\nexport function rewrite(source: StringLiteral | null, target: string, edits: Array<SourceEditInterface>, ts: TypescriptService): void {\n if (!source) return;\n\n const resolved = ts.resolve(source.value, target);\n if (!resolved || resolved.isExternalLibraryImport) return;\n const { extension, relativeFileName } = resolved;\n const path = extension ? relativeFileName.slice(0, -extension.length) : relativeFileName;\n\n edits.push({ end: source.end, start: source.start, text: `'${ path }.js'` });\n}\n\n/**\n * Rewrites every project specifier in a parsed file and returns the text with the rewrites applied.\n *\n * @param parse - Parse of the text, whose spans are offsets into `content`\n * @param target - Resolved absolute path of the file the text belongs to\n * @param content - The text the parse describes, handed back unchanged when it is empty\n * @param ts - Service whose module resolution decides which specifiers name project files\n * @returns The text with every project specifier rewritten, or `content` itself when none was\n *\n * @remarks\n * Only top-level statements are visited, since only those can carry module syntax.\n * An import, an `export *`, and a named export are read for their `from` clause,\n * while `import x = require('m')` is read for its module name.\n * `import A = B.C` names no module, so it is left alone, as is an `export { a }` that carries no `from` clause.\n * Every specifier found goes through {@link rewrite}, so a package stays as it was written,\n * and only a project file is rewritten.\n * The parse and the text have to come from the same source, since the spans are offsets into it - a parse of one text\n * applied to another lands its edits in the wrong places.\n *\n * @example\n * ```ts\n * const content = \"import { build } from '@components/builder';\\nexport const x = 1;\";\n * const parse = parseSync('src/index.ts', content, { sourceType: 'module' });\n *\n * resolveSource(parse, 'D:/app/src/index.ts', content, ts);\n * // \"import { build } from './components/builder';\\nexport const x = 1;\"\n * ```\n *\n * @see rewrite\n * @see applyEdits\n *\n * @since 3.0.0\n */\n\nexport function resolveSource(parse: ParseResult, target: string, content: string = '', ts: TypescriptService): string {\n if(!content) return content;\n const edits: Array<SourceEditInterface> = [];\n\n for (const statement of parse.program.body) {\n switch (statement.type) {\n case 'ImportDeclaration':\n case 'ExportAllDeclaration':\n case 'ExportNamedDeclaration':\n rewrite(statement.source, target, edits, ts);\n break;\n\n case 'TSImportEqualsDeclaration':\n if (statement.moduleReference.type === 'TSExternalModuleReference')\n rewrite(statement.moduleReference.expression, target, edits, ts);\n }\n }\n\n return applyEdits(content, edits);\n}\n\n","/**\n * Header text included at the top of generated declaration bundle files.\n *\n * @remarks\n * This constant provides a standardized header comment prepended to all\n * declaration bundle files generated by the TypeScript module. The header clearly\n * indicates that the file was automatically generated and should not be edited manually.\n *\n * The header serves as:\n * - A warning to developers not to manually modify generated files\n * - Documentation indicating the source of the file\n * - A consistent marker for identifying generated declaration files\n *\n * @example\n * ```ts\n * import { HeaderDeclarationBundle } from './typescript.constant';\n * import { writeFileSync } from 'fs';\n *\n * const bundledContent = `${HeaderDeclarationBundle}\\n${actualDeclarations}`;\n * writeFileSync('dist/index.d.ts', bundledContent);\n * ```\n *\n * @since 1.5.9\n */\n\nexport const HeaderDeclarationBundle = `/**\n * This file was automatically generated by xBuild.\n * DO NOT EDIT MANUALLY.\n */\n`;\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { FileSnapshotInterface } from '@models/interfaces/files-model.interface';\nimport type { IScriptSnapshot, SourceFile, ParsedCommandLine, CompilerOptions } from 'typescript';\n\n/**\n * Imports\n */\n\nimport ts from 'typescript';\nimport { relative } from '@remotex-labs/xmap';\nimport { inject } from '@remotex-labs/xinject';\nimport { FilesModel } from '@models/files.model';\nimport { createMatcher } from '@components/glob.component';\n\n/**\n * A TypeScript language service host backed by cached file snapshots and the set of files it has tracked.\n *\n * @remarks\n * Satisfies `ts.LanguageServiceHost`, giving the language service its filesystem access, script snapshots, and\n * compiler configuration.\n * Reads and versions are delegated to the shared {@link FilesModel}, while the file set handed over through\n * {@link getScriptFileNames} is maintained here.\n * A path enters the tracked set the first time it is refreshed or its version is queried,\n * so the set grows from the configured entry files to every dependency the language service resolves into them.\n * Paths matched by the configuration's `exclude` globs are skipped by {@link refreshFiles} and reported as ignored\n * to incremental checks through {@link ignoreSourceFile}.\n *\n * @example\n * ```ts\n * const host = new LanguageHostService(parsedConfig); // entry files tracked and read up front\n *\n * host.refresh('src/index.ts'); // re-read and track one file\n * host.getScriptSnapshot('src/index.ts'); // what the language service parses\n * host.options = nextParsedConfig; // swap configuration and re-track from scratch\n * ```\n *\n * @see FilesModel\n * @since 2.0.0\n */\n\nexport class LanguageHostService implements ts.LanguageServiceHost {\n /**\n * Shared model that reads files, caches their snapshots, and tracks their versions.\n *\n * @remarks\n * Registered as a singleton, so every host and build step works against one cache keyed by resolved absolute path.\n *\n * @example\n * ```ts\n * host.filesCache.touch('src/index.ts').version; // 1\n * ```\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n readonly filesCache = inject(FilesModel);\n\n /**\n * Resolved absolute paths of every file this host has tracked for the language service.\n *\n * @remarks\n * Returned verbatim from {@link getScriptFileNames}.\n * A path is added the first time it is refreshed or its version is queried, then kept even after the file is\n * deleted, so the language service observes the deletion through an empty snapshot rather than a vanishing file.\n *\n * @see track\n * @since 3.0.0\n */\n\n private readonly trackedFiles = new Set<string>();\n\n /**\n * Memoized exclusion verdict per path, keyed by the resolved absolute path.\n *\n * @remarks\n * Exclusion is asked for on every refresh and on every source file an incremental check walks,\n * while the answer only changes with the configuration, so {@link reload} clears this rather than recomputing it.\n *\n * @see isExcluded\n * @since 3.0.0\n */\n\n private readonly exclusions = new Map<string, boolean>();\n\n /**\n * A predicate compiled from the configuration's `exclude` globs, tested against working-directory-relative\n * paths.\n *\n * @remarks\n * Assigned by {@link reload} before any lookup can reach it, hence the definite assignment.\n * It takes a relative path, so {@link isExcluded} is what callers use.\n *\n * @see compileExclude\n * @since 3.0.0\n */\n\n private matches!: (path: string) => boolean;\n\n /**\n * Initializes a new {@link LanguageHostService} from a parsed configuration.\n *\n * @param config - Parsed TypeScript configuration carrying the compiler options, entry file names,\n * and the raw `exclude` globs\n *\n * @remarks\n * Runs {@link reload}, so the entry files are read into the cache and tracked before the host is handed out.\n *\n * @example\n * ```ts\n * const config = ts.getParsedCommandLineOfConfigFile('tsconfig.json', {}, ts.sys as never)!;\n * const host = new LanguageHostService(config);\n * host.getScriptFileNames(); // the configuration's entry files\n * ```\n *\n * @see reload\n * @since 3.0.0\n */\n\n constructor(private config: ParsedCommandLine) {\n this.reload();\n }\n\n /**\n * The live set of resolved paths currently tracked by this host.\n *\n * @returns The tracked set itself, mutated as files are refreshed and cleared\n *\n * @remarks\n * Exposes the same paths as {@link getScriptFileNames} without copying,\n * so a caller can iterate them or feed them straight back into {@link refreshFiles}.\n *\n * @example\n * ```ts\n * host.refresh('src/index.ts');\n * host.tracked.has(host.realpath('src/index.ts')); // true\n * ```\n *\n * @see getScriptFileNames\n * @since 3.0.0\n */\n\n get tracked(): Set<string> {\n return this.trackedFiles;\n }\n\n /**\n * A source-file predicate that incremental checks can use to skip excluded files.\n *\n * @returns A predicate reporting `true` for a source file whose path matches the exclude globs\n *\n * @remarks\n * Bridges the path-based {@link isExcluded} to TypeScript's `ignoreSourceFile` hook by reading the absolute\n * `fileName`, so it agrees with how {@link refreshFiles} filters paths.\n *\n * @example\n * ```ts\n * builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, host.ignoreSourceFile);\n * ```\n *\n * @see refreshFiles\n * @since 3.0.0\n */\n\n get ignoreSourceFile(): (file: SourceFile) => boolean {\n return (file: SourceFile): boolean => this.isExcluded(file.fileName);\n }\n\n /**\n * Replaces the configuration and re-tracks the project from scratch.\n *\n * @param config - The new parsed configuration\n *\n * @remarks\n * Delegates to {@link reload}, so the exclude predicate is recompiled and the new `config.fileNames` replace the\n * tracked set entirely.\n *\n * @example\n * ```ts\n * host.options = ts.getParsedCommandLineOfConfigFile('tsconfig.json', {}, ts.sys as never)!;\n * host.getScriptFileNames(); // the new entry files, nothing carried over\n * ```\n *\n * @see reload\n * @since 3.0.0\n */\n\n set options(config: ParsedCommandLine) {\n this.config = config;\n this.reload();\n }\n\n /**\n * Drops the tracked set and repopulates it from the configured entry files.\n *\n * @remarks\n * The {@link filesCache} snapshots survive, so only membership is reset,\n * and the files are re-read on the way back in through {@link refreshFiles}.\n *\n * @example\n * ```ts\n * host.refresh('src/scratch.ts');\n * host.clearTracked();\n * host.getScriptFileNames(); // back to the configured entry files, scratch.ts dropped\n * ```\n *\n * @see refreshFiles\n * @since 3.0.0\n */\n\n clearTracked(): void {\n this.trackedFiles.clear();\n this.refreshFiles(this.config.fileNames);\n }\n\n /**\n * Rebuilds the exclude predicate and the tracked set from the current configuration.\n *\n * @remarks\n * The single initialization path shared by the constructor and the {@link options} setter:\n * - compiles the `exclude` globs into {@link matches},\n * - drops the memoized {@link exclusions}, whose verdicts belong to the previous globs,\n * - refreshes every entry file through {@link clearTracked}, which reads them into the cache and tracks them.\n *\n * Call it directly when the configuration object was edited in place rather than replaced.\n *\n * @example\n * ```ts\n * host.reload();\n * host.getScriptFileNames(); // what the configuration now selects\n * ```\n *\n * @see clearTracked\n * @since 3.0.0\n */\n\n reload(): void {\n this.matches = this.compileExclude(this.config.raw?.exclude);\n this.exclusions.clear();\n\n this.clearTracked();\n }\n\n /**\n * Re-reads a file from the disk, tracks it, and returns its entry.\n *\n * @param path - File path, relative or absolute\n * @returns The entry for the file, with `version` advanced when the content changed\n *\n * @remarks\n * The path is tracked before the read, so it stays listed even when the file turns out to be gone.\n * Exclusion is not consulted here - {@link refreshFiles} is the caller that filters.\n *\n * @example\n * ```ts\n * const state = host.refresh('src/index.ts');\n * state.version; // 1 at first sight, advanced on every later change\n * state.snapshot?.text; // the content just read\n * ```\n *\n * @see track\n * @since 3.0.0\n */\n\n refresh(path: string): FileSnapshotInterface {\n return this.filesCache.refresh(this.track(path));\n }\n\n /**\n * Refreshes and tracks a batch of files, skipping any path matched by the exclude globs.\n *\n * @param paths - Paths to refresh, defaulting to the currently tracked set\n *\n * @remarks\n * Each retained path goes through {@link refresh} and so becomes tracked.\n * Calling it with no argument brings the already tracked files current, which is what a watch cycle does.\n *\n * @example\n * ```ts\n * host.refreshFiles([ 'src/a.ts', 'src/a.spec.ts' ]); // a.spec.ts skipped when excluded\n * host.refreshFiles(); // re-read everything already tracked\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n refreshFiles(paths: Array<string> | Set<string> = this.trackedFiles): void {\n for (const path of paths) {\n if (this.isExcluded(path)) continue;\n this.refresh(path);\n }\n }\n\n /**\n * Returns the compiler options currently in force.\n *\n * @returns The active TypeScript compiler options\n *\n * @example\n * ```ts\n * host.getCompilationSettings().target; // ts.ScriptTarget.ES2020\n * ```\n *\n * @since 2.0.0\n */\n\n getCompilationSettings(): CompilerOptions {\n return this.config.options;\n }\n\n /**\n * Reports whether a file exists on disk.\n *\n * @param path - Absolute path\n * @returns `true` when the file exists\n *\n * @remarks\n * Goes straight to `ts.sys`, bypassing the snapshot cache, so it reflects the filesystem as it stands now.\n *\n * @example\n * ```ts\n * host.fileExists('/project/src/index.ts'); // true\n * ```\n *\n * @since 2.0.0\n */\n\n fileExists(path: string): boolean {\n return ts.sys.fileExists(path);\n }\n\n /**\n * Reads file content through the snapshot cache.\n *\n * @param path - File path, relative or absolute\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The file content, or `undefined` when the path holds no readable file\n *\n * @remarks\n * Served from the cache once the file has been read, so the encoding only takes effect on the first read of a path.\n *\n * @example\n * ```ts\n * host.readFile('src/index.ts'); // export const x = 10;\n * host.readFile('src/gone.ts'); // undefined\n * ```\n *\n * @see FilesModel.touch\n * @since 3.0.0\n */\n\n readFile(path: string, encoding?: BufferEncoding): string | undefined {\n return this.filesCache.touch(path, encoding).snapshot?.text;\n }\n\n /**\n * Lists the files under a directory that match the given criteria.\n *\n * @param path - Directory to start from\n * @param extensions - File extensions to accept\n * @param exclude - Glob patterns to skip\n * @param include - Glob patterns to keep\n * @param depth - Maximum recursion depth\n * @returns The matching file paths\n *\n * @example\n * ```ts\n * host.readDirectory('src', [ '.ts' ], [ 'node_modules' ], undefined, 2); // [ 'src/index.ts', ... ]\n * ```\n *\n * @since 2.0.0\n */\n\n readDirectory(path: string, extensions?: Array<string>, exclude?: Array<string>, include?: Array<string>, depth?: number): Array<string> {\n return ts.sys.readDirectory(path, extensions, exclude, include, depth);\n }\n\n /**\n * Returns the immediate subdirectories of a path.\n *\n * @param path - Directory to list\n * @returns The subdirectory names\n *\n * @example\n * ```ts\n * host.getDirectories('src'); // [ 'services', 'models' ]\n * ```\n *\n * @since 2.0.0\n */\n\n getDirectories(path: string): Array<string> {\n return ts.sys.getDirectories(path);\n }\n\n /**\n * Reports whether a directory exists.\n *\n * @param path - Absolute path\n * @returns `true` when the directory exists\n *\n * @example\n * ```ts\n * host.directoryExists('src/services'); // true\n * ```\n *\n * @since 2.0.0\n */\n\n directoryExists(path: string): boolean {\n return ts.sys.directoryExists(path);\n }\n\n /**\n * Returns the working directory that relative paths resolve against.\n *\n * @returns The absolute path of the current working directory\n *\n * @example\n * ```ts\n * host.getCurrentDirectory(); // '/project'\n * ```\n *\n * @since 2.0.0\n */\n\n getCurrentDirectory(): string {\n return ts.sys.getCurrentDirectory();\n }\n\n /**\n * Returns the resolved paths of every file tracked by this host.\n *\n * @returns A snapshot array of the tracked absolute paths\n *\n * @remarks\n * This is the program's file set as far as the language service is concerned.\n * A deleted file stays listed, so its removal surfaces as a diagnostic rather than as a silently shrinking program.\n *\n * @example\n * ```ts\n * host.getScriptFileNames(); // [ '/project/src/index.ts', '/project/src/utils.ts' ]\n * ```\n *\n * @see tracked\n * @since 2.0.0\n */\n\n getScriptFileNames(): Array<string> {\n return [ ...this.trackedFiles ];\n }\n\n /**\n * Returns the path of the default lib file matching the given options.\n *\n * @param options - Compiler options, of which `target` decides the lib\n * @returns Absolute path to the matching `lib.*.d.ts`\n *\n * @example\n * ```ts\n * host.getDefaultLibFileName({ target: ts.ScriptTarget.ES2020 }); // '.../lib.es2020.full.d.ts'\n * ```\n *\n * @since 2.0.0\n */\n\n getDefaultLibFileName(options: CompilerOptions): string {\n return ts.getDefaultLibFilePath(options);\n }\n\n /**\n * Returns the version identifier of a file and tracks it.\n *\n * @param path - File path, relative or absolute\n * @returns The version as a string, such as `'1'` or `'2'`\n *\n * @remarks\n * The language service reparses a file only when this string changes, so the value must stay stable while the file\n * does.\n * The read is served from the cache, and {@link refresh} is what moves the version forward.\n *\n * @example\n * ```ts\n * host.getScriptVersion('src/index.ts'); // '1'\n * host.refresh('src/index.ts'); // the file changed on disk\n * host.getScriptVersion('src/index.ts'); // '2' - the language service reparses it\n * ```\n *\n * @see track\n * @since 2.0.0\n */\n\n getScriptVersion(path: string): string {\n return this.filesCache.touch(this.track(path)).version.toString();\n }\n\n /**\n * Returns the script snapshot of a file.\n *\n * @param path - File path, relative or absolute\n * @returns The snapshot, or `undefined` when the path holds no readable file\n *\n * @remarks\n * Reads through the cache, loading from the disk at first sight only.\n * Unlike {@link getScriptVersion}, it leaves the tracked set alone - tracking is driven by version queries.\n *\n * @example\n * ```ts\n * const snapshot = host.getScriptSnapshot('src/index.ts');\n * snapshot?.getText(0, snapshot.getLength()); // export const x = 10;\n * ```\n *\n * @see getScriptVersion\n * @since 2.0.0\n */\n\n getScriptSnapshot(path: string): IScriptSnapshot | undefined {\n return this.filesCache.touch(path).snapshot;\n }\n\n /**\n * Resolves a path to the absolute form used as the tracking and cache key.\n *\n * @param path - File path, relative or absolute\n * @returns The resolved absolute path\n *\n * @remarks\n * Implements the optional `realpath` host hook with the same normalization {@link FilesModel} applies to its cache\n * keys, so the paths reported to TypeScript match the ones tracked here.\n *\n * @example\n * ```ts\n * host.realpath('src/index.ts'); // '/project/src/index.ts'\n * ```\n *\n * @see FilesModel.resolve\n * @since 3.0.0\n */\n\n realpath(path: string): string {\n return this.filesCache.resolve(path);\n }\n\n /**\n * Compiles exclude globs into a matcher over working-directory-relative paths.\n *\n * @param globs - Patterns whose matching paths are excluded, or `undefined` when the configuration has none\n * @returns A predicate reporting `true` for a matched relative path, or one that always reports `false`\n *\n * @remarks\n * The empty case is handled explicitly, since {@link createMatcher} reads an empty pattern list as matching\n * everything, which would exclude the whole project.\n *\n * @see createMatcher\n * @since 3.0.0\n */\n\n private compileExclude(globs?: Array<string>): (path: string) => boolean {\n return globs && globs.length > 0 ? createMatcher(globs) : (): boolean => false;\n }\n\n /**\n * Reports whether a path is excluded by the configuration, memorizing the verdict.\n *\n * @param path - File path as the caller holds it, relative or absolute\n * @returns `true` when the path matches the exclude globs\n *\n * @remarks\n * The path is resolved before the verdict is stored, so the same file reached by two spellings is matched once,\n * and every later lookup of either costs a map read.\n *\n * @see exclusions\n * @since 3.0.0\n */\n\n private isExcluded(path: string): boolean {\n const target = this.filesCache.resolve(path);\n let excluded = this.exclusions.get(target);\n if (excluded === undefined) this.exclusions.set(\n target, excluded = this.matches(relative(process.cwd(), target))\n );\n\n return excluded;\n }\n\n /**\n * Adds a path to the tracked set and returns its resolved key.\n *\n * @param path - File path, relative or absolute\n * @returns The resolved absolute path used as the tracking key\n *\n * @remarks\n * Centralizes the tracking shared by {@link refresh} and {@link getScriptVersion}.\n * A path is added the first time it is seen and never removed,\n * so a deletion leaves a still-listed entry that resolves to an empty snapshot.\n *\n * @see trackedFiles\n * @since 3.0.0\n */\n\n private track(path: string): string {\n const target = this.filesCache.resolve(path);\n this.trackedFiles.add(target);\n\n return target;\n }\n}\n"],"mappings":"oVAWA,UAAYA,MAAU,OACtB,UAAYC,MAAW,QACvB,OAAS,WAAAC,MAAe,OACxB,OAAS,gBAAAC,MAAoB,KCd7B,IAAAC,EAAA,w7JDgBA,OAAS,QAAAC,MAAY,qBACrB,OAAS,UAAAC,OAAc,wBACvB,OAAS,WAAAC,OAAe,4BACxB,OAAS,WAAAC,GAAS,QAAAC,GAAM,YAAAC,OAAgB,cETxC,OAAS,OAAAC,OAAW,UACpB,OAAS,gBAAAC,OAAoB,KCC7B,OAAS,gBAAAC,GAAc,YAAAC,OAAgB,KACvC,OAAS,WAAAC,OAAe,qBACxB,OAAS,cAAAC,OAAkB,wBA+BpB,IAAMC,EAAN,KAAiB,CAWH,SAAW,IAAI,IAWf,MAAQ,IAAI,IAkB7B,OAAc,CACV,KAAK,MAAM,MAAM,EACjB,KAAK,SAAS,MAAM,CACxB,CAuBA,YAAYC,EAAiD,CACzD,OAAO,KAAK,MAAM,IAAI,KAAK,QAAQA,CAAI,CAAC,CAC5C,CAuBA,MAAMA,EAAcC,EAAkD,CAClE,IAAMC,EAAS,KAAK,QAAQF,CAAI,EAEhC,OAAO,KAAK,MAAM,IAAIE,CAAM,GAAK,KAAK,KAAKA,EAAQ,KAAK,KAAKA,CAAM,EAAGD,CAAQ,CAClF,CA0BA,QAAQD,EAAcG,EAAeF,EAAkD,CACnF,IAAMC,EAAS,KAAK,QAAQF,CAAI,EAEhC,OAAO,KAAK,KAAKE,EAAQC,GAAS,KAAK,KAAKD,CAAM,EAAGD,CAAQ,CACjE,CA6BA,WAAWG,EAA6B,CACpC,IAAMC,EAAWD,GAAS,KAAK,MAAM,KAAK,EAC1C,QAAWJ,KAAQK,EACf,KAAK,QAAQL,CAAI,CAEzB,CAmBA,QAAQA,EAAsB,CAC1B,IAAIE,EAAS,KAAK,SAAS,IAAIF,CAAI,EACnC,OAAIE,IAAW,QAAW,KAAK,SAAS,IAAIF,EAAME,EAASI,GAAQN,CAAI,CAAC,EAEjEE,CACX,CAkBQ,KAAKA,EAAgBK,EAAyBN,EAA2B,QAAgC,CAC7G,IAAMO,EAAQ,KAAK,MAAM,IAAIN,CAAM,EAEnC,OAAKK,GAAM,OAAO,EAMdC,GAAO,UAAYD,EAAK,QAAgBC,EAErC,KAAK,MAAMN,EAAQ,CACtB,QAASK,EAAK,QACd,SAAUC,GAAO,SAAW,GAAK,EACjC,SAAU,KAAK,SAASC,GAAaP,EAAQD,CAAQ,CAAC,CAC1D,CAAC,EAXOO,GAAS,CAACA,EAAM,SAAiBA,EAE9B,KAAK,MAAMN,EAAQ,CAAE,QAAS,EAAG,SAAU,OAAW,SAAUM,GAAO,SAAW,GAAK,CAAE,CAAC,CAUzG,CAiBQ,YAAYE,EAAiBC,EAAkC,CACnE,IAAMC,EAAYF,EAAQ,OACpBG,EAAYF,EAAQ,OACpBG,EAAM,KAAK,IAAIF,EAAWC,CAAS,EAErCE,EAAS,EACb,KAAOA,EAASD,GAAOJ,EAAQ,WAAWK,CAAM,IAAMJ,EAAQ,WAAWI,CAAM,GAAGA,IAElF,IAAIC,EAAS,EACb,KAAOA,EAASF,EAAMC,GAAUL,EAAQ,WAAWE,EAAY,EAAII,CAAM,IAAML,EAAQ,WAAWE,EAAY,EAAIG,CAAM,GAAGA,IAE3H,MAAO,CACH,KAAM,CAAE,MAAOD,EAAQ,OAAQH,EAAYG,EAASC,CAAO,EAC3D,UAAWH,EAAYE,EAASC,CACpC,CACJ,CAeQ,SAASC,EAAkC,CAC/C,MAAO,CACH,KAAAA,EACA,QAAS,CAACC,EAAOC,IAAgBF,EAAK,MAAMC,EAAOC,CAAG,EACtD,UAAW,IAAcF,EAAK,OAC9B,eAAiBG,GACM,KAAK,YAAYA,EAAS,QAAQ,EAAGA,EAAS,UAAU,CAAC,EAAGH,CAAI,CAC3F,CACJ,CAeQ,MAAMf,EAAgBM,EAAqD,CAC/E,YAAK,MAAM,IAAIN,EAAQM,CAAK,EAErBA,CACX,CAcQ,KAAKR,EAAiC,CAC1C,OAAOqB,GAASrB,EAAM,CAAE,eAAgB,EAAM,CAAC,CACnD,CACJ,EApTaD,EAANuB,EAAA,CAHNC,GAAW,CACR,MAAO,WACX,CAAC,GACYxB,GDhCb,OAAS,UAAAyB,GAAQ,cAAAC,OAAkB,wBACnC,OAAS,aAAAC,EAAW,iBAAAC,OAAqB,qBAYzC,IAAMC,EAAuB,sBAavBC,GAAuB,sBAgChBC,EAAN,KAAuB,CAgBjB,cAgBA,cAiBA,YAuBQ,WAAa,IAAI,IAqBlC,aAAc,CACV,KAAK,YAAcC,EAAUC,GAAI,CAAC,EAClC,KAAK,cAAgBD,EAAU,YAAY,QAAQ,EACnD,KAAK,cAAgBA,EAAU,YAAY,OAAO,EAElD,KAAK,cAAc,KAAK,aAAa,CACzC,CAwBA,OAAO,QAAQE,EAAsB,CACjC,OAAQH,EAAiB,QAAUI,GAAOC,CAAU,GAAG,QAAQF,CAAI,CACvE,CA2BA,gBAAgBG,EAAkE,CAC9E,OAAOR,EAAqB,KAAKQ,EAAS,QAAU,EAAE,GAAKR,EAAqB,KAAKQ,EAAS,YAAc,EAAE,CAClH,CAuBA,aAAaH,EAAyC,CAClD,OAAO,KAAK,WAAW,IAAIH,EAAiB,QAAQG,CAAI,CAAC,CAC7D,CAgCA,aAAaA,EAAcI,EAAgBC,EAAiB,GAAa,CACrE,IAAMC,EAAMT,EAAiB,QAAQG,CAAI,EACrC,CAACK,GAAS,KAAK,WAAW,IAAIC,CAAG,GAErC,KAAK,SAASA,EAAKF,CAAM,CAC7B,CA2BA,cAAcJ,EAAoB,CAC9B,GAAI,CAACA,EAAM,OAEX,IAAMM,EAAMT,EAAiB,QAAQG,CAAI,EACzC,GAAI,KAAK,WAAW,IAAIM,CAAG,EAAG,OAE9B,IAAIF,EACJ,GAAI,CACAA,EAASG,GAAa,GAAID,CAAI,OAAQ,OAAO,CACjD,OAASE,EAAO,CACZ,MAAMX,EAAiB,QAAQS,EAAKE,CAAK,CAC7C,CAEA,KAAK,SAASF,EAAKF,CAAM,CAC7B,CAgBA,OAAe,QAAQE,EAAaE,EAAuB,CACvD,OAAO,IAAI,MACP,kCAAmCF,CAAI;AAAA,EAAME,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAE,EACxG,CACJ,CAmBQ,SAASF,EAAaF,EAAsB,CAChD,GAAI,CAAAR,GAAqB,KAAKQ,CAAM,EAEpC,GAAI,CACA,KAAK,WAAW,IAAIE,EAAK,IAAIG,GAAcL,EAAQE,CAAG,CAAC,CAC3D,OAASE,EAAO,CACZ,MAAMX,EAAiB,QAAQS,EAAKE,CAAK,CAC7C,CACJ,CACJ,EAjPIE,EAhESb,EAgEM,SAhENA,EAANc,EAAA,CAHNC,GAAW,CACR,MAAO,WACX,CAAC,GACYf,GFxBN,IAAMgB,EAAN,KAAmB,CA4EtB,YAAqBC,EAAsCC,EAAa,CAAnD,YAAAD,EACjB,KAAK,QAAUE,EAAiB,QAAQD,CAAG,EAC3C,KAAK,OAAO,OAAS,EACrB,KAAK,OAAO,OAAS,WACzB,CAJqB,OAhEb,OAeS,QAAU,IAAIE,GAWd,QAYA,UAAYC,GAAOF,CAAgB,EAgDpD,IAAI,MAAiC,CACjC,OAAO,KAAK,QAAQ,KAAK,KAAK,KAAK,OAAO,CAC9C,CAmBA,IAAI,WAA2C,CAC3C,OAAO,KAAK,QAAQ,UAAU,KAAK,KAAK,OAAO,CACnD,CA0BA,MAAM,OAAuB,CACzB,GAAI,KAAK,OAAO,MACZ,OAAO,MAAM,KAAK,iBAAiB,EAEvC,MAAM,KAAK,gBAAgB,CAC/B,CAwBA,MAAM,MAAsB,CACxB,GAAI,CAAC,KAAK,OAAQ,OAAO,KAAK,QAAQ,KAAK,CAAE,KAAM,OAAQ,QAAS,EAAM,CAAC,EAE3E,MAAM,IAAI,QAAc,CAACG,EAASC,IAAW,CACzC,KAAK,OAAQ,MAAMC,GAAO,CAClBA,EAAKD,EAAOC,CAAG,EACdF,EAAQ,CACjB,CAAC,CACL,CAAC,EAED,KAAK,OAAS,OACd,KAAK,QAAQ,KAAK,CAAE,KAAM,OAAQ,QAAS,EAAK,CAAC,CACrD,CAwBA,MAAM,SAAyB,CAC3B,MAAM,KAAK,KAAK,EAChB,MAAM,KAAK,MAAM,CACrB,CAaQ,eAAsB,CAC1B,GAAI,KAAK,OAAO,OAAS,EAAG,CACxB,IAAMG,EAAU,KAAK,OAAQ,QAAQ,EAClCA,GAAW,OAAOA,GAAY,UAAYA,EAAQ,OACjD,KAAK,OAAO,KAAOA,EAAQ,KACnC,CACJ,CAeQ,iBAAiC,CACrC,OAAO,IAAI,QAAeH,GAAY,CAClC,KAAK,OAAc,eAAa,CAACI,EAAKC,IAAQ,CAC1C,KAAK,cAAcD,EAAKC,EAAK,IAAM,KAAK,gBAAgBD,EAAKC,CAAG,CAAC,CACrE,CAAC,EAED,KAAK,OAAO,OAAO,KAAK,OAAO,KAAM,KAAK,OAAO,KAAM,IAAM,CACzD,KAAK,cAAc,EACnB,IAAMF,EAAkC,CACpC,KAAM,KAAK,OAAO,KAClB,KAAM,KAAK,OAAO,KAClB,IAAK,UAAW,KAAK,OAAO,IAAK,IAAK,KAAK,OAAO,IAAK,EAC3D,EAEA,KAAK,OAAO,UAAUA,CAAO,EAC7B,KAAK,QAAQ,KAAK,CAAE,GAAGA,EAAS,KAAM,OAAQ,CAAC,EAC/CH,EAAQ,CACZ,CAAC,CACL,CAAC,CACL,CAmBQ,kBAAkC,CACtC,OAAO,IAAI,QAASA,GAAY,CAC5B,IAAMM,EAAU,CACZ,IAAKC,EAAa,KAAK,OAAO,KAAOC,EAAK,KAAK,UAAU,cAAe,KAAM,QAAS,YAAY,CAAC,EACpG,KAAMD,EAAa,KAAK,OAAO,MAAQC,EAAK,KAAK,UAAU,cAAe,KAAM,QAAS,YAAY,CAAC,CAC1G,EAEA,KAAK,OAAe,eAAaF,EAAS,CAACF,EAAKC,IAAQ,CACpD,KAAK,cAAcD,EAAKC,EAAK,IAAM,KAAK,gBAAgBD,EAAKC,CAAG,CAAC,CACrE,CAAC,EAED,KAAK,OAAO,OAAO,KAAK,OAAO,KAAM,KAAK,OAAO,KAAM,IAAM,CACzD,KAAK,cAAc,EACnB,IAAMF,EAAkC,CACpC,KAAM,KAAK,OAAO,KAClB,KAAM,KAAK,OAAO,KAClB,IAAK,WAAY,KAAK,OAAO,IAAK,IAAK,KAAK,OAAO,IAAK,EAC5D,EAEA,KAAK,OAAO,UAAUA,CAAO,EAC7B,KAAK,QAAQ,KAAK,CAAE,GAAGA,EAAS,KAAM,OAAQ,CAAC,EAC/CH,EAAQ,CACZ,CAAC,CACL,CAAC,CACL,CAoBQ,cAAcI,EAAsBC,EAAqBI,EAAkC,CAC/F,GAAI,CACA,KAAK,QAAQ,KAAK,CAAE,KAAM,UAAW,IAAKL,EAAI,KAAO,EAAG,CAAC,EAErD,KAAK,OAAO,UACZ,KAAK,OAAO,UAAUA,EAAKC,EAAKI,CAAc,EAE9CA,EAAe,CAEvB,OAASC,EAAO,CACZ,KAAK,UAAUL,EAAaK,CAAK,CACrC,CACJ,CAgBQ,eAAeC,EAAqB,CAgBxC,MAf6C,CACzC,KAAM,YACN,IAAK,WACL,GAAI,yBACJ,IAAK,yBACL,IAAK,yBACL,GAAI,aACJ,IAAK,mBACL,KAAM,mBACN,IAAK,YACL,IAAK,aACL,IAAK,YACL,IAAK,YACT,EAEoBA,CAAG,GAAK,0BAChC,CAwBA,MAAc,gBAAgBP,EAAsBC,EAAoC,CACpF,IAAMO,EAAcR,EAAI,MAAQ,IAAM,GAAKA,EAAI,KAAK,QAAQ,OAAQ,EAAE,GAAK,GACrES,EAAWL,EAAK,KAAK,QAASI,CAAW,EAE/C,GAAI,CAACC,EAAS,WAAW,KAAK,OAAO,EAAG,CACpCR,EAAI,WAAa,IACjBA,EAAI,IAAI,EAER,MACJ,CAEA,GAAI,CACA,IAAMS,EAAQ,MAAMC,GAAKF,CAAQ,EAE7BC,EAAM,YAAY,EAClB,MAAM,KAAK,gBAAgBD,EAAUD,EAAaP,CAAG,EAC9CS,EAAM,OAAO,GACpB,MAAM,KAAK,WAAWD,EAAUR,CAAG,CAE3C,OAASK,EAAO,CACZ,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,MAAeA,EAAO,IAAKN,EAAI,GAAI,CAAC,EACvE,KAAK,aAAaC,CAAG,CACzB,CACJ,CAoBA,MAAc,gBAAgBQ,EAAkBD,EAAqBP,EAAoC,CAErG,IAAIW,GADU,MAAMC,GAAQJ,CAAQ,GACf,IAAIK,GAAQ,CAC7B,IAAML,EAAWL,EAAKI,EAAaM,CAAI,EACjCP,EAAMQ,EAAQD,CAAI,EAAE,MAAM,CAAC,GAAK,SAEtC,OAAGP,IAAQ,SACA;AAAA,gCACUE,CAAS;AAAA;AAAA,8DAEqBK,CAAK;AAAA;AAAA,kBAKjD;AAAA,4BACUL,CAAS;AAAA;AAAA,0DAEqBK,CAAK,0BAA2BP,CAAI;AAAA;AAAA,aAGvF,CAAC,EAAE,KAAK,EAAE,EAENK,EAGAA,EAAW,qBAAsBA,CAAS,SAF1CA,EAAW,qDAKf,IAAII,EAAa,IACXC,EAAWT,EAAY,MAAM,GAAG,EAAE,IAAIU,IACxCF,GAAc,GAAIE,CAAK,IAEhB,gBAAiBF,CAAW,KAAME,CAAK,YACjD,EAAE,KAAK,EAAE,EAEJC,EAAaC,EAAK,QAAQ,gBAAiBR,CAAQ,EACpD,QAAQ,aAAc,gCAAkCK,CAAQ,EAChE,QAAQ,UAAW,IAAMT,EAAY,MAAM,GAAG,EAAE,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,CAAC,EAE3EP,EAAI,UAAU,IAAK,CAAE,eAAgB,WAAY,CAAC,EAClDA,EAAI,IAAIkB,CAAU,CACtB,CAkBA,MAAc,WAAWV,EAAkBR,EAAoC,CAC3E,IAAMM,EAAMQ,EAAQN,CAAQ,EAAE,MAAM,CAAC,GAAK,MACpCY,EAAc,KAAK,eAAed,CAAG,EAErCe,EAAO,MAAMC,GAASd,CAAQ,EACpCR,EAAI,UAAU,IAAK,CAAE,eAAgBoB,CAAY,CAAC,EAClDpB,EAAI,IAAIqB,CAAI,CAChB,CAaQ,aAAarB,EAA2B,CAC5CA,EAAI,UAAU,IAAK,CAAE,eAAgB,YAAa,CAAC,EACnDA,EAAI,IAAI,WAAW,CACvB,CAeQ,UAAUA,EAAqBK,EAAoB,CACvD,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,MAAAA,CAAM,CAAC,EAC1CL,EAAI,UAAU,IAAK,CAAE,eAAgB,YAAa,CAAC,EACnDA,EAAI,IAAI,uBAAuB,CACnC,CACJ,EIpkBA,OAAS,cAAAuB,OAAkB,wBAC3B,OAAS,WAAAC,OAAe,4BCFxB,OAAS,QAAAC,OAAY,qBCqId,IAAMC,EAAsC,CAC9C,GAAU,IACV,GAAY,KACZ,GAAY,KACZ,GAAgB,IACrB,EDhHO,SAASC,EAAIC,EAAsB,CACtC,MAAO,kBAAkB,SAASA,CAAI,EAAI,KAAOA,EAAOA,CAC5D,CAuBO,SAASC,EAAGC,EAAcC,EAAuB,CACpD,OAAOD,EAAK,WAAWC,CAAK,CAChC,CA4BO,SAASC,GAAWF,EAAcC,EAAwB,CAC7D,OAAQA,IAAU,GAAKF,EAAGC,EAAMC,EAAQ,CAAC,IAAM,MACvCA,EAAQ,IAAMD,EAAK,QAAUD,EAAGC,EAAMC,EAAQ,CAAC,IAAM,GACjE,CAoBO,SAASE,EAAMC,EAAsB,CACxC,MAAO,MAAOA,CAAK,GACvB,CA0BO,SAASC,EAASL,EAAcM,EAA2B,CAC9D,IAAIC,EAAOD,EAAY,EACjBE,EAAOT,EAAGC,EAAMO,CAAI,EAK1B,KAHIC,IAAS,IAAaA,IAAS,KAAYD,IAC3CR,EAAGC,EAAMO,CAAI,IAAM,IAAeA,IAE/BA,EAAOP,EAAK,QAAUD,EAAGC,EAAMO,CAAI,IAAM,IAC5CA,GAAQR,EAAGC,EAAMO,CAAI,IAAM,GAAiB,EAAI,EAEpD,OAAOA,CACX,CAyBO,SAASE,GAAUT,EAAcM,EAA2B,CAC/D,QAASI,EAASJ,EAAWK,EAAQ,EAAGD,EAASV,EAAK,OAAQU,IAAU,CACpE,IAAMZ,EAAOC,EAAGC,EAAMU,CAAM,EAE5B,GAAIZ,IAAS,GAAgBY,YACpBZ,IAAS,GAAaa,QAC1B,IAAIb,IAAS,IAAe,EAAEa,IAAU,EAAG,OAAOD,EAC9CZ,IAAS,KAAeY,EAASL,EAASL,EAAMU,CAAM,GACnE,CAEA,MAAO,EACX,CA0BO,SAASE,GAAWZ,EAAcM,EAA2B,CAChE,IAAIO,EAAQ,GAEZ,QAASH,EAASJ,EAAY,EAAGK,EAAQ,EAAGD,EAASV,EAAK,OAAQU,IAAU,CACxE,IAAMZ,EAAOC,EAAGC,EAAMU,CAAM,EAE5B,GAAIZ,IAAS,GAAgBY,YACpBZ,IAAS,IAAaa,YACtBb,IAAS,IAAa,CAC3B,GAAIa,IAAU,EAAG,OAAOE,EAAQH,EAAS,GACzCC,GACJ,MACSb,IAAS,IAAca,IAAU,EAAGE,EAAQ,GAC5Cf,IAAS,KAAeY,EAASL,EAASL,EAAMU,CAAM,EACnE,CAEA,MAAO,EACX,CA2BO,SAASI,GAAad,EAAcM,EAAqC,CAC5E,IAAMS,EAAMV,EAASL,EAAMM,CAAS,EACpC,GAAIS,GAAOf,EAAK,OAAQ,MAAO,CAAE,MAAOM,EAAY,CAAE,EAEtD,IAAII,EAASJ,EAAY,EAAGU,EAAM,IAC5BR,EAAOT,EAAGC,EAAMU,CAAM,EAK5B,KAHIF,IAAS,IAAaA,IAAS,MAAcQ,GAAO,KAAMN,KAC1DX,EAAGC,EAAMU,CAAM,IAAM,KAAiBM,GAAO,MAAON,KAEjDA,EAASK,EAAKL,IACbX,EAAGC,EAAMU,CAAM,IAAM,GAAgBM,GAAO,KAAOhB,EAAK,EAAEU,CAAM,EAC3DX,EAAGC,EAAMU,CAAM,IAAM,GAAYM,GAAO,MAC5CA,GAAOhB,EAAKU,CAAM,EAG3B,MAAO,CAAEM,EAAM,IAAKD,EAAM,CAAE,CAChC,CAsBO,SAASE,GAAWjB,EAAckB,EAAsB,CAC3D,QAASR,EAASQ,EAAMR,EAASV,EAAK,OAAQU,IAAU,CACpD,GAAIX,EAAGC,EAAMU,CAAM,IAAM,GAAY,OAAOA,EACxCX,EAAGC,EAAMU,CAAM,IAAM,IAAgBA,GAC7C,CAEA,OAAOV,EAAK,MAChB,CAwCO,SAASmB,EAAgBnB,EAAcoB,EAA0B,GAAOC,EAAc,EAAGC,EAAgC,CAAC,EAAW,CACxI,GAAM,CAAE,IAAAC,EAAM,EAAM,EAAID,EAEpBN,EAAM,GACNf,EAAQ,EACRuB,EAAWJ,EAETK,EAAQF,EAAM,aACdG,EAAKD,EAAQ,OAAwB,IACrCE,EAAWxB,EAAMuB,EAAK,OAASA,EAAK,IAAI,EAAI,IAElD,KAAOzB,EAAQD,EAAK,QAAQ,CACxB,IAAMF,EAAOC,EAAGC,EAAMC,CAAK,EACrB2B,EAAQ7B,EAAGC,EAAMC,EAAQ,CAAC,EAEhC,GAAI2B,IAAU,KAAgB9B,IAAS,IAAa+B,EAAY/B,CAAI,GAAI,CACpE,IAAMgC,EAAQrB,GAAUT,EAAMC,EAAQ,CAAC,EAEvC,GAAIH,IAAS,GAAW,CACpB,IAAMiB,EAAMe,IAAU,GAAK9B,EAAK,OAAS8B,EACnCC,EAAQZ,EAAgBnB,EAAK,MAAMC,EAAQ,EAAGc,CAAG,EAAGS,MAAqBF,CAAO,EAEtFN,GAAO,MAAoBe,EAAQF,EAAY/B,CAAI,EACnDG,EAAQc,EAAM,EACd,QACJ,CAEA,GAAIe,IAAU,GAAI,CACd,IAAMC,EAAQZ,EAAgBnB,EAAK,MAAMC,EAAQ,EAAG6B,CAAK,EAAGN,MAAqBF,CAAO,EAClFU,EAAUf,GAAWjB,EAAM8B,EAAQ,CAAC,EACpCG,EAAOd,EAAgBnB,EAAK,MAAM8B,EAAQ,EAAGE,CAAO,EAAG,GAAO,EAAGV,CAAO,EAE9EN,GAAOb,GACFqB,EAAWC,EAAQ,IACpB,MAAOtB,EAAM4B,CAAK,EAAIE,EAAO,SAAsB,IACnD,SAA4BA,CAChC,EAEAhC,EAAQ+B,EACR,QACJ,CACJ,CAEA,OAAQlC,EAAM,CACV,QACIkB,GAAO,IACPf,IACAuB,EAAW,GACX,MAEJ,QACIR,GAAOf,EAAQ,EAAID,EAAK,OAASH,EAAIG,EAAKC,EAAQ,CAAC,CAAC,EAAI,OACxDA,GAAS,EACT,MAEJ,QACIe,GAAOQ,GAAY,CAACD,iBACpBtB,IACA,MAEJ,QACI,GAAI2B,IAAU,IAAaP,IAAQ,MAAcpB,EAAQ,GAAKmB,IAAmBlB,GAAWF,EAAMC,CAAK,EAAG,CACtG,IAAMiC,EAAOjC,IAAU,GAAKoB,IAAQ,qBAA2B,GAC3DtB,EAAGC,EAAMC,EAAQ,CAAC,IAAM,IACxBe,GAAOkB,EAAO/B,EAAMuB,EAAK,GAAkB,EAAI,IAAKzB,GAAS,EAAGuB,EAAW,KAE3ER,GAAOkB,EAAOP,EAAU1B,GAAS,EAEzC,MACIe,IAAQQ,EAAWC,EAAQ,IAAM,QACjCxB,IAEJ,MAEJ,SAAkB,CACd,IAAM6B,EAAQlB,GAAWZ,EAAMC,CAAK,EAEhC6B,IAAU,IACVd,GAAO,MAAOf,MAEde,GAAOb,EAAMgB,EAAgBnB,EAAK,MAAMC,EAAQ,EAAG6B,CAAK,EAAGN,KAAsBF,CAAO,CAAC,EACzFrB,EAAQ6B,EAAQ,GAEpB,KACJ,CAEA,QAAoB,CAChB,GAAM,CAAEK,EAAKC,CAAK,EAAItB,GAAad,EAAMC,CAAK,EAC9Ce,IAAQQ,GAAY,CAACD,GAAOY,IAAQ,gBAA8B,IAAMA,EACxElC,EAAQmC,EACR,KACJ,CAEA,SACA,QACQf,IAAQvB,GAAQkB,GAAO,IAAkBQ,EAAWJ,GACnDJ,GAAOnB,EAAIG,EAAKC,CAAK,CAAC,EAC3BA,IACA,MAEJ,QACIe,GAAOnB,EAAIG,EAAKC,CAAK,CAAC,EAAGA,GACjC,CACJ,CAEA,OAAOe,CACX,CAyEO,SAASqB,GAAarC,EAAcsB,EAAgC,CAAC,EAAW,CACnF,OAAO,IAAI,OAAO,IAAMH,EAAgBnB,EAAM,GAAM,EAAGsB,CAAO,EAAI,IAAKA,EAAQ,KAAK,CACxF,CAkCO,SAASgB,EAAcC,EAAsBjB,EAAgC,CAAC,EAA8B,CAC/G,IAAMkB,EAAyB,CAAC,EAC1BC,EAAyB,CAAC,EAEhC,QAASzC,KAAQuC,EAAO,CACpB,IAAIG,EAAM,GACV,KAAO3C,EAAGC,EAAM,CAAC,IAAM,IAAaD,EAAGC,EAAM,CAAC,IAAM,IAChD0C,EAAM,CAACA,EACP1C,EAAOA,EAAK,MAAM,CAAC,GAGtB0C,EAAMD,EAAUD,GAAS,KAAKH,GAAarC,EAAMsB,CAAO,CAAC,CAC9D,CAEA,OAAQqB,IACHH,EAAQ,SAAW,GAAKA,EAAQ,KAAKI,GAAKA,EAAE,KAAKD,CAAI,CAAC,IACvD,CAACF,EAAQ,KAAKG,GAAKA,EAAE,KAAKD,CAAI,CAAC,CACvC,CDljBA,OAAS,WAAAE,GAAS,QAAAC,EAAM,YAAAC,OAAgB,qBACxC,OAAS,SAAAC,GAAO,gBAAAC,GAAc,eAAAC,GAAa,aAAAC,GAAW,YAAAC,OAAgB,KA2C/D,IAAMC,EAAN,cAA2BC,EAAwB,CAmEtD,YAAYC,EAAsBC,EAAiC,CAC/D,MAAM,EADwB,aAAAA,EAG9B,KAAK,KAAOC,GAAQF,CAAI,EACxB,KAAK,QAAUG,EAAc,KAAK,SAAS,QAAU,CAAC,EAAG,CACrD,IAAK,KAAK,SAAS,KAAO,EAC9B,CAAC,CACL,CAPkC,QA5DjB,KAQA,QAQA,SAAW,IAAI,IAQf,QAAU,IAAI,IAQvB,cAAgB,EAQhB,MAwDC,UAAUC,EAA+BC,EAAmBC,EAA0C,CAC3G,IAAMC,EAAc,MAAM,UAAUH,EAAgBC,EAAOC,CAAQ,EACnE,MAAI,EAAE,KAAK,gBAAkB,GAAG,KAAK,MAAM,EAEpC,KAAK,cAAc,IAAM,CAC5BC,EAAY,EACR,EAAE,KAAK,gBAAkB,GAAG,KAAK,KAAK,CAC9C,CAAC,CACL,CAQA,IAAY,UAAmB,CAC3B,OAAO,KAAK,SAAS,UAAY,GACrC,CAWQ,OAAc,CAClB,KAAK,MAAM,KAAK,KAAM,KAAK,QAAQ,KAAK,IAAI,EAAG,KAAK,SAAS,SAAS,EAClE,KAAK,SAAS,gBAAgB,KAAK,cAAc,KAAK,IAAI,CAClE,CAYQ,MAAa,CACb,KAAK,OAAO,aAAa,KAAK,KAAK,EACvC,QAAWC,KAAW,KAAK,SAAS,OAAO,EAAGA,EAAQ,MAAM,EAE5D,KAAK,MAAQ,OACb,KAAK,QAAQ,MAAM,EACnB,KAAK,SAAS,MAAM,CACxB,CAcQ,OAAc,CAElB,GADA,KAAK,MAAQ,OACT,KAAK,QAAQ,OAAS,EAAG,OAE7B,IAAMC,EAAQ,OAAO,YAAY,KAAK,OAAO,EAC7C,KAAK,QAAQ,MAAM,EAEnB,GAAI,CACA,KAAK,KAAKA,CAAK,CACnB,MAAQ,CAER,CACJ,CAUQ,aAAaC,EAAoB,CACrC,IAAMF,EAAU,KAAK,SAAS,IAAIE,CAAI,EACjCF,IAELA,EAAQ,MAAM,EACd,KAAK,SAAS,OAAOE,CAAI,EAC7B,CAoBQ,aAAaC,EAAeD,EAAoB,CACpD,IAAME,EAAeC,GAAS,KAAK,KAAMH,CAAI,EACvCI,EAAOC,GAAUL,EAAM,CAAE,eAAgB,EAAM,CAAC,EAChDM,EAAQF,GAAM,eAAe,EAAIG,GAASP,EAAM,CAAE,eAAgB,EAAM,CAAC,EAAII,EAEnF,GAAIA,GAAM,eAAe,EAAG,CACxB,GAAI,CAACE,EAAO,OACRL,IAAU,UAAU,KAAK,aAAaD,CAAI,EAE1CM,EAAM,OAAO,GAAK,KAAK,QAAQN,CAAI,EAAG,KAAK,MAAMA,CAAI,EAChDM,EAAM,YAAY,GAAK,KAAK,SAAS,WAC1C,KAAK,MAAMN,EAAM,KAAK,QAAQ,KAAK,IAAI,EAAG,EAAI,CACtD,CAEA,GAAI,CAAC,KAAK,QAAQE,CAAY,EAAG,OAC7B,KAAK,MAAO,KAAK,MAAM,QAAQ,EAC9B,KAAK,MAAQ,WAAW,KAAK,MAAM,KAAK,IAAI,EAAG,KAAK,QAAQ,EAEjE,IAAIM,EACCF,EAIDE,EAAOF,EAAM,cAAgBA,EAAM,aAHnC,KAAK,aAAaN,CAAI,EACtBQ,EAAO,GAKX,KAAK,QAAQ,IAAIN,EAAc,CAAE,KAAAM,EAAM,MAAAF,CAAM,CAAC,CAClD,CAgBQ,MAAMN,EAAcS,EAAwCC,EAAqB,GAAa,CAClG,GAAI,KAAK,SAAS,IAAIV,CAAI,GAAK,KAAK,QAAQA,CAAI,EAAG,OACnD,IAAMF,EAAUa,GAAMC,GAAaZ,CAAI,EAAG,CAAE,UAAAU,EAAW,OAAAD,CAAO,EAAG,CAACR,EAAOY,IAAa,CAClF,GAAI,CAACA,EAAU,OACf,IAAMC,EAASd,EAAK,SAASa,CAAQ,EAAIb,EAAOe,EAAKf,EAAMa,CAAQ,EACnE,KAAK,aAAaZ,EAAOa,CAAM,CACnC,CAAC,EAEDhB,EAAQ,GAAG,QAAUH,GAAiB,CAClC,KAAK,aAAaK,CAAI,EACtB,KAAK,MAAML,CAAK,CACpB,CAAC,EAED,KAAK,SAAS,IAAIK,EAAMF,CAAO,CACnC,CAWQ,QAAQgB,EAAyB,CAErC,MADI,IAACA,GAAUA,EAAO,SAAS,GAAG,GAC9B,CAAC,KAAK,SAAS,KACXA,GAAUA,EAAO,MAAM,OAAO,EAAE,KAChCE,GAAOA,EAAI,WAAW,GAAG,CAAC,EAKtC,CAeQ,cAAcC,EAAoB,CACtC,IAAMC,EAAuB,CAAED,CAAK,EAEpC,KAAOC,EAAM,QAAQ,CACjB,IAAMC,EAAMD,EAAM,IAAI,EAElBE,EACJ,GAAI,CACAA,EAAUC,GAAYF,EAAK,CAAE,cAAe,EAAK,CAAC,CACtD,MAAQ,CACJ,QACJ,CAEA,QAAWG,KAASF,EAAS,CACzB,IAAMG,EAAOR,EAAKO,EAAM,YAAcH,EAAKG,EAAM,IAAI,EACjD,KAAK,QAAQC,CAAI,IAEjBD,EAAM,eAAe,EACrB,KAAK,MAAMC,EAAM,KAAK,QAAQ,KAAK,IAAI,EAAG,KAAK,SAAS,SAAS,EAC1D,KAAK,SAAS,WAAaD,EAAM,YAAY,GACpDJ,EAAM,KAAKK,CAAI,EAEvB,CACJ,CACJ,CACJ,EA7UanC,EAANoC,EAAA,CAHNC,GAAW,CACR,MAAO,WACX,CAAC,GACYrC,GGhDb,OAAS,UAAAsC,MAAc,wBAEvB,OAAS,gBAAAC,OAAoB,qBAC7B,OAAS,SAAAC,MAAa,sCAEtB,OAAS,mBAAAC,MAAuB,sCAChC,OAAS,mBAAAC,OAAuB,yCAChC,OAAS,iBAAAC,OAAqB,2CAgCvB,SAASC,GAAUC,EAAmB,GAA0B,CAEnE,IAAMC,EADYC,EAAOC,CAAgB,EAChB,aAAaH,CAAQ,EAC9C,GAAIC,EAAQ,OAAOA,EAEnB,IAAMG,EAAWF,EAAOG,CAAU,EAAE,MAAML,CAAQ,EAC5CM,EAAOF,EAAS,UAAU,KAEhC,GAAI,CAACA,GAAY,CAACE,EAAM,OAAO,KAC/B,IAAMC,EAAQD,EAAK,MAAM;AAAA,CAAI,EAE7B,MAAO,CACH,oBAAqB,CAACE,EAAMC,EAAQC,EAAOC,IAAY,CACnD,IAAMC,EAAQD,GAAS,YAAc,EAC/BE,EAASF,GAAS,aAAe,EAGjCG,EAAY,KAAK,IAAIN,EAAOK,EAAQ,CAAC,EACrCE,EAAU,KAAK,IAAIP,EAAOI,EAAOL,EAAM,MAAM,EAEnD,MAAO,CACH,KAAAC,EACA,KAAM,KACN,KAAMD,EAAM,MAAMO,EAAY,EAAGC,CAAO,EAAE,KAAK;AAAA,CAAI,EACnD,OAAQf,EACR,OAAQS,EACR,QAAAM,EACA,UAAAD,EACA,WAAY,KACZ,YAAa,GACb,cAAe,GACf,gBAAiB,EACrB,CACJ,CACJ,CACJ,CA+BO,SAASE,GAAcC,EAAiE,CAC3F,OAAIA,aAAe,MAAcrB,EAAgBqB,CAAG,EAChDA,EAAI,kBAAkB,MAAcrB,EAAgBqB,EAAI,MAAM,EAE7DA,EAAI,SAIF,CACH,KAAM,iBACN,QAASA,EAAI,MAAQ,GACrB,SAAU,GACV,MAAO,CACH,CACI,OAAQ,IAAKA,EAAI,SAAS,IAAK,GAC/B,KAAMA,EAAI,SAAS,KACnB,OAAQA,EAAI,SAAS,QAAU,EAC/B,SAAUA,EAAI,SAAS,KACvB,KAAM,GACN,MAAO,GACP,OAAQ,GACR,YAAa,EACjB,CACJ,CACJ,EAnBW,CAAE,MAAO,CAAC,EAAG,KAAM,iBAAkB,QAASA,EAAI,MAAQ,GAAI,SAAU,EAAG,CAoB1F,CAiCO,SAASC,GAAiBD,EAA6BN,EAA+BQ,EAAmB,GAAiC,CAC7I,IAAMC,EAAYlB,EAAOC,CAAgB,EACnCkB,EAASL,GAAcC,CAAG,EAC1BK,EAAqCC,GAAaF,EAAQ,CAC5D,GAAGV,EACH,iBAAkBQ,IAAYR,GAAS,qBAAuB,IAC9D,UAAUa,EAAoC,CAC1C,OAAOzB,GAAUyB,CAAI,CACzB,CACJ,CAAC,EAED,OAAAF,EAAS,MAAM,OAAOG,GAAS,CAC3B,GAAI,EAAEd,GAAS,qBAAuB,KAAUS,EAAU,gBAAgBK,CAAK,EAAG,MAAO,GACtF,CAACH,EAAS,YAAcG,EAAM,OAC7BH,EAAS,WAAazB,GAClB,CACI,KAAMC,GAAc2B,EAAM,IAAI,EAC9B,KAAMA,EAAM,MAAQ,EACpB,OAAQA,EAAM,QAAU,EACxB,UAAWA,EAAM,WAAa,CAClC,EACA,CAAE,MAAOC,EAAM,UAAW,CAC9B,EAER,CAAC,EAEMJ,CACX,CAqCO,SAASK,GAAYC,EAAoCC,EAAcC,EAAiBC,EAAiC,CAAC,EAAW,CACxI,IAAMC,EAAQ,CAAE;AAAA,EAAMH,CAAK,KAAMH,EAAM,WAAWI,CAAO,CAAE,EAAG,EAC9D,QAAWG,KAAQF,GAAS,CAAC,EACtBE,EAAK,MAAMD,EAAM,KAAK;AAAA,GAAQN,EAAM,KAAKO,EAAK,IAAI,CAAC,EAG1D,OAAIL,EAAS,YAAYI,EAAM,KAAK;AAAA;AAAA,EAAQJ,EAAS,UAAW,EAAE,EAC9DA,EAAS,MAAM,QACfI,EAAM,KAAK;AAAA;AAAA;AAAA,MAAmCJ,EAAS,MAAM,IAAIM,GAASA,EAAM,MAAM,EAAE,KAAK;AAAA,KAAQ,CAAE;AAAA,CAAI,EAGxGF,EAAM,KAAK,EAAE,CACxB,CC7OA,OAAOG,MAAQ,aACf,OAAS,cAAAC,OAAkB,wBAC3B,OAAS,aAAAC,GAAW,YAAAC,GAAU,WAAAC,OAAe,qBCD7C,OAAS,cAAAC,OAAkB,KAC3B,OAAS,aAAAC,OAAiB,aAC1B,OAAS,UAAAC,OAAc,wBACvB,OAAS,SAAAC,GAAO,aAAAC,OAAiB,cAGjC,OAAS,2BAAAC,OAA+B,gBACxC,OAAS,QAAAC,EAAM,WAAAC,EAAS,YAAAC,OAAgB,qBCkBjC,SAASC,EAAWC,EAAYC,EAAiBC,EAAyC,CAC7F,IAAIC,EAASH,EAAK,IAElB,KAAOG,EAASF,EAAQ,QAAQ,CAC5B,IAAMG,EAAOH,EAAQ,WAAWE,CAAM,EACtC,GAAIC,IAAS,IAAcA,IAAS,EAAU,MAC9CD,GACJ,CACIF,EAAQ,WAAWE,CAAM,IAAM,IAASA,IACxCF,EAAQ,WAAWE,CAAM,IAAM,IAASA,IAE5CD,EAAM,KAAK,CAAE,MAAOF,EAAK,MAAO,IAAKG,CAAO,CAAC,CACjD,CA4BO,SAASE,EAAWJ,EAAiBC,EAA2C,CACnF,GAAIA,EAAM,OAAS,EAAG,OAAOD,EAC7BC,EAAM,KAAK,CAACI,EAAMC,IAAUD,EAAK,MAAQC,EAAM,KAAK,EAEpD,IAAMC,EAAuB,IAAI,MAAMN,EAAM,OAAS,EAAI,CAAC,EACvDO,EAAQ,EACRN,EAAS,EAEb,QAASO,EAAI,EAAGA,EAAIR,EAAM,OAAQQ,IAAK,CACnC,IAAMC,EAAOT,EAAMQ,CAAC,EAChBC,EAAK,MAAQR,IACjBK,EAAMC,GAAO,EAAIR,EAAQ,MAAME,EAAQQ,EAAK,KAAK,EACjDH,EAAMC,GAAO,EAAIE,EAAK,MAAQ,GAC9BR,EAASQ,EAAK,IAClB,CAEA,OAAAH,EAAMC,GAAO,EAAIR,EAAQ,MAAME,CAAM,EACrCK,EAAM,OAASC,EAERD,EAAM,KAAK,EAAE,CACxB,CC5EO,IAAMI,EAA0B;AAAA;AAAA;AAAA;EFiChC,IAAMC,EAAN,KAAuB,CA0D1B,YAA6BC,EAAuB,CAAvB,QAAAA,CAAwB,CAAxB,GAxCpB,MAAQ,IAAI,IAQJ,WAAaC,GAAOC,CAAU,EAe9B,QAAU,IAAI,IAyC/B,OAAc,CACV,KAAK,MAAM,MAAM,EACjB,KAAK,QAAQ,MAAM,CACvB,CA4BA,MAAMC,EAAyC,CAC3C,IAAMC,EAAS,KAAK,WAAW,QAAQD,CAAI,EACrCE,EAAO,KAAK,WAAW,MAAMD,CAAM,EACnCE,EAAS,KAAK,MAAM,IAAIF,CAAM,EAEpC,GAAIE,GAAQ,UAAYD,EAAK,QAAS,OAAOC,EAE7C,IAAMC,EAAQ,KAAK,MAAMH,EAAQC,EAAK,UAAU,MAAQ,GAAIA,EAAK,OAAO,EACxE,YAAK,MAAM,IAAID,EAAQG,CAAK,EAErBA,CACX,CAiCA,MAAM,KAAKC,EAAqCC,EAAyC,CACrF,IAAMC,EAAyB,CAAC,EAC1BC,EAA0B,CAAC,EAC3BC,EAAU,IAAI,IACdC,EAAQ,IAAI,IAElB,OAAW,CAAEC,EAAMP,CAAM,IAAK,OAAO,QAAQC,CAAW,EACpDK,EAAM,IAAI,KAAK,WAAW,QAAQN,CAAK,EAAGO,CAAI,EAElD,IAAMC,EAAU,CAAE,GAAGF,EAAM,KAAK,CAAE,EAClC,KAAOE,EAAQ,OAAS,GAAG,CACvB,IAAMX,EAASW,EAAQ,IAAI,EAC3B,GAAIH,EAAQ,IAAIR,CAAM,GAAKA,EAAO,SAAS,OAAO,EAAG,SACrDQ,EAAQ,IAAIR,CAAM,EAElB,IAAMG,EAAQ,KAAK,MAAMH,CAAM,EAC/B,QAAWY,KAAcT,EAAM,oBACtBK,EAAQ,IAAII,CAAU,GAAGD,EAAQ,KAAKC,CAAU,EAEzD,IAAMC,EAAS,KAAK,WAAWb,EAAQK,EAAQI,EAAM,IAAIT,CAAM,CAAC,EAC5D,KAAK,QAAQ,IAAIa,CAAM,IAAMV,EAAM,SAAWW,GAAWD,CAAM,IAEnE,KAAK,QAAQ,IAAIA,EAAQV,EAAM,OAAO,EACtCG,EAAQ,KAAKO,CAAM,EACnBN,EAAS,KAAKJ,EAAM,WAAW,EACnC,CAEA,OAAO,KAAK,MAAMG,EAASC,CAAQ,CACvC,CA2BA,MAAM,WAAWH,EAAqCC,EAAyC,CAC3F,IAAMU,EAAU,KAAK,GAAG,OAAO,QACzBC,EAAO,KAAK,WAAW,QAAQX,GAAUU,EAAQ,gBAAkBA,EAAQ,QAAU,GAAG,EAE9F,OAAO,KAAK,MACR,OAAO,KAAKX,CAAW,EAAE,IAAIM,GAAQO,EAAKD,EAAM,GAAIN,CAAK,OAAO,CAAC,EACjE,OAAO,OAAON,CAAW,EAAE,IAAID,GAAS,KAAK,OAAOA,CAAK,CAAC,CAC9D,CACJ,CAkBQ,OAAOA,EAAuB,CAClC,IAAMH,EAAS,KAAK,WAAW,QAAQG,CAAK,EACtCe,EAAO,KAAK,MAAMlB,CAAM,EAE9B,OAAO,KAAK,OAAO,KAAK,eAAeA,EAAQkB,CAAI,EAAG,KAAK,eAAelB,EAAQkB,CAAI,CAAC,CAC3F,CAgBA,MAAc,MAAMZ,EAAwBC,EAAiD,CACzF,GAAID,EAAQ,OAAS,EAAG,OAAOA,EAE/B,IAAMa,EAAc,IAAI,IAAIb,EAAQ,IAAIO,GAAUO,EAAQP,CAAM,CAAC,CAAC,EAClE,aAAM,QAAQ,IAAI,CAAE,GAAGM,CAAY,EAAE,IAAIE,GAAaC,GAAMD,EAAW,CAAE,UAAW,EAAK,CAAC,CAAC,CAAC,EAC5F,MAAM,QAAQ,IAAIf,EAAQ,IAAI,CAACO,EAAQU,IAAUC,GAAUX,EAAQN,EAASgB,CAAK,EAAG,OAAO,CAAC,CAAC,EAEtFjB,CACX,CAsBQ,WAAWmB,EAAgBpB,EAAiBK,EAAuB,CACvE,GAAM,CAAE,eAAAgB,EAAgB,OAAAC,EAAQ,QAAAC,CAAQ,EAAI,KAAK,GAAG,OAAO,QACrDZ,EAAOX,GAAUqB,GAAkBC,EACnC3B,EAASgB,EAAO,KAAK,WAAW,QAAQA,CAAI,EAAII,EAAQK,CAAM,EACpE,GAAIf,EAAM,OAAOO,EAAKjB,EAAQ,GAAIU,CAAK,OAAO,EAE9C,IAAMmB,EAAOD,EAAU,KAAK,WAAW,QAAQA,CAAO,EAAIR,EAAQK,CAAM,EAExE,OAAOR,EAAKjB,EAAQ8B,GAASD,EAAMJ,CAAM,EAAE,QAAQ,iBAAkB,SAAS,CAAC,CACnF,CAkBQ,eAAezB,EAAgBG,EAAoE,CACvG,IAAMK,EAAU,IAAI,IAAY,CAAER,CAAO,CAAC,EACpC+B,EAA4C,CAAC,EAC7CpB,EAAU,CAAE,GAAGR,EAAM,mBAAoB,EAE/C,KAAOQ,EAAQ,OAAS,GAAG,CACvB,IAAMC,EAAaD,EAAQ,IAAI,EAC/B,GAAIH,EAAQ,IAAII,CAAU,EAAG,SAC7BJ,EAAQ,IAAII,CAAU,EAEtB,IAAMM,EAAO,KAAK,MAAMN,CAAU,EAClCmB,EAAQ,KAAKb,CAAI,EAEjB,QAAWc,KAAUd,EAAK,oBACjBV,EAAQ,IAAIwB,CAAM,GAAGrB,EAAQ,KAAKqB,CAAM,CACrD,CAEA,OAAAD,EAAQ,KAAK5B,CAAK,EAEX4B,CACX,CAoBQ,eAAe/B,EAAgBG,EAA0D,CAC7F,IAAM8B,EAAU,IAAI,IACdC,EAAa,IAAI,IACjB1B,EAAU,IAAI,IAAY,CAAER,CAAO,CAAC,EACpCW,EAAU,CAAER,CAAM,EAExB,KAAOQ,EAAQ,OAAS,GAAG,CACvB,IAAMO,EAAOP,EAAQ,IAAI,EACzB,QAAWwB,KAAWjB,EAAK,eAAe,QAASe,EAAQ,IAAI,KAAK,OAAOE,CAAO,CAAC,EAEnF,OAAW,CAAEC,EAAQC,CAAS,IAAK,OAAO,QAAQnB,EAAK,cAAc,EAAG,CAChEmB,EAAS,MAAMH,EAAW,IAAI,kBAAmBE,CAAO,IAAI,EAC5DC,EAAS,OAAO,QAChBH,EAAW,IAAI,YAAaG,EAAS,MAAM,IAAIF,GAAW,KAAK,OAAOA,CAAO,CAAC,EAAE,KAAK,IAAI,CAAE,YAAaC,CAAO,IAAI,EAEvH,QAAW1B,KAAQ2B,EAAS,YAAc,CAAC,EAAGH,EAAW,IAAI,eAAgBxB,CAAK,UAAW0B,CAAO,IAAI,CAC5G,CAEA,QAAWE,KAAQpB,EAAK,eAAe,KAC/BV,EAAQ,IAAI8B,CAAI,IACpB9B,EAAQ,IAAI8B,CAAI,EAChB3B,EAAQ,KAAK,KAAK,MAAM2B,CAAI,CAAC,EAErC,CAEA,MAAO,CAAE,QAAAL,EAAS,WAAAC,CAAW,CACjC,CAgBQ,aAAaH,EAA+E,CAChG,IAAMQ,EAAS,IAAI,IAEnB,QAAWrB,KAAQa,EACf,OAAW,CAAEK,EAAQC,CAAS,IAAK,OAAO,QAAQnB,EAAK,cAAc,EAAG,CACpE,IAAIf,EAAQoC,EAAO,IAAIH,CAAM,EACxBjC,GAAOoC,EAAO,IAAIH,EAAQjC,EAAQ,CAAE,KAAM,GAAO,MAAO,IAAI,IAAO,WAAY,IAAI,GAAM,CAAC,EAE3FkC,EAAS,OAAMlC,EAAM,KAAO,IAChCA,EAAM,UAAYkC,EAAS,QAC3B,QAAW3B,KAAQ2B,EAAS,YAAc,CAAC,EAAGlC,EAAM,WAAW,IAAIO,CAAI,EACvE,QAAWyB,KAAWE,EAAS,OAAS,CAAC,EAAGlC,EAAM,MAAM,IAAI,KAAK,OAAOgC,CAAO,CAAC,CACpF,CAGJ,OAAOI,CACX,CAgBQ,cAAcA,EAA2D,CAC7E,IAAML,EAA4B,CAAC,EAEnC,OAAW,CAAEE,EAAQjC,CAAM,IAAKoC,EAAQ,CAChCpC,EAAM,MAAM+B,EAAW,KAAK,WAAYE,CAAO,IAAI,EACvD,QAAW1B,KAAQP,EAAM,WAAY+B,EAAW,KAAK,eAAgBxB,CAAK,UAAW0B,CAAO,IAAI,EAEhG,IAAMI,EAAyB,CAAC,EAC5BrC,EAAM,SAASqC,EAAQ,KAAKrC,EAAM,OAAO,EACzCA,EAAM,MAAM,KAAO,GAAGqC,EAAQ,KAAK,KAAM,CAAE,GAAGrC,EAAM,KAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAE,IAAI,EAClFqC,EAAQ,OAAS,GAAGN,EAAW,KAAK,UAAWM,EAAQ,KAAK,IAAI,CAAE,UAAWJ,CAAO,IAAI,CAChG,CAEA,OAAOF,CACX,CAmBQ,OAAOH,EAA2CU,EAAyC,CAC/F,IAAMC,EAAuB,CAAEC,CAAwB,EACjDC,EAAU,KAAK,cAAc,KAAK,aAAab,CAAO,CAAC,EACzDa,EAAQ,OAAS,GAAGF,EAAM,KAAK,GAAGE,EAAS,EAAE,EAEjD,QAAW1B,KAAQa,EAAS,CACxB,IAAMc,EAAU3B,EAAK,QAAQ,KAAK,EAC9B2B,GAASH,EAAM,KAAKG,EAAS,EAAE,CACvC,CAEA,OAAIJ,EAAQ,QAAQ,KAAO,GAAGC,EAAM,KAAK;AAAA,GAAgB,CAAE,GAAGD,EAAQ,OAAQ,EAAE,KAAK,EAAE,KAAK;AAAA,EAAO,CAAE;AAAA,GAAM,EAC3GC,EAAM,KAAK,GAAGD,EAAQ,UAAU,EAC5BA,EAAQ,QAAQ,KAAO,GAAKA,EAAQ,WAAW,KAAO,GAAGC,EAAM,KAAK,YAAY,EAE7E,GAAIA,EAAM,KAAK;AAAA,CAAI,CAAE;AAAA,CAChC,CAYQ,OAAOP,EAAwC,CACnD,OAAOA,EAAQ,MAAQ,GAAIA,EAAQ,IAAK,OAAQA,EAAQ,KAAM,GAAKA,EAAQ,IAC/E,CAqBQ,MAAMnC,EAAgByB,EAAgBqB,EAA4C,CACtF,IAAMC,EAAcC,GAAwBhD,EAAQyB,EAAQ,CAAE,cAAe,EAAK,CAAC,EAAE,KAC/EwB,EAAiC,CACnC,MAAO,CAAC,EACR,OAAAjD,EACA,OAAQkD,GAAUlD,EAAQ+C,EAAa,CAAE,WAAY,QAAS,CAAC,EAC/D,QAASA,EACT,YAAa,CAAC,EACd,eAAgB,OAAO,OAAO,IAAI,EAClC,eAAgB,OAAO,OAAO,IAAI,EAClC,eAAgB,CAAE,KAAM,IAAI,IAAO,QAAS,CAAC,EAAG,UAAW,OAAO,OAAO,IAAI,CAAE,EAC/E,oBAAqB,IAAI,GAC7B,EAEMI,EAAsB,CAAC,EACvB,CAAE,KAAAC,CAAK,EAAIH,EAAQ,OAAO,QAEhC,QAAWI,KAAaD,EAChB,KAAK,MAAMC,EAAWJ,CAAO,GAAGE,EAAK,KAAKE,EAAU,KAAK,EAEjE,YAAK,cAAcJ,EAASG,EAAMD,CAAI,EAE/B,CACH,QAAAL,EACA,QAASQ,EAAWP,EAAaE,EAAQ,WAAW,EACpD,YAAaK,EAAWP,EAAaE,EAAQ,KAAK,EAClD,eAAgBA,EAAQ,eACxB,eAAgBA,EAAQ,eACxB,eAAgBA,EAAQ,eACxB,oBAAqBA,EAAQ,mBACjC,CACJ,CAkBQ,MAAMI,EAAkCJ,EAAyC,CACrF,OAAQI,EAAU,KAAM,CACpB,IAAK,oBACD,YAAK,YAAYA,EAAWJ,CAAO,EAE5B,GAEX,IAAK,uBACD,YAAK,gBAAgBI,EAAWJ,CAAO,EAEhC,GAEX,IAAK,yBACD,OAAO,KAAK,iBAAiBI,EAAWJ,CAAO,EAEnD,IAAK,2BACD,OAAO,KAAK,mBAAmBI,EAAWJ,CAAO,EAErD,IAAK,4BACD,OAAO,KAAK,kBAAkBI,EAAWJ,CAAO,EAEpD,IAAK,qBACL,IAAK,+BACD,OAAAM,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EAEnD,GAEX,QACI,MAAO,EACf,CACJ,CAiBQ,YAAYI,EAA8BJ,EAAsC,CAEpF,GADAM,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EACtD,KAAK,KAAKI,EAAU,OAAQJ,CAAO,EAAG,OAE1C,IAAMb,EAASa,EAAQ,eAAeI,EAAU,OAAO,KAAK,IAAM,CAAC,EACnE,GAAIA,EAAU,WAAW,OAAS,EAAG,CACjCjB,EAAO,KAAO,GAEd,MACJ,CAEA,QAAWjC,KAASkD,EAAU,WAC1B,OAAQlD,EAAM,KAAM,CAChB,IAAK,yBACDiC,EAAO,UAAYjC,EAAM,MAAM,KAC/B,MAEJ,IAAK,4BACAiC,EAAO,aAAe,CAAC,GAAG,KAAKjC,EAAM,MAAM,IAAI,EAChD,MAEJ,SACKiC,EAAO,QAAU,CAAC,GAAG,KAAK,KAAK,QAAQ,KAAK,OAAOjC,EAAM,QAAQ,EAAGA,EAAM,MAAM,IAAI,CAAC,CAC9F,CAER,CAmBQ,kBAAkBkD,EAAsCJ,EAAyC,CACrG,GAAM,CAAE,gBAAAO,CAAgB,EAAIH,EAC5B,GAAIG,EAAgB,OAAS,4BAA6B,MAAO,GAEjED,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EAC1D,IAAMxB,EAAS+B,EAAgB,WAE/B,OAAK,KAAK,KAAK/B,EAAQwB,CAAO,KACxBA,EAAQ,eAAexB,EAAO,KAAK,IAAM,CAAC,GAAG,aAAe,CAAC,GAAG,KAAK4B,EAAU,GAAG,IAAI,EAErF,EACX,CAoBQ,iBAAiBA,EAAmCJ,EAAyC,CACjG,GAAM,CAAE,QAAAhB,CAAQ,EAAIgB,EAAQ,eAE5B,GAAII,EAAU,YACV,YAAK,gBAAgBA,EAAU,YAAapB,CAAO,EACnDgB,EAAQ,YAAY,KAAK,CAAE,MAAOI,EAAU,MAAO,IAAKA,EAAU,YAAY,KAAM,CAAC,EAE9E,GAGXE,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EAC1D,IAAMQ,EAAQJ,EAAU,QAAU,CAAC,KAAK,KAAKA,EAAU,OAAQJ,CAAO,GAC/DA,EAAQ,eAAeI,EAAU,OAAO,KAAK,IAAM,CAAC,GAAG,QAAU,CAAC,EACnEpB,EAEN,QAAW9B,KAASkD,EAAU,WAC1BI,EAAM,KAAK,KAAK,QAAQ,KAAK,OAAOtD,EAAM,KAAK,EAAG,KAAK,OAAOA,EAAM,QAAQ,CAAC,CAAC,EAElF,MAAO,EACX,CAgBQ,gBAAgBkD,EAAiCJ,EAAsC,CAC3FM,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EAE1D,IAAMjD,EAAS,KAAK,KAAKqD,EAAU,OAAQJ,CAAO,EAC5CS,EAAUL,EAAU,SAAW,KAAK,OAAOA,EAAU,QAAQ,EAAI,KAEvE,GAAIrD,EAAQ,CACJ0D,EAAST,EAAQ,eAAe,UAAUS,CAAO,EAAI1D,EACpDiD,EAAQ,eAAe,KAAK,IAAIjD,CAAM,EAE3C,MACJ,CAEA,IAAMoC,EAASa,EAAQ,eAAeI,EAAU,OAAO,KAAK,IAAM,CAAC,EAC/DK,GAAUtB,EAAO,aAAe,CAAC,GAAG,KAAKsB,CAAO,EAC/CtB,EAAO,KAAO,EACvB,CAoBQ,mBAAmBiB,EAAqCJ,EAAyC,CACrG,GAAM,CAAE,YAAAF,CAAY,EAAIM,EAClBM,EAAQ,KAAK,eAAeZ,CAAW,EAG7C,OAFIY,GAAOV,EAAQ,eAAe,QAAQ,KAAK,CAAE,KAAMU,EAAO,MAAO,SAAU,CAAC,EAE5EA,GAASZ,EAAY,OAAS,cAC9BE,EAAQ,YAAY,KAAK,CAAE,MAAOI,EAAU,MAAO,IAAKN,EAAY,MAAO,KAAM,UAAW,CAAC,EAEtF,KAGXQ,EAAWF,EAAWJ,EAAQ,QAASA,EAAQ,WAAW,EAEnD,GACX,CAuBQ,cAAcA,EAAgCG,EAAoCD,EAA2B,CACjH,GAAM,CAAE,QAAAN,EAAS,YAAAe,CAAY,EAAIX,EAC7BY,EAAQ,EACRtC,EAAQ,EAEZ,QAAWuC,KAAWb,EAAQ,OAAO,SACjC,GAAI,EAAAa,EAAQ,OAAS,SAAWA,EAAQ,MAAM,WAAW,CAAC,IAAM,IAEhE,MAAOD,EAAQT,EAAK,QAAUA,EAAKS,CAAK,EAAE,KAAOC,EAAQ,OAAOD,IAChE,GAAI,EAAAA,EAAQT,EAAK,QAAUA,EAAKS,CAAK,EAAE,MAAQC,EAAQ,OAEvD,MAAOvC,EAAQ4B,EAAK,QAAUA,EAAK5B,CAAK,EAAIuC,EAAQ,KAAKvC,IACrDA,EAAQ4B,EAAK,QAAU,KAAK,MAAMN,EAASiB,EAAQ,IAAKX,EAAK5B,CAAK,CAAC,GAEvEgC,EAAWO,EAASjB,EAASe,CAAW,GAEhD,CAqBQ,KAAKnC,EAAuBwB,EAA+C,CAC/E,IAAMc,EAAW,KAAK,GAAG,QAAQtC,EAAO,MAAOwB,EAAQ,MAAM,EAC7D,GAAI,CAACc,GAAYA,EAAS,wBAAyB,OAAO,KAE1D,GAAM,CAAE,UAAAC,EAAW,iBAAAC,EAAkB,iBAAAC,CAAiB,EAAIH,EACpD/D,EAAS,KAAK,WAAW,QAAQkE,CAAgB,EAEvD,OAAAjB,EAAQ,oBAAoB,IAAIjD,CAAM,EACtCiD,EAAQ,MAAM,KAAK,CACf,IAAKxB,EAAO,IACZ,MAAOA,EAAO,MACd,KAAM,IAAKuC,EAAYC,EAAiB,MAAM,EAAG,CAACD,EAAU,MAAM,EAAIC,CAAiB,QAC3F,CAAC,EAEMjE,CACX,CAgBQ,gBAAgB+C,EAA0BtC,EAA2C,CACzF,GAAIsC,EAAY,OAAS,sBAAuB,CAC5C,QAAW5C,KAAS4C,EAAY,aACxB5C,EAAM,GAAG,OAAS,cAAcM,EAAM,KAAK,CAAE,KAAMN,EAAM,GAAG,IAAK,CAAC,EAE1E,MACJ,CAEI,OAAQ4C,GAAeA,EAAY,IAAM,SAAUA,EAAY,IAAItC,EAAM,KAAK,CAAE,KAAMsC,EAAY,GAAG,IAAK,CAAC,CACnH,CAWQ,eAAeA,EAA+D,CAClF,OAAIA,EAAY,OAAS,aAAqBA,EAAY,KAEnD,OAAQA,EAAcA,EAAY,IAAI,KAAO,MACxD,CAWQ,OAAOrC,EAAgC,CAC3C,MAAO,SAAUA,EAAOA,EAAK,KAAO,KAAK,UAAUA,EAAK,KAAK,CACjE,CAaQ,QAAQA,EAAcyD,EAAsC,CAChE,OAAOzD,IAASyD,EAAQ,CAAE,KAAAzD,CAAK,EAAI,CAAE,KAAAA,EAAM,MAAAyD,CAAM,CACrD,CAiBQ,MAAMtB,EAAiBuB,EAAeC,EAAsB,CAChE,QAAS9C,EAAQ6C,EAAO7C,EAAQ8C,EAAK9C,IAAS,CAC1C,IAAM+C,EAAOzB,EAAQ,WAAWtB,CAAK,EACrC,GAAI+C,IAAS,IAAcA,IAAS,GAAYA,IAAS,IAAWA,IAAS,GAAS,MAAO,EACjG,CAEA,MAAO,EACX,CACJ,EGx9BA,OAAOC,MAAQ,aACf,OAAS,YAAAC,OAAgB,qBACzB,OAAS,UAAAC,OAAc,wBA8BhB,IAAMC,EAAN,KAA4D,CA+E/D,YAAoBC,EAA2B,CAA3B,YAAAA,EAChB,KAAK,OAAO,CAChB,CAFoB,OA/DX,WAAaC,GAAOC,CAAU,EActB,aAAe,IAAI,IAanB,WAAa,IAAI,IAc1B,QA6CR,IAAI,SAAuB,CACvB,OAAO,KAAK,YAChB,CAoBA,IAAI,kBAAkD,CAClD,OAAQC,GAA8B,KAAK,WAAWA,EAAK,QAAQ,CACvE,CAqBA,IAAI,QAAQH,EAA2B,CACnC,KAAK,OAASA,EACd,KAAK,OAAO,CAChB,CAoBA,cAAqB,CACjB,KAAK,aAAa,MAAM,EACxB,KAAK,aAAa,KAAK,OAAO,SAAS,CAC3C,CAuBA,QAAe,CACX,KAAK,QAAU,KAAK,eAAe,KAAK,OAAO,KAAK,OAAO,EAC3D,KAAK,WAAW,MAAM,EAEtB,KAAK,aAAa,CACtB,CAuBA,QAAQI,EAAqC,CACzC,OAAO,KAAK,WAAW,QAAQ,KAAK,MAAMA,CAAI,CAAC,CACnD,CAqBA,aAAaC,EAAqC,KAAK,aAAoB,CACvE,QAAWD,KAAQC,EACX,KAAK,WAAWD,CAAI,GACxB,KAAK,QAAQA,CAAI,CAEzB,CAeA,wBAA0C,CACtC,OAAO,KAAK,OAAO,OACvB,CAmBA,WAAWA,EAAuB,CAC9B,OAAOE,EAAG,IAAI,WAAWF,CAAI,CACjC,CAsBA,SAASA,EAAcG,EAA+C,CAClE,OAAO,KAAK,WAAW,MAAMH,EAAMG,CAAQ,EAAE,UAAU,IAC3D,CAoBA,cAAcH,EAAcI,EAA4BC,EAAyBC,EAAyBC,EAA+B,CACrI,OAAOL,EAAG,IAAI,cAAcF,EAAMI,EAAYC,EAASC,EAASC,CAAK,CACzE,CAgBA,eAAeP,EAA6B,CACxC,OAAOE,EAAG,IAAI,eAAeF,CAAI,CACrC,CAgBA,gBAAgBA,EAAuB,CACnC,OAAOE,EAAG,IAAI,gBAAgBF,CAAI,CACtC,CAeA,qBAA8B,CAC1B,OAAOE,EAAG,IAAI,oBAAoB,CACtC,CAoBA,oBAAoC,CAChC,MAAO,CAAE,GAAG,KAAK,YAAa,CAClC,CAgBA,sBAAsBM,EAAkC,CACpD,OAAON,EAAG,sBAAsBM,CAAO,CAC3C,CAwBA,iBAAiBR,EAAsB,CACnC,OAAO,KAAK,WAAW,MAAM,KAAK,MAAMA,CAAI,CAAC,EAAE,QAAQ,SAAS,CACpE,CAsBA,kBAAkBA,EAA2C,CACzD,OAAO,KAAK,WAAW,MAAMA,CAAI,EAAE,QACvC,CAqBA,SAASA,EAAsB,CAC3B,OAAO,KAAK,WAAW,QAAQA,CAAI,CACvC,CAgBQ,eAAeS,EAAkD,CACrE,OAAOA,GAASA,EAAM,OAAS,EAAIC,EAAcD,CAAK,EAAI,IAAe,EAC7E,CAgBQ,WAAWT,EAAuB,CACtC,IAAMW,EAAS,KAAK,WAAW,QAAQX,CAAI,EACvCY,EAAW,KAAK,WAAW,IAAID,CAAM,EACzC,OAAIC,IAAa,QAAW,KAAK,WAAW,IACxCD,EAAQC,EAAW,KAAK,QAAQC,GAAS,QAAQ,IAAI,EAAGF,CAAM,CAAC,CACnE,EAEOC,CACX,CAiBQ,MAAMZ,EAAsB,CAChC,IAAMW,EAAS,KAAK,WAAW,QAAQX,CAAI,EAC3C,YAAK,aAAa,IAAIW,CAAM,EAErBA,CACX,CACJ,EJziBO,IAAMG,EAAN,KAAwB,CA6J3B,YAAqBC,EAAsB,gBAAiB,CAAvC,gBAAAA,EACjB,KAAK,aAAe,KAAK,YAAY,EACrC,KAAK,oBAAsB,IAAIC,EAAoB,KAAK,YAAY,EACpE,KAAK,cAAgB,KAAK,oBAAoB,WAAW,MAAM,KAAK,UAAU,EAAE,QAChF,KAAK,gBAAkB,KAAK,sBAAsB,EAClD,KAAK,gBAAkBC,EAAG,sBACtB,KAAK,oBAAqBA,EAAG,uBAAuB,EAAI,CAC5D,EAEA,KAAK,YAAc,IAAIC,EAAiB,IAAI,CAChD,CAVqB,WA7IZ,gBAiBA,oBA4BQ,iBAAmB,IAAI,IAavB,YAAyD,CACtE,WAAYD,EAAG,IAAI,WACnB,SAAU,CAACE,EAAcC,IACrB,KAAK,oBAAoB,SAASD,EAAMC,CAAQ,EACpD,oBAAqB,IAAcH,EAAG,IAAI,oBAAoB,EAC9D,0BAA2B,IAAeA,EAAG,IAAI,yBACrD,EAYiB,YAST,aAaA,cASA,gBAWA,QA0ER,OAAO,OAAOI,EAAiB,GAAsB,CACjD,IAAMC,EAA0B,CAAC,EACjC,OAAW,CAAEC,EAAMC,CAAM,IAAKV,EAAkB,MACxCU,EAAM,SAAS,QAAQH,CAAK,GAAGC,EAAS,KAAKC,CAAI,EAGzD,OAAOD,CACX,CAoBA,IAAI,QAA4B,CAC5B,OAAO,KAAK,YAChB,CAuCA,MAAMG,EAA0D,CAC5D,IAAMC,EAAU,KAAK,gBAAgB,WAAW,EAChD,GAAI,CAACA,EAAS,MAAO,CAAC,EAEtB,IAAMC,EAAS,KAAK,oBAAoB,iBAClCC,EAAQT,GACPA,EAAK,SAAS,SAAS,cAAc,EAAU,GAE3CQ,EAAOR,CAAI,EAGlBU,EAEJ,IADA,KAAK,QAAUZ,EAAG,+CAA+CS,EAAS,KAAK,YAAa,KAAK,OAAO,EACjGG,EAAW,KAAK,QAAQ,yCAAyC,OAAWD,CAAI,GACnF,GAAI,aAAcC,EAAS,SAAU,CACjC,IAAMV,EAAOU,EAAS,SACtB,KAAK,iBAAiB,IAAIV,EAAK,SAAU,CACrC,GAAGU,EAAS,OACZ,GAAG,KAAK,QAAS,wBAAwBV,CAAI,EAC7C,GAAG,KAAK,gBAAgB,yBAAyBA,EAAK,QAAQ,CAClE,EAAE,IAAIW,GAAc,KAAK,iBAAiBA,CAAU,CAAC,CAAC,CAC1D,CAGJ,OAAO,KAAK,qBAAqBJ,EAASD,GAAa,KAAK,iBAAiB,KAAK,CAAC,CACvF,CA2BA,MAAM,KAAKM,EAAqCC,EAAyC,CACrF,OAAAA,IAAW,KAAK,OAAO,QAAQ,QAAU,OAElC,KAAK,YAAY,KAAKD,EAAaC,CAAM,CACpD,CAyBA,MAAM,WAAWD,EAAqCC,EAAyC,CAC3F,OAAAA,IAAW,KAAK,OAAO,QAAQ,QAAU,OAElC,KAAK,YAAY,WAAWD,EAAaC,CAAM,CAC1D,CAqBA,WAAWC,EAA4B,CACnC,KAAK,oBAAoB,aAAaA,CAAK,CAC/C,CA8BA,QAAQC,EAAmBC,EAA8D,CACrF,IAAMC,EAAYD,EAAiB,KAAK,oBAAoB,WAAW,QAAQE,GAAQF,CAAc,CAAC,EAAI,QAAQ,IAAI,EAEhHG,EADW,KAAK,gBAAgB,6BAA6BF,CAAS,EACpD,IAAIF,EAAW,MAAS,GAAG,eACnD,GAAGI,EAAQ,OAAOA,EAElB,IAAMC,EAAmCtB,EAAG,kBACxCiB,EAAWC,GAAkB,GAAI,KAAK,aAAa,QAAS,KAAK,oBAAqB,KAAK,eAC/F,EAAE,eAEF,GAAII,EAAQ,CACR,IAAMhB,EAAOiB,GAASJ,EAAWG,EAAO,gBAAgB,EAExDA,EAAO,UAAYH,EACnBG,EAAO,iBAAmBhB,EAAK,WAAW,GAAG,EAAIA,EAAO,KAAMA,CAAK,EACvE,CAEA,OAAOgB,CACX,CAuBA,SAAgB,CACZ,IAAMf,EAAQV,EAAkB,MAAM,IAAI,KAAK,UAAU,EACpDU,IAELA,EAAM,WACF,EAAAA,EAAM,SAAW,KAErB,KAAK,gBAAgB,QAAQ,EAC7BV,EAAkB,MAAM,OAAO,KAAK,UAAU,GAClD,CAoBA,CAAC,OAAO,SAAW,OAAO,IAAI,gBAAgB,CAAC,GAAU,CACrD,KAAK,QAAQ,CACjB,CAmBA,OAAe,QAAQS,EAAe,gBAAoC,CACtE,IAAMkB,EAAMC,GAAUnB,CAAI,EACpBC,EAAQV,EAAkB,MAAM,IAAI2B,CAAG,EAE7C,GAAIjB,EACA,OAAAA,EAAM,WAECA,EAAM,SAGjB,IAAMmB,EAAW,IAAI7B,EAAkB2B,CAAG,EAC1C,OAAA3B,EAAkB,MAAM,IAAI2B,EAAK,CAAE,SAAAE,EAAU,SAAU,CAAE,CAAC,EAEnDA,CACX,CAuBQ,QAAQtB,EAAiB,GAAgB,CAC7C,GAAM,CAAE,QAAAuB,CAAQ,EAAI,KAAK,oBAAoB,WAAW,MAAM,KAAK,UAAU,EAC7E,MAAI,CAACvB,GAASuB,IAAY,KAAK,cAAsB,IAErD,KAAK,cAAgBA,EACrB,KAAK,aAAe,KAAK,YAAY,EACrC,KAAK,oBAAoB,QAAU,KAAK,aACxC,KAAK,gBAAkB,KAAK,sBAAsB,EAClD,KAAK,YAAY,MAAM,EACvB,KAAK,iBAAiB,MAAM,EAC5B,KAAK,QAAU,OAER,GACX,CAeQ,uBAA+C,CACnD,OAAO3B,EAAG,4BACNA,EAAG,IAAI,oBAAoB,EAC3BM,GAAQ,KAAK,oBAAoB,SAASA,CAAI,EAC9C,KAAK,aAAa,OACtB,CACJ,CAuBQ,qBAAqBG,EAAkBD,EAAyD,CACpG,IAAMQ,EAAQ,KAAK,oBAAoB,WACjCM,EAAqC,CAAC,EAE5C,QAAWM,KAAQpB,EAAW,CAC1B,IAAMF,EAAOU,EAAM,QAAQY,CAAI,EACzBC,EAAc,KAAK,iBAAiB,IAAIvB,CAAI,EAE7CuB,IACDpB,EAAQ,cAAcH,CAAI,EAAGgB,EAAO,KAAK,GAAGO,CAAW,EACtD,KAAK,iBAAiB,OAAOvB,CAAI,EAC1C,CAEA,OAAOgB,CACX,CAiBQ,iBAAiBT,EAA6C,CAClE,IAAMS,EAA8B,CAChC,QAAStB,EAAG,6BAA6Ba,EAAW,YAAa;AAAA,CAAI,EACrE,SAAUA,EAAW,QACzB,EAEA,GAAIA,EAAW,MAAQA,EAAW,QAAU,OAAW,CACnD,GAAM,CAAE,KAAAiB,EAAM,UAAAC,CAAU,EAAIlB,EAAW,KAAK,8BAA8BA,EAAW,KAAK,EAC1FS,EAAO,KAAOT,EAAW,KAAK,SAC9BS,EAAO,KAAOQ,EAAO,EACrBR,EAAO,OAASS,EAAY,EAC5BT,EAAO,KAAOT,EAAW,IAC7B,CAEA,OAAOS,CACX,CAmBQ,aAAiC,CACrC,IAAIU,EAAShC,EAAG,iCACZ,KAAK,WACL,CACI,UAAW,GACX,aAAc,GACd,cAAe,GACf,eAAgB,GAChB,oBAAqB,EACzB,EACA,CACI,GAAGA,EAAG,IACN,oCAAqC,IAAM,CAAC,CAChD,CACJ,EAEA,OAAKgC,IACDA,EAAS,CACL,QAAS,CACL,OAAQ,GACR,OAAQhC,EAAG,aAAa,OACxB,OAAQA,EAAG,WAAW,SACtB,UAAW,GACX,aAAc,GACd,cAAe,GACf,eAAgB,GAChB,oBAAqB,GACrB,iBAAkBA,EAAG,qBAAqB,QAC9C,EACA,OAAQ,CAAC,EACT,UAAW,CAAC,EACZ,kBAAmB,MACvB,GAGJgC,EAAO,QAAU,CACb,GAAGA,EAAO,QACV,OAAQ,GACR,QAASA,EAAO,SAAS,SAAW,QAAQ,IAAI,EAChD,gBAAiB,GACjB,0BAA2B,EAC/B,EAEOA,CACX,CACJ,EAvpBIC,EA9CSpC,EA8Ce,QAAQ,IAAI,KA9C3BA,EAANqC,EAAA,CALNC,GAAW,CACR,QAAQ7B,EAAkC,CACtC,OAAOT,EAAkB,QAAQS,CAAI,CACzC,CACJ,CAAC,GACYT","names":["http","https","extname","readFileSync","server_default","join","inject","Subject","readdir","stat","readFile","cwd","readFileSync","readFileSync","statSync","resolve","Injectable","FilesModel","path","encoding","target","stats","paths","pathList","resolve","info","entry","readFileSync","oldText","newText","oldLength","newLength","max","prefix","suffix","text","start","end","previous","statSync","__decorateClass","Injectable","inject","Injectable","normalize","SourceService","FRAMEWORK_PATH_REGEX","EMPTY_MAPPINGS_REGEX","FrameworkService","normalize","cwd","path","inject","FilesModel","position","source","force","key","readFileSync","error","SourceService","__publicField","__decorateClass","Injectable","ServerModule","config","dir","FrameworkService","Subject","inject","resolve","reject","err","address","req","res","options","readFileSync","join","defaultHandler","error","ext","requestPath","fullPath","stats","stat","fileList","readdir","file","extname","activePath","segments","path","htmlResult","server_default","contentType","data","readFile","Injectable","Subject","join","RegexCloser","lit","char","at","glob","index","isGlobstar","group","body","classEnd","openIndex","scan","lead","findClose","cursor","depth","braceClose","comma","compileClass","end","out","segmentEnd","from","compileFragment","isSegmentStart","alt","options","dot","wasStart","guard","DS","GLOBSTAR","nChar","RegexCloser","close","inner","tailEnd","tail","root","src","next","globToRegExp","createMatcher","globs","include","exclude","neg","path","r","resolve","join","relative","watch","realpathSync","readdirSync","lstatSync","statSync","WatchService","Subject","base","options","resolve","createMatcher","observerOrNext","error","complete","unsubscribe","watcher","batch","path","event","relativePath","relative","link","lstatSync","stats","statSync","type","ignore","recursive","watch","realpathSync","filename","target","join","seg","root","stack","dir","entries","readdirSync","entry","full","__decorateClass","Injectable","inject","resolveError","xterm","parseErrorStack","formatErrorCode","highlightCode","getSource","fileName","mapped","inject","FrameworkService","snapshot","FilesModel","code","lines","line","column","_bias","options","after","before","startLine","endLine","getErrorStack","raw","getErrorMetadata","verbose","framework","parsed","resolved","resolveError","path","frame","xterm","formatStack","metadata","name","message","notes","parts","note","stack","ts","Injectable","normalize","relative","dirname","existsSync","parseSync","inject","mkdir","writeFile","isolatedDeclarationSync","join","dirname","relative","removeNode","node","content","edits","cursor","code","applyEdits","left","right","parts","index","i","edit","HeaderDeclarationBundle","DeclarationModel","ts","inject","FilesModel","path","target","file","cached","entry","entryPoints","outdir","outputs","contents","visited","names","name","pending","dependency","output","existsSync","options","base","join","node","directories","dirname","directory","mkdir","index","writeFile","source","declarationDir","outDir","rootDir","root","relative","closure","nested","exports","statements","binding","module","bindings","star","merged","clauses","surface","parts","HeaderDeclarationBundle","imports","content","version","declaration","isolatedDeclarationSync","context","parseSync","kept","body","statement","applyEdits","removeNode","moduleReference","named","exposed","local","bundleEdits","inner","comment","resolved","extension","relativeFileName","resolvedFileName","alias","start","end","code","ts","relative","inject","LanguageHostService","config","inject","FilesModel","file","path","paths","ts","encoding","extensions","exclude","include","depth","options","globs","createMatcher","target","excluded","relative","TypescriptService","configPath","LanguageHostService","ts","DeclarationModel","file","encoding","force","reloaded","path","entry","reachable","program","ignore","skip","affected","diagnostic","entryPoints","outdir","files","specifier","containingFile","container","dirname","cached","result","relative","key","normalize","instance","version","name","diagnostics","line","character","config","__publicField","__decorateClass","Injectable"]}
1
+ {"version":3,"sources":["src/modules/server/server.module.ts","src/modules/server/html/server.html","src/services/framework.service.ts","src/models/files.model.ts","src/services/watch.service.ts","src/components/glob.component.ts","src/constants/glob.constant.ts","src/providers/stack.provider.ts","src/modules/typescript/services/typescript.service.ts","src/modules/typescript/models/declaration.model.ts","src/components/transformer.component.ts","src/modules/typescript/constants/typescript.constant.ts","src/modules/typescript/services/host.service.ts"],"sourceRoot":"https://github.com/remotex-labs/xBuild/tree/v3.0.2/","sourcesContent":["/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport type { ServerAddressInterface, ServerConfigurationInterface, ServerEventsType } from '@server/interfaces/server.interface';\n\n/**\n * Imports\n */\n\nimport * as http from 'http';\nimport * as https from 'https';\nimport { extname } from 'path';\nimport { readFileSync } from 'fs';\nimport html from './html/server.html';\nimport { join } from '@remotex-labs/xmap';\nimport { inject } from '@remotex-labs/xinject';\nimport { Subject } from '@remotex-labs/xobservable';\nimport { readdir, stat, readFile } from 'fs/promises';\nimport { FrameworkService } from '@services/framework.service';\n\n/**\n * Serves one directory over HTTP or HTTPS, files and listings alike.\n *\n * @remarks\n * Meant for looking at build output while developing:\n * a request maps to a path under the root, a file is sent with a content type guessed from its extension,\n * and a directory is rendered as a browsable listing.\n * A configuration can take a request over before any of that happens,\n * which is the hook to reach for when the output needs an API beside it or a single-page fallback.\n * Nothing here writes to a terminal: what it does is reported on a stream, so a run decides what to say about it.\n * Constructed rather than injected, so a build can run several of them over different roots at once.\n *\n * @example\n * ```ts\n * const server = new ServerModule({ port: 0, verbose: true }, 'dist');\n *\n * await server.start(); // resolves once listening, after onStart has run\n * server.config.port; // 54321 - the port the system picked, written back\n * await server.stop();\n * ```\n *\n * @see ServerConfigurationInterface\n * @since 2.0.0\n */\n\nexport class ServerModule {\n /**\n * Node server currently listening, absent until {@link start} and again after {@link stop}.\n *\n * @remarks\n * Holds either an HTTP or an HTTPS server,\n * since the HTTPS type extends the HTTP one and the two are interchangeable here.\n * Its presence is what {@link stop} treats as whether anything is running.\n *\n * @since 2.0.0\n */\n\n private server?: http.Server;\n\n /**\n * The stream everything this server does is reported on.\n *\n * @remarks\n * The server says what happened and writes none of it,\n * so a run decides for itself what reaches a terminal, and one that wants none of it subscribes to nothing.\n * Kept private and reached through {@link pipe} and {@link subscribe},\n * which is what keeps a reader from reporting an event of its own.\n *\n * @see ServerEventsType\n * @since 3.0.0\n */\n\n private readonly events$ = new Subject<ServerEventsType>();\n\n /**\n * Absolute directory every request is resolved inside.\n *\n * @remarks\n * Resolved once in the constructor, so a later change to the working directory cannot move what is being served.\n *\n * @since 2.0.0\n */\n\n private readonly rootDir: string;\n\n /**\n * Framework service, consulted for the directory the bundled certificates ship in.\n *\n * @remarks\n * Only reached when HTTPS is started without a key and certificate of its own.\n *\n * @see FrameworkService\n * @since 2.0.0\n */\n\n private readonly framework = inject(FrameworkService);\n\n /**\n * Creates a server over one directory.\n *\n * @param config - How to listen and what to do with requests\n * @param dir - Directory to serve, resolved to an absolute path immediately\n *\n * @remarks\n * The configuration is kept by reference rather than copied: the host and port defaults land on it here,\n * and the port the system assigns lands on it once listening.\n * The object the caller passed is therefore also how the caller learns what was bound.\n * A port of `0`, which is also the default, leaves the choice to the operating system.\n *\n * @example\n * ```ts\n * const config = { port: 8080, https: true, onRequest: (req, res, next) => next() };\n * const server = new ServerModule(config, './public');\n *\n * config.host; // 'localhost' - defaulted here, on the caller's own object\n * ```\n *\n * @see ServerConfigurationInterface\n * @since 2.0.0\n */\n\n constructor(readonly config: ServerConfigurationInterface, dir: string) {\n this.rootDir = FrameworkService.resolve(dir);\n this.config.port ||= 0;\n this.config.host ||= 'localhost';\n }\n\n /**\n * The event stream's `pipe`, bound to the stream.\n *\n * @remarks\n * Hands out the operator chain without handing out the subject,\n * so a reader composes on what the server reports and cannot report anything itself.\n *\n * @example\n * ```ts\n * server.pipe(filter(event => event.type === 'request')).subscribe(report);\n * ```\n *\n * @see subscribe\n * @since 3.0.0\n */\n\n get pipe(): typeof this.events$.pipe {\n return this.events$.pipe.bind(this.events$);\n }\n\n /**\n * The event stream's `subscribe`, bound to the stream.\n *\n * @remarks\n * How a run learns what the server is doing, since the server itself writes nothing.\n * Answers with the handle that ends the subscription, as the stream's own `subscribe` does.\n *\n * @example\n * ```ts\n * const unsubscribe = server.subscribe(event => event.type); // 'start', then 'request'\n * unsubscribe();\n * ```\n *\n * @see pipe\n * @since 3.0.0\n */\n\n get subscribe(): typeof this.events$.subscribe {\n return this.events$.subscribe.bind(this.events$);\n }\n\n /**\n * Starts listening over HTTPS when the configuration asks for it and over HTTP otherwise.\n *\n * @returns A promise settling once the server is listening\n *\n * @remarks\n * The `onStart` hook runs from the listen callback,\n * so it has already been called - and the assigned port already written back - by the time this resolves.\n * Nothing guards against starting twice:\n * a second call replaces the reference and leaves the first server listening with no way left to close it,\n * so reach for {@link restart} rather than starting again.\n *\n * @example\n * ```ts\n * const server = new ServerModule({ port: 3000, onStart: ({ url }) => console.log(url) }, 'dist');\n * await server.start(); // logs 'http://localhost:3000'\n * ```\n *\n * @see stop\n * @see restart\n *\n * @since 2.0.0\n */\n\n async start(): Promise<void> {\n if (this.config.https)\n return await this.startHttpsServer();\n\n await this.startHttpServer();\n }\n\n /**\n * Closes the server and waits for it to finish.\n *\n * @returns A promise settling once every connection has ended\n *\n * @throws Error - Reported by Node when the server was already closed underneath\n *\n * @remarks\n * Closing refuses new connections and waits on the ones in flight,\n * so a request already in progress delays this rather than ending mid-flight.\n * Stopping when nothing is running is not an error - it reports as much and returns.\n *\n * @example\n * ```ts\n * await server.stop(); // 'Server stopped.'\n * await server.stop(); // 'No server is currently running.'\n * ```\n *\n * @see start\n * @since 2.0.0\n */\n\n async stop(): Promise<void> {\n if (!this.server) return this.events$.next({ type: 'stop', running: false });\n\n await new Promise<void>((resolve, reject) => {\n this.server!.close(err => {\n if (err) reject(err);\n else resolve();\n });\n });\n\n this.server = undefined;\n this.events$.next({ type: 'stop', running: true });\n }\n\n /**\n * Stops the server and starts it again.\n *\n * @returns A promise settling once the new server is listening\n *\n * @remarks\n * Reads the configuration afresh on the way back up, so an edit made while it was running takes effect.\n * A port left at `0` is no longer `0` by then, since the previous run wrote the assigned one back,\n * so a restart keeps the port it was given rather than asking for another.\n *\n * @example\n * ```ts\n * server.config.verbose = true;\n * await server.restart(); // 'Restarting server...' then listening again, now logging requests\n * ```\n *\n * @see stop\n * @see start\n *\n * @since 2.0.0\n */\n\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n /**\n * Writes the port the system assigned back onto the configuration.\n *\n * @remarks\n * Only a configured `0` is replaced, since `0` is the value that leaves the choice to the operating system.\n * A port asked for by number is already what was bound.\n * Called from the listen callback, before `onStart`, so the hook and every later reader see the real port.\n *\n * @since 2.0.0\n */\n\n private setActualPort(): void {\n if (this.config.port === 0) {\n const address = this.server!.address();\n if(address && typeof address === 'object' && address.port)\n this.config.port = address.port;\n }\n }\n\n /**\n * Creates and starts the plain HTTP server.\n *\n * @returns A promise settling once the server is listening\n *\n * @remarks\n * Every request goes through {@link handleRequest},\n * which is handed the default handling as a callback,\n * so a configuration hook can decide whether to run it.\n *\n * @since 2.0.0\n */\n\n private startHttpServer(): Promise<void> {\n return new Promise<void>((resolve) => {\n this.server = http.createServer((req, res) => {\n this.handleRequest(req, res, () => this.defaultResponse(req, res));\n });\n\n this.server.listen(this.config.port, this.config.host, () => {\n this.setActualPort();\n const address: ServerAddressInterface = {\n host: this.config.host!,\n port: this.config.port!,\n url: `http://${ this.config.host }:${ this.config.port }`\n };\n\n this.config.onStart?.(address);\n this.events$.next({ ...address, type: 'start' });\n resolve();\n });\n });\n }\n\n /**\n * Creates and starts the HTTPS server.\n *\n * @returns A promise settling once the server is listening\n *\n * @throws Error - Raised when a key or certificate cannot be read\n *\n * @remarks\n * A configuration naming neither key nor certificate falls back to the pair shipped with the framework,\n * so HTTPS can be switched on without producing one first.\n * That pair is self-signed, so a browser will warn about it, which is what a development server can live with.\n * Both files are read synchronously, before anything is listening,\n * so a missing one fails the start rather than the first request.\n *\n * @since 2.0.0\n */\n\n private startHttpsServer(): Promise<void> {\n return new Promise((resolve) => {\n const options = {\n key: readFileSync(this.config.key ?? join(this.framework.frameworkRoot, '..', 'certs', 'server.key')),\n cert: readFileSync(this.config.cert ?? join(this.framework.frameworkRoot, '..', 'certs', 'server.crt'))\n };\n\n this.server = https.createServer(options, (req, res) => {\n this.handleRequest(req, res, () => this.defaultResponse(req, res));\n });\n\n this.server.listen(this.config.port, this.config.host, () => {\n this.setActualPort();\n const address: ServerAddressInterface = {\n host: this.config.host!,\n port: this.config.port!,\n url: `https://${ this.config.host }:${ this.config.port }`\n };\n\n this.config.onStart?.(address);\n this.events$.next({ ...address, type: 'start' });\n resolve();\n });\n });\n }\n\n /**\n * Passes a request to the configuration's hook or to the default handling when there is none.\n *\n * @param req - Request as it arrived\n * @param res - Response to write to\n * @param defaultHandler - The static-file handling, for the hook to call or to skip\n *\n * @remarks\n * A hook that never calls the handler owns the response entirely,\n * which is what makes an API route or a single-page fallback possible.\n * Only what throws synchronously reaches the error response here:\n * the default handling is asynchronous and catches its own failures,\n * and a hook that rejects a promise of its own is beyond this.\n *\n * @see sendError\n * @since 2.0.0\n */\n\n private handleRequest(req: IncomingMessage, res: ServerResponse, defaultHandler: () => void): void {\n try {\n this.events$.next({ type: 'request', url: req.url ?? '' });\n\n if (this.config.onRequest) {\n this.config.onRequest(req, res, defaultHandler);\n } else {\n defaultHandler();\n }\n } catch (error) {\n this.sendError(res, <Error> error);\n }\n }\n\n /**\n * Maps a file extension to the content type it is served as.\n *\n * @param ext - Extension without its dot\n * @returns The matching content type, or the binary fallback for an extension not listed\n *\n * @remarks\n * Covers what a build emits rather than the web at large.\n * TypeScript is served as plain text, so a browser shows a source file instead of downloading it,\n * and an unlisted extension downloads under the binary fallback rather than under a guess.\n *\n * @since 2.0.0\n */\n\n private getContentType(ext: string): string {\n const contentTypes: Record<string, string> = {\n html: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n cjs: 'application/javascript',\n mjs: 'application/javascript',\n ts: 'text/plain',\n map: 'application/json',\n json: 'application/json',\n png: 'image/png',\n jpg: 'image/jpeg',\n gif: 'image/gif',\n txt: 'text/plain'\n };\n\n return contentTypes[ext] || 'application/octet-stream';\n }\n\n /**\n * Resolves a request to a path under the root and serves whatever is there.\n *\n * @param req - Request as it arrived\n * @param res - Response to write to\n *\n * @remarks\n * The request path is joined onto the root and the result checked for the root prefix,\n * so a path climbing out with `..` is refused with a 403.\n * The check is by prefix rather than true containment,\n * so a sibling directory whose name starts with the root's own would pass it.\n * A directory is listed and a file is sent.\n * Anything else on disk - a socket or a device - matches neither, and the request ends unanswered.\n * A path that cannot be reached at all is reported as missing,\n * and a failed `favicon.ico` is passed over in the log, since browsers ask for one unprompted on every visit.\n *\n * @see handleFile\n * @see handleDirectory\n *\n * @since 2.0.0\n */\n\n private async defaultResponse(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const requestPath = req.url === '/' ? '' : req.url?.replace(/^\\/+/, '') || '';\n const fullPath = join(this.rootDir, requestPath);\n\n if (!fullPath.startsWith(this.rootDir)) {\n res.statusCode = 403;\n res.end();\n\n return;\n }\n\n try {\n const stats = await stat(fullPath);\n\n if (stats.isDirectory()) {\n await this.handleDirectory(fullPath, requestPath, res);\n } else if (stats.isFile()) {\n await this.handleFile(fullPath, res);\n }\n } catch (error) {\n this.events$.next({ type: 'error', error: <Error> error, url: req.url });\n this.sendNotFound(res);\n }\n }\n\n /**\n * Renders a directory as a browsable listing.\n *\n * @param fullPath - Absolute path of the directory to list\n * @param requestPath - The same directory as the request spelled it, relative to the root\n * @param res - Response to write to\n *\n * @remarks\n * Entries are told apart by whether they have an extension,\n * so a directory carrying a dot in its name is drawn as a file,\n * since a listing is navigation rather than a report.\n * The request path is also split into a trail of links, one per directory it names,\n * which is what lets a visitor climb back out.\n * Names are put into the template as they are, so a filename containing markup reaches the page intact.\n *\n * @since 2.0.0\n */\n\n private async handleDirectory(fullPath: string, requestPath: string, res: ServerResponse): Promise<void> {\n const files = await readdir(fullPath);\n let fileList = files.map(file => {\n const fullPath = join(requestPath, file);\n const ext = extname(file).slice(1) || 'folder';\n\n if(ext === 'folder') {\n return `\n <a href=\"/${ fullPath }\" class=\"folder-row\">\n <div class=\"icon\"><i class=\"fa-solid fa-folder\"></i></div>\n <div class=\"meta\"><div class=\"name\">${ file }</div><div class=\"sub\">Folder</div></div>\n </a>\n `;\n }\n\n return `\n <a href=\"/${ fullPath }\" class=\"file-row\">\n <div class=\"icon\"><i class=\"fa-solid fa-file-code\"></i></div>\n <div class=\"meta\"><div class=\"name\">${ file }</div><div class=\"sub\">${ ext }</div></div>\n </a>\n `;\n }).join('');\n\n if(!fileList) {\n fileList = '<div class=\"empty\">No files or folders here.</div>';\n } else {\n fileList = `<div class=\"list\">${ fileList }</div>`;\n }\n\n let activePath = '/';\n const segments = requestPath.split('/').map(path => {\n activePath += `${ path }/`;\n\n return `<li><a href=\"${ activePath }\">${ path }</a></li>`;\n }).join('');\n\n const htmlResult = html.replace('${ fileList }', fileList)\n .replace('${ paths }', '<li><a href=\"/\">root</a></li>' + segments)\n .replace('${ up }', '/' + requestPath.split('/').slice(0, -1).join('/'));\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(htmlResult);\n }\n\n /**\n * Sends one file.\n *\n * @param fullPath - Absolute path of the file to send\n * @param res - Response to write to\n *\n * @remarks\n * Read whole before anything is written,\n * so the response carries no length and a large file is held in memory rather than streamed,\n * which a development server over its own build output can afford.\n * A file with no extension is treated as text.\n *\n * @see getContentType\n * @since 2.0.0\n */\n\n private async handleFile(fullPath: string, res: ServerResponse): Promise<void> {\n const ext = extname(fullPath).slice(1) || 'txt';\n const contentType = this.getContentType(ext);\n\n const data = await readFile(fullPath);\n res.writeHead(200, { 'Content-Type': contentType });\n res.end(data);\n }\n\n /**\n * Answers a request that reached nothing.\n *\n * @param res - Response to write to\n *\n * @remarks\n * Plain text rather than the listing template, since the answer is for whatever asked rather than for a reader.\n *\n * @since 2.0.0\n */\n\n private sendNotFound(res: ServerResponse): void {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n }\n\n /**\n * Answers a request that failed and reports why.\n *\n * @param res - Response to write to\n * @param error - The failure to report\n *\n * @remarks\n * The reason is logged rather than sent,\n * so a stack trace reaches the developer running the server and not whoever is connected to it.\n *\n * @since 2.0.0\n */\n\n private sendError(res: ServerResponse, error: Error): void {\n this.events$.next({ type: 'error', error });\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end('Internal Server Error');\n }\n}\n","<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"/><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/><title>Dark File Browser — FTP-like</title><link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css\" integrity=\"sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw==\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" /><style>:root{--bg:#0b0f14;--panel:#0f1720;--muted:#9aa4b2;--accent:#E5C07B;--glass:rgba(255,255,255,0.03);--card:#0c1116;--radius:12px;--gap:12px;--shadow:0 6px 18px rgba(0,0,0,0.4);--file-icon-size:40px;font-family:Inter,ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial}*{box-sizing:border-box;font-style:normal !important}html,body{height:100%;margin:0;font-size:14px;color:#dce7ef;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:radial-gradient(1200px 600px at 10% 10%,rgba(110,231,183,0.04),transparent 8%),linear-gradient(180deg,rgba(255,255,255,0.01),transparent 20%),var(--bg);padding:28px;display:flex;gap:20px;align-items:flex-start;justify-content:center}.app{width:1100px;max-width:98vw;display:flex;gap:18px;padding:18px;border-radius:16px;box-shadow:var(--shadow);border:1px solid rgba(255,255,255,0.03);background:linear-gradient(180deg,rgba(255,255,255,0.02),rgba(255,255,255,0));overflow:hidden}.sidebar{width:260px;background:linear-gradient(180deg,rgba(255,255,255,0.01),transparent);border-radius:var(--radius);padding:14px}.brand{display:flex;gap:12px;align-items:center;margin-bottom:10px}.logo{width:46px;height:46px;border-radius:10px;background:linear-gradient(135deg,#b65b9f 0%,#804b8f 100%);display:flex;align-items:center;justify-content:center;font-weight:700}.brand h1{font-size:16px;margin:0}.muted{color:var(--muted);font-size:13px}.search{margin:12px 0}.search input{width:100%;padding:10px 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.03);background:var(--glass);color:inherit}.quick-list{margin-top:12px}.quick-list a{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;background:transparent;color:var(--muted);text-decoration:none;cursor:pointer;transition:color 0.15s ease}.quick-list a:hover{color:var(--accent)}.main{flex:1;display:flex;flex-direction:column}.topbar{display:flex;align-items:center;gap:12px;padding-bottom:12px}.breadcrumbs{list-style:none;display:flex;gap:8px;align-items:center;background:var(--glass);padding:8px 12px;border-radius:var(--radius);margin:0}.breadcrumbs li{display:flex;align-items:center}.breadcrumbs li:not(:last-child)::after{content:'>';margin-left:8px;color:var(--muted)}.breadcrumbs a{color:var(--muted);text-decoration:none;transition:color 0.15s ease}.breadcrumbs a:hover{color:var(--accent)}.list{margin-top:14px;display:grid;grid-template-columns:1fr;gap:10px}.list a{display:flex;text-decoration:none;color:inherit}.folder-row,.file-row{display:flex;gap:12px;align-items:center;padding:10px;border-radius:10px;background:linear-gradient(180deg,rgba(255,255,255,0.01),transparent);border:1px solid rgba(255,255,255,0.02);transition:color 0.25s ease}.icon{width:var(--file-icon-size);height:var(--file-icon-size);border-radius:10px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.02);flex-shrink:0;transition:background 0.25s ease,color 0.25s ease}.folder-row:hover,.file-row:hover{color:var(--accent)}.folder-row:hover .icon{background:rgba(152,195,121,0.2)}.file-row:hover .icon{background:rgba(224,108,117,0.2)}.folder-row:hover .icon i{color:#98C379}.file-row:hover .icon i{color:#e09c6c}.meta{display:flex;flex-direction:column}.name{font-weight:600}.sub{color:var(--muted);font-size:13px}.empty{padding:40px;text-align:center;color:var(--muted)}@media (max-width:880px){.app{flex-direction:column;padding:12px}.sidebar,.main{width:100%}}</style></head><body><div class=\"app\"><aside class=\"sidebar\"><div class=\"brand\"><div class=\"logo\">F</div><div><h1>xBuildFTP</h1><div class=\"muted\">Browse & serve files</div></div></div><div class=\"search\"><input placeholder=\"Search files & folders...\"/></div><div class=\"quick-list\"><a href=\"/\">🏠 Home</a><a href=\"${ up }\">⬆️ Up</a></div></aside><main class=\"main\"><div class=\"topbar\"><div class=\"topbar\"><ul class=\"breadcrumbs\"> ${ paths } </ul></div></div> ${ fileList } </main></div></body><script> const searchInput = document.querySelector('.search input'); const listItems = document.querySelectorAll('.list > .folder-row, .list > .file-row'); const emptyMessage = document.querySelector('.empty'); searchInput.addEventListener('input', () => { const query = searchInput.value.toLowerCase(); let anyVisible = false; listItems.forEach(item => { const name = item.querySelector('.name').textContent.toLowerCase(); if (name.includes(query)) { item.style.display = 'flex'; anyVisible = true; } else { item.style.display = 'none'; } }); emptyMessage.style.display = anyVisible ? 'none' : 'block'; }); </script></html>","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { PositionInterface, FormatStackFrameInterface } from '@remotex-labs/xmap';\n\n/**\n * Imports\n */\n\nimport { cwd } from 'process';\nimport { readFileSync } from 'fs';\nimport { FilesModel } from '@models/files.model';\nimport { inject, Injectable } from '@remotex-labs/xinject';\nimport { normalize, SourceService } from '@remotex-labs/xmap';\n\n/**\n * Matches a path that belongs to the framework rather than to the project being built.\n *\n * @remarks\n * Case-insensitive, since the same file surfaces as `xBuild` from a checkout and as `xbuild` from `node_modules`.\n * The lookahead spares a project's own `xbuild.config`, which names the framework without being part of it.\n *\n * @since 3.0.0\n */\n\nconst FRAMEWORK_PATH_REGEX = /xbuild(?!\\.config)/i;\n\n/**\n * Matches a source map whose `mappings` field is empty.\n *\n * @remarks\n * Such a map resolves nothing,\n * so keeping it would cost a lookup on every frame and answer with the generated position anyway.\n * Kept at module level so the pattern is compiled once rather than on every registration.\n *\n * @since 3.0.0\n */\n\nconst EMPTY_MAPPINGS_REGEX = /\"mappings\"\\s*:\\s*\"\"/;\n\n/**\n * Holds the framework's own paths and the source maps a stack trace is resolved through.\n *\n * @remarks\n * Two jobs in service of one thing - reporting an error against the source a reader recognizes.\n * It tells framework frames apart from a project's own,\n * and it hands out the {@link SourceService} that maps a generated position back to its source.\n * Maps arrive either as text through {@link addSourceMap} or read from a `.map` companion through\n * {@link loadSourceMap}, and both are keyed by resolved path, so the same file registered under a relative and an\n * absolute path is parsed once.\n * The framework's own map is loaded on construction, which is what lets an error thrown inside the build be reported\n * against its source.\n * Registered as a singleton, so every consumer shares one registry.\n *\n * @example\n * ```ts\n * const framework = inject(FrameworkService);\n *\n * framework.projectRoot; // 'D:/app' - where the build was started\n * framework.getSourceMap(framework.frameworkFile); // the framework's own SourceService\n * framework.isFrameworkFile({ source: 'D:/app/src/index.ts' }); // false - a project file\n * ```\n *\n * @see SourceService\n * @since 2.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class FrameworkService {\n /**\n * Absolute path of the framework file this service was loaded from.\n *\n * @remarks\n * Normalized like {@link frameworkRoot} and {@link projectRoot},\n * so all three compare and join the same way whatever the platform.\n *\n * @example\n * ```ts\n * framework.frameworkFile; // 'D:/app/node_modules/@remotex-labs/xbuild/dist/index.js'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly frameworkFile: string;\n\n /**\n * Absolute path of the directory the framework was distributed in.\n *\n * @remarks\n * Where anything shipped beside the build is found, the server's certificates among them.\n *\n * @example\n * ```ts\n * framework.frameworkRoot; // 'D:/app/node_modules/@remotex-labs/xbuild/dist'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly frameworkRoot: string;\n\n /**\n * Absolute path of the directory the build was started from.\n *\n * @remarks\n * The user's project root rather than the framework's,\n * so it is what a path is made relative to when a frame is printed.\n *\n * @example\n * ```ts\n * framework.projectRoot; // 'D:/app'\n * ```\n *\n * @since 3.0.0\n */\n\n readonly projectRoot: string;\n\n /**\n * Shared file cache, held on the class so {@link resolve} needs no instance.\n *\n * @remarks\n * What is wanted here is the memo it keeps rather than the snapshots: resolving through it is what keeps this\n * registry, the file cache, and everything else keyed by path agreeing on what one path is.\n * Claimed by the first {@link resolve} rather than by a static initializer, since an initializer would run while\n * this module is being imported, and importing it must not reach the container.\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n private static files?: FilesModel;\n\n /**\n * Source maps keyed by the resolved path of the file each one describes.\n *\n * @since 2.0.0\n */\n\n private readonly sourceMaps = new Map<string, SourceService>();\n\n /**\n * Captures the framework's paths and loads its own source map.\n *\n * @throws Error - When the framework ships without a readable `.map` companion\n *\n * @remarks\n * A framework shipped without its map is a broken build rather than a supported one,\n * so the read failure surfaces here instead of being swallowed.\n *\n * @example\n * ```ts\n * const framework = new FrameworkService();\n * framework.getSourceMap(framework.frameworkFile); // SourceService\n * ```\n *\n * @see loadSourceMap\n * @since 2.0.0\n */\n\n constructor() {\n this.projectRoot = normalize(cwd());\n this.frameworkFile = normalize(import.meta.filename);\n this.frameworkRoot = normalize(import.meta.dirname);\n\n this.loadSourceMap(this.frameworkFile);\n }\n\n /**\n * Normalizes a path to the absolute form every cache here is keyed by.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns Absolute path with forward slashes\n *\n * @remarks\n * Static so that a caller with no framework service in hand can still key a path the way this package does, which\n * is what keeps entry-point names, source-map keys, and file entries from disagreeing about one file.\n * The first call claims the file cache, and every later call finds it already claimed, so the container is reached\n * only once something asks for a path rather than when this module is imported.\n * Resolution is memoized by the cache behind it, so resolving the same path again costs a lookup.\n *\n * @example\n * ```ts\n * FrameworkService.resolve('src/index.ts'); // 'D:/app/src/index.ts'\n * ```\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n static resolve(path: string): string {\n return (FrameworkService.files ??= inject(FilesModel)).resolve(path);\n }\n\n /**\n * Reports whether a position belongs to the framework rather than to the project being built.\n *\n * @param position - Position or stack frame to judge, as the source map resolver reports it\n * @returns `true` when the position comes from framework code\n *\n * @remarks\n * The judgment is made on the path, matched case-insensitively, since the same file surfaces as `xBuild` from a\n * checkout and as `xbuild` from `node_modules`.\n * A project's own `xbuild.config` names the framework without being part of it, so it is excluded by name.\n * The source root is consulted only when the source itself does not settle the question.\n *\n * @example\n * ```ts\n * framework.isFrameworkFile({ source: 'D:/app/node_modules/xbuild/dist/index.js' }); // true\n * framework.isFrameworkFile({ source: 'D:/app/xbuild.config.ts' }); // false\n * framework.isFrameworkFile({ source: 'D:/app/src/index.ts' }); // false\n * ```\n *\n * @see PositionInterface\n * @see FormatStackFrameInterface\n *\n * @since 2.2.5\n */\n\n isFrameworkFile(position: PositionInterface | FormatStackFrameInterface): boolean {\n return FRAMEWORK_PATH_REGEX.test(position.source ?? '') || FRAMEWORK_PATH_REGEX.test(position.sourceRoot ?? '');\n }\n\n /**\n * Returns the source map registered for a file.\n *\n * @param path - Path of the file, relative or absolute\n * @returns The source map of that file, or `undefined` when none was registered\n *\n * @remarks\n * A pure registry read: a file that was never registered stays unregistered, since nothing here reaches the disk.\n * Use {@link loadSourceMap} to register one.\n *\n * @example\n * ```ts\n * framework.getSourceMap('dist/index.js'); // undefined - never registered\n * framework.loadSourceMap('dist/index.js');\n * framework.getSourceMap('dist/index.js'); // SourceService\n * ```\n *\n * @see SourceService\n * @since 2.0.0\n */\n\n getSourceMap(path: string): SourceService | undefined {\n return this.sourceMaps.get(FrameworkService.resolve(path));\n }\n\n /**\n * Registers a source map from its text.\n *\n * @param path - Path of the file the map describes, relative or absolute\n * @param source - Raw source map content\n * @param force - Whether a map the file already carries is replaced rather than kept\n *\n * @throws Error - When the content is not a source map the resolver can parse\n *\n * @remarks\n * A file that already carries a map keeps it, so the first registration wins, and a later call costs only a lookup.\n * A caller that knows the file was written again says so with `force`, which parses the map it was handed and puts\n * it in place of the one registered before: a watch rebuilding a file leaves the map registered for it describing\n * text that is no longer there, and a stale map resolves a frame to the wrong line rather than to none.\n * A map with empty mappings is dropped rather than registered, resolving through such a map being the same as not\n * resolving at all, and it leaves what was registered before it in place rather than clearing it.\n *\n * @example\n * ```ts\n * framework.addSourceMap('dist/index.js', readFileSync('dist/index.js.map', 'utf-8'));\n * framework.getSourceMap('dist/index.js'); // SourceService\n *\n * framework.addSourceMap('dist/index.js', rebuilt); // kept - the first registration wins\n * framework.addSourceMap('dist/index.js', rebuilt, true); // replaced - the file was written again\n * ```\n *\n * @see loadSourceMap\n * @since 3.0.0\n */\n\n addSourceMap(path: string, source: string, force: boolean = false): void {\n const key = FrameworkService.resolve(path);\n if (!force && this.sourceMaps.has(key)) return;\n\n this.register(key, source);\n }\n\n /**\n * Registers the source map a file's `.map` companion carries.\n *\n * @param path - Path of the generated file, relative or absolute\n *\n * @throws Error - When the companion cannot be read or does not parse\n *\n * @remarks\n * The companion is looked for beside the file, as `<path>.map`, which is where every file this toolchain emits\n * carries its map.\n * A file that already carries a map is left alone before the disk is touched,\n * so repeating the call on a tracked file costs only a lookup.\n * An empty path is ignored outright,\n * and a companion that parses but maps nothing registers no map and raises nothing.\n *\n * @example\n * ```ts\n * framework.loadSourceMap('dist/index.js'); // reads dist/index.js.map\n * framework.loadSourceMap('dist/index.js'); // cached - no read\n * ```\n *\n * @see addSourceMap\n * @since 3.0.0\n */\n\n loadSourceMap(path: string): void {\n if (!path) return;\n\n const key = FrameworkService.resolve(path);\n if (this.sourceMaps.has(key)) return;\n\n let source: string;\n try {\n source = readFileSync(`${ key }.map`, 'utf-8');\n } catch (error) {\n throw FrameworkService.failure(key, error);\n }\n\n this.register(key, source);\n }\n\n /**\n * Builds the error reported when a source map cannot be registered.\n *\n * @param key - Resolved path of the file the map describes\n * @param error - Failure raised while reading or parsing it\n * @returns The error to throw, naming the file and carrying the original reason\n *\n * @remarks\n * The reading and the parsing halves fail in the same way as far as a caller is concerned,\n * so both report the file first and the reason after it.\n *\n * @since 3.0.0\n */\n\n private static failure(key: string, error: unknown): Error {\n return new Error(\n `Failed to load source map for: ${ key }\\n${ error instanceof Error ? error.message : String(error) }`\n );\n }\n\n /**\n * Parses a source map and files it under a resolved path.\n *\n * @param key - Resolved path of the file the map describes\n * @param source - Raw source map content\n *\n * @throws Error - When the content is not a source map the resolver can parse\n *\n * @remarks\n * The single point where a map enters the registry,\n * so both entry points resolve their path once and skip an already registered file before reaching here.\n * A map with empty mappings is dropped rather than registered, since resolving through such a map answers with\n * the position it was given.\n *\n * @since 3.0.0\n */\n\n private register(key: string, source: string): void {\n if (EMPTY_MAPPINGS_REGEX.test(source)) return;\n\n try {\n this.sourceMaps.set(key, new SourceService(source, key));\n } catch (error) {\n throw FrameworkService.failure(key, error);\n }\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { Stats } from 'fs';\nimport type { TextChangeRange } from 'typescript';\nimport type { FileSnapshotInterface, ScriptSnapshotType } from './interfaces/files-model.interface';\n\n/**\n * Imports\n */\n\nimport { readFileSync, statSync } from 'fs';\nimport { resolve } from '@remotex-labs/xmap';\nimport { Injectable } from '@remotex-labs/xinject';\n\n/**\n * In-memory cache of file contents keyed by resolved absolute path.\n *\n * @remarks\n * Backs the TypeScript language service, which asks for a script version on every request and only reparses when\n * that version changes.\n * Content is read once and re-read only when the modification time moves,\n * so repeated lookups of an unchanged file cost a map read.\n * Reach for {@link touch} when any cached content will do,\n * {@link refresh} when the file may have changed on disk or when a watcher already carries its `Stats`,\n * and {@link refreshAll} to catch what the watcher failed to report.\n *\n * @example\n * ```ts\n * const model = inject(FilesModel);\n *\n * model.touch('src/index.ts').version; // 1 - read from disk\n * model.touch('src/index.ts').version; // 1 - served from the cache\n * model.refresh('src/index.ts').version; // 2 - the file changed on disk\n * model.clear(); // every entry dropped\n * ```\n *\n * @see FileSnapshotInterface\n * @since 2.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class FilesModel {\n /**\n * Memoized mapping from an input path to its resolved absolute form.\n *\n * @remarks\n * Kept apart from {@link cache} because several input paths can resolve to the same absolute path,\n * and resolution is repeated far more often than content changes.\n *\n * @since 3.0.0\n */\n\n private readonly resolved = new Map<string, string>();\n\n /**\n * Entries keyed by resolved absolute path.\n *\n * @remarks\n * Holds one {@link FileSnapshotInterface} per tracked path, including paths that carry no readable file.\n *\n * @since 3.0.0\n */\n\n private readonly cache = new Map<string, FileSnapshotInterface>();\n\n /**\n * Drops every cached entry and every memoized path.\n *\n * @remarks\n * Leaves the model in its initial state, so the next request re-reads from disk and restarts versions at `1`.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts');\n * model.clear();\n * model.getSnapshot('src/index.ts'); // undefined\n * ```\n *\n * @since 2.0.0\n */\n\n clear(): void {\n this.cache.clear();\n this.resolved.clear();\n }\n\n /**\n * Returns the cached entry for a path without touching the filesystem.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns The cached entry, or `undefined` when the path was never tracked\n *\n * @remarks\n * A pure cache read: it never reads or stats the file, so an untracked path stays untracked.\n * Use {@link touch} to track the path instead.\n *\n * @example\n * ```ts\n * model.getSnapshot('src/index.ts'); // undefined - never tracked\n * model.touch('src/index.ts');\n * model.getSnapshot('src/index.ts'); // { mtimeMs: 1754000000000, version: 1, snapshot: { ... } }\n * ```\n *\n * @see touch\n * @since 2.0.0\n */\n\n getSnapshot(path: string): FileSnapshotInterface | undefined {\n return this.cache.get(this.resolve(path));\n }\n\n /**\n * Returns the entry for a path, reading the file when it is not tracked yet.\n *\n * @param path - Filesystem path, relative or absolute\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, cached or newly created\n *\n * @remarks\n * A tracked path is returned as it stands, without a `stat` call, however stale it may be.\n * Use {@link refresh} when the file may have changed since it was cached.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts').version; // 1 - read from disk\n * model.touch('src/index.ts').version; // 1 - served from the cache, no stat\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n touch(path: string, encoding?: BufferEncoding): FileSnapshotInterface {\n const target = this.resolve(path);\n\n return this.cache.get(target) ?? this.sync(target, this.stat(target), encoding);\n }\n\n /**\n * Synchronizes a path with the filesystem and returns its entry.\n *\n * @param path - Filesystem path, relative or absolute\n * @param stats - Already obtained `Stats` for the path, sparing a `stat` call\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, rebuilt only when the file actually changed\n *\n * @remarks\n * The content is re-read when the modification time differs from the cached one,\n * so calling this on an unchanged file leaves its version intact.\n * A path that is missing or is not a regular file yields an entry with an `undefined` snapshot.\n *\n * @example\n * ```ts\n * model.touch('src/index.ts').version; // 1\n * model.refresh('src/index.ts').version; // 1 - mtime unchanged\n * model.refresh('src/index.ts').version; // 2 - the file was written to\n * ```\n *\n * @see touch\n * @since 3.0.0\n */\n\n refresh(path: string, stats?: Stats, encoding?: BufferEncoding): FileSnapshotInterface {\n const target = this.resolve(path);\n\n return this.sync(target, stats ?? this.stat(target), encoding);\n }\n\n /**\n * Synchronizes a set of paths, or every path already tracked.\n *\n * @param paths - Paths to synchronize, defaulting to everything in the cache\n *\n * @remarks\n * The safety net under file watching: a change that goes unreported leaves an entry stale with nothing to\n * announce it - the version never moves,\n * so the language service is never told to reparse, and the build keeps compiling text that is no longer on disk.\n * Sweeping asks the filesystem rather than the watcher,\n * so a missed event costs a needless rebuild at worst rather than a wrong one.\n * Every path gets a `stat`, and only the ones whose time moved are read again.\n * The keys it walks are already resolved,\n * so re-synchronizing them writes back over the same keys and cannot extend the walk.\n * A tracked path that is still missing keeps the entry and the version it had,\n * so repeated sweeps do not inflate the versions of files that were deleted.\n *\n * @example\n * ```ts\n * model.refreshAll([ 'src/index.ts' ]); // that one path\n * model.refreshAll(); // every tracked path, re-read where it changed\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n refreshAll(paths?: Array<string>): void {\n const pathList = paths ?? this.cache.keys();\n for (const path of pathList) {\n this.refresh(path);\n }\n }\n\n /**\n * Normalizes a path to its absolute form.\n *\n * @param path - Filesystem path, relative or absolute\n * @returns Absolute path with forward slashes\n *\n * @remarks\n * The result is memoized per input string, since the same paths are resolved on every cache lookup.\n *\n * @example\n * ```ts\n * model.resolve('src/index.ts'); // 'D:/project/src/index.ts'\n * ```\n *\n * @since 2.0.0\n */\n\n resolve(path: string): string {\n let target = this.resolved.get(path);\n if (target === undefined) this.resolved.set(path, target = resolve(path));\n\n return target;\n }\n\n /**\n * Brings the entry for a resolved path in line with the given filesystem state.\n *\n * @param target - Resolved absolute path\n * @param info - `Stats` for the path, or `undefined` when it does not exist\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The entry for the path, reused when nothing changed\n *\n * @remarks\n * A path that is not a regular file keeps its already empty entry untouched,\n * so repeated events for a missing path do not inflate its version.\n * A file whose modification time matches the cached one is left as is, and the content is not read.\n *\n * @since 3.0.0\n */\n\n private sync(target: string, info: Stats | undefined, encoding: BufferEncoding = 'utf-8'): FileSnapshotInterface {\n const entry = this.cache.get(target);\n\n if (!info?.isFile()) {\n if (entry && !entry.snapshot) return entry;\n\n return this.store(target, { mtimeMs: 0, snapshot: undefined, version: (entry?.version ?? 0) + 1 });\n }\n\n if (entry?.mtimeMs === info.mtimeMs) return entry;\n\n return this.store(target, {\n mtimeMs: info.mtimeMs,\n version: (entry?.version ?? 0) + 1,\n snapshot: this.snapshot(readFileSync(target, encoding))\n });\n }\n\n /**\n * Computes the span that differs between two versions of a text.\n *\n * @param oldText - Text the language service last parsed\n * @param newText - Text that replaces it\n * @returns The replaced span in `oldText` together with the length of its replacement\n *\n * @remarks\n * Narrows the change by trimming the shared prefix and the shared suffix,\n * which lets the language service reuse the untouched parts of the syntax tree.\n * The suffix scan stops at the prefix boundary, so the two never overlap on a text that shrank.\n *\n * @since 3.0.0\n */\n\n private changeRange(oldText: string, newText: string): TextChangeRange {\n const oldLength = oldText.length;\n const newLength = newText.length;\n const max = Math.min(oldLength, newLength);\n\n let prefix = 0;\n while (prefix < max && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix)) prefix++;\n\n let suffix = 0;\n while (suffix < max - prefix && oldText.charCodeAt(oldLength - 1 - suffix) === newText.charCodeAt(newLength - 1 - suffix)) suffix++;\n\n return {\n span: { start: prefix, length: oldLength - prefix - suffix },\n newLength: newLength - prefix - suffix\n };\n }\n\n /**\n * Wraps file content in a script snapshot.\n *\n * @param text - Content read from disk\n * @returns A snapshot exposing the content both as `text` and through the `IScriptSnapshot` methods\n *\n * @remarks\n * `getChangeRange` closes over this text as the new version and delegates to {@link changeRange},\n * so the language service can diff against any earlier snapshot it still holds.\n *\n * @since 3.0.0\n */\n\n private snapshot(text: string): ScriptSnapshotType {\n return {\n text,\n getText: (start, end): string => text.slice(start, end),\n getLength: (): number => text.length,\n getChangeRange: (previous):\n TextChangeRange => this.changeRange(previous.getText(0, previous.getLength()), text)\n };\n }\n\n /**\n * Writes an entry to the cache and hands it back.\n *\n * @param target - Resolved absolute path\n * @param entry - Entry to store under that path\n * @returns The stored entry\n *\n * @remarks\n * Exists so {@link sync} can store and return in a single expression.\n *\n * @since 3.0.0\n */\n\n private store(target: string, entry: FileSnapshotInterface): FileSnapshotInterface {\n this.cache.set(target, entry);\n\n return entry;\n }\n\n /**\n * Reads the filesystem state of a path.\n *\n * @param path - Resolved absolute path\n * @returns The `Stats` for the path, or `undefined` when it does not exist\n *\n * @remarks\n * A missing path is an ordinary outcome here rather than a failure, so the throwing form is disabled.\n *\n * @since 3.0.0\n */\n\n private stat(path: string): Stats | undefined {\n return statSync(path, { throwIfNoEntry: false });\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { FSWatcher, Dirent } from 'fs';\nimport type { ErrorType, CompleteType, UnsubscribeType } from '@remotex-labs/xobservable';\nimport type { WatchEventType, ChangeType, ObserverType } from './interfaces/watch-service.interface';\nimport type { WatchChangeInterface, WatchOptionsInterface } from './interfaces/watch-service.interface';\n\n/**\n * Imports\n */\n\nimport { Injectable } from '@remotex-labs/xinject';\nimport { Subject } from '@remotex-labs/xobservable';\nimport { ChangeCode } from '@constants/watch.constant';\nimport { createMatcher } from '@components/glob.component';\nimport { resolve, join, relative } from '@remotex-labs/xmap';\nimport { watch, realpathSync, readdirSync, lstatSync, statSync } from 'fs';\n\n/**\n * A filesystem watcher that multicasts debounced batches of path changes to every subscriber.\n *\n * @remarks\n * Extends a multicast {@link Subject}: the underlying `fs.watch` handles are opened on the **first** subscription and\n * torn down only when the **last** subscription ends, while every active subscriber receives each emitted batch.\n * Events are filtered by a glob matcher, coalesced within a debounced window, and delivered as a single\n * {@link WatchEventType} keyed by path relative to the base.\n * Because `fs.watch` never follows symbolic links,\n * {@link WatchOptionsInterface.followSymlinks} places explicit watchers on the links it finds.\n * As a {@link Subject}, the emitted stream can be reshaped with `pipe` and operators before subscribing.\n *\n * @example\n * <caption>Multiple independent subscribers - each receives every batch</caption>\n * ```ts\n * const watcher = new WatchService('src', { recursive: true, filter: [ '**\\/*.{ts,js}' ], debounce: 100 });\n *\n * const stopA = watcher.subscribe((changes) => rebuild(changes)); // opens the fs watchers\n * const stopB = watcher.subscribe((changes) => reloadTypes(changes)); // reuses them\n *\n * stopB(); // watchers stay open - `stopA` is still subscribed\n * stopA(); // last subscriber leaves - every handle is closed\n * ```\n *\n * @example\n * <caption>Scoped teardown - the subscription disposes automatically at the end of the block</caption>\n * ```ts\n * const watcher = new WatchService(cwd(), { followSymlinks: true, filter: [ '**\\/*.{ts,js}' ] });\n * using sub = watcher.subscribe((changes) => console.log(Object.keys(changes)));\n * ```\n *\n * @see Subject.pipe\n * @see WatchEventType\n * @see WatchOptionsInterface\n *\n * @since 3.0.0\n */\n\n@Injectable({\n scope: 'singleton'\n})\nexport class WatchService extends Subject<WatchEventType> {\n /**\n * The absolute root path being watched.\n *\n * @since 3.0.0\n */\n\n private readonly base: string;\n\n /**\n * Predicate deciding whether a path passes the configured filter.\n *\n * @since 3.0.0\n */\n\n private readonly matcher: ReturnType<typeof createMatcher>;\n\n /**\n * Active `fs.watch` handles, keyed by the path each was opened on.\n *\n * @since 3.0.0\n */\n\n private readonly watchers = new Map<string, FSWatcher>();\n\n /**\n * Changes accumulated in the current debounced window, keyed by path relative to the base.\n *\n * @since 3.0.0\n */\n\n private readonly pending = new Map<string, WatchChangeInterface>();\n\n /**\n * Count of currently active subscriptions, used to start watchers on the first and stop them on the last.\n *\n * @since 3.0.0\n */\n\n private subscriptions = 0;\n\n /**\n * Handle for the scheduled debounced flush, or `undefined` while idle.\n *\n * @since 3.0.0\n */\n\n private timer?: ReturnType<typeof setTimeout>;\n\n /**\n * Creates a watcher rooted at a base path.\n *\n * @param base - Directory to watch, resolved to an absolute path\n * @param options - Filtering, debounce, recursion, and symlink behavior\n *\n * @remarks\n * No watcher is opened until the first subscriber attaches, so constructing one costs a resolve and a matcher.\n *\n * @example\n * ```ts\n * const watcher = new WatchService('src', { filter: [ '**\\/*.ts' ] }); // nothing is watched yet\n * ```\n *\n * @see WatchOptionsInterface\n * @since 3.0.0\n */\n\n constructor(base: string, private options?: WatchOptionsInterface) {\n super();\n\n this.base = resolve(base);\n this.matcher = createMatcher(this.options?.filter ?? [], {\n dot: this.options?.dot ?? false\n });\n }\n\n /**\n * Subscribes to the debounced change stream, starting the watchers on the first subscriber.\n *\n * @param observerOrNext - A full observer object, or a `next` callback\n * @param error - Error handler, used when the first argument is a `next` callback\n * @param complete - Completion handler, used when the first argument is a `next` callback\n * @returns Idempotent, disposable unsubscribe function that detaches this subscriber and,\n * once it is the last one, closes every open watcher\n *\n * @remarks\n * The first subscription opens the `fs.watch` handles, and each later subscription reuses them.\n * Unsubscribing runs at most once.\n * The handles, the pending batch, and the flush timer are released only when the final subscriber leaves,\n * so a watcher shared by several consumers stays alive until all of them detach.\n *\n * @example\n * ```ts\n * const stop = watcher.subscribe((changes) => rebuild(changes));\n * stop(); // detaches, and closes the handles when no other subscriber is left\n * ```\n *\n * @see ObserverType\n * @see Subject.subscribe\n *\n * @since 3.0.0\n */\n\n override subscribe(observerOrNext?: ObserverType, error?: ErrorType, complete?: CompleteType): UnsubscribeType {\n const unsubscribe = super.subscribe(observerOrNext, error, complete);\n if (++this.subscriptions === 1) this.start();\n\n return this.toUnsubscribe(() => {\n unsubscribe();\n if (--this.subscriptions === 0) this.stop();\n });\n }\n\n /**\n * The debounced window in milliseconds, defaulting to 150.\n *\n * @since 3.0.0\n */\n\n private get debounce(): number {\n return this.options?.debounce ?? 150;\n }\n\n /**\n * Opens the base watcher and the symlink watchers when configured.\n *\n * @remarks\n * Invoked once when the subscriber count rises from zero to one.\n *\n * @since 3.0.0\n */\n\n private start(): void {\n this.watch(this.base, this.ignored.bind(this), this.options?.recursive);\n if (this.options?.followSymlinks) this.watchSymlinks(this.base);\n }\n\n /**\n * Clears the pending timer and closes every open watcher.\n *\n * @remarks\n * Invoked once when the subscriber count falls back to zero, returning the service to its pre-subscription state so\n * a later subscription can start clean.\n *\n * @since 3.0.0\n */\n\n private stop(): void {\n if (this.timer) clearTimeout(this.timer);\n for (const watcher of this.watchers.values()) watcher.close();\n\n this.timer = undefined;\n this.pending.clear();\n this.watchers.clear();\n }\n\n /**\n * Emits the accumulated batch to every subscriber and clears the window.\n *\n * @remarks\n * A no-op when nothing is pending, so an expired timer with no changes emits nothing.\n * A `next` that throws is reported to that subscriber's own `error` handler by the {@link Subject},\n * which then rethrows the failures as one aggregate.\n * That aggregate is swallowed here, so one faulty consumer cannot stop the watcher for the others.\n *\n * @since 3.0.0\n */\n\n private flush(): void {\n this.timer = undefined;\n if (this.pending.size === 0) return;\n\n const batch = Object.fromEntries(this.pending) as WatchEventType;\n this.pending.clear();\n\n try {\n this.next(batch);\n } catch {\n /* handled per-observer by the Subject */\n }\n }\n\n /**\n * Closes and forgets the watcher registered on a path, if any.\n *\n * @param path - Path whose watcher should be released\n *\n * @since 3.0.0\n */\n\n private watcherClose(path: string): void {\n const watcher = this.watchers.get(path);\n if (!watcher) return;\n\n watcher.close();\n this.watchers.delete(path);\n }\n\n /**\n * Classifies a raw watch event and queues it for the next flush.\n *\n * @param event - The `fs.watch` event name, either `rename` or `change`\n * @param path - Absolute path the event refers to\n *\n * @remarks\n * A symlink is stat-followed: when it resolves to a matching file, it is watched directly,\n * and when it resolves to a directory under a recursive watch, it is watched recursively.\n * A broken link is dropped.\n * The change type is read from that followed `stat` - a missing entry is {@link ChangeCode.Deleted} and closes its\n * watcher, an entry whose `birthtime` equals its `mtime` is {@link ChangeCode.Added},\n * and anything else is {@link ChangeCode.Change}.\n * Only paths that pass the filter arm the debounced timer and enter the pending batch.\n *\n * @since 3.0.0\n */\n\n private watcherEvent(event: string, path: string): void {\n const relativePath = relative(this.base, path);\n const link = lstatSync(path, { throwIfNoEntry: false });\n const stats = link?.isSymbolicLink() ? statSync(path, { throwIfNoEntry: false }) : link;\n\n if (link?.isSymbolicLink()) {\n if (!stats) return;\n if (event === 'rename') this.watcherClose(path);\n\n if (stats.isFile() && this.matcher(path)) this.watch(path);\n else if (stats.isDirectory() && this.options?.recursive)\n this.watch(path, this.ignored.bind(this), true);\n }\n\n if (!this.matcher(relativePath)) return;\n if (this.timer) this.timer.refresh();\n else this.timer = setTimeout(this.flush.bind(this), this.debounce);\n\n let type: ChangeType;\n if (!stats) {\n this.watcherClose(path);\n type = ChangeCode.Deleted;\n } else {\n type = stats.birthtimeMs === stats.mtimeMs ? ChangeCode.Added : ChangeCode.Change;\n }\n\n this.pending.set(relativePath, { type, stats });\n }\n\n /**\n * Opens an `fs.watch` on a path and registers its change and error handlers.\n *\n * @param path - Path to watch, ignored if already watched or filtered out by {@link ignored}\n * @param ignore - Optional per-entry ignore predicate forwarded to `fs.watch`\n * @param recursive - Whether the watch should cover nested entries\n *\n * @remarks\n * The watch is opened on the real (symlink-resolved) path, while events are reported against the original `path`.\n * A watcher error closes the watcher and forwards the error to every subscriber.\n *\n * @since 3.0.0\n */\n\n private watch(path: string, ignore?: (filename: string) => boolean, recursive: boolean = false): void {\n if (this.watchers.has(path) || this.ignored(path)) return;\n const watcher = watch(realpathSync(path), { recursive, ignore }, (event, filename) => {\n if (!filename) return;\n const target = path.includes(filename) ? path : join(path, filename);\n this.watcherEvent(event, target);\n });\n\n watcher.on('error', (error: Error) => {\n this.watcherClose(path);\n this.error(error);\n });\n\n this.watchers.set(path, watcher);\n }\n\n /**\n * Whether a path should be skipped by the watcher.\n *\n * @param target - Path to test\n * @returns `true` for an empty path, a `~` backup file, or - unless `dot` is set - any dot-prefixed segment\n *\n * @since 3.0.0\n */\n\n private ignored(target: string): boolean {\n if (!target || target.endsWith('~')) return true;\n if (!this.options?.dot) {\n if (target && target.split(/[/\\\\]/).some(\n seg => seg.startsWith('.'))\n ) return true;\n }\n\n return false;\n }\n\n /**\n * Walks the tree under a root and watches every symbolic link found.\n *\n * @param root - Directory to scan for links\n *\n * @remarks\n * Iterative and single-level per read, so ignored directories are pruned before entry and never fully materialized.\n * Descends into real subdirectories only when recursion is enabled.\n * Unreadable directories are skipped silently.\n *\n * @since 3.0.0\n */\n\n private watchSymlinks(root: string): void {\n const stack: Array<string> = [ root ];\n\n while (stack.length) {\n const dir = stack.pop()!;\n\n let entries: Array<Dirent>;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n const full = join(entry.parentPath ?? dir, entry.name);\n if (this.ignored(full)) continue;\n\n if (entry.isSymbolicLink()) {\n this.watch(full, this.ignored.bind(this), this.options?.recursive);\n } else if (this.options?.recursive && entry.isDirectory()) {\n stack.push(full);\n }\n }\n }\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { Dirent } from 'fs';\nimport type { GlobOptionsInterface } from './interfaces/glob-component.interface';\n\n/**\n * Imports\n */\n\nimport { readdirSync } from 'fs';\nimport { join } from '@remotex-labs/xmap';\nimport { Char } from '@constants/char.constant';\nimport { FrameworkService } from '@services/framework.service';\nimport { RegexElement, RegexCloser } from '@constants/glob.constant';\n\n/**\n * Escapes a single character for literal use inside a regular expression.\n *\n * @param char - The character to escape\n * @returns The character prefixed with a backslash when it carries special meaning in a regular expression,\n * or the character unchanged otherwise\n *\n * @remarks\n * A backslash is prepended when `char` is one of the regex metacharacters `.+^$()|\\{}[]*?`.\n * Any other character is returned as-is.\n * Intended for building patterns from user-supplied glob fragments where each source character must match itself.\n *\n * @example\n * ```ts\n * lit('.'); // '\\\\.'\n * lit('a'); // 'a'\n * ```\n *\n * @since 3.0.0\n */\n\nexport function lit(char: string): string {\n return '.+^$()|\\\\{}[]*?'.includes(char) ? '\\\\' + char : char;\n}\n\n/**\n * Returns the UTF-16 code unit of a glob string at a given index.\n *\n * @param glob - The glob string to read from\n * @param index - The zero-based position of the character to read\n * @returns The code unit at `index`, or `NaN` when `index` is out of range\n *\n * @remarks\n * A thin wrapper over {@link String.charCodeAt} used while scanning a glob pattern character by character.\n * Comparing code units avoids allocating single-character substrings on the hot path.\n *\n * @example\n * ```ts\n * at('a*b', 1); // 42 - Char.Star\n * at('a*b', 9); // NaN - past the end\n * ```\n *\n * @see Char\n * @since 3.0.0\n */\n\nexport function at(glob: string, index: number): number {\n return glob.charCodeAt(index);\n}\n\n/**\n * Determines whether the `**` at a given index forms a globstar segment.\n *\n * @param glob - The glob string being scanned\n * @param index - The zero-based position of the first `*` of the candidate `**`\n * @returns `true` when the `**` occupies a whole path segment, `false` otherwise\n *\n * @remarks\n * A globstar is a `**` that spans an entire path segment,\n * so it must be bounded on both sides by a slash or by the start or end of the string.\n * The character before `index` must be the start of the string or a slash,\n * and the character after the `**` must be the end of the string or a slash.\n * A `**` embedded within a segment, such as in `a**b`, matches as two consecutive single stars rather than a globstar.\n * The caller is responsible for confirming that both characters at `index` and `index + 1` are `*`.\n *\n * @example\n * ```ts\n * isGlobstar('**', 0); // true - the whole string\n * isGlobstar('a/**', 2); // true - preceded by a slash, ends the string\n * isGlobstar('a**b', 1); // false - embedded in a segment\n * ```\n *\n * @see Char\n * @since 3.0.0\n */\n\nexport function isGlobstar(glob: string, index: number): boolean {\n return (index === 0 || at(glob, index - 1) === Char.Slash)\n && (index + 2 === glob.length || at(glob, index + 2) === Char.Slash);\n}\n\n/**\n * Wraps a regex fragment in a non-capturing group.\n *\n * @param body - The regex source to enclose\n * @returns The body wrapped as `(?:body)`\n *\n * @remarks\n * Groups a fragment so a following quantifier or alternation applies to the whole fragment rather than its last token.\n *\n * @example\n * ```ts\n * group('a|b'); // '(?:a|b)'\n * group('a|b') + '?'; // '(?:a|b)?' - the quantifier covers both alternatives\n * ```\n *\n * @since 3.0.0\n */\n\nexport function group(body: string): string {\n return `(?:${ body })`;\n}\n\n/**\n * Finds the index of the `]` that closes a character class.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `[`\n * @returns The index of the closing `]`, or the length of the string when the class is unterminated\n *\n * @remarks\n * Applies POSIX-style character-class rules while scanning.\n * A leading `!` or `^` negates the class and is skipped, and a `]` immediately after the opening bracket\n * (or after the negation) is treated as a literal member rather than a close.\n * A backslash escapes the next character, so an escaped `]` does not close the class.\n *\n * @example\n * ```ts\n * classEnd('[abc]def', 0); // 4\n * classEnd('[]abc]', 0); // 5 - the leading ] is a member\n * classEnd('[abc', 0); // 4 - unterminated, so the length\n * ```\n *\n * @see compileClass\n * @since 3.0.0\n */\n\nexport function classEnd(glob: string, openIndex: number): number {\n let scan = openIndex + 1;\n const lead = at(glob, scan);\n\n if (lead === Char.Bang || lead === Char.Caret) scan++;\n if (at(glob, scan) === Char.RBracket) scan++; // leading ] is literal\n\n while (scan < glob.length && at(glob, scan) !== Char.RBracket)\n scan += at(glob, scan) === Char.Backslash ? 2 : 1;\n\n return scan;\n}\n\n/**\n * Finds the index of the `)` that closes an extglob group.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `(`\n * @returns The index of the matching `)`, or `-1` when the group is unterminated\n *\n * @remarks\n * Tracks nesting depth so an inner `( ... )` does not end the outer group.\n * A backslash escapes the next character, and a `[ ... ]` character class is skipped via {@link classEnd},\n * so parentheses inside it are not counted.\n *\n * @example\n * ```ts\n * findClose('@(a|b)c', 1); // 5\n * findClose('@(a|(b))', 1); // 7 - the inner group does not end it\n * findClose('@(a', 1); // -1 - unterminated\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function findClose(glob: string, openIndex: number): number {\n for (let cursor = openIndex, depth = 0; cursor < glob.length; cursor++) {\n const char = at(glob, cursor);\n\n if (char === Char.Backslash) cursor++;\n else if (char === Char.LParen) depth++;\n else if (char === Char.RParen && --depth === 0) return cursor;\n else if (char === Char.LBracket) cursor = classEnd(glob, cursor);\n }\n\n return -1;\n}\n\n/**\n * Finds the index of the `}` that closes an expandable brace group.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `{`\n * @returns The index of the matching `}` when the group contains a top-level comma, `-1` otherwise\n *\n * @remarks\n * A brace group is expandable only when it holds at least one top-level comma, so `{a,b}` closes but `{a}` does not.\n * Tracks nesting depth so an inner `{ ... }` does not end the outer group,\n * skips a `[ ... ]` character class via {@link classEnd}, and treats a backslash as escaping the next character.\n * Returning `-1` signals the caller to emit the `{` as a literal.\n *\n * @example\n * ```ts\n * braceClose('{a,b}c', 0); // 4\n * braceClose('{a,{b,c}}', 0); // 8 - the inner group does not end it\n * braceClose('{abc}', 0); // -1 - no top-level comma, so a literal\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function braceClose(glob: string, openIndex: number): number {\n let comma = false;\n\n for (let cursor = openIndex + 1, depth = 0; cursor < glob.length; cursor++) {\n const char = at(glob, cursor);\n\n if (char === Char.Backslash) cursor++;\n else if (char === Char.LBrace) depth++;\n else if (char === Char.RBrace) {\n if (depth === 0) return comma ? cursor : -1; // expandable only with a comma\n depth--;\n }\n else if (char === Char.Comma && depth === 0) comma = true;\n else if (char === Char.LBracket) cursor = classEnd(glob, cursor);\n }\n\n return -1;\n}\n\n/**\n * Compiles a glob character class into its regex equivalent.\n *\n * @param glob - The glob string being scanned\n * @param openIndex - The index of the opening `[`\n * @returns A tuple of the compiled regex source and the index just past the class\n *\n * @remarks\n * Translates glob character-class syntax into a regex class.\n * A leading `!` or `^` becomes a negation that also excludes the path separator, emitted as `[^/`.\n * A `]` immediately after the opening (or after the negation) is escaped as a literal member,\n * and a `^` inside the class is escaped so it is not read as a negation.\n * An unterminated class is not a class at all - the function returns the literal `\\[` and advances past the `[`.\n *\n * @example\n * ```ts\n * compileClass('[a-z]x', 0); // [ '[a-z]', 5 ]\n * compileClass('[!a]', 0); // [ '[^/a]', 4 ] - negated, and the separator excluded with it\n * compileClass('[abc', 0); // [ '\\\\[', 1 ] - unterminated, so a literal bracket\n * ```\n *\n * @see classEnd\n * @since 3.0.0\n */\n\nexport function compileClass(glob: string, openIndex: number): [string, number] {\n const end = classEnd(glob, openIndex);\n if (end >= glob.length) return [ '\\\\[', openIndex + 1 ]; // unterminated → literal\n\n let cursor = openIndex + 1, out = '[';\n const lead = at(glob, cursor);\n\n if (lead === Char.Bang || lead === Char.Caret) { out += '^/'; cursor++; }\n if (at(glob, cursor) === Char.RBracket) { out += '\\\\]'; cursor++; }\n\n for (; cursor < end; cursor++) {\n if (at(glob, cursor) === Char.Backslash) out += '\\\\' + glob[++cursor];\n else if (at(glob, cursor) === Char.Caret) out += '\\\\^';\n else out += glob[cursor];\n }\n\n return [ out + ']', end + 1 ];\n}\n\n/**\n * Finds the index of the next path separator at or after a position.\n *\n * @param glob - The glob string being scanned\n * @param from - The zero-based position to start scanning from\n * @returns The index of the next unescaped `/`, or the length of the string when none remains\n *\n * @remarks\n * Marks the end of the current path segment.\n * A backslash escapes the next character, so an escaped `/` does not end the segment.\n *\n * @example\n * ```ts\n * segmentEnd('src/index.ts', 0); // 3\n * segmentEnd('index.ts', 0); // 8 - no separator left, so the length\n * ```\n *\n * @since 3.0.0\n */\n\nexport function segmentEnd(glob: string, from: number): number {\n for (let cursor = from; cursor < glob.length; cursor++) {\n if (at(glob, cursor) === Char.Slash) return cursor;\n if (at(glob, cursor) === Char.Backslash) cursor++;\n }\n\n return glob.length;\n}\n\n/**\n * Compiles a glob fragment into a regular-expression source.\n *\n * @param glob - The glob fragment to compile\n * @param isSegmentStart - Whether the fragment begins at the start of a path segment\n * @param alt - The code unit that separates alternatives, or `0` when the fragment is not an alternation body\n * @param options - Compilation options, of which only {@link GlobOptionsInterface.dot} is read, defaulting to `false`\n * @returns The regex source for the fragment, without the anchoring `^` and `$`\n *\n * @remarks\n * The core of the compiler, invoked recursively for the bodies of extglob, brace, and negation groups.\n * It walks the fragment one character at a time and emits the matching regex, handling wildcards (`*`, `**`, `?`),\n * character classes, brace expansion, extglob prefixes (`?( )`, `*( )`, `+( )`, `@( )`, `!( )`), and escapes.\n *\n * Segment-start tracking drives the leading-dot guard: at the start of a segment a wildcard must not match a dotfile,\n * so a {@link RegexElement.NotDot} guard is emitted.\n * `isSegmentStart` seeds this state for the fragment, and it is re-armed after every `/` and at each alternative.\n * When `options.dot` is `true`, the guard is suppressed everywhere, so wildcards match dotfiles as ordinary names,\n * and `**` descends into dot directories.\n *\n * The `alt` parameter marks the fragment as the body of an alternation.\n * When set to {@link Char.Pipe} or {@link Char.Comma}, an unescaped separator of that kind becomes a regex `|`,\n * and `**` is treated as two single stars rather than a globstar.\n * Any other occurrence of `|` or `,` is emitted literally.\n *\n * @example\n * ```ts\n * compileFragment('*.ts', true); // (?!\\.)[^/]*\\.ts\n * compileFragment('a,b', false, Char.Comma); // a|b\n * compileFragment('*.ts', true, 0, { dot: true }); // [^/]*\\.ts\n * ```\n *\n * @see globToRegExp\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function compileFragment(glob: string, isSegmentStart: boolean = false, alt: number = 0, options: GlobOptionsInterface = {}): string {\n const { dot = false } = options;\n\n let out = '';\n let index = 0;\n let wasStart = isSegmentStart;\n\n const guard = dot ? '' : RegexElement.NotDot;\n const DS = guard + RegexElement.NotSlash + '+';\n const GLOBSTAR = group(DS + '(?:/' + DS + ')*') + '?';\n\n while (index < glob.length) {\n const char = at(glob, index);\n const nChar = at(glob, index + 1);\n\n if (nChar === Char.LParen && (char === Char.Bang || RegexCloser[char])) {\n const close = findClose(glob, index + 1);\n\n if (char !== Char.Bang) { // ?*+@( ... )\n const end = close === -1 ? glob.length : close; // unclosed → group runs to the end\n const inner = compileFragment(glob.slice(index + 2, end), wasStart, Char.Pipe, options);\n\n out += RegexElement.Open + inner + RegexCloser[char];\n index = end + 1;\n continue;\n }\n\n if (close !== -1) {\n const inner = compileFragment(glob.slice(index + 2, close), wasStart, Char.Pipe, options);\n const tailEnd = segmentEnd(glob, close + 1);\n const tail = compileFragment(glob.slice(close + 1, tailEnd), false, 0, options);\n\n out += group(\n (wasStart ? guard : '') +\n `(?!${ group(inner) + tail + RegexElement.SegBreak })` +\n RegexElement.NotSlashLazy + tail\n );\n\n index = tailEnd;\n continue;\n }\n }\n\n switch (char) {\n case Char.Slash:\n out += RegexElement.Slash;\n index++;\n wasStart = true;\n break;\n\n case Char.Backslash:\n out += index + 1 < glob.length ? lit(glob[index + 1]) : '\\\\\\\\';\n index += 2;\n break;\n\n case Char.Question:\n out += wasStart && !dot ? RegexElement.NotDotSlash : RegexElement.NotSlash;\n index++;\n break;\n\n case Char.Star:\n if (nChar === Char.Star && alt !== Char.Pipe && (index > 0 || isSegmentStart) && isGlobstar(glob, index)) {\n const root = index === 0 && alt === 0 ? RegexElement.AbsRoot : '';\n if (at(glob, index + 2) === Char.Slash) {\n out += root + group(DS + RegexElement.Slash) + '*'; index += 3; wasStart = true;\n } else {\n out += root + GLOBSTAR; index += 2;\n }\n } else {\n out += (wasStart ? guard : '') + RegexElement.NotSlashRun;\n index++;\n }\n break;\n\n case Char.LBrace: {\n const close = braceClose(glob, index);\n\n if (close === -1) {\n out += '\\\\{'; index++;\n } else {\n out += group(compileFragment(glob.slice(index + 1, close), wasStart, Char.Comma, options));\n index = close + 1;\n }\n break;\n }\n\n case Char.LBracket: {\n const [ src, next ] = compileClass(glob, index);\n out += (wasStart && !dot && src !== '\\\\[' ? RegexElement.NotDot : '') + src;\n index = next;\n break;\n }\n\n case Char.Pipe:\n case Char.Comma:\n if (alt === char) { out += RegexElement.Alt; wasStart = isSegmentStart; }\n else out += lit(glob[index]);\n index++;\n break;\n\n default:\n out += lit(glob[index]); index++;\n }\n }\n\n return out;\n}\n\n/**\n * Compiles a glob pattern into an anchored regular expression.\n *\n * @param glob - The glob pattern to compile\n * @param options - Compilation options carrying the regex flags and the dotfile setting\n * @returns A {@link RegExp} anchored with `^` and `$` that matches exactly the paths described by the glob\n *\n * @remarks\n * The entry point of the compiler.\n * It compiles the pattern with {@link compileFragment} starting at a segment boundary, then wraps the result\n * in `^ ... $` so the expression matches a whole path rather than a substring.\n *\n * Supported glob syntax:\n * - `*` - matches any run of characters within a single path segment, never crossing a `/`.\n * - `?` - matches exactly one character within a segment.\n * - `**` - globstar, matching across segment boundaries, spanning any number of intermediate segments.\n * - `[abc]`, `[a-z]`, `[a-zA-Z0-9]` - a character class matching exactly one listed character or range.\n * Multiple ranges combine, and it never matches more than one character.\n * - `[!abc]`, `[^abc]` - a negated character class matching exactly one character not listed.\n * - `{a,b}`, `{a,{b,c}}` - brace alternation, matching any one of the comma-separated alternatives.\n * A brace group with no top-level comma, such as `{abc}`, is treated as the literal text `{abc}`.\n * - `@( ... )` - extglob group matching its `|`-separated alternatives exactly once.\n * - `?( ... )` - extglob group matching zero or one of its alternatives.\n * - `*( ... )` - extglob group matching zero or more of its alternatives.\n * - `+( ... )` - extglob group matching one or more of its alternatives.\n * - `!( ... )` - extglob negation matching anything the alternatives do not.\n * - `\\` - escapes the next character so it is matched literally, so `\\*.js` matches the literal name `*.js`.\n * - `/` - the literal path separator, which segment-relative wildcards never cross.\n *\n * Character classes and `?` always consume exactly one character.\n * To constrain a run of characters, follow the class with `*` (`[ab]*c` allows any run before `c`)\n * or repeat it with an extglob (`+([ab])c` requires every character before `c` to be `a` or `b`).\n *\n * The `!( ... )` negation is single-segment: its body never crosses a `/`, and the guarantee holds when\n * the negation is the last thing in its segment or is followed by a literal tail such as `.ts`.\n * It is not whole-pattern negation - a leading `!` not followed by `(` is matched as a literal `!`.\n *\n * Leading dots are guarded: at the start of a segment,\n * `*`, `?`, `[ ... ]`, and `**` do not match a name that begins with `.` unless the pattern spells the dot out.\n * So `*` matches `env` but not `.env`.\n * To include dotfiles, name the dot explicitly:\n * - `.*` - matches only dotfiles, such as `.env`.\n * - `{.,}*` - matches every name, dotfiles included.\n *\n * Passing {@link GlobOptionsInterface.dot} as `true` lifts the guard for the whole pattern,\n * so plain wildcards match dotfiles, and `**` descends into dot directories - `**\\/*` then matches `.git/config`.\n *\n * @example\n * <caption>Common patterns and what they match</caption>\n * ```text\n * *.{ts,js} x.ts, x.js\n * @(a|b) a, b\n * +(ab) ab, abab (not: '')\n * !(a).js ab.js, x.js (not: a.js)\n * !(*.spec).ts app.ts, index.ts (not: app.spec.ts)\n * !(*.spec|*.test).ts app.ts (not: app.spec.ts, app.test.ts)\n * ```\n *\n * @example\n * <caption>Every file except a spec, recursively - the two most useful forms</caption>\n * ```ts\n * globToRegExp('**\\/!(*.spec).{ts,js}'); // any .ts or .js file whose name does not end in .spec\n * globToRegExp('**\\/!(*.spec.ts)'); // any file at all except those ending in .spec.ts\n * ```\n *\n * @see compileFragment\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function globToRegExp(glob: string, options: GlobOptionsInterface = {}): RegExp {\n return new RegExp('^' + compileFragment(glob, true, 0, options) + '$', options.flags);\n}\n\n/**\n * Builds a predicate that tests a path against a set of include and exclude globs.\n *\n * @param globs - The glob patterns to match against, where a leading `!` marks an exclusion\n * @param options - Compilation options applied to every compiled pattern\n * @returns A predicate returning `true` when `path` is included by the set and excluded by none of it\n *\n * @remarks\n * Each glob is compiled once with {@link globToRegExp} and sorted into an include or exclude list.\n * A leading `!` marks the pattern as an exclusion and is stripped before compilation.\n * A repeated `!` toggles, so `!!pattern` is an inclusion again.\n * A `!` immediately followed by `(` is left in place - it is the extglob negation {@link globToRegExp} handles,\n * not a whole-pattern exclusion.\n *\n * The predicate accepts a path when it is matched by at least one include pattern and by no exclude pattern.\n * When the set contains no include patterns, every path is considered included,\n * so a set of only exclusions matches everything except what it excludes.\n *\n * @example\n * ```ts\n * const isSource = createMatcher([ '**\\/*.ts', '!**\\/*.spec.ts' ]);\n * isSource('src/app.ts'); // true\n * isSource('src/app.spec.ts'); // false - excluded\n * isSource('src/app.js'); // false - not included\n * ```\n *\n * @see globToRegExp\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function createMatcher(globs: Array<string>, options: GlobOptionsInterface = {}): (path: string) => boolean {\n const include: Array<RegExp> = [];\n const exclude: Array<RegExp> = [];\n\n for (let glob of globs) {\n let neg = false;\n while (at(glob, 0) === Char.Bang && at(glob, 1) !== Char.LParen) {\n neg = !neg;\n glob = glob.slice(1);\n }\n\n (neg ? exclude : include).push(globToRegExp(glob, options));\n }\n\n return (path) =>\n (include.length === 0 || include.some(r => r.test(path))) &&\n !exclude.some(r => r.test(path));\n}\n\n/**\n * Walks a directory tree and collects every file the globs match.\n *\n * @param base - The directory the walk starts from and the patterns are matched against\n * @param globs - The glob patterns to match, where a leading `!` marks an exclusion\n * @param options - Compilation options applied to every compiled pattern\n * @returns The matched files as paths relative to `base`, with forward slashes, in the order the walk reaches them\n *\n * @remarks\n * The base is resolved through the shared path cache,\n * and every path below it is built by appending a name to its directory's path.\n * A file therefore costs one string and one {@link createMatcher} test rather than a resolve of its own.\n * The walk is iterative, so a deep tree cannot overflow the stack,\n * and a directory that cannot be read is skipped rather than thrown from.\n * Unless `dot` is set, a name beginning with `.` is skipped before it is tested, which prunes whole trees such as `.git`.\n * A pattern that spells a leading dot, as `.github/**` or `**\\/.cache/*` does, disarms this and lets the walk descend.\n * Symbolic links are not followed, since a link never reports itself as a directory, which is what keeps a link cycle\n * from being walked.\n *\n * @example\n * ```ts\n * collectFiles(cwd(), [ 'src/**\\/*.ts', '!**\\/*.spec.ts' ]);\n * // [ 'src/index.ts', 'src/models/files.model.ts' ]\n * ```\n *\n * @see createMatcher\n * @see GlobOptionsInterface\n *\n * @since 3.0.0\n */\n\nexport function collectFiles(base: string, globs: Array<string>, options: GlobOptionsInterface = {}): Array<string> {\n const root = FrameworkService.resolve(base);\n const matcher = createMatcher(globs, options);\n const dotted = options.dot || globs.some(glob => at(glob, 0) === Char.Dot || glob.includes('/.'));\n\n const files: Array<string> = [];\n const stack: Array<string> = [ '' ];\n\n while (stack.length > 0) {\n const directory = stack.pop()!;\n\n let entries: Array<Dirent>;\n try {\n entries = readdirSync(directory ? join(root, directory) : root, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n if (!dotted && at(entry.name, 0) === Char.Dot) continue;\n const path = directory ? `${ directory }/${ entry.name }` : entry.name;\n\n if (entry.isDirectory()) stack.push(path);\n else if (matcher(path)) files.push(path);\n }\n }\n\n return files;\n}\n","/**\n * Imports\n */\n\nimport { Char } from '@constants/char.constant';\n\n/**\n * Regular-expression fragments emitted while compiling a glob into a {@link RegExp} source.\n *\n * @remarks\n * Each member is a reusable snippet of regex syntax with a fixed meaning in the compiled output,\n * so the compiler can assemble a pattern by concatenating members rather than repeating string literals.\n * Declared as a `const enum` so references inline to their literal value at compile time.\n *\n * @example\n * ```ts\n * RegexElement.NotDot + RegexElement.NotSlashRun; // '(?!\\\\.)[^/]*' - the source for a leading `*`\n * ```\n *\n * @see RegexCloser\n * @since 3.0.0\n */\n\nexport const enum RegexElement {\n /**\n * The alternation separator `|`.\n *\n * @since 3.0.0\n */\n\n Alt = '|',\n\n /**\n * The opening of a non-capturing group `(?:`.\n *\n * @since 3.0.0\n */\n\n Open = '(?:',\n\n /**\n * The literal path separator `/`.\n *\n * @since 3.0.0\n */\n\n Slash = '/',\n\n /**\n * A zero-width guard `(?!\\.)` that forbids a leading dot at the start of a segment.\n *\n * @remarks\n * Prevents a wildcard from matching a dotfile unless the pattern names the dot explicitly.\n *\n * @since 3.0.0\n */\n\n NotDot = '(?!\\\\.)',\n\n /**\n * A single character class `[^/]` matching any one character except the path separator.\n *\n * @since 3.0.0\n */\n\n NotSlash = '[^/]',\n\n /**\n * A segment boundary `(?:$|/)` matching either the end of the string or a slash.\n *\n * @since 3.0.0\n */\n\n SegBreak = '(?:$|/)',\n\n /**\n * A greedy run `[^/]*` of characters that are not the path separator.\n *\n * @since 3.0.0\n */\n\n NotSlashRun = '[^/]*',\n\n /**\n * A single character class `[^./]` matching any one character except `.` or `/`.\n *\n * @remarks\n * Emitted for `?` at the start of a segment, where a leading dot must not match.\n *\n * @since 3.0.0\n */\n\n NotDotSlash = '[^./]',\n\n /**\n * A lazy run `[^/]*?` of characters that are not the path separator.\n *\n * @remarks\n * Used as the body of a negation so the negative lookahead governs how much the segment consumes.\n *\n * @since 3.0.0\n */\n\n NotSlashLazy = '[^/]*?',\n\n /**\n * An optional absolute-path root `(?:[A-Za-z]:)?/?` matching a Windows drive prefix and/or a leading slash.\n *\n * @remarks\n * Emitted before a leading globstar so a relative pattern such as `**\\/*.ts` also matches an absolute path\n * like `/a/b/c.ts` or `C:/a/b/c.ts`.\n * Both parts are optional, so a purely relative path still matches.\n * Path separators are assumed to be forward slashes, so normalize Windows backslashes before testing.\n *\n * @since 3.0.0\n */\n\n AbsRoot = '(?:[A-Za-z]:)?/?',\n}\n\n/**\n * Maps an extglob prefix character to the regex closer that ends its non-capturing group.\n *\n * @remarks\n * Keyed by the {@link Char} code unit that precedes a `(` in an extglob construct,\n * the value carries the group-closing parenthesis together with the quantifier that reproduces the prefix semantics.\n * - `@( ... )` matches the group exactly once.\n * - `+( ... )` matches the group one or more times.\n * - `*( ... )` matches the group zero or more times.\n * - `?( ... )` matches the group zero or one time.\n * The presence of a key also signals that the prefix opens an extglob group,\n * so the compiler tests membership before treating the character as extglob syntax.\n *\n * @example\n * ```ts\n * RegexCloser[Char.Plus]; // ')+' - so `+(ab)` compiles to `(?:ab)+`\n * RegexCloser[Char.Bang]; // undefined - `!(` is a negation, handled apart\n * ```\n *\n * @see Char\n * @see RegexElement\n *\n * @since 3.0.0\n */\n\nexport const RegexCloser: Record<number, string> = {\n [Char.At]: ')',\n [Char.Plus]: ')+',\n [Char.Star]: ')*',\n [Char.Question]: ')?'\n} as const;\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { PartialMessage } from 'esbuild';\nimport type { SourceService } from '@remotex-labs/xmap';\nimport type { ParsedStackTraceInterface } from '@remotex-labs/xmap/parser.component';\nimport type { StackTraceInterface, ResolveMetadataInterface } from '@providers/interfaces/stack-provider.interface';\n\n/**\n * Imports\n */\n\nimport { inject } from '@remotex-labs/xinject';\nimport { FilesModel } from '@models/files.model';\nimport { resolveError } from '@remotex-labs/xmap';\nimport { xterm } from '@remotex-labs/xansi/xterm.component';\nimport { FrameworkService } from '@services/framework.service';\nimport { parseErrorStack } from '@remotex-labs/xmap/parser.component';\nimport { formatErrorCode } from '@remotex-labs/xmap/formatter.component';\nimport { highlightCode } from '@remotex-labs/xmap/highlighter.component';\n\n/**\n * Returns a source resolver for a file, from its source map when one is registered and from its cached text otherwise.\n *\n * @param fileName - Path of the file a stack frame points at, relative or absolute\n * @returns The resolver for that file, or `null` when the file has neither a map nor cached text\n *\n * @remarks\n * A registered map wins since it resolves back to the authored file rather than to the emitted one.\n * Without a map the cached text stands in through a minimal resolver that slices the surrounding lines as its\n * code window, so an unmapped file still prints a snippet.\n * That window spans three lines either side unless the caller asks for a different span and is clamped to the\n * bounds of the file.\n * `startLine` and `endLine` come back as 1-based line numbers rather than as indexes into the text,\n * which is how {@link formatErrorCode} reads them, so a printed number labels the line it belongs to.\n * The line passes through as it arrived, while the column comes back one higher than it was given.\n *\n * @example\n * ```ts\n * getSource('dist/index.js'); // SourceService - the registered map\n * getSource('src/index.ts')?.getPositionWithCode(10, 4); // line 10, column 5, lines 7-13 as code\n * getSource('missing.ts'); // null\n * ```\n *\n * @see SourceService\n * @see FilesModel.touch\n * @see FrameworkService.getSourceMap\n *\n * @since 2.0.0\n */\n\nexport function getSource(fileName: string = ''): SourceService | null {\n const framework = inject(FrameworkService);\n const mapped = framework.getSourceMap(fileName);\n if (mapped) return mapped;\n\n const snapshot = inject(FilesModel).touch(fileName);\n const code = snapshot.snapshot?.text;\n\n if (!snapshot || !code) return null;\n const lines = code.split('\\n');\n\n return {\n getPositionWithCode: (line, column, _bias, options) => {\n const after = options?.linesAfter ?? 3;\n const before = options?.linesBefore ?? 3;\n\n // both bounds are 1-based line numbers, so only the slice start converts to an index\n const startLine = Math.max(line - before, 1);\n const endLine = Math.min(line + after, lines.length);\n\n return {\n line,\n name: null,\n code: lines.slice(startLine - 1, endLine).join('\\n'),\n source: fileName,\n column: column,\n endLine,\n startLine,\n sourceRoot: null,\n sourceIndex: -1,\n generatedLine: -1,\n generatedColumn: -1\n };\n }\n } as SourceService;\n}\n\n/**\n * Brings an error and an esbuild message to the same shape - a name, a message, and a list of frames.\n *\n * @param raw - Thrown error, or the message esbuild reported for a failed build\n * @returns The parsed trace, with an empty frame list when there is nothing to point at\n *\n * @remarks\n * An `Error` is parsed from its own stack text, whether it arrives on its own or wrapped as the `detail` of an\n * esbuild message.\n * A plain esbuild message carries no stack, so its location becomes the single frame of the trace, flagged as\n * ordinary code: not eval, not async, not native, and not a constructor call.\n * A message without a location resolves to no frames at all, which leaves the caller with the text alone.\n *\n * @example\n * ```ts\n * getErrorStack(new Error('boom')).stack.length; // 12 - frames parsed from error.stack\n *\n * getErrorStack({ text: 'Unexpected token', location: { file: 'src/index.ts', line: 4, column: 2 } }).stack;\n * // [ { source: '@src/index.ts', fileName: 'src/index.ts', line: 4, column: 2, ... } ]\n *\n * getErrorStack({ text: 'Could not resolve module' }).stack; // []\n * ```\n *\n * @see parseErrorStack\n * @see ParsedStackTraceInterface\n *\n * @since 2.0.0\n */\n\nexport function getErrorStack(raw: Partial<PartialMessage> | Error): ParsedStackTraceInterface {\n if (raw instanceof Error) return parseErrorStack(raw);\n if (raw.detail instanceof Error) return parseErrorStack(raw.detail);\n\n if (!raw.location) {\n return { stack: [], name: 'esBuildMessage', message: raw.text ?? '', rawStack: '' };\n }\n\n return {\n name: 'esBuildMessage',\n message: raw.text ?? '',\n rawStack: '',\n stack: [\n {\n source: `@${ raw.location.file }`,\n line: raw.location.line,\n column: raw.location.column || 1,\n fileName: raw.location.file,\n eval: false,\n async: false,\n native: false,\n constructor: false\n }\n ]\n };\n}\n\n/**\n * Resolves an error back to its authored sources and picks the code window to print with it.\n *\n * @param raw - Thrown error, or the message esbuild reported for a failed build\n * @param options - Frame selection and code window size, as {@link resolveError} takes them\n * @param verbose - Whether native frames stay in the resolved stack\n * @returns The resolved trace, carrying `formatCode` when a frame supplied a code window\n *\n * @remarks\n * Every frame resolves through {@link getSource}, so a mapped frame points at the authored file and an unmapped\n * one falls back to the cached text of the emitted file.\n * `verbose` and `withFrameworkFrames` each admit native frames to the stack, while `withFrameworkFrames` alone\n * decides whether a framework frame may supply the code window.\n * The window is taken from the first frame that carries code, highlighted and marked at that position, and is\n * left unset when no frame carries any - a resolve against sources that are gone prints as a bare trace.\n *\n * @example\n * ```ts\n * const metadata = getErrorMetadata(error, { linesBefore: 2, linesAfter: 2 });\n * metadata.stack[0].format; // 'at run src/index.ts:12:8'\n * metadata.formatCode; // lines 10-14, highlighted, with column 8 marked in bright pink\n * ```\n *\n * @see resolveError\n * @see getErrorStack\n * @see StackTraceInterface\n * @see ResolveMetadataInterface\n *\n * @since 3.0.0\n */\n\nexport function getErrorMetadata(raw: PartialMessage | Error, options?: StackTraceInterface, verbose: boolean = false): ResolveMetadataInterface {\n const framework = inject(FrameworkService);\n const parsed = getErrorStack(raw);\n const resolved: ResolveMetadataInterface = resolveError(parsed, {\n ...options,\n withNativeFrames: verbose || (options?.withFrameworkFrames ?? false),\n getSource(path: string): SourceService | null {\n return getSource(path);\n }\n });\n\n resolved.stack.filter(frame => {\n if (!(options?.withFrameworkFrames ?? false) && framework.isFrameworkFile(frame)) return false;\n if(!resolved.formatCode && frame.code) {\n resolved.formatCode = formatErrorCode(\n {\n code: highlightCode(frame.code),\n line: frame.line ?? 1,\n column: frame.column ?? 1,\n startLine: frame.stratLine ?? 1\n },\n { color: xterm.brightPink }\n );\n }\n });\n\n return resolved;\n}\n\n/**\n * Renders resolved metadata as the block that gets printed to the terminal.\n *\n * @param metadata - Resolved trace, as {@link getErrorMetadata} returns it\n * @param name - Name to head the block with, such as `TypeError` or `esBuildMessage`\n * @param message - Message to head the block with\n * @param notes - Extra lines esbuild attached to the message, printed in gray under the heading\n * @returns The block, ready to write as-is\n *\n * @remarks\n * The heading is always written, the code window and the trace only when the metadata holds them, so an error\n * resolved against missing sources still prints as a single readable line.\n * Coloring of the window and of each frame is left as {@link getErrorMetadata} produced it - nothing here is\n * highlighted a second time.\n *\n * @example\n * ```ts\n * formatStack(metadata, 'TypeError', 'x is not a function');\n * //\n * // TypeError: x is not a function\n * //\n * // 11 | x();\n * // | ^\n * //\n * // Enhanced Stack Trace:\n * // at run src/index.ts:11:2\n * ```\n *\n * @see xterm\n * @see getErrorMetadata\n * @see ResolveMetadataInterface\n *\n * @since 2.0.0\n */\n\nexport function formatStack(metadata: ResolveMetadataInterface, name: string, message: string, notes: PartialMessage['notes'] = []): string {\n const parts = [ `\\n${ name }: ${ xterm.lightCoral(message) }` ];\n for (const note of notes ?? []) {\n if(note.text) parts.push('\\n ' + xterm.gray(note.text));\n }\n\n if (metadata.formatCode) parts.push(`\\n\\n${ metadata.formatCode }`);\n if (metadata.stack.length) {\n parts.push(`\\n\\nEnhanced Stack Trace:\\n ${ metadata.stack.map(stack => stack.format).join('\\n ') }\\n`);\n }\n\n return parts.join('');\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { ModuleResolutionCache, SourceFile } from 'typescript';\nimport type { LanguageService, Diagnostic, Program } from 'typescript';\nimport type { EmitAndSemanticDiagnosticsBuilderProgram } from 'typescript';\nimport type { CacheEntryInterface } from './interfaces/typescript-service.interface';\nimport type { ParsedCommandLine, BuilderProgramHost, ReadBuildProgramHost } from 'typescript';\nimport type { DiagnosticInterface, ResolvedModuleInterface } from './interfaces/typescript-service.interface';\n\n/**\n * Imports\n */\n\nimport ts from 'typescript';\nimport { Injectable } from '@remotex-labs/xinject';\nimport { normalize, relative, dirname } from '@remotex-labs/xmap';\nimport { DeclarationModel } from '@typescript/models/declaration.model';\nimport { LanguageHostService } from '@typescript/services/host.service';\n\n/**\n * One TypeScript project, wrapping its language service, module resolution, and declaration emit.\n *\n * @remarks\n * Everything a build needs from TypeScript comes through here:\n *\n * - **Diagnostics** - {@link check}\n * - **Declaration files** - {@link emit} and {@link emitBundle}\n * - **Specifier resolution** - {@link resolve}\n *\n * Each configuration file gets one shared instance, reference counted,\n * so several consumers naming the same `tsconfig.json` share one language service,\n * and the last {@link dispose} tears it down.\n * The parse forces `emitDeclarationOnly` on,\n * since this asks the compiler for types alone while the bundler produces the JavaScript.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService, 'tsconfig.json');\n *\n * service.check(); // [] - the project type-checks\n * await service.emit({ index: 'src/index.ts' }); // [ 'D:/app/dist/index.d.ts' ]\n * service.dispose(); // released - torn down once nothing else holds it\n * ```\n *\n * @see DeclarationModel\n * @see LanguageHostService\n *\n * @since 2.0.0\n */\n\n@Injectable({\n factory(path?: string): TypescriptService {\n return TypescriptService.acquire(path);\n }\n})\nexport class TypescriptService {\n /**\n * The language service this project's queries run against.\n *\n * @remarks\n * Backed by {@link languageHostService} and a document registry,\n * so the syntax trees of shared files survive between requests.\n *\n * @example\n * ```ts\n * service.languageService.getProgram()?.getSourceFiles().length; // 214\n * ```\n *\n * @since 2.0.0\n */\n\n readonly languageService: LanguageService;\n\n /**\n * The host the language service reads files and versions through.\n *\n * @remarks\n * Exposed because it owns the tracked file set, which is what decides the program's file list.\n *\n * @example\n * ```ts\n * service.languageHostService.tracked.size; // grows as the language service resolves imports\n * ```\n *\n * @see LanguageHostService\n * @since 2.0.0\n */\n\n readonly languageHostService: LanguageHostService;\n\n /**\n * The live instances, keyed by their normalized configuration path.\n *\n * @remarks\n * Static, so sharing spans the whole process rather than one injector,\n * and each entry carries the reference count that decides when its language service is torn down.\n *\n * @see acquire\n * @since 3.0.0\n */\n\n private static readonly cache = new Map<string, CacheEntryInterface>();\n\n /**\n * The diagnostics of every file checked so far, keyed by the file name the compiler reported.\n *\n * @remarks\n * Only the affected files are recomputed on a {@link check},\n * so the untouched entries here are what makes the result whole-project rather than only-what-changed.\n * The key is the absolute path the compiler reported,\n * so a caller's own names are resolved before they are read back.\n *\n * @see reconcileDiagnostics\n * @since 3.0.0\n */\n\n private readonly diagnosticsCache = new Map<string, Array<DiagnosticInterface>>();\n\n /**\n * The host the builder program reads through.\n *\n * @remarks\n * Routes every read to {@link languageHostService},\n * so the builder sees the same cached content the language service does\n * rather than reaching the disk a second time and disagreeing with it.\n *\n * @since 3.0.0\n */\n\n private readonly builderHost: ReadBuildProgramHost & BuilderProgramHost = {\n createHash: ts.sys.createHash,\n readFile: (file: string, encoding?: BufferEncoding): string | undefined =>\n this.languageHostService.readFile(file, encoding),\n getCurrentDirectory: (): string => ts.sys.getCurrentDirectory(),\n useCaseSensitiveFileNames: (): boolean => ts.sys.useCaseSensitiveFileNames\n };\n\n /**\n * The declaration cache and emitter bound to this project.\n *\n * @remarks\n * Constructed with this service, whose {@link resolve} is what decides which specifiers name project files.\n *\n * @see DeclarationModel\n * @since 3.0.0\n */\n\n private readonly declaration: DeclarationModel;\n\n /**\n * The configuration currently in force, replaced whenever the file behind it is reparsed.\n *\n * @see parseConfig\n * @since 3.0.0\n */\n\n private parsedConfig: ParsedCommandLine;\n\n /**\n * The snapshot version of the configuration file behind the current parse.\n *\n * @remarks\n * Taken from the shared file model, which advances a version whenever the watcher re-reads a file that changed,\n * so comparing it against the version the model now holds tells {@link reload} whether anything needs reparsing.\n *\n * @see reload\n * @since 3.0.0\n */\n\n private configVersion: number;\n\n /**\n * The cache backing {@link resolve}, rebuilt whenever the compiler options change.\n *\n * @see createResolutionCache\n * @since 3.0.0\n */\n\n private resolutionCache: ModuleResolutionCache;\n\n /**\n * The builder program of the last {@link check}, carried forward, so the next check only revisits what changed.\n *\n * @remarks\n * Absent before the first check and after a {@link reload}, either of which makes the next check a full pass.\n *\n * @since 3.0.0\n */\n\n private builder?: EmitAndSemanticDiagnosticsBuilderProgram;\n\n /**\n * Creates a service for one configuration file.\n *\n * @param configPath - Path of the `tsconfig.json` to run against\n *\n * @remarks\n * Prefer injecting the service, which shares and reference counts instances per configuration path.\n * An instance built here stays outside the shared cache, so nothing else can reach it,\n * and {@link dispose} has no hold of its own to release.\n * A configuration that cannot be read does not throw - {@link parseConfig} falls back to a built-in default.\n *\n * @example\n * ```ts\n * const service = new TypescriptService('tsconfig.build.json');\n * service.config.options.emitDeclarationOnly; // true - forced on regardless of the file\n * ```\n *\n * @see acquire\n * @since 3.0.0\n */\n\n constructor(readonly configPath: string = 'tsconfig.json') {\n this.parsedConfig = this.parseConfig();\n this.languageHostService = new LanguageHostService(this.parsedConfig);\n this.configVersion = this.languageHostService.filesCache.touch(this.configPath).version;\n this.resolutionCache = this.createResolutionCache();\n this.languageService = ts.createLanguageService(\n this.languageHostService, ts.createDocumentRegistry(true)\n );\n\n this.declaration = new DeclarationModel(this);\n }\n\n /**\n * Reparses the configuration of every shared instance whose file has changed.\n *\n * @param force - Whether every instance reparses regardless of whether its configuration file has moved\n * @returns The configuration paths reparsed by this call, in the order their instances were acquired\n *\n * @remarks\n * This walks the whole shared cache rather than reaching one instance through a holder.\n * A single call after a watch event covers every project in the process,\n * and a configuration several consumers share is reparsed once rather than once per consumer.\n *\n * Each version comes from the shared file model as it stands rather than from disk,\n * since re-reading a changed file is the watcher's part,\n * so an instance whose configuration has not moved costs a map lookup and nothing more.\n *\n * Forcing skips that comparison and reparses every instance\n * that catches a change the configuration file's own version misses, such as an edit to a file it extends.\n * The cost is the state of every project in the process rather than the state of what moved.\n *\n * A change discards everything the old options fed:\n * the file set, the resolution cache, the cached declarations, the cached diagnostics, and the builder program,\n * so the next {@link check} runs as a full pass.\n * An instance the constructor built rather than the cache is never reached here.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService, 'tsconfig.json');\n *\n * TypescriptService.reload(); // [] - nothing has been written since the configuration was read\n * TypescriptService.reload(); // [ 'tsconfig.json' ] - reparsed, and service.config describes the edit\n * TypescriptService.reload(true); // [ 'tsconfig.json' ] - reparsed with nothing written since\n * ```\n *\n * @see check\n * @see acquire\n *\n * @since 3.0.0\n */\n\n static reload(force: boolean = false): Array<string> {\n const reloaded: Array<string> = [];\n for (const [ path, entry ] of TypescriptService.cache) {\n if (entry.instance.refresh(force)) reloaded.push(path);\n }\n\n return reloaded;\n }\n\n /**\n * The parsed configuration this service is running against.\n *\n * @returns The compiler options, file names, and raw configuration currently in force\n *\n * @remarks\n * {@link reload} replaces it wholesale,\n * so a reference taken from here describes the configuration as it stood when it was read.\n *\n * @example\n * ```ts\n * service.config.options.rootDir; // 'D:/app' - defaulted to the working directory when the file omits it\n * service.config.fileNames.length; // 42\n * ```\n *\n * @since 3.0.0\n */\n\n get config(): ParsedCommandLine {\n return this.parsedConfig;\n }\n\n /**\n * Type-checks the project and returns the diagnostics of the files named.\n *\n * @param reachable - Files to report on, as the build reaches them, reporting everything checked when omitted\n * @returns Diagnostics of those files, formatted for reporting\n *\n * @remarks\n * Only the files the builder reports as affected are rechecked,\n * their semantic, syntactic, and suggestion diagnostics replacing what was cached for them,\n * while untouched files keep the diagnostics they already had.\n * That is what makes the result whole-project without rechecking it whole.\n * A file matched by the configuration's `exclude` globs is skipped,\n * and a file that has left the program loses its cached diagnostics\n * rather than reporting them against a file that is no longer there.\n *\n * The check covers the program while the report covers `reachable`,\n * which is what lets several variants share one service:\n * the diagnostics are computed once for whatever changed,\n * and each variant reads back the files its own build reaches at the cost of a lookup per file.\n * Narrowing the check instead would consume a file for the variant that saw it first\n * and leave the next one with nothing to report.\n * Each name is resolved as it is read, so a build's own paths serve as they are, relative or absolute.\n *\n * @example\n * ```ts\n * service.check(); // [ { file: 'src/index.ts', line: 3, column: 7, code: 2322, category: 1, message: '...' } ]\n * service.check(); // [] once the file is fixed and the watcher has refreshed it\n *\n * service.check(context.stage.reachableFiles); // only what this variant's build reaches\n * ```\n *\n * @see DiagnosticInterface\n * @see reconcileDiagnostics\n *\n * @since 3.0.0\n */\n\n check(reachable?: Iterable<string>): Array<DiagnosticInterface> {\n const program = this.languageService.getProgram();\n if (!program) return [];\n\n const ignore = this.languageHostService.ignoreSourceFile;\n const skip = (file: SourceFile): boolean => {\n if(file.fileName.includes('node_modules')) return true;\n\n return ignore(file);\n };\n\n let affected;\n this.builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(program, this.builderHost, this.builder);\n while (affected = this.builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, skip)) {\n if ('fileName' in affected.affected) {\n const file = affected.affected;\n this.diagnosticsCache.set(file.fileName, [\n ...affected.result,\n ...this.builder!.getSyntacticDiagnostics(file),\n ...this.languageService.getSuggestionDiagnostics(file.fileName)\n ].map(diagnostic => this.formatDiagnostic(diagnostic)));\n }\n }\n\n return this.reconcileDiagnostics(program, reachable ?? this.diagnosticsCache.keys());\n }\n\n /**\n * Writes one declaration file per project file the entry points reach.\n *\n * @param entryPoints - Entry files to walk, keyed by the output name each entry itself is written under\n * @param outdir - Directory to write into, defaulting to the configuration's `outDir` and then to `dist`\n * @returns The output paths written by this call, empty when everything was already current\n *\n * @remarks\n * This path always passes a directory on, so `declarationDir` is never consulted.\n * Name it explicitly to write somewhere other than `outDir`.\n * The keys name the entries alone, while the files reached through them keep the layout of the source tree.\n * Declarations come out of this project's program, so the checker writes the types the source leaves out,\n * and a type it cannot write surfaces through {@link check} rather than as a failure to write.\n *\n * @example\n * ```ts\n * await service.emit({ index: 'src/index.ts' }); // [ 'dist/index.d.ts', 'dist/builder.d.ts' ] - absolute\n * await service.emit({ index: 'src/index.ts' }); // [] - nothing changed since\n * await service.emit({ index: 'src/index.ts' }, 'types'); // the same files, written under ./types\n * ```\n *\n * @see emitBundle\n * @since 3.0.0\n */\n\n async emit(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n outdir ??= this.config.options.outDir ?? 'dist';\n\n return this.declaration.emit(entryPoints, outdir);\n }\n\n /**\n * Writes one bundled declaration file per entry point.\n *\n * @param entryPoints - Entry files to bundle, keyed by the output name each is written under\n * @param outdir - Directory to write into, defaulting to the configuration's `outDir` and then to `dist`\n * @returns The output paths written, in the order the entry points were given\n *\n * @remarks\n * Each entry becomes one file carrying the declarations of everything it reaches,\n * so a package ships a single `.d.ts` instead of a tree mirroring its source.\n * The keys name the outputs, with `.d.ts` appended to each,\n * which is the shape the bundler's own entry points take and what keeps two entries of one name apart.\n * Every call rebuilds its bundles rather than reading a cache, so unlike {@link emit} this always writes.\n *\n * @example\n * ```ts\n * await service.emitBundle({ index: 'src/index.ts' }, 'dist'); // [ 'D:/app/dist/index.d.ts' ]\n * ```\n *\n * @see emit\n * @since 3.0.0\n */\n\n async emitBundle(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n outdir ??= this.config.options.outDir ?? 'dist';\n\n return this.declaration.emitBundle(entryPoints, outdir);\n }\n\n /**\n * Re-reads a batch of files so the language service sees their current content.\n *\n * @param files - Paths to refresh, relative or absolute\n *\n * @remarks\n * Each path is tracked as it is refreshed,\n * so naming a file the program has not reached yet adds it rather than passing over it.\n *\n * @example\n * ```ts\n * service.touchFiles([ 'src/index.ts' ]);\n * service.check(); // now reflects what is on disk\n * ```\n *\n * @see LanguageHostService.refreshFiles\n * @since 2.0.0\n */\n\n touchFiles(files: Array<string>): void {\n this.languageHostService.refreshFiles(files);\n }\n\n /**\n * Resolves a specifier the way the type checker resolves it.\n *\n * @param specifier - Module specifier as written in the source\n * @param containingFile - File the specifier was written in, since resolution is relative to its directory\n * @returns The resolved module, or `undefined` when the specifier resolves to nothing\n *\n * @remarks\n * An alias or a `paths` mapping resolves the way the compiler sees it rather than the way Node would,\n * which is what lets the declarations rewrite an alias into a path that still resolves.\n * The result carries two fields beyond what the compiler returns:\n * the directory the specifier resolved against, and the path from that directory to the target.\n * The first resolution attaches both, and the cached entry serves them back.\n * With no containing file, the working directory stands in for it.\n *\n * @example\n * ```ts\n * const module = service.resolve('@components/builder', 'D:/app/src/index.ts');\n *\n * module?.resolvedFileName; // 'D:/app/src/components/builder.ts'\n * module?.relativeFileName; // './components/builder.ts'\n * module?.isExternalLibraryImport; // false - a project file, not a package\n * ```\n *\n * @see ResolvedModuleInterface\n * @since 3.0.0\n */\n\n resolve(specifier: string, containingFile?: string): ResolvedModuleInterface | undefined {\n const container = containingFile ? this.languageHostService.filesCache.resolve(dirname(containingFile)) : process.cwd();\n const dirCache = this.resolutionCache.getOrCreateCacheForDirectory(container);\n const cached = dirCache.get(specifier, undefined)?.resolvedModule;\n if(cached) return cached as ResolvedModuleInterface;\n\n const result = <ResolvedModuleInterface> ts.resolveModuleName(\n specifier, containingFile ?? '', this.parsedConfig.options, this.languageHostService, this.resolutionCache\n ).resolvedModule;\n\n if (result) {\n const path = relative(container, result.resolvedFileName);\n\n result.container = container;\n result.relativeFileName = path.startsWith('.') ? path : `./${ path }`;\n }\n\n return result;\n }\n\n /**\n * Releases this consumer's hold on the shared instance.\n *\n * @remarks\n * The language service is torn down and the instance dropped from the shared cache\n * only once the last holder has released it,\n * so a service several consumers share outlives any one of them.\n * The hold released is the one the shared cache keeps under this service's configuration path,\n * so a release takes effect only on an instance the shared cache holds.\n *\n * @example\n * ```ts\n * const service = inject(TypescriptService);\n *\n * service.dispose(); // released - torn down only if nothing else holds it\n * ```\n *\n * @see acquire\n * @since 3.0.0\n */\n\n dispose(): void {\n const entry = TypescriptService.cache.get(this.configPath);\n if (!entry) return;\n\n entry.refCount--;\n if (entry.refCount > 0) return;\n\n this.languageService.dispose();\n TypescriptService.cache.delete(this.configPath);\n }\n\n /**\n * Releases the service when it leaves a `using` scope.\n *\n * @remarks\n * Delegates to {@link dispose}, so scope-bound and explicit release share one reference count.\n *\n * @example\n * ```ts\n * {\n * using service = inject(TypescriptService);\n * service.check();\n * } // released here\n * ```\n *\n * @see dispose\n * @since 3.0.0\n */\n\n [Symbol.dispose ?? Symbol.for('Symbol.dispose')](): void {\n this.dispose();\n }\n\n /**\n * Returns the shared instance for a configuration path, creating it on the first request.\n *\n * @param path - Path of the `tsconfig.json` the instance runs against\n * @returns The instance for that path, with its reference count raised\n *\n * @remarks\n * The path is normalized before it serves as the key,\n * so the same configuration reached by two spellings is one instance.\n * The instance is constructed with that normalized key,\n * which is what lets a release find its own entry.\n * Reached through the injectable factory rather than called directly.\n *\n * @see dispose\n * @since 3.0.0\n */\n\n private static acquire(path: string = 'tsconfig.json'): TypescriptService {\n const key = normalize(path);\n const entry = TypescriptService.cache.get(key);\n\n if (entry) {\n entry.refCount++;\n\n return entry.instance;\n }\n\n const instance = new TypescriptService(key);\n TypescriptService.cache.set(key, { instance, refCount: 1 });\n\n return instance;\n }\n\n /**\n * Rebuilds everything this instance derives from its compiler options once its configuration file has moved.\n *\n * @param force - Whether the rebuild runs even though the configuration file's version has not moved\n * @returns Whether the configuration was reparsed\n *\n * @remarks\n * Split out of {@link reload}, so the shared cache decides which instance reloads,\n * while the state it rebuilds stays with the instance holding it.\n * The version is the one the shared file model already holds,\n * since re-reading a file that changed is the watcher's part,\n * so this observes a change rather than going looking for one.\n * Forcing drops that guard and rebuilds regardless,\n * which is the only way through for a change the version leaves out.\n * The version is taken and stored either way,\n * so a forced rebuild leaves nothing behind for the next call to mistake for a change.\n *\n * @see reload\n * @since 3.0.0\n */\n\n private refresh(force: boolean = false): boolean {\n const { version } = this.languageHostService.filesCache.touch(this.configPath);\n if (!force && version === this.configVersion) return false;\n\n this.configVersion = version;\n this.parsedConfig = this.parseConfig();\n this.languageHostService.options = this.parsedConfig;\n this.resolutionCache = this.createResolutionCache();\n this.declaration.clear();\n this.diagnosticsCache.clear();\n this.builder = undefined;\n\n return true;\n }\n\n /**\n * Builds the module resolution cache for the current options.\n *\n * @returns A cache keyed the way the language host normalizes paths\n *\n * @remarks\n * Real paths go through the host,\n * so a symlinked file is keyed the same here as in the file cache,\n * and the two cannot disagree about which file a specifier reached.\n *\n * @since 3.0.0\n */\n\n private createResolutionCache(): ModuleResolutionCache {\n return ts.createModuleResolutionCache(\n ts.sys.getCurrentDirectory(),\n path => this.languageHostService.realpath(path),\n this.parsedConfig.options\n );\n }\n\n /**\n * Reads the diagnostics of a set of files out of the cache, dropping whatever no longer belongs to the program.\n *\n * @param program - Program the files are looked up in\n * @param reachable - Files to read, named as the caller has them, relative or absolute\n * @returns The cached diagnostics of those files, in the order they were named\n *\n * @remarks\n * The walk covers the files asked for rather than the cache,\n * so reporting one variant's inputs costs what that variant reaches rather than what the project holds.\n * Each name is resolved before the lookup,\n * since the cache is keyed by the absolute path the compiler reported,\n * while a build names its inputs relative to its own working directory.\n * A file that leaves the program - deleted, excluded, or no longer reached -\n * would otherwise keep reporting the diagnostics it had when it left,\n * since nothing marks it affected once it is gone,\n * so a name the program no longer carries is dropped from the cache as it is read.\n *\n * @since 3.0.0\n */\n\n private reconcileDiagnostics(program: Program, reachable: Iterable<string>): Array<DiagnosticInterface> {\n const files = this.languageHostService.filesCache;\n const result: Array<DiagnosticInterface> = [];\n\n for (const name of reachable) {\n const path = files.resolve(name);\n const diagnostics = this.diagnosticsCache.get(path);\n\n if (!diagnostics) continue;\n if (program.getSourceFile(path)) result.push(...diagnostics);\n else this.diagnosticsCache.delete(path);\n }\n\n return result;\n }\n\n /**\n * Reduces a compiler diagnostic to the shape that reporting consumes.\n *\n * @param diagnostic - Diagnostic as the compiler produced it\n * @returns The message and category, with the position and code when the diagnostic has a location\n *\n * @remarks\n * Chained messages are flattened into one string, and line and column are counted from one rather than from zero,\n * since the compiler counts from zero while every editor and terminal reports from one.\n * A diagnostic with no file - a configuration error, say - carries the message and category alone.\n *\n * @see DiagnosticInterface\n * @since 2.0.0\n */\n\n private formatDiagnostic(diagnostic: Diagnostic): DiagnosticInterface {\n const result: DiagnosticInterface = {\n message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n'),\n category: diagnostic.category\n };\n\n if (diagnostic.file && diagnostic.start !== undefined) {\n const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n result.file = diagnostic.file.fileName;\n result.line = line + 1;\n result.column = character + 1;\n result.code = diagnostic.code;\n }\n\n return result;\n }\n\n /**\n * Reads the configuration file and forces the options this build depends on.\n *\n * @returns The parsed configuration, with the forced options applied\n *\n * @remarks\n * Declaration emit is forced on and source maps off,\n * since this asks the compiler for types alone while the bundler produces the JavaScript.\n * `stripInternal` and `skipLibCheck` follow from that.\n * A configuration that cannot be read yields a built-in default rather than an error,\n * so a project without a `tsconfig.json` still type-checks under sensible settings.\n * `rootDir` falls back to the working directory,\n * without which output paths would follow whichever directory the sources happen to share.\n *\n * @since 2.0.0\n */\n\n private parseConfig(): ParsedCommandLine {\n let config = ts.getParsedCommandLineOfConfigFile(\n this.configPath,\n {\n sourceMap: false,\n skipLibCheck: true,\n stripInternal: true,\n declarationMap: false,\n emitDeclarationOnly: true\n },\n {\n ...ts.sys,\n onUnRecoverableConfigFileDiagnostic: () => {}\n }\n );\n\n if (!config) {\n config = {\n options: {\n strict: true,\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.NodeNext,\n sourceMap: false,\n skipLibCheck: true,\n stripInternal: true,\n declarationMap: false,\n emitDeclarationOnly: true,\n moduleResolution: ts.ModuleResolutionKind.NodeNext\n },\n errors: [],\n fileNames: [],\n projectReferences: undefined\n };\n }\n\n config.options = {\n ...config.options,\n noEmit: true,\n rootDir: config.options?.rootDir ?? process.cwd(),\n isolatedModules: false,\n useCaseSensitiveFileNames: true\n };\n\n return config;\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { TypescriptService } from '@typescript/services/typescript.service';\nimport type { DeclarationEntryInterface } from './interfaces/declaration-model.interface';\nimport type { NamedBindingInterface, ParseContextInterface } from './interfaces/declaration-model.interface';\nimport type { Declaration, Directive, ModuleExportName, Statement, StringLiteral } from '@oxc-project/types';\nimport type { BundleSurfaceInterface, MergedImportInterface } from './interfaces/declaration-model.interface';\nimport type { ExportNamedDeclaration, ImportDeclaration, TSImportEqualsDeclaration } from '@oxc-project/types';\nimport type { ExportAllDeclaration, ExportDefaultDeclaration, ExportDefaultDeclarationKind } from '@oxc-project/types';\n\n/**\n * Imports\n */\n\nimport { existsSync } from 'fs';\nimport { parseSync } from 'oxc-parser';\nimport { inject } from '@remotex-labs/xinject';\nimport { mkdir, writeFile } from 'fs/promises';\nimport { Char } from '@constants/char.constant';\nimport { FilesModel } from '@models/files.model';\nimport { join, dirname, relative } from '@remotex-labs/xmap';\nimport { applyEdits, removeNode } from '@components/transformer.component';\nimport { HeaderDeclarationBundle } from '@typescript/constants/typescript.constant';\n\n/**\n * Builds and caches the declaration of every file a build touches, in both the forms it needs.\n *\n * @remarks\n * Each file is reduced to a {@link DeclarationEntryInterface}: the standalone declaration with its project specifiers\n * resolved, the same text stripped down to inlinable declarations, and the dependency, import, and export records that\n * stripping produced.\n * Declarations are emitted by the project's own program, so the checker writes the types an annotation leaves out,\n * and an entry costs one declaration emit and one parse.\n * Both forms and every record come out of that single parse.\n * Entries are held against the snapshot version of their file,\n * so a file is rebuilt only once the file model has observed the change,\n * and {@link clear} drops the cache when the compiler options behind the entries move.\n * One instance owns one cache,\n * so a build that wants entries shared across its steps passes the model around rather than constructing a second one.\n *\n * @example\n * ```ts\n * const declarations = new DeclarationModel(inject(TypescriptService));\n * const entry = declarations.touch('src/index.ts');\n *\n * entry.content; // 'declare const version: string;\\n'\n * entry.declaration; // the same text, prefixed with its imports\n * entry.projectDependencies; // Set { 'D:/app/src/builder.ts' }\n * declarations.touch('src/index.ts') === entry; // true - unchanged file, cached entry\n * ```\n *\n * @see DeclarationEntryInterface\n * @since 3.0.0\n */\n\nexport class DeclarationModel {\n /**\n * Entries keyed by the resolved absolute path of the file they describe.\n *\n * @remarks\n * Exposed for consumers that walk an already-built graph.\n * Use {@link touch} to build or refresh an entry.\n *\n * @example\n * ```ts\n * declarations.touch('src/index.ts');\n * declarations.cache.size; // 1\n * ```\n *\n * @see DeclarationEntryInterface\n * @since 3.0.0\n */\n\n readonly cache = new Map<string, DeclarationEntryInterface>();\n\n /**\n * Shared file snapshot cache the entries are versioned against.\n *\n * @since 3.0.0\n */\n\n private readonly filesCache = inject(FilesModel);\n\n /**\n * Entry version last written to each output path.\n *\n * @remarks\n * Keyed by output path rather than source path,\n * so emitting into a different directory writes every file again instead of reporting them as already current.\n * What it records is what was written rather than what is on disk,\n * so {@link emit} checks the file is still there before it passes over one,\n * which is what makes an output that something else removed come back on the next run.\n *\n * @since 3.0.0\n */\n\n private readonly emitted = new Map<string, number>();\n\n /**\n * Creates a declaration cache bound to one TypeScript service.\n *\n * @param ts - Service whose module resolution decides which specifiers are project files\n *\n * @example\n * ```ts\n * const declarations = new DeclarationModel(inject(TypescriptService));\n * declarations.cache.size; // 0\n * ```\n *\n * @see TypescriptService\n * @since 3.0.0\n */\n\n constructor(private readonly ts: TypescriptService) {}\n\n /**\n * Drops every cached entry.\n *\n * @remarks\n * Needed when something the declarations depend on has changed without the snapshot versions reflecting it -\n * the compiler options, or the resolution cache behind them.\n * A file whose content changed does not need this, since its entry is rebuilt on the next {@link touch}.\n * The record of what already reached the disk goes with them,\n * so the next call to {@link emit} writes every file again,\n * which is also what a cleaned output directory calls for.\n *\n * @example\n * ```ts\n * declarations.touch('src/index.ts');\n * declarations.clear();\n * declarations.cache.size; // 0\n * ```\n *\n * @see touch\n * @since 3.0.0\n */\n\n clear(): void {\n this.cache.clear();\n this.emitted.clear();\n }\n\n /**\n * Returns the declaration entry of a file, building it only when the cached one is stale.\n *\n * @param path - Filesystem path of the file, relative or absolute\n * @returns The entry describing the file's declarations, dependencies, and exports\n *\n * @remarks\n * The file is tracked through the file model, so a path never seen before is read from the disk once,\n * and a tracked path costs a map lookup.\n * The cached entry is returned whenever its version still matches the file's snapshot version, which only advances\n * when the file model observes a change on disk.\n * A file that is missing or unreadable yields an entry built from empty content rather than throwing.\n *\n * @example\n * ```ts\n * const entry = declarations.touch('src/index.ts');\n * entry.version; // 1\n * declarations.touch('src/index.ts') === entry; // true\n * ```\n *\n * @see clear\n * @see DeclarationEntryInterface\n *\n * @since 3.0.0\n */\n\n touch(path: string): DeclarationEntryInterface {\n const target = this.filesCache.resolve(path);\n const file = this.filesCache.touch(target);\n const cached = this.cache.get(target);\n\n if (cached?.version === file.version) return cached;\n\n const entry = this.build(target, file.version);\n this.cache.set(target, entry);\n\n return entry;\n }\n\n /**\n * Writes one declaration file per project file the entry points reach, skipping what has not changed.\n *\n * @param entryPoints - Entry files to walk, keyed by the output name each entry itself is written under\n * @param outdir - Directory to write into, overriding the configuration's `declarationDir` and `outDir`\n * @returns The output paths written by this call, empty when everything was already current\n *\n * @remarks\n * The walk follows the dependency edges out of each entry, so a project whose `tsconfig.json` lists only its entry\n * points still emits every file those entries reach.\n * Nothing outside the project is emitted, since only project files are edges,\n * and a `.d.ts` input is skipped along with everything only it reaches - it is already a declaration.\n * A key names the output of the entry it is keyed to and of nothing else.\n * The files reached through it keep mirroring the source tree the way `tsc` lays them out:\n * `declarationDir` wins over `outDir`, and the per-file path is taken relative to `rootDir`.\n * A file whose entry was written unchanged since the last call is left alone, so a watch cycle rewrites only what\n * moved.\n *\n * @example\n * ```ts\n * await declarations.emit({ main: 'src/index.ts' }); // [ 'dist/main.d.ts', 'dist/builder.d.ts' ]\n * await declarations.emit({ main: 'src/index.ts' }); // [] - nothing changed\n * await declarations.emit({ main: 'src/index.ts' }, './types'); // the same files, written under ./types\n * ```\n *\n * @see clear\n * @see emitBundle\n *\n * @since 3.0.0\n */\n\n async emit(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n const outputs: Array<string> = [];\n const contents: Array<string> = [];\n const visited = new Set<string>();\n const names = new Map<string, string>();\n\n for (const [ name, entry ] of Object.entries(entryPoints))\n names.set(this.filesCache.resolve(entry), name);\n\n const pending = [ ...names.keys() ];\n while (pending.length > 0) {\n const target = pending.pop()!;\n if (visited.has(target) || target.endsWith('.d.ts')) continue;\n visited.add(target);\n\n const entry = this.touch(target);\n for (const dependency of entry.projectDependencies)\n if (!visited.has(dependency)) pending.push(dependency);\n\n const output = this.outputPath(target, outdir, names.get(target));\n if (this.emitted.get(output) === entry.version && existsSync(output)) continue;\n\n this.emitted.set(output, entry.version);\n outputs.push(output);\n contents.push(entry.declaration);\n }\n\n return this.write(outputs, contents);\n }\n\n /**\n * Bundles every entry point and writes each one to a declaration file of its own.\n *\n * @param entryPoints - Entry files to bundle, keyed by the output name each is written under\n * @param outdir - Directory to write into, overriding the configuration's `declarationDir` and `outDir`\n * @returns The output paths written, in the order the entry points were given\n *\n * @remarks\n * The key names the output rather than the source doing so, `.d.ts` being appended to it, so two entries both\n * called `index.ts` are told apart by the names they were keyed under.\n * A key carrying a directory writes into it, and the directory is created if it is not there.\n * Bundles are always rebuilt, since assembling one from cached entries costs little,\n * and they open with {@link HeaderDeclarationBundle} so a generated file is recognizable as one.\n * With no output directory configured or passed, they land in the working directory.\n *\n * @example\n * ```ts\n * await declarations.emitBundle({ index: 'src/index.ts', 'utils/index': 'src/utils/index.ts' }, 'dist/types');\n * // [ 'D:/app/dist/types/index.d.ts', 'D:/app/dist/types/utils/index.d.ts' ]\n * ```\n *\n * @see emit\n * @since 3.0.0\n */\n\n async emitBundle(entryPoints: Record<string, string>, outdir?: string): Promise<Array<string>> {\n const options = this.ts.config.options;\n const base = this.filesCache.resolve(outdir ?? options.declarationDir ?? options.outDir ?? '.');\n\n return this.write(\n Object.keys(entryPoints).map(name => join(base, `${ name }.d.ts`)),\n Object.values(entryPoints).map(entry => this.bundle(entry))\n );\n }\n\n /**\n * Builds the bundled declaration text of one entry point.\n *\n * @param entry - Filesystem path of the entry file, relative or absolute\n * @returns The complete declaration file content, header included\n *\n * @remarks\n * Nothing is written and nothing is cached beyond the entries themselves, so the same entry can be bundled\n * repeatedly, and each call reflects the files as the cache currently sees them.\n * Declarations are inlined once per file even when several files depend on it, and a dependency cycle is walked\n * once rather than followed around.\n *\n * @see render\n * @since 3.0.0\n */\n\n private bundle(entry: string): string {\n const target = this.filesCache.resolve(entry);\n const node = this.touch(target);\n\n return this.render(this.collectClosure(target, node), this.collectSurface(target, node));\n }\n\n /**\n * Creates the directories of a batch and writes its files concurrently.\n *\n * @param outputs - Absolute output paths to write\n * @param contents - Content of each output, in the same order\n * @returns The written paths, for direct return by callers\n *\n * @remarks\n * Each directory is created once for the whole batch rather than once per file, and an empty batch touches the disk\n * not at all.\n *\n * @since 3.0.0\n */\n\n private async write(outputs: Array<string>, contents: Array<string>): Promise<Array<string>> {\n if (outputs.length < 1) return outputs;\n\n const directories = new Set(outputs.map(output => dirname(output)));\n await Promise.all([ ...directories ].map(directory => mkdir(directory, { recursive: true })));\n await Promise.all(outputs.map((output, index) => writeFile(output, contents[index], 'utf-8')));\n\n return outputs;\n }\n\n /**\n * Maps a source path to the declaration path it is written to.\n *\n * @param source - Resolved absolute path of the source file\n * @param outdir - Directory overriding both configured output directories\n * @param name - Output name to use instead of the one the source implies, carrying no extension\n * @returns The absolute output path\n *\n * @remarks\n * The directory is the first of `outdir`, `declarationDir`, and `outDir` that is set,\n * and the source's own directory only when none of them is.\n * A name replaces everything the source would have decided, `.d.ts` being appended to it, and a name carrying a\n * directory nests the output inside the base.\n * Without one the path mirrors the source tree relative to `rootDir` - the source directory standing in when no\n * `rootDir` is set, which flattens the output the way `tsc` does - and the extension follows the input, so `.ts`\n * and `.tsx` become `.d.ts` while `.mts` and `.cts` keep their module flavor as `.d.mts` and `.d.cts`.\n *\n * @since 3.0.0\n */\n\n private outputPath(source: string, outdir?: string, name?: string): string {\n const { declarationDir, outDir, rootDir } = this.ts.config.options;\n const base = outdir ?? declarationDir ?? outDir;\n const target = base ? this.filesCache.resolve(base) : dirname(source);\n if (name) return join(target, `${ name }.d.ts`);\n\n const root = rootDir ? this.filesCache.resolve(rootDir) : dirname(source);\n\n return join(target, relative(root, source).replace(/\\.([cm]?)tsx?$/, '.d.$1ts'));\n }\n\n /**\n * Collects every project file the entry reaches, dependencies first.\n *\n * @param target - Resolved absolute path of the entry file\n * @param entry - Cache entry of the entry file\n * @returns The entries to inline, in the order their content is concatenated\n *\n * @remarks\n * A depth-first walk over the dependency edges with an explicit stack, so a deep dependency chain cannot overflow\n * the stack, and a visited set, so a cycle terminates, and a shared dependency is inlined once.\n * The entry counts as visited from the start, so a dependency cycling back to it does not inline it twice, and it\n * lands last regardless, which keeps the file the bundle describes at the bottom.\n *\n * @since 3.0.0\n */\n\n private collectClosure(target: string, entry: DeclarationEntryInterface): Array<DeclarationEntryInterface> {\n const visited = new Set<string>([ target ]);\n const closure: Array<DeclarationEntryInterface> = [];\n const pending = [ ...entry.projectDependencies ];\n\n while (pending.length > 0) {\n const dependency = pending.pop()!;\n if (visited.has(dependency)) continue;\n visited.add(dependency);\n\n const node = this.touch(dependency);\n closure.push(node);\n\n for (const nested of node.projectDependencies)\n if (!visited.has(nested)) pending.push(nested);\n }\n\n closure.push(entry);\n\n return closure;\n }\n\n /**\n * Collects the names and re-export statements the bundle exposes.\n *\n * @param target - Resolved absolute path of the entry file\n * @param entry - Cache entry of the entry file\n * @returns The entry's surface, merged with the surface of every project file it star re-exports\n *\n * @remarks\n * Star re-exports of project files are followed transitively, their names becoming the entry's own, while package\n * re-exports are kept as statements and passed straight through.\n * The entry counts as visited from the start, so a star re-export cycling back to it is not walked again.\n * Namespace re-exports of project files are left out: flattening one would mean synthesizing a `declare namespace`\n * around the target's exports, which the inlined fragments do not describe well enough.\n *\n * @see BundleSurfaceInterface\n * @since 3.0.0\n */\n\n private collectSurface(target: string, entry: DeclarationEntryInterface): BundleSurfaceInterface {\n const exports = new Set<string>();\n const statements = new Set<string>();\n const visited = new Set<string>([ target ]);\n const pending = [ entry ];\n\n while (pending.length > 0) {\n const node = pending.pop()!;\n for (const binding of node.projectExports.exports) exports.add(this.clause(binding));\n\n for (const [ module, bindings ] of Object.entries(node.packageExports)) {\n if (bindings.star) statements.add(`export * from '${ module }';`);\n if (bindings.named?.length)\n statements.add(`export { ${ bindings.named.map(binding => this.clause(binding)).join(', ') } } from '${ module }';`);\n\n for (const name of bindings.namespaces ?? []) statements.add(`export * as ${ name } from '${ module }';`);\n }\n\n for (const star of node.projectExports.star) {\n if (visited.has(star)) continue;\n visited.add(star);\n pending.push(this.touch(star));\n }\n }\n\n return { exports, statements };\n }\n\n /**\n * Merges the package imports of every inlined file into one record per module.\n *\n * @param closure - Entries whose content the bundle carries\n * @returns The merged bindings, keyed by module specifier in first-seen order\n *\n * @remarks\n * One pass over the files and their modules folds each module's side effect flag, default binding, namespaces,\n * and named bindings into a single record the bundle can write back as statements.\n *\n * @see MergedImportInterface\n * @since 3.0.0\n */\n\n private mergeImports(closure: Array<DeclarationEntryInterface>): Map<string, MergedImportInterface> {\n const merged = new Map<string, MergedImportInterface>();\n\n for (const node of closure) {\n for (const [ module, bindings ] of Object.entries(node.packageImports)) {\n let entry = merged.get(module);\n if (!entry) merged.set(module, entry = { side: false, named: new Set(), namespaces: new Set() });\n\n if (bindings.side) entry.side = true;\n entry.default ??= bindings.default;\n for (const name of bindings.namespaces ?? []) entry.namespaces.add(name);\n for (const binding of bindings.named ?? []) entry.named.add(this.clause(binding));\n }\n }\n\n return merged;\n }\n\n /**\n * Writes the merged imports back out as import statements.\n *\n * @param merged - Bindings collected per module\n * @returns One statement per import form a module was used with\n *\n * @remarks\n * A module can need several statements: a side effect import, one for each namespace binding,\n * and one carrying its default and named bindings together.\n * Named bindings are sorted, so the same set of files always produces the same bundle.\n *\n * @since 3.0.0\n */\n\n private renderImports(merged: Map<string, MergedImportInterface>): Array<string> {\n const statements: Array<string> = [];\n\n for (const [ module, entry ] of merged) {\n if (entry.side) statements.push(`import '${ module }';`);\n for (const name of entry.namespaces) statements.push(`import * as ${ name } from '${ module }';`);\n\n const clauses: Array<string> = [];\n if (entry.default) clauses.push(entry.default);\n if (entry.named.size > 0) clauses.push(`{ ${ [ ...entry.named ].sort().join(', ') } }`);\n if (clauses.length > 0) statements.push(`import ${ clauses.join(', ') } from '${ module }';`);\n }\n\n return statements;\n }\n\n /**\n * Assembles the finished bundle from its header, imports, inlined content, and exports.\n *\n * @param closure - Entries to inline, dependencies first\n * @param surface - Names and statements the bundle exposes\n * @returns The complete declaration file content\n *\n * @remarks\n * Imports are merged over the whole closure rather than the surface, since every inlined declaration is free to\n * reference them, while the exports come from the surface alone.\n * A bundle that exposes nothing still closes with an empty export clause, without which its declarations would be\n * read as globals rather than as a module.\n *\n * @see HeaderDeclarationBundle\n * @since 3.0.0\n */\n\n private render(closure: Array<DeclarationEntryInterface>, surface: BundleSurfaceInterface): string {\n const parts: Array<string> = [ HeaderDeclarationBundle ];\n const imports = this.renderImports(this.mergeImports(closure));\n if (imports.length > 0) parts.push(...imports, '');\n\n for (const node of closure) {\n const content = node.content.trim();\n if (content) parts.push(content, '');\n }\n\n if (surface.exports.size > 0) parts.push(`export {\\n\\t${ [ ...surface.exports ].sort().join(',\\n\\t') }\\n};`);\n parts.push(...surface.statements);\n if (surface.exports.size < 1 && surface.statements.size < 1) parts.push('export {};');\n\n return `${ parts.join('\\n') }\\n`;\n }\n\n /**\n * Writes a binding the way an import or export clause spells it.\n *\n * @param binding - Name and the alias it was renamed to, if any\n * @returns The bare name, or `name as alias` when the clause renamed it\n *\n * @see NamedBindingInterface\n * @since 3.0.0\n */\n\n private clause(binding: NamedBindingInterface): string {\n return binding.alias ? `${ binding.name } as ${ binding.alias }` : binding.name;\n }\n\n /**\n * Emits the declarations of one file through the project's program.\n *\n * @param target - Resolved absolute path of the file\n * @returns The emitted declaration text, empty when the program reaches the file not at all\n *\n * @remarks\n * The emit runs against the shared program, so the checker supplies whatever an annotation leaves out\n * rather than every exported symbol having to spell its own type.\n * `forceDtsEmit` is what returns the text at all, since the parsed configuration forces `noEmit` on\n * to keep the compiler off the disk the bundler writes to.\n * A path the program has not reached is tracked and the program asked once more,\n * which covers a file the build reaches while `tsconfig.json` neither lists nor includes it.\n * A path its `exclude` globs match stays out even then, and yields no declarations rather than an error.\n *\n * @since 3.0.0\n */\n\n private emitDeclaration(target: string): string {\n const service = this.ts.languageService;\n\n if (!service.getProgram()?.getSourceFile(target)) {\n this.ts.touchFiles([ target ]);\n if (!service.getProgram()?.getSourceFile(target)) return '';\n }\n\n return service.getEmitOutput(target, true, true)\n .outputFiles.find(file => file.name.endsWith('.d.ts'))?.text ?? '';\n }\n\n /**\n * Emits the declarations of one file and reduces them to a cache entry.\n *\n * @param target - Resolved absolute path of the file\n * @param version - Snapshot version the entry is recorded against\n * @returns The freshly built entry\n *\n * @remarks\n * The emitted text is parsed once, and that parse drives everything: the statement walk queues both edit lists and\n * records the graph, and the comment walk that follows it queues the doc comments the stripping orphaned.\n * Emit diagnostics are not surfaced here - a declaration the checker cannot write is reported against the source\n * file itself by {@link TypescriptService.check}.\n *\n * @see strip\n * @see emitDeclaration\n * @see pruneComments\n *\n * @since 3.0.0\n */\n\n private build(target: string, version: number): DeclarationEntryInterface {\n // const declaration = isolatedDeclarationSync(target, source, { stripInternal: true }).code;\n const declaration = this.emitDeclaration(target);\n const context: ParseContextInterface = {\n edits: [],\n target,\n parsed: parseSync(target, declaration, { sourceType: 'module' }),\n content: declaration,\n bundleEdits: [],\n packageImports: Object.create(null),\n packageExports: Object.create(null),\n projectExports: { star: new Set(), exports: [], namespace: Object.create(null) },\n projectDependencies: new Set()\n };\n\n const kept: Array<number> = [];\n const { body } = context.parsed.program;\n\n for (const statement of body)\n if (this.strip(statement, context)) kept.push(statement.start);\n\n this.pruneComments(context, body, kept);\n\n return {\n version,\n content: applyEdits(declaration, context.bundleEdits),\n declaration: applyEdits(declaration, context.edits),\n packageImports: context.packageImports,\n packageExports: context.packageExports,\n projectExports: context.projectExports,\n projectDependencies: context.projectDependencies\n };\n }\n\n /**\n * Dispatches one top-level statement to the handler for its module syntax.\n *\n * @param statement - Statement to strip\n * @param context - Pass the edits are queued against and the bindings recorded on\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * Only top-level statements are visited, since only those can carry module syntax.\n * `export =` and `export as namespace` are dropped without a record: both describe how a module is consumed whole,\n * which a fragment inlined into a bundle can no longer express.\n * Anything that is not module syntax is kept untouched.\n *\n * @since 3.0.0\n */\n\n private strip(statement: Directive | Statement, context: ParseContextInterface): boolean {\n switch (statement.type) {\n case 'ImportDeclaration':\n this.stripImport(statement, context);\n\n return false;\n\n case 'ExportAllDeclaration':\n this.stripStarExport(statement, context);\n\n return false;\n\n case 'ExportNamedDeclaration':\n return this.stripNamedExport(statement, context);\n\n case 'ExportDefaultDeclaration':\n return this.stripDefaultExport(statement, context);\n\n case 'TSImportEqualsDeclaration':\n return this.stripImportEquals(statement, context);\n\n case 'TSExportAssignment':\n case 'TSNamespaceExportDeclaration':\n removeNode(statement, context.content, context.bundleEdits);\n\n return false;\n\n default:\n return true;\n }\n }\n\n /**\n * Removes an `import` statement, recording either a dependency or the package bindings it pulled in.\n *\n * @param statement - Import statement to strip\n * @param context - Pass the deletion is queued against\n *\n * @remarks\n * An import of a project file only contributes an edge, since the target's declarations are inlined,\n * and its bindings are already in scope in the bundle.\n * Everything else is recorded per module, so the bundle can reissue one import statement for it.\n *\n * @see link\n * @since 3.0.0\n */\n\n private stripImport(statement: ImportDeclaration, context: ParseContextInterface): void {\n removeNode(statement, context.content, context.bundleEdits);\n if (this.link(statement.source, context)) return;\n\n const module = context.packageImports[statement.source.value] ??= {};\n if (statement.specifiers.length < 1) {\n module.side = true;\n\n return;\n }\n\n for (const entry of statement.specifiers) {\n switch (entry.type) {\n case 'ImportDefaultSpecifier':\n module.default ??= entry.local.name;\n break;\n\n case 'ImportNamespaceSpecifier':\n (module.namespaces ??= []).push(entry.local.name);\n break;\n\n default:\n (module.named ??= []).push(this.binding(this.nameOf(entry.imported), entry.local.name));\n }\n }\n }\n\n /**\n * Removes an `import x = require('module')` statement the way its ESM equivalent is removed.\n *\n * @param statement - Import-equals statement to strip\n * @param context - Pass the deletion is queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * Only the external-module form names a module.\n * `import A = B.C` aliases a local name and is kept as it stands, since the namespace it reaches into is inlined\n * with the rest of the fragment.\n * A package binding is recorded as a namespace import, which is what `require` binds in type space.\n *\n * @see stripImport\n * @since 3.0.0\n */\n\n private stripImportEquals(statement: TSImportEqualsDeclaration, context: ParseContextInterface): boolean {\n const { moduleReference } = statement;\n if (moduleReference.type !== 'TSExternalModuleReference') return true;\n\n removeNode(statement, context.content, context.bundleEdits);\n const source = moduleReference.expression;\n\n if (!this.link(source, context))\n ((context.packageImports[source.value] ??= {}).namespaces ??= []).push(statement.id.name);\n\n return false;\n }\n\n /**\n * Strips an `export` that carries a declaration, a specifier list, or a re-export clause.\n *\n * @param statement - Named export statement to strip\n * @param context - Pass the edits are queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * A declaration keeps its body and loses only the `export` keyword, so `export declare const x` becomes\n * `declare const x` and stays valid where the fragment lands.\n * A specifier list is removed outright: names re-exported from a project file, or from nothing at all, are recorded\n * as this file's own surface, since the declarations behind them are inlined.\n * Only a clause pointing at a package is recorded as a re-export the bundle has to emit again.\n *\n * @see collectDeclared\n * @since 3.0.0\n */\n\n private stripNamedExport(statement: ExportNamedDeclaration, context: ParseContextInterface): boolean {\n const { exports } = context.projectExports;\n\n if (statement.declaration) {\n this.collectDeclared(statement.declaration, exports);\n context.bundleEdits.push({ start: statement.start, end: statement.declaration.start });\n\n return true;\n }\n\n removeNode(statement, context.content, context.bundleEdits);\n const named = statement.source && !this.link(statement.source, context)\n ? (context.packageExports[statement.source.value] ??= {}).named ??= []\n : exports;\n\n for (const entry of statement.specifiers)\n named.push(this.binding(this.nameOf(entry.local), this.nameOf(entry.exported)));\n\n return false;\n }\n\n /**\n * Removes an `export *` statement, recording the module or project file behind it.\n *\n * @param statement - Star export statement to strip\n * @param context - Pass the deletion is queued against\n *\n * @remarks\n * A star export of a project file becomes an edge plus an entry the bundler follows to collect the names it\n * exposes, whereas a namespace form records the name it is exposed under instead.\n *\n * @see link\n * @since 3.0.0\n */\n\n private stripStarExport(statement: ExportAllDeclaration, context: ParseContextInterface): void {\n removeNode(statement, context.content, context.bundleEdits);\n\n const target = this.link(statement.source, context);\n const exposed = statement.exported ? this.nameOf(statement.exported) : null;\n\n if (target) {\n if (exposed) context.projectExports.namespace[exposed] = target;\n else context.projectExports.star.add(target);\n\n return;\n }\n\n const module = context.packageExports[statement.source.value] ??= {};\n if (exposed) (module.namespaces ??= []).push(exposed);\n else module.star = true;\n }\n\n /**\n * Strips an `export default`, keeping the declaration behind it whenever there is one to keep.\n *\n * @param statement - Default export statement to strip\n * @param context - Pass the edits are queued against\n * @returns Whether the statement survives in the stripped content\n *\n * @remarks\n * A named class, function, or interface keeps its body and is recorded as `Name as default`,\n * with `export default` rewritten to `declare` so the fragment stays a valid ambient declaration.\n * A default export of an identifier is dropped, since the declaration it names is a statement of its own that\n * the fragment already carries.\n * An anonymous default has no binding a bundle could re-export, so it is dropped without a record.\n *\n * @see defaultBinding\n * @since 3.0.0\n */\n\n private stripDefaultExport(statement: ExportDefaultDeclaration, context: ParseContextInterface): boolean {\n const { declaration } = statement;\n const local = this.defaultBinding(declaration);\n if (local) context.projectExports.exports.push({ name: local, alias: 'default' });\n\n if (local && declaration.type !== 'Identifier') {\n context.bundleEdits.push({ start: statement.start, end: declaration.start, text: 'declare ' });\n\n return true;\n }\n\n removeNode(statement, context.content, context.bundleEdits);\n\n return false;\n }\n\n /**\n * Queues the removal of every doc comment the stripping left attached to nothing.\n *\n * @param context - Pass the deletions are queued against\n * @param body - Top-level statements of the file, in source order\n * @param kept - Start offsets of the surviving statements, in source order\n *\n * @remarks\n * Only comments that sit between two top-level statements are judged, so the documentation a surviving declaration\n * carries on its own members is never touched.\n * Such a comment is kept when nothing but whitespace separates it from the next surviving statement.\n * Anything else - a stripped statement between the two, another comment, or a trailing position with no statement\n * after it at all - makes it an orphan.\n * Only `/**` comments are considered, so line comments and plain block comments stay put.\n * Comments and statements are both in source order, so all three are walked together in one pass,\n * and a file with many comments does not cost a scan per comment.\n *\n * @see build\n * @since 3.0.0\n */\n\n private pruneComments(context: ParseContextInterface, body: Array<Directive | Statement>, kept: Array<number>): void {\n const { content, bundleEdits } = context;\n let inner = 0;\n let index = 0;\n\n for (const comment of context.parsed.comments) {\n if (comment.type !== 'Block' || comment.value.charCodeAt(0) !== Char.Star) continue;\n\n while (inner < body.length && body[inner].end <= comment.start) inner++;\n if (inner < body.length && body[inner].start < comment.start) continue;\n\n while (index < kept.length && kept[index] < comment.end) index++;\n if (index < kept.length && this.blank(content, comment.end, kept[index])) continue;\n\n removeNode(comment, content, bundleEdits);\n }\n }\n\n /**\n * Resolves a specifier, recording it as a dependency and rewriting it when it names a project file.\n *\n * @param source - Specifier literal as written in the declaration\n * @param context - Pass the specifier was read from\n * @returns The resolved absolute path, or `null` when the specifier names a package or does not resolve\n *\n * @remarks\n * The one place a specifier is looked at, so the two outputs cannot disagree on which files are inlined.\n * An internal target leaves an edge behind for the bundle and a relative rewrite for the standalone declaration,\n * while a package leaves both untouched.\n * The rewrite names the declaration rather than the source, the resolved extension giving way to `.d.ts`, so an\n * emitted file points at the file emitted beside it rather than at a source that was never shipped.\n * Resolution goes through the TypeScript service, so aliases and `paths` mappings resolve the way the type checker\n * sees them rather than the way Node would, and the path it reports is normalized the way the file cache keys are.\n *\n * @since 3.0.0\n */\n\n private link(source: StringLiteral, context: ParseContextInterface): string | null {\n const resolved = this.ts.resolve(source.value, context.target);\n if (!resolved || resolved.isExternalLibraryImport) return null;\n\n const { extension, relativeFileName, resolvedFileName } = resolved;\n const target = this.filesCache.resolve(resolvedFileName);\n\n context.projectDependencies.add(target);\n context.edits.push({\n end: source.end,\n start: source.start,\n text: `'${ extension ? relativeFileName.slice(0, -extension.length) : relativeFileName }.d.ts'`\n });\n\n return target;\n }\n\n /**\n * Appends the names a declaration binds to the exported surface.\n *\n * @param declaration - Declaration carried by an `export` statement\n * @param names - Bindings the declared names are appended to\n *\n * @remarks\n * A variable statement can bind several names at once, while every other declaration binds at most one.\n * Bindings that are not plain identifiers - a destructured variable, or an ambient module declared by its quoted\n * path - contribute nothing, having no name a bundle could re-export.\n *\n * @since 3.0.0\n */\n\n private collectDeclared(declaration: Declaration, names: Array<NamedBindingInterface>): void {\n if (declaration.type === 'VariableDeclaration') {\n for (const entry of declaration.declarations)\n if (entry.id.type === 'Identifier') names.push({ name: entry.id.name });\n\n return;\n }\n\n if ('id' in declaration && declaration.id && 'name' in declaration.id) names.push({ name: declaration.id.name });\n }\n\n /**\n * Returns the local name a default export binds, when it binds one.\n *\n * @param declaration - Declaration or expression behind `export default`\n * @returns The bound name, or `undefined` for an anonymous or non-binding default\n *\n * @since 3.0.0\n */\n\n private defaultBinding(declaration: ExportDefaultDeclarationKind): string | undefined {\n if (declaration.type === 'Identifier') return declaration.name;\n\n return 'id' in declaration ? declaration.id?.name : undefined;\n }\n\n /**\n * Reads the name out of an import or export clause entry.\n *\n * @param name - Identifier or string literal naming a binding\n * @returns The identifier, or the literal re-quoted so it can be emitted back into a clause\n *\n * @since 3.0.0\n */\n\n private nameOf(name: ModuleExportName): string {\n return 'name' in name ? name.name : JSON.stringify(name.value);\n }\n\n /**\n * Pairs the name a binding carries on the module with its local name.\n *\n * @param name - Name the binding is known by on the other side of the clause\n * @param alias - Local name the clause binds it under\n * @returns The bare name when the two match, and the pair when the clause renamed it\n *\n * @see NamedBindingInterface\n * @since 3.0.0\n */\n\n private binding(name: string, alias: string): NamedBindingInterface {\n return name === alias ? { name } : { name, alias };\n }\n\n /**\n * Reports whether a range of the content holds nothing but whitespace.\n *\n * @param content - Text the range points into\n * @param start - Inclusive start offset of the range\n * @param end - Exclusive end offset of the range\n * @returns `true` when every character in the range is a space, tab, or line break\n *\n * @remarks\n * Scans in place and stops at the first other character, so it costs nothing on the long ranges left behind by\n * stripped statements and allocates no substring on the short ones.\n *\n * @since 3.0.0\n */\n\n private blank(content: string, start: number, end: number): boolean {\n for (let index = start; index < end; index++) {\n const code = content.charCodeAt(index);\n if (code !== Char.Space && code !== Char.Tab && code !== Char.Lf && code !== Char.Cr) return false;\n }\n\n return true;\n }\n}\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { ParseResult } from 'oxc-parser';\nimport type { Span, StringLiteral } from '@oxc-project/types';\nimport type { TypescriptService } from '@typescript/services/typescript.service';\nimport type { SourceEditInterface } from './interfaces/transformer-component.interface';\n\n/**\n * Imports\n */\n\nimport { Char } from '@constants/char.constant';\n\n/**\n * Records an edit that deletes a node along with the rest of its line.\n *\n * @param node - Span of the node to delete, as the parser reported it\n * @param content - Source text the span points into\n * @param edits - Collector the deletion is appended to\n *\n * @remarks\n * The deleted range runs from the start of the node through the spaces and tabs that follow it and one line terminator,\n * so a statement that sat alone on its line does not leave a blank line behind.\n * Anything before the node on that line is kept, since the scan only moves forward from the node's end.\n *\n * @example\n * ```ts\n * const content = \"import 'a';\\nconst x = 1;\";\n * const edits: Array<SourceEditInterface> = [];\n *\n * removeNode({ start: 0, end: 11 }, content, edits);\n * edits; // [ { start: 0, end: 12 } ]\n * applyEdits(content, edits); // 'const x = 1;'\n * ```\n *\n * @see applyEdits\n * @since 3.0.0\n */\n\nexport function removeNode(node: Span, content: string, edits: Array<SourceEditInterface>): void {\n let cursor = node.end;\n\n while (cursor < content.length) {\n const code = content.charCodeAt(cursor);\n if (code !== Char.Space && code !== Char.Tab) break;\n cursor++;\n }\n if (content.charCodeAt(cursor) === Char.Cr) cursor++;\n if (content.charCodeAt(cursor) === Char.Lf) cursor++;\n\n edits.push({ start: node.start, end: cursor });\n}\n\n/**\n * Rewrites the source text with a set of edits applied.\n *\n * @param content - Source text the edits point into\n * @param edits - Edits to apply, sorted in place by start offset\n * @returns The rewritten text, or `content` itself when there is nothing to apply\n *\n * @remarks\n * The edits are ordered by start offset and applied left to right,\n * so a transform can collect them in whatever order it walks the tree.\n * An edit starting inside a range an earlier edit already replaced is dropped rather than merged,\n * which keeps the output well-formed when two passes claim overlapping spans.\n * An edit carrying no `text` deletes its span.\n * The array is sorted in place, so a caller that depends on its original order should pass a copy.\n *\n * @example\n * ```ts\n * applyEdits('const a = 1;', [ { start: 0, end: 5, text: 'let' } ]); // 'let a = 1';\n * applyEdits('const a = 1;', [ { start: 0, end: 6 } ]); // 'a = 1;' - deleted\n * applyEdits('const a = 1;', []); // 'const a = 1;' - returned untouched\n * ```\n *\n * @see SourceEditInterface\n * @since 3.0.0\n */\n\nexport function applyEdits(content: string, edits: Array<SourceEditInterface>): string {\n if (edits.length < 1) return content;\n edits.sort((left, right) => left.start - right.start);\n\n const parts: Array<string> = new Array(edits.length * 2 + 1);\n let index = 0;\n let cursor = 0;\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n if (edit.start < cursor) continue;\n parts[index++] = content.slice(cursor, edit.start);\n parts[index++] = edit.text ?? '';\n cursor = edit.end;\n }\n\n parts[index++] = content.slice(cursor);\n parts.length = index;\n\n return parts.join('');\n}\n\n/**\n * Queues an edit rewriting a specifier to the relative path of the project file it resolves to.\n *\n * @param source - Specifier literal to rewrite, or `null` when the statement carries none\n * @param target - Resolved absolute path of the file the specifier was written in\n * @param edits - Collector the rewrite is appended to\n * @param ts - Service whose module resolution decides what the specifier names\n *\n * @remarks\n * Only a project file is rewritten, so a specifier naming a package or resolving nowhere is left as it was written.\n * So is a statement with no specifier at all, which is what `export { a }` without a `from` clause looks like.\n * The replacement is measured from the importing file's own directory and carries no extension,\n * so an alias or a `paths` mapping becomes a specifier that still resolves once the file no longer sits in the source\n * tree.\n *\n * @example\n * ```ts\n * const edits: Array<SourceEditInterface> = [];\n *\n * rewrite(statement.source, 'D:/app/src/index.ts', edits, ts);\n * edits; // [ { start: 21, end: 43, text: \"'./components/builder.js'\" } ]\n * ```\n *\n * @see resolveSource\n * @since 3.0.0\n */\n\nexport function rewrite(source: StringLiteral | null, target: string, edits: Array<SourceEditInterface>, ts: TypescriptService): void {\n if (!source) return;\n\n const resolved = ts.resolve(source.value, target);\n if (!resolved || resolved.isExternalLibraryImport) return;\n const { extension, relativeFileName } = resolved;\n const path = extension ? relativeFileName.slice(0, -extension.length) : relativeFileName;\n\n edits.push({ end: source.end, start: source.start, text: `'${ path }.js'` });\n}\n\n/**\n * Rewrites every project specifier in a parsed file and returns the text with the rewrites applied.\n *\n * @param parse - Parse of the text, whose spans are offsets into `content`\n * @param target - Resolved absolute path of the file the text belongs to\n * @param content - The text the parse describes, handed back unchanged when it is empty\n * @param ts - Service whose module resolution decides which specifiers name project files\n * @returns The text with every project specifier rewritten, or `content` itself when none was\n *\n * @remarks\n * Only top-level statements are visited, since only those can carry module syntax.\n * An import, an `export *`, and a named export are read for their `from` clause,\n * while `import x = require('m')` is read for its module name.\n * `import A = B.C` names no module, so it is left alone, as is an `export { a }` that carries no `from` clause.\n * Every specifier found goes through {@link rewrite}, so a package stays as it was written,\n * and only a project file is rewritten.\n * The parse and the text have to come from the same source, since the spans are offsets into it - a parse of one text\n * applied to another lands its edits in the wrong places.\n *\n * @example\n * ```ts\n * const content = \"import { build } from '@components/builder';\\nexport const x = 1;\";\n * const parse = parseSync('src/index.ts', content, { sourceType: 'module' });\n *\n * resolveSource(parse, 'D:/app/src/index.ts', content, ts);\n * // \"import { build } from './components/builder';\\nexport const x = 1;\"\n * ```\n *\n * @see rewrite\n * @see applyEdits\n *\n * @since 3.0.0\n */\n\nexport function resolveSource(parse: ParseResult, target: string, content: string = '', ts: TypescriptService): string {\n if(!content) return content;\n const edits: Array<SourceEditInterface> = [];\n\n for (const statement of parse.program.body) {\n switch (statement.type) {\n case 'ImportDeclaration':\n case 'ExportAllDeclaration':\n case 'ExportNamedDeclaration':\n rewrite(statement.source, target, edits, ts);\n break;\n\n case 'TSImportEqualsDeclaration':\n if (statement.moduleReference.type === 'TSExternalModuleReference')\n rewrite(statement.moduleReference.expression, target, edits, ts);\n }\n }\n\n return applyEdits(content, edits);\n}\n\n","/**\n * Header text included at the top of generated declaration bundle files.\n *\n * @remarks\n * This constant provides a standardized header comment prepended to all\n * declaration bundle files generated by the TypeScript module. The header clearly\n * indicates that the file was automatically generated and should not be edited manually.\n *\n * The header serves as:\n * - A warning to developers not to manually modify generated files\n * - Documentation indicating the source of the file\n * - A consistent marker for identifying generated declaration files\n *\n * @example\n * ```ts\n * import { HeaderDeclarationBundle } from './typescript.constant';\n * import { writeFileSync } from 'fs';\n *\n * const bundledContent = `${HeaderDeclarationBundle}\\n${actualDeclarations}`;\n * writeFileSync('dist/index.d.ts', bundledContent);\n * ```\n *\n * @since 1.5.9\n */\n\nexport const HeaderDeclarationBundle = `/**\n * This file was automatically generated by xBuild.\n * DO NOT EDIT MANUALLY.\n */\n`;\n","/**\n * Type-only imports erased during TypeScript compilation.\n */\n\nimport type { FileSnapshotInterface } from '@models/interfaces/files-model.interface';\nimport type { IScriptSnapshot, SourceFile, ParsedCommandLine, CompilerOptions } from 'typescript';\n\n/**\n * Imports\n */\n\nimport ts from 'typescript';\nimport { relative } from '@remotex-labs/xmap';\nimport { inject } from '@remotex-labs/xinject';\nimport { FilesModel } from '@models/files.model';\nimport { createMatcher } from '@components/glob.component';\n\n/**\n * A TypeScript language service host backed by cached file snapshots and the set of files it has tracked.\n *\n * @remarks\n * Satisfies `ts.LanguageServiceHost`, giving the language service its filesystem access, script snapshots, and\n * compiler configuration.\n * Reads and versions are delegated to the shared {@link FilesModel}, while the file set handed over through\n * {@link getScriptFileNames} is maintained here.\n * A path enters the tracked set the first time it is refreshed or its version is queried,\n * so the set grows from the configured entry files to every dependency the language service resolves into them.\n * Paths matched by the configuration's `exclude` globs are skipped by {@link refreshFiles} and reported as ignored\n * to incremental checks through {@link ignoreSourceFile}.\n *\n * @example\n * ```ts\n * const host = new LanguageHostService(parsedConfig); // entry files tracked and read up front\n *\n * host.refresh('src/index.ts'); // re-read and track one file\n * host.getScriptSnapshot('src/index.ts'); // what the language service parses\n * host.options = nextParsedConfig; // swap configuration and re-track from scratch\n * ```\n *\n * @see FilesModel\n * @since 2.0.0\n */\n\nexport class LanguageHostService implements ts.LanguageServiceHost {\n /**\n * Shared model that reads files, caches their snapshots, and tracks their versions.\n *\n * @remarks\n * Registered as a singleton, so every host and build step works against one cache keyed by resolved absolute path.\n *\n * @example\n * ```ts\n * host.filesCache.touch('src/index.ts').version; // 1\n * ```\n *\n * @see FilesModel\n * @since 3.0.0\n */\n\n readonly filesCache = inject(FilesModel);\n\n /**\n * Resolved absolute paths of every file this host has tracked for the language service.\n *\n * @remarks\n * Returned verbatim from {@link getScriptFileNames}.\n * A path is added the first time it is refreshed or its version is queried, then kept even after the file is\n * deleted, so the language service observes the deletion through an empty snapshot rather than a vanishing file.\n *\n * @see track\n * @since 3.0.0\n */\n\n private readonly trackedFiles = new Set<string>();\n\n /**\n * Memoized exclusion verdict per path, keyed by the resolved absolute path.\n *\n * @remarks\n * Exclusion is asked for on every refresh and on every source file an incremental check walks,\n * while the answer only changes with the configuration, so {@link reload} clears this rather than recomputing it.\n *\n * @see isExcluded\n * @since 3.0.0\n */\n\n private readonly exclusions = new Map<string, boolean>();\n\n /**\n * A predicate compiled from the configuration's `exclude` globs, tested against working-directory-relative\n * paths.\n *\n * @remarks\n * Assigned by {@link reload} before any lookup can reach it, hence the definite assignment.\n * It takes a relative path, so {@link isExcluded} is what callers use.\n *\n * @see compileExclude\n * @since 3.0.0\n */\n\n private matches!: (path: string) => boolean;\n\n /**\n * Initializes a new {@link LanguageHostService} from a parsed configuration.\n *\n * @param config - Parsed TypeScript configuration carrying the compiler options, entry file names,\n * and the raw `exclude` globs\n *\n * @remarks\n * Runs {@link reload}, so the entry files are read into the cache and tracked before the host is handed out.\n *\n * @example\n * ```ts\n * const config = ts.getParsedCommandLineOfConfigFile('tsconfig.json', {}, ts.sys as never)!;\n * const host = new LanguageHostService(config);\n * host.getScriptFileNames(); // the configuration's entry files\n * ```\n *\n * @see reload\n * @since 3.0.0\n */\n\n constructor(private config: ParsedCommandLine) {\n this.reload();\n }\n\n /**\n * The live set of resolved paths currently tracked by this host.\n *\n * @returns The tracked set itself, mutated as files are refreshed and cleared\n *\n * @remarks\n * Exposes the same paths as {@link getScriptFileNames} without copying,\n * so a caller can iterate them or feed them straight back into {@link refreshFiles}.\n *\n * @example\n * ```ts\n * host.refresh('src/index.ts');\n * host.tracked.has(host.realpath('src/index.ts')); // true\n * ```\n *\n * @see getScriptFileNames\n * @since 3.0.0\n */\n\n get tracked(): Set<string> {\n return this.trackedFiles;\n }\n\n /**\n * A source-file predicate that incremental checks can use to skip excluded files.\n *\n * @returns A predicate reporting `true` for a source file whose path matches the exclude globs\n *\n * @remarks\n * Bridges the path-based {@link isExcluded} to TypeScript's `ignoreSourceFile` hook by reading the absolute\n * `fileName`, so it agrees with how {@link refreshFiles} filters paths.\n *\n * @example\n * ```ts\n * builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, host.ignoreSourceFile);\n * ```\n *\n * @see refreshFiles\n * @since 3.0.0\n */\n\n get ignoreSourceFile(): (file: SourceFile) => boolean {\n return (file: SourceFile): boolean => this.isExcluded(file.fileName);\n }\n\n /**\n * Replaces the configuration and re-tracks the project from scratch.\n *\n * @param config - The new parsed configuration\n *\n * @remarks\n * Delegates to {@link reload}, so the exclude predicate is recompiled and the new `config.fileNames` replace the\n * tracked set entirely.\n *\n * @example\n * ```ts\n * host.options = ts.getParsedCommandLineOfConfigFile('tsconfig.json', {}, ts.sys as never)!;\n * host.getScriptFileNames(); // the new entry files, nothing carried over\n * ```\n *\n * @see reload\n * @since 3.0.0\n */\n\n set options(config: ParsedCommandLine) {\n this.config = config;\n this.reload();\n }\n\n /**\n * Drops the tracked set and repopulates it from the configured entry files.\n *\n * @remarks\n * The {@link filesCache} snapshots survive, so only membership is reset,\n * and the files are re-read on the way back in through {@link refreshFiles}.\n *\n * @example\n * ```ts\n * host.refresh('src/scratch.ts');\n * host.clearTracked();\n * host.getScriptFileNames(); // back to the configured entry files, scratch.ts dropped\n * ```\n *\n * @see refreshFiles\n * @since 3.0.0\n */\n\n clearTracked(): void {\n this.trackedFiles.clear();\n this.refreshFiles(this.config.fileNames);\n }\n\n /**\n * Rebuilds the exclude predicate and the tracked set from the current configuration.\n *\n * @remarks\n * The single initialization path shared by the constructor and the {@link options} setter:\n * - compiles the `exclude` globs into {@link matches},\n * - drops the memoized {@link exclusions}, whose verdicts belong to the previous globs,\n * - refreshes every entry file through {@link clearTracked}, which reads them into the cache and tracks them.\n *\n * Call it directly when the configuration object was edited in place rather than replaced.\n *\n * @example\n * ```ts\n * host.reload();\n * host.getScriptFileNames(); // what the configuration now selects\n * ```\n *\n * @see clearTracked\n * @since 3.0.0\n */\n\n reload(): void {\n this.matches = this.compileExclude(this.config.raw?.exclude);\n this.exclusions.clear();\n\n this.clearTracked();\n }\n\n /**\n * Re-reads a file from the disk, tracks it, and returns its entry.\n *\n * @param path - File path, relative or absolute\n * @returns The entry for the file, with `version` advanced when the content changed\n *\n * @remarks\n * The path is tracked before the read, so it stays listed even when the file turns out to be gone.\n * Exclusion is not consulted here - {@link refreshFiles} is the caller that filters.\n *\n * @example\n * ```ts\n * const state = host.refresh('src/index.ts');\n * state.version; // 1 at first sight, advanced on every later change\n * state.snapshot?.text; // the content just read\n * ```\n *\n * @see track\n * @since 3.0.0\n */\n\n refresh(path: string): FileSnapshotInterface {\n return this.filesCache.refresh(this.track(path));\n }\n\n /**\n * Refreshes and tracks a batch of files, skipping any path matched by the exclude globs.\n *\n * @param paths - Paths to refresh, defaulting to the currently tracked set\n *\n * @remarks\n * Each retained path goes through {@link refresh} and so becomes tracked.\n * Calling it with no argument brings the already tracked files current, which is what a watch cycle does.\n *\n * @example\n * ```ts\n * host.refreshFiles([ 'src/a.ts', 'src/a.spec.ts' ]); // a.spec.ts skipped when excluded\n * host.refreshFiles(); // re-read everything already tracked\n * ```\n *\n * @see refresh\n * @since 3.0.0\n */\n\n refreshFiles(paths: Array<string> | Set<string> = this.trackedFiles): void {\n for (const path of paths) {\n if (this.isExcluded(path)) continue;\n this.refresh(path);\n }\n }\n\n /**\n * Returns the compiler options currently in force.\n *\n * @returns The active TypeScript compiler options\n *\n * @example\n * ```ts\n * host.getCompilationSettings().target; // ts.ScriptTarget.ES2020\n * ```\n *\n * @since 2.0.0\n */\n\n getCompilationSettings(): CompilerOptions {\n return this.config.options;\n }\n\n /**\n * Reports whether a file exists on disk.\n *\n * @param path - Absolute path\n * @returns `true` when the file exists\n *\n * @remarks\n * Goes straight to `ts.sys`, bypassing the snapshot cache, so it reflects the filesystem as it stands now.\n *\n * @example\n * ```ts\n * host.fileExists('/project/src/index.ts'); // true\n * ```\n *\n * @since 2.0.0\n */\n\n fileExists(path: string): boolean {\n return ts.sys.fileExists(path);\n }\n\n /**\n * Reads file content through the snapshot cache.\n *\n * @param path - File path, relative or absolute\n * @param encoding - Encoding used when the file is read, defaulting to `utf-8`\n * @returns The file content, or `undefined` when the path holds no readable file\n *\n * @remarks\n * Served from the cache once the file has been read, so the encoding only takes effect on the first read of a path.\n *\n * @example\n * ```ts\n * host.readFile('src/index.ts'); // export const x = 10;\n * host.readFile('src/gone.ts'); // undefined\n * ```\n *\n * @see FilesModel.touch\n * @since 3.0.0\n */\n\n readFile(path: string, encoding?: BufferEncoding): string | undefined {\n return this.filesCache.touch(path, encoding).snapshot?.text;\n }\n\n /**\n * Lists the files under a directory that match the given criteria.\n *\n * @param path - Directory to start from\n * @param extensions - File extensions to accept\n * @param exclude - Glob patterns to skip\n * @param include - Glob patterns to keep\n * @param depth - Maximum recursion depth\n * @returns The matching file paths\n *\n * @example\n * ```ts\n * host.readDirectory('src', [ '.ts' ], [ 'node_modules' ], undefined, 2); // [ 'src/index.ts', ... ]\n * ```\n *\n * @since 2.0.0\n */\n\n readDirectory(path: string, extensions?: Array<string>, exclude?: Array<string>, include?: Array<string>, depth?: number): Array<string> {\n return ts.sys.readDirectory(path, extensions, exclude, include, depth);\n }\n\n /**\n * Returns the immediate subdirectories of a path.\n *\n * @param path - Directory to list\n * @returns The subdirectory names\n *\n * @example\n * ```ts\n * host.getDirectories('src'); // [ 'services', 'models' ]\n * ```\n *\n * @since 2.0.0\n */\n\n getDirectories(path: string): Array<string> {\n return ts.sys.getDirectories(path);\n }\n\n /**\n * Reports whether a directory exists.\n *\n * @param path - Absolute path\n * @returns `true` when the directory exists\n *\n * @example\n * ```ts\n * host.directoryExists('src/services'); // true\n * ```\n *\n * @since 2.0.0\n */\n\n directoryExists(path: string): boolean {\n return ts.sys.directoryExists(path);\n }\n\n /**\n * Returns the working directory that relative paths resolve against.\n *\n * @returns The absolute path of the current working directory\n *\n * @example\n * ```ts\n * host.getCurrentDirectory(); // '/project'\n * ```\n *\n * @since 2.0.0\n */\n\n getCurrentDirectory(): string {\n return ts.sys.getCurrentDirectory();\n }\n\n /**\n * Returns the resolved paths of every file tracked by this host.\n *\n * @returns A snapshot array of the tracked absolute paths\n *\n * @remarks\n * This is the program's file set as far as the language service is concerned.\n * A deleted file stays listed, so its removal surfaces as a diagnostic rather than as a silently shrinking program.\n *\n * @example\n * ```ts\n * host.getScriptFileNames(); // [ '/project/src/index.ts', '/project/src/utils.ts' ]\n * ```\n *\n * @see tracked\n * @since 2.0.0\n */\n\n getScriptFileNames(): Array<string> {\n return [ ...this.trackedFiles ];\n }\n\n /**\n * Returns the path of the default lib file matching the given options.\n *\n * @param options - Compiler options, of which `target` decides the lib\n * @returns Absolute path to the matching `lib.*.d.ts`\n *\n * @example\n * ```ts\n * host.getDefaultLibFileName({ target: ts.ScriptTarget.ES2020 }); // '.../lib.es2020.full.d.ts'\n * ```\n *\n * @since 2.0.0\n */\n\n getDefaultLibFileName(options: CompilerOptions): string {\n return ts.getDefaultLibFilePath(options);\n }\n\n /**\n * Returns the version identifier of a file and tracks it.\n *\n * @param path - File path, relative or absolute\n * @returns The version as a string, such as `'1'` or `'2'`\n *\n * @remarks\n * The language service reparses a file only when this string changes, so the value must stay stable while the file\n * does.\n * The read is served from the cache, and {@link refresh} is what moves the version forward.\n *\n * @example\n * ```ts\n * host.getScriptVersion('src/index.ts'); // '1'\n * host.refresh('src/index.ts'); // the file changed on disk\n * host.getScriptVersion('src/index.ts'); // '2' - the language service reparses it\n * ```\n *\n * @see track\n * @since 2.0.0\n */\n\n getScriptVersion(path: string): string {\n return this.filesCache.touch(this.track(path)).version.toString();\n }\n\n /**\n * Returns the script snapshot of a file.\n *\n * @param path - File path, relative or absolute\n * @returns The snapshot, or `undefined` when the path holds no readable file\n *\n * @remarks\n * Reads through the cache, loading from the disk at first sight only.\n * Unlike {@link getScriptVersion}, it leaves the tracked set alone - tracking is driven by version queries.\n *\n * @example\n * ```ts\n * const snapshot = host.getScriptSnapshot('src/index.ts');\n * snapshot?.getText(0, snapshot.getLength()); // export const x = 10;\n * ```\n *\n * @see getScriptVersion\n * @since 2.0.0\n */\n\n getScriptSnapshot(path: string): IScriptSnapshot | undefined {\n return this.filesCache.touch(path).snapshot;\n }\n\n /**\n * Resolves a path to the absolute form used as the tracking and cache key.\n *\n * @param path - File path, relative or absolute\n * @returns The resolved absolute path\n *\n * @remarks\n * Implements the optional `realpath` host hook with the same normalization {@link FilesModel} applies to its cache\n * keys, so the paths reported to TypeScript match the ones tracked here.\n *\n * @example\n * ```ts\n * host.realpath('src/index.ts'); // '/project/src/index.ts'\n * ```\n *\n * @see FilesModel.resolve\n * @since 3.0.0\n */\n\n realpath(path: string): string {\n return this.filesCache.resolve(path);\n }\n\n /**\n * Compiles exclude globs into a matcher over working-directory-relative paths.\n *\n * @param globs - Patterns whose matching paths are excluded, or `undefined` when the configuration has none\n * @returns A predicate reporting `true` for a matched relative path, or one that always reports `false`\n *\n * @remarks\n * The empty case is handled explicitly, since {@link createMatcher} reads an empty pattern list as matching\n * everything, which would exclude the whole project.\n *\n * @see createMatcher\n * @since 3.0.0\n */\n\n private compileExclude(globs?: Array<string>): (path: string) => boolean {\n return globs && globs.length > 0 ? createMatcher(globs) : (): boolean => false;\n }\n\n /**\n * Reports whether a path is excluded by the configuration, memorizing the verdict.\n *\n * @param path - File path as the caller holds it, relative or absolute\n * @returns `true` when the path matches the exclude globs\n *\n * @remarks\n * The path is resolved before the verdict is stored, so the same file reached by two spellings is matched once,\n * and every later lookup of either costs a map read.\n *\n * @see exclusions\n * @since 3.0.0\n */\n\n private isExcluded(path: string): boolean {\n const target = this.filesCache.resolve(path);\n let excluded = this.exclusions.get(target);\n if (excluded === undefined) this.exclusions.set(\n target, excluded = this.matches(relative(process.cwd(), target))\n );\n\n return excluded;\n }\n\n /**\n * Adds a path to the tracked set and returns its resolved key.\n *\n * @param path - File path, relative or absolute\n * @returns The resolved absolute path used as the tracking key\n *\n * @remarks\n * Centralizes the tracking shared by {@link refresh} and {@link getScriptVersion}.\n * A path is added the first time it is seen and never removed,\n * so a deletion leaves a still-listed entry that resolves to an empty snapshot.\n *\n * @see trackedFiles\n * @since 3.0.0\n */\n\n private track(path: string): string {\n const target = this.filesCache.resolve(path);\n this.trackedFiles.add(target);\n\n return target;\n }\n}\n"],"mappings":"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","names":["http","https","extname","readFileSync","server_default","join","inject","Subject","readdir","stat","readFile","cwd","readFileSync","readFileSync","statSync","resolve","Injectable","FilesModel","path","encoding","target","stats","paths","pathList","resolve","info","entry","readFileSync","oldText","newText","oldLength","newLength","max","prefix","suffix","text","start","end","previous","statSync","__decorateClass","Injectable","inject","Injectable","normalize","SourceService","FRAMEWORK_PATH_REGEX","EMPTY_MAPPINGS_REGEX","FrameworkService","normalize","cwd","path","inject","FilesModel","position","source","force","key","readFileSync","error","SourceService","__publicField","__decorateClass","Injectable","ServerModule","config","dir","FrameworkService","Subject","inject","resolve","reject","err","address","req","res","options","readFileSync","join","defaultHandler","error","ext","requestPath","fullPath","stats","stat","fileList","readdir","file","extname","activePath","segments","path","htmlResult","server_default","contentType","data","readFile","Injectable","Subject","join","RegexCloser","lit","char","at","glob","index","isGlobstar","group","body","classEnd","openIndex","scan","lead","findClose","cursor","depth","braceClose","comma","compileClass","end","out","segmentEnd","from","compileFragment","isSegmentStart","alt","options","dot","wasStart","guard","DS","GLOBSTAR","nChar","RegexCloser","close","inner","tailEnd","tail","root","src","next","globToRegExp","createMatcher","globs","include","exclude","neg","path","r","resolve","join","relative","watch","realpathSync","readdirSync","lstatSync","statSync","WatchService","Subject","base","options","resolve","createMatcher","observerOrNext","error","complete","unsubscribe","watcher","batch","path","event","relativePath","relative","link","lstatSync","stats","statSync","type","ignore","recursive","watch","realpathSync","filename","target","join","seg","root","stack","dir","entries","readdirSync","entry","full","__decorateClass","Injectable","inject","resolveError","xterm","parseErrorStack","formatErrorCode","highlightCode","getSource","fileName","mapped","inject","FrameworkService","snapshot","FilesModel","code","lines","line","column","_bias","options","after","before","startLine","endLine","getErrorStack","raw","getErrorMetadata","verbose","framework","parsed","resolved","resolveError","path","frame","xterm","formatStack","metadata","name","message","notes","parts","note","stack","ts","Injectable","normalize","relative","dirname","existsSync","parseSync","inject","mkdir","writeFile","join","dirname","relative","removeNode","node","content","edits","cursor","code","applyEdits","left","right","parts","index","i","edit","HeaderDeclarationBundle","DeclarationModel","ts","inject","FilesModel","path","target","file","cached","entry","entryPoints","outdir","outputs","contents","visited","names","name","pending","dependency","output","existsSync","options","base","join","node","directories","dirname","directory","mkdir","index","writeFile","source","declarationDir","outDir","rootDir","root","relative","closure","nested","exports","statements","binding","module","bindings","star","merged","clauses","surface","parts","HeaderDeclarationBundle","imports","content","service","version","declaration","context","parseSync","kept","body","statement","applyEdits","removeNode","moduleReference","named","exposed","local","bundleEdits","inner","comment","resolved","extension","relativeFileName","resolvedFileName","alias","start","end","code","ts","relative","inject","LanguageHostService","config","inject","FilesModel","file","path","paths","ts","encoding","extensions","exclude","include","depth","options","globs","createMatcher","target","excluded","relative","TypescriptService","configPath","LanguageHostService","ts","DeclarationModel","file","encoding","force","reloaded","path","entry","reachable","program","ignore","skip","affected","diagnostic","entryPoints","outdir","files","specifier","containingFile","container","dirname","cached","result","relative","key","normalize","instance","version","name","diagnostics","line","character","config","__publicField","__decorateClass","Injectable"]}