File size: 2,911 Bytes
9299241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/env node
// Builds source-checkout runtime output for externally published first-party plugins.
import fs from "node:fs";
import path from "node:path";
import { performance } from "node:perf_hooks";
import { pathToFileURL } from "node:url";
import { collectSourceCheckoutPluginBuildEntries } from "./lib/bundled-plugin-build-entries.mjs";
import { assertRealOutputRoot } from "./lib/output-root-guard.mjs";
import { buildPluginNpmRuntime } from "./lib/plugin-npm-runtime-build.mts";

type ExternalPluginLocalDistParams = {
  repoRoot?: string;
  env?: NodeJS.ProcessEnv;
  logLevel?: "silent" | "warn";
};

/** Lists external first-party packages that need source-checkout dist output. */
export function listExternalPluginLocalDistPackageDirs(
  params: Pick<ExternalPluginLocalDistParams, "repoRoot" | "env"> = {},
): string[] {
  const repoRoot = path.resolve(params.repoRoot ?? ".");
  return collectSourceCheckoutPluginBuildEntries({ cwd: repoRoot, env: params.env })
    .filter(({ isolated }) => isolated)
    .map(({ id }) => `extensions/${id}`);
}

/** Builds isolated plugin graphs, then stages every output below its excluded root dist path. */
export async function buildExternalPluginLocalDist(
  params: ExternalPluginLocalDistParams = {},
): Promise<{ durationMs: number; pluginDirs: string[] }> {
  const repoRoot = path.resolve(params.repoRoot ?? ".");
  const packageDirs = listExternalPluginLocalDistPackageDirs({
    repoRoot,
    env: params.env,
  });
  const startedAt = performance.now();
  const pluginDirs: string[] = [];

  for (const packageDir of packageDirs) {
    const result = await buildPluginNpmRuntime({
      repoRoot,
      packageDir,
      // Standalone package validation owns its existing bundler warnings; this
      // root build still surfaces errors and validates every emitted host import.
      logLevel: params.logLevel ?? "error",
    });
    if (!result) {
      throw new Error(`${packageDir} did not produce source-checkout runtime output`);
    }
    const targetDir = path.join(repoRoot, "dist", "extensions", result.pluginDir);
    assertRealOutputRoot(targetDir);
    fs.rmSync(targetDir, { recursive: true, force: true });
    fs.mkdirSync(path.dirname(targetDir), { recursive: true });
    fs.cpSync(result.outDir, targetDir, { recursive: true });
    fs.rmSync(result.outDir, { recursive: true, force: true });
    pluginDirs.push(result.pluginDir);
  }

  return {
    durationMs: performance.now() - startedAt,
    pluginDirs,
  };
}

if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
  try {
    const result = await buildExternalPluginLocalDist();
    console.log(
      `[external-plugin-local-dist] built ${result.pluginDirs.length} plugins in ${Math.round(result.durationMs)}ms`,
    );
  } catch (error) {
    console.error(error instanceof Error ? error.message : String(error));
    process.exitCode = 1;
  }
}