UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

151 lines (149 loc) • 6 kB
const require_fs = require('../fs.cjs'); const require_obsolete_files = require('../obsolete-files.cjs'); let effect = require("effect"); //#region src/services/scaffold/upgrade-audit/steps/apply-manifest.ts const applyRewrites = (projectDir, rewrites, dryRun) => effect.Effect.gen(function* () { const touched = []; for (const rewrite of rewrites) for (const file of rewrite.files) { const source = yield* require_fs.readText(projectDir, file); const next = source.replaceAll(rewrite.from, rewrite.to); if (next !== source) { touched.push(file); if (!dryRun) yield* require_fs.writeText(projectDir, file, next); } } return touched; }); const applyDeletions = (projectDir, dryRun) => effect.Effect.gen(function* () { const removed = []; for (const path of require_obsolete_files.OBSOLETE_FILES) if (yield* require_fs.fileExists(projectDir, path)) { removed.push(path); if (!dryRun) yield* require_fs.removePath(projectDir, path); } return removed; }); const bareSpecifiers = (source) => { const specifiers = []; for (const match of source.matchAll(/(?:import|export)[^"'`]*?from\s*["']([^"']+)["']|import\s*\(\s*["']([^"']+)["']\s*\)|require\s*\(\s*["']([^"']+)["']\s*\)/g)) { const spec = match[1] ?? match[2] ?? match[3]; if (spec && !spec.startsWith(".") && !spec.startsWith("/")) specifiers.push(spec); } return specifiers; }; const packageNameOf = (specifier) => { if (specifier.startsWith("@")) { const [, scope, name] = specifier.split("/"); return scope && name ? `${scope}/${name}` : specifier; } return specifier.split("/")[0]; }; const isProtocolSpecifier = (specifier) => /^[^/]+:/.test(specifier); const memberPackageNames = (projectDir) => effect.Effect.gen(function* () { const pkgPaths = yield* require_fs.listFiles(projectDir, "{package.json,ui/package.json,api/package.json,plugins/*/package.json}"); const names = /* @__PURE__ */ new Set(); for (const pkgPath of pkgPaths) { if (pkgPath === "package.json") continue; const pkg = JSON.parse(yield* require_fs.readText(projectDir, pkgPath)); if (typeof pkg.name === "string") names.add(pkg.name); } return names; }); const declarePluginDeps = (projectDir, dryRun) => effect.Effect.gen(function* () { const catalog = JSON.parse(yield* require_fs.readText(projectDir, "package.json")).workspaces?.catalog ?? {}; const members = yield* memberPackageNames(projectDir); const pluginPkgs = yield* require_fs.listFiles(projectDir, "plugins/*/package.json"); const added = []; const unresolved = []; for (const pkgPath of pluginPkgs) { const pluginDir = pkgPath.slice(0, pkgPath.lastIndexOf("/")); const declared = /* @__PURE__ */ new Set(); const pkg = JSON.parse(yield* require_fs.readText(projectDir, pkgPath)); for (const name of [...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]) declared.add(name); const sources = yield* require_fs.listFiles(projectDir, `${pluginDir}/src/**/*.{ts,tsx}`); const needed = /* @__PURE__ */ new Set(); for (const source of sources) { const text = yield* require_fs.readText(projectDir, source); for (const specifier of bareSpecifiers(text)) { if (isProtocolSpecifier(specifier)) continue; needed.add(packageNameOf(specifier)); } } const nextDeps = { ...pkg.dependencies ?? {} }; let modified = false; for (const name of needed) { if (declared.has(name) || name === pluginDir.split("/")[1]) continue; if (members.has(name)) { added.push(`${pluginDir}: ${name} (workspace:*)`); nextDeps[name] = "workspace:*"; modified = true; continue; } if (!(name in catalog)) { unresolved.push(`${pluginDir}: ${name} (not in catalog — declare manually)`); continue; } added.push(`${pluginDir}: ${name}`); nextDeps[name] = "catalog:"; modified = true; } if (modified && !dryRun) yield* require_fs.writeText(projectDir, pkgPath, `${JSON.stringify({ ...pkg, dependencies: nextDeps }, null, 2)}\n`); } return { added, unresolved }; }); const consumerizeRefs = (projectDir, dryRun) => effect.Effect.gen(function* () { const pkgPaths = yield* require_fs.listFiles(projectDir, "{package.json,ui/package.json,api/package.json,plugins/*/package.json}"); const memberNames = /* @__PURE__ */ new Set(); for (const pkgPath of pkgPaths) { if (pkgPath === "package.json") continue; const pkg = JSON.parse(yield* require_fs.readText(projectDir, pkgPath)); if (typeof pkg.name === "string") memberNames.add(pkg.name); } const fixed = []; for (const pkgPath of pkgPaths) { const pkg = JSON.parse(yield* require_fs.readText(projectDir, pkgPath)); let modified = false; for (const field of [ "dependencies", "devDependencies", "peerDependencies" ]) { const deps = pkg[field]; if (deps === null || typeof deps !== "object") continue; const record = deps; for (const [name, ref] of Object.entries(record)) if (typeof ref === "string" && (ref.startsWith("workspace:") || ref.startsWith("file:")) && !memberNames.has(name)) { record[name] = "catalog:"; modified = true; } } if (modified) { fixed.push(pkgPath); if (!dryRun) yield* require_fs.writeText(projectDir, pkgPath, `${JSON.stringify(pkg, null, 2)}\n`); } } return fixed; }); const applyManifest = (projectDir, rewrites, dryRun) => effect.Effect.gen(function* () { const rewritten = yield* applyRewrites(projectDir, rewrites, dryRun); const deleted = yield* applyDeletions(projectDir, dryRun); const deps = yield* declarePluginDeps(projectDir, dryRun); const refs = yield* consumerizeRefs(projectDir, dryRun); return { writes: rewritten, deletes: deleted, notes: [ ...refs.length > 0 ? [`workspace:/file: refs → catalog: in ${refs.join(", ")}`] : [], ...deps.added.length > 0 ? [`plugin deps added: ${deps.added.join(", ")}`] : [], ...deps.unresolved ] }; }); //#endregion exports.applyManifest = applyManifest; exports.consumerizeRefs = consumerizeRefs; //# sourceMappingURL=apply-manifest.cjs.map