| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import { existsSync, readFileSync } from 'node:fs'; |
| import { extname, join, relative, resolve, sep } from 'node:path'; |
| import { build } from 'esbuild'; |
| |
| const defaultRepoRoot = resolve(import.meta.dirname, '..'); |
| const sourceExtensions = ['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs', '.json']; |
| |
| export const windowsPackageSourceEntrypoints = [ |
| 'packages/runtime/src/filesystem-worker/index.ts', |
| 'packages/runtime/src/filesystem-worker/worker-entry.ts', |
| 'packages/runtime/src/sandbox/index.ts', |
| ]; |
| |
| /** |
| * Workspace sources `entryPoints` reach, transitively, resolved through the |
| * workspace `exports` map back to `src` rather than to built `dist`. Two lanes |
| * derive a path filter from this instead of maintaining one by hand, so a |
| * dependency added anywhere under an entry point cannot escape the filter that |
| * is supposed to schedule the runner able to observe it. |
| * |
| * Static imports only, which is the limit of what "generated, not curated" |
| * buys here: a process boundary is invisible to it. `root-authority.test.ts` |
| * forks `fixtures/root-initialization-race.js` and |
| * `filesystem-worker/worker-entry.ts` is bundled rather than imported, so |
| * neither appears in a closure that starts from them. Both are free of `win32` |
| * today, which is why the filters derived from this are complete — not because |
| * the derivation guarantees it. |
| */ |
| export async function collectWorkspaceSourceClosure(entryPoints, repoRoot = defaultRepoRoot) { |
| const workspaces = loadWorkspacePackages(repoRoot); |
| const result = await build({ |
| absWorkingDir: repoRoot, |
| bundle: true, |
| entryPoints, |
| format: 'esm', |
| logLevel: 'silent', |
| metafile: true, |
| outdir: 'workspace-source-closure', |
| packages: 'external', |
| platform: 'node', |
| plugins: [workspaceSourcePlugin(repoRoot, workspaces)], |
| treeShaking: false, |
| write: false, |
| }); |
| return Object.keys(result.metafile.inputs) |
| .map(normalize) |
| .filter((path) => path.startsWith('packages/')) |
| .sort(); |
| } |
| |
| export function windowsReleasePatternCoversSource(path, pattern) { |
| if (path === pattern) return true; |
| return pattern.endsWith('/**') && path.startsWith(pattern.slice(0, -2)); |
| } |
| |
| function workspaceSourcePlugin(repoRoot, workspaces) { |
| return { |
| name: 'maka-workspace-source', |
| setup(esbuild) { |
| esbuild.onResolve({ filter: /^@maka\// }, ({ path: specifier }) => { |
| const workspace = [...workspaces.values()].find( |
| ({ name }) => specifier === name || specifier.startsWith(`${name}/`), |
| ); |
| if (!workspace) return undefined; |
| const subpath = |
| specifier === workspace.name ? '.' : `.${specifier.slice(workspace.name.length)}`; |
| const exported = exportTarget(workspace.manifest.exports?.[subpath]); |
| const candidate = exported |
| ? resolve(workspace.directory, exported.replace(/^\.\/dist\//u, './src/')) |
| : resolve(workspace.directory, 'src', specifier.slice(workspace.name.length + 1)); |
| return { path: resolveSourceCandidate(candidate, repoRoot, specifier) }; |
| }); |
| }, |
| }; |
| } |
| |
| function resolveSourceCandidate(candidate, repoRoot, specifier) { |
| const extension = extname(candidate); |
| const candidates = [candidate]; |
| if (['.js', '.mjs', '.cjs'].includes(extension)) { |
| const stem = candidate.slice(0, -extension.length); |
| candidates.push(...sourceExtensions.map((sourceExtension) => `${stem}${sourceExtension}`)); |
| } else if (!extension) { |
| candidates.push(...sourceExtensions.map((sourceExtension) => `${candidate}${sourceExtension}`)); |
| candidates.push( |
| ...sourceExtensions.map((sourceExtension) => join(candidate, `index${sourceExtension}`)), |
| ); |
| } |
| const resolved = candidates.find((path) => existsSync(path)); |
| if (!resolved || !normalize(relative(repoRoot, resolved)).startsWith('packages/')) { |
| throw new Error( |
| `Unable to resolve local Windows package import ${specifier} from ${candidate}`, |
| ); |
| } |
| return resolved; |
| } |
| |
| function exportTarget(value) { |
| if (typeof value === 'string') return value; |
| if (!value || typeof value !== 'object') return undefined; |
| for (const condition of ['types', 'import', 'default']) { |
| const target = exportTarget(value[condition]); |
| if (target) return target; |
| } |
| return undefined; |
| } |
| |
| function loadWorkspacePackages(repoRoot) { |
| const rootManifest = JSON.parse(readFileSync(join(repoRoot, 'package.json'), 'utf8')); |
| const result = new Map(); |
| for (const workspacePath of rootManifest.workspaces ?? []) { |
| const directory = resolve(repoRoot, workspacePath); |
| const manifest = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8')); |
| result.set(manifest.name, { directory, manifest, name: manifest.name }); |
| } |
| return result; |
| } |
| |
| function normalize(path) { |
| return path.split(sep).join('/'); |
| } |