{"version":3,"file":"retire-zephyr.mjs","names":[],"sources":["../../../../../src/services/scaffold/upgrade-audit/steps/retire-zephyr.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { fileExists, listFiles, readText, writeText } from \"../fs\";\nimport type { StepResult } from \"./author-config\";\n\n/**\n * Strips ZephyrCloud deploy wiring from a v1 child tree. v2 deploys run\n * through the `bos deploy` train (build → bundle upload to the R2-backed\n * store → FastKV publish → image → Railway); the per-build Zephyr hooks\n * and their `reportDeployResult` writes into `bos.config.json` are v1-only\n * machinery. The production URLs currently in the authored descriptor come\n * from the last v1 Zephyr deploys and are replaced by the first v2 deploy.\n *\n * Handles three shapes:\n * - ui/rsbuild.config.ts: statement blocks\n *     `if (shouldDeploy) { plugins.push(withZephyr({ ... })); }`\n *   plus the now-unused integrity import and bos-config path const.\n * - api/plugins rspack configs: conditional default export\n *     `export default shouldDeploy ? withZephyr({ ... }) : baseConfig`\n *   unwrapped to `export default baseConfig`.\n * - package.json deps: `zephyr-rsbuild-plugin` / `zephyr-rspack-plugin`\n *   removed from every workspace package.json and the root catalog.\n *\n * `shouldDeploy` itself is kept where it still gates non-Zephyr behavior\n * (e.g. `devtool: shouldDeploy ? false : \"source-map\"`).\n */\n\nconst ZEPHYR_DEPS = [\"zephyr-rsbuild-plugin\", \"zephyr-rspack-plugin\"] as const;\n\n/** Extracts a balanced-brace block starting at `openIdx` (on \"{\"). */\nconst extractBlock = (source: string, openIdx: number): string | null => {\n  let depth = 0;\n  for (let i = openIdx; i < source.length; i++) {\n    const ch = source[i];\n    if (ch === \"{\") depth++;\n    else if (ch === \"}\") {\n      depth--;\n      if (depth === 0) return source.slice(openIdx, i + 1);\n    }\n  }\n  return null;\n};\n\n/** Removes whole `if (shouldDeploy) { ... withZephyr ... }` statement blocks. */\nconst removeZephyrIfBlocks = (source: string): { next: string; removed: number } => {\n  let next = source;\n  let removed = 0;\n  for (;;) {\n    const ifStart = next.indexOf(\"if (shouldDeploy)\");\n    if (ifStart === -1) break;\n    const blockOpen = next.indexOf(\"{\", ifStart);\n    if (blockOpen === -1) break;\n    const block = extractBlock(next, blockOpen);\n    if (block === null || !block.includes(\"withZephyr\")) break;\n    let end = blockOpen + block.length;\n    if (next[end] === \"\\n\") end += 1;\n    next = (next.slice(0, ifStart) + next.slice(end)).replace(/\\n{3,}/g, \"\\n\\n\");\n    removed += 1;\n  }\n  return { next, removed };\n};\n\n/**\n * Unwraps `export default shouldDeploy ? withZephyr({ ... }) : BASE;` to\n * `export default BASE;`. Locates the ternary colon after the withZephyr\n * call closes (never inside the args object, where `key:` pairs live).\n */\nconst unwrapZephyrTernary = (source: string): { next: string; unwrapped: boolean } => {\n  const marker = source.indexOf(\"export default shouldDeploy\");\n  if (marker === -1) return { next: source, unwrapped: false };\n  const withIdx = source.indexOf(\"withZephyr(\", marker);\n  if (withIdx === -1) return { next: source, unwrapped: false };\n  const callOpen = source.indexOf(\"{\", withIdx);\n  if (callOpen === -1) return { next: source, unwrapped: false };\n  const args = extractBlock(source, callOpen);\n  if (args === null) return { next: source, unwrapped: false };\n  const closeParen = source.indexOf(\")\", callOpen + args.length);\n  if (closeParen === -1) return { next: source, unwrapped: false };\n  const colonIdx = source.indexOf(\":\", closeParen);\n  if (colonIdx === -1) return { next: source, unwrapped: false };\n  const semiIdx = source.indexOf(\";\", colonIdx);\n  if (semiIdx === -1) return { next: source, unwrapped: false };\n  const base = source.slice(colonIdx + 1, semiIdx).trim();\n  if (!base || base.includes(\"withZephyr\")) return { next: source, unwrapped: false };\n  return {\n    next: `${source.slice(0, marker)}export default ${base};${source.slice(semiIdx + 1)}`,\n    unwrapped: true,\n  };\n};\n\nconst stripUnusedImports = (source: string, path: string, notes: string[]): string => {\n  let next = source;\n\n  const zephyrImport = next.match(\n    /import\\s*\\{\\s*withZephyr\\s*\\}\\s*from\\s*\"zephyr-(?:rsbuild|rspack)-plugin\";\\n/,\n  );\n  if (zephyrImport && !next.replace(zephyrImport[0], \"\").includes(\"withZephyr\")) {\n    next = next.replace(zephyrImport[0], \"\");\n    notes.push(`${path}: removed the withZephyr import`);\n  }\n\n  const integrityImport = next.match(\n    /import\\s*\\{([^}]*)\\}\\s*from\\s*\"everything-dev\\/integrity\";\\n/,\n  );\n  if (integrityImport) {\n    const names = integrityImport[1]\n      .split(\",\")\n      .map((n) => n.trim().replace(/\\s+as\\s+\\S+/, \"\"))\n      .filter(Boolean);\n    const withoutImport = next.replace(integrityImport[0], \"\");\n    const allUnused = names.every((name) => !withoutImport.includes(name));\n    if (allUnused) {\n      next = next.replace(integrityImport[0], \"\");\n      notes.push(`${path}: removed the unused everything-dev/integrity import`);\n    }\n  }\n\n  // Drop the shouldDeploy declaration when nothing references it anymore.\n  const declMatch = next.match(/const shouldDeploy = process\\.env\\.DEPLOY === \"true\";\\n/);\n  if (declMatch && !next.replace(declMatch[0], \"\").includes(\"shouldDeploy\")) {\n    next = next.replace(declMatch[0], \"\");\n    notes.push(`${path}: removed the unused shouldDeploy declaration`);\n  }\n\n  // Drop the bos.config.json path helper — reportDeployResult wrote there,\n  // and bos.config.json itself is retired by the v2 authored descriptor.\n  const bosPathMatch = next.match(/const uiBosConfigPath = [^\\n]*;\\n/);\n  if (bosPathMatch && !next.replace(bosPathMatch[0], \"\").includes(\"uiBosConfigPath\")) {\n    next = next.replace(bosPathMatch[0], \"\");\n    notes.push(`${path}: removed the unused uiBosConfigPath declaration`);\n  }\n\n  return next.replace(/\\n{3,}/g, \"\\n\\n\");\n};\n\nconst rewriteBuildConfig = (\n  projectDir: string,\n  path: string,\n  dryRun: boolean,\n  notes: string[],\n): Effect.Effect<boolean, Error> =>\n  Effect.gen(function* () {\n    const exists = yield* fileExists(projectDir, path);\n    if (!exists) {\n      notes.push(`${path} absent — skipped`);\n      return false;\n    }\n    const source = yield* readText(projectDir, path);\n    if (!source.includes(\"withZephyr\")) {\n      notes.push(`${path}: no Zephyr wiring — left untouched`);\n      return false;\n    }\n\n    let next = source;\n\n    const ifBlocks = removeZephyrIfBlocks(next);\n    next = ifBlocks.next;\n    if (ifBlocks.removed > 0) {\n      notes.push(`${path}: removed ${ifBlocks.removed} withZephyr deploy block(s)`);\n    }\n\n    const ternary = unwrapZephyrTernary(next);\n    next = ternary.next;\n    if (ternary.unwrapped) {\n      notes.push(`${path}: unwrapped the shouldDeploy ? withZephyr(...) : base default export`);\n    }\n\n    next = stripUnusedImports(next, path, notes);\n\n    if (next !== source && !dryRun) yield* writeText(projectDir, path, next);\n    return next !== source;\n  });\n\nconst stripZephyrDeps = (\n  projectDir: string,\n  dryRun: boolean,\n  notes: string[],\n): Effect.Effect<string[], Error> =>\n  Effect.gen(function* () {\n    const changed: string[] = [];\n    const pkgPaths = yield* listFiles(\n      projectDir,\n      \"{package.json,ui/package.json,api/package.json,plugins/*/package.json}\",\n    );\n    for (const pkgPath of pkgPaths) {\n      const source = yield* readText(projectDir, pkgPath);\n      const pkg = JSON.parse(source) as {\n        dependencies?: Record<string, string>;\n        devDependencies?: Record<string, string>;\n        workspaces?: { catalog?: Record<string, string> };\n      };\n      let modified = false;\n      for (const dep of ZEPHYR_DEPS) {\n        for (const field of [\"dependencies\", \"devDependencies\"] as const) {\n          if (pkg[field] && dep in pkg[field]) {\n            delete pkg[field][dep];\n            modified = true;\n            notes.push(`${pkgPath}: removed ${dep} from ${field}`);\n          }\n        }\n      }\n      if (pkg.workspaces?.catalog) {\n        for (const dep of ZEPHYR_DEPS) {\n          if (dep in pkg.workspaces.catalog) {\n            delete pkg.workspaces.catalog[dep];\n            modified = true;\n            notes.push(`${pkgPath}: removed ${dep} from the catalog`);\n          }\n        }\n      }\n      if (modified) {\n        if (!dryRun) {\n          yield* writeText(projectDir, pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n        }\n        changed.push(pkgPath);\n      }\n    }\n    return changed;\n  });\n\nexport const retireZephyr = (\n  projectDir: string,\n  dryRun: boolean,\n): Effect.Effect<StepResult, Error> =>\n  Effect.gen(function* () {\n    const writes: string[] = [];\n    const notes: string[] = [\n      \"v2 deploys run through the bos deploy train (bundle upload + FastKV publish + image + Railway) — Zephyr wiring is retired\",\n      \"production URLs in the authored descriptor are from the last v1 Zephyr deploy; the first v2 deploy replaces them\",\n    ];\n\n    const configs = [\"ui/rsbuild.config.ts\", \"api/rspack.config.js\"];\n    const pluginConfigs = yield* listFiles(projectDir, \"plugins/*/rspack.config.js\");\n    for (const path of [...configs, ...pluginConfigs]) {\n      const changed = yield* rewriteBuildConfig(projectDir, path, dryRun, notes);\n      if (changed) writes.push(path);\n    }\n\n    const depChanges = yield* stripZephyrDeps(projectDir, dryRun, notes);\n    writes.push(...depChanges);\n\n    if (writes.length === 0) {\n      notes.push(\"no Zephyr wiring found — nothing to retire\");\n    }\n\n    return { writes, deletes: [], notes };\n  });\n"],"mappings":"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"}