File size: 3,797 Bytes
9c12830
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env node

// Builds browser runtime bundles for the diffs viewer assets.
import path from "node:path";
import { fileURLToPath } from "node:url";
import { build, type Plugin } from "esbuild";
import { writeGeneratedTextAsset } from "./lib/generated-text-asset.mts";

const modulePath = fileURLToPath(import.meta.url);
const repoRoot = path.resolve(path.dirname(modulePath), "..");
const pierreDiffsEmptySideEffectNamespace = "openclaw-diffs-empty-side-effect";
const pierreDiffsEmptySideEffectPath = "pierre-diffs-parse-decorations-side-effect";

const targets = {
  curated: {
    entry: "extensions/diffs/src/viewer-client.ts",
    output: "extensions/diffs/assets/viewer-runtime.js",
    shikiAlias: "scripts/diffs-shiki-curated.ts",
    languagePackAvailable: false,
  },
  full: {
    entry: "extensions/diffs/src/viewer-client.ts",
    output: "extensions/diffs-language-pack/assets/viewer-runtime.js",
    languagePackAvailable: true,
  },
};

function toPosixPath(value: string) {
  return value.replaceAll("\\", "/");
}

/**
 * Creates the esbuild plugin that neutralizes Pierre diffs' browser side-effect import.
 */
export function createPierreDiffsSideEffectImportPlugin(): {
  name: string;
  setup(buildContext: unknown): void;
};
export function createPierreDiffsSideEffectImportPlugin() {
  return {
    name: "openclaw-diffs-pierre-side-effect-imports",
    setup(buildContext) {
      buildContext.onResolve({ filter: /^diff$/ }, (args) => {
        const importer = toPosixPath(args.importer);
        if (!importer.endsWith("/@pierre/diffs/dist/utils/parseDiffDecorations.js")) {
          return undefined;
        }
        return {
          path: pierreDiffsEmptySideEffectPath,
          namespace: pierreDiffsEmptySideEffectNamespace,
          sideEffects: true,
        };
      });
      buildContext.onLoad(
        {
          filter: /^pierre-diffs-parse-decorations-side-effect$/,
          namespace: pierreDiffsEmptySideEffectNamespace,
        },
        () => ({
          contents: "export {};\n",
          loader: "js",
        }),
      );
    },
  } satisfies Plugin;
}

/**
 * Builds one configured diffs viewer runtime target.
 */
async function buildDiffsViewerRuntime(targetName: string | undefined) {
  const target = Object.entries(targets).find(([name]) => name === targetName)?.[1];
  if (!target) {
    throw new Error(
      `Usage: node --import tsx scripts/build-diffs-viewer-runtime.mts ${Object.keys(targets).join("|")}`,
    );
  }

  const outputPath = path.join(repoRoot, target.output);
  const shikiAlias = "shikiAlias" in target ? target.shikiAlias : undefined;
  const result = await build({
    entryPoints: [path.join(repoRoot, target.entry)],
    bundle: true,
    platform: "browser",
    target: "es2020",
    format: "esm",
    minify: true,
    define: {
      __OPENCLAW_DIFFS_LANGUAGE_PACK__: String(target.languagePackAvailable),
      NaN: "Number.NaN",
    },
    legalComments: "none",
    outfile: outputPath,
    write: false,
    plugins: [
      createPierreDiffsSideEffectImportPlugin(),
      ...(shikiAlias
        ? [
            {
              name: "openclaw-diffs-curated-shiki",
              setup(buildContext) {
                buildContext.onResolve({ filter: /^shiki$/ }, () => ({
                  path: path.join(repoRoot, shikiAlias),
                }));
              },
            } satisfies Plugin,
          ]
        : []),
    ],
  });

  const outputFile = result.outputFiles?.[0];
  if (!outputFile) {
    throw new Error(`esbuild did not produce ${target.output}`);
  }

  const runtime = outputFile.text.replace(/[ \t]+$/gm, "");
  await writeGeneratedTextAsset(outputPath, runtime);
}

if (process.argv[1] === modulePath) {
  await buildDiffsViewerRuntime(process.argv[2]);
}