import { existsSync, readdirSync, readFileSync } from 'node:fs' import { dirname, join, resolve as resolvePath } from 'node:path' import { pathToFileURL, fileURLToPath } from 'node:url' const root = resolvePath(process.env.NETLIFY_VERIFY_REPO_ROOT || '/tmp/netliloop-work/build') const { default: ts } = await import(pathToFileURL(join(root, 'node_modules/typescript/lib/typescript.js')).href) const workspaces = new Map() for (const dir of readdirSync(join(root, 'packages'))) { const manifestPath = join(root, 'packages', dir, 'package.json') if (!existsSync(manifestPath)) continue const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) workspaces.set(manifest.name, { dir: dirname(manifestPath), manifest }) } const sourceFile = path => { const mapped = path.replace('/lib/', '/src/').replace('/dist/', '/src/') if (existsSync(mapped)) return mapped if (mapped.endsWith('.js') && existsSync(mapped.slice(0, -3) + '.ts')) return mapped.slice(0, -3) + '.ts' } const paths = {} for (const [name, workspace] of workspaces) { const entry = typeof workspace.manifest.exports === 'string' ? workspace.manifest.exports : workspace.manifest.main if (typeof entry !== 'string') continue const source = sourceFile(join(workspace.dir, entry)) if (source) paths[name] = [source] } let program const emitTyped = (file) => { program ??= ts.createProgram([root + '/packages/build/src/plugins/child/main.js', ...Object.values(paths).flat()], { allowJs: true, module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext, target: ts.ScriptTarget.ES2022, paths, noEmitOnError: false, skipLibCheck: true, }) const source = program.getSourceFile(file) if (!source) throw new Error('Source outside compiler graph: ' + file) let output program.emit(source, (name, contents) => { if (name.endsWith('.js')) output = contents }) return output } export async function resolve(specifier, context, nextResolve) { const workspace = workspaces.get(specifier) if (workspace) { const entry = typeof workspace.manifest.exports === 'string' ? workspace.manifest.exports : workspace.manifest.main if (typeof entry === 'string') { const source = sourceFile(join(workspace.dir, entry)) if (source) return { url: pathToFileURL(source).href, shortCircuit: true } } } if (specifier.startsWith('.') && context.parentURL?.startsWith('file:')) { const url = new URL(specifier, context.parentURL) const path = fileURLToPath(url) if (path.startsWith(root + '/packages/')) { const source = sourceFile(path) if (source) return { url: pathToFileURL(source).href, shortCircuit: true } } } return nextResolve(specifier, context) } export async function load(url, context, nextLoad) { if (url.startsWith('file:') && url.endsWith('.ts')) { const source = emitTyped(fileURLToPath(url)) return { format: 'module', source, shortCircuit: true } } return nextLoad(url, context) }