openxiangda 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,6 +30,7 @@ const runtimeDistDir = path.join(rootDir, "dist/form-runtime");
30
30
  const tmpDir = path.join(rootDir, ".tmp");
31
31
  const runtimeVersionPlaceholder = "__SY_FORM_RUNTIME_VERSION__";
32
32
  const runtimeCacheFileName = "build-cache.json";
33
+ const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
33
34
 
34
35
  const runtimePackages = [
35
36
  "react",
@@ -164,7 +165,6 @@ function parseArgs(argv) {
164
165
  }
165
166
  if (arg === "--force") {
166
167
  result.force = true;
167
- result.runtimeCache = false;
168
168
  continue;
169
169
  }
170
170
  if (arg === "--dry-run") {
@@ -196,7 +196,7 @@ build-forms - 构建表单页面
196
196
  选项:
197
197
  --form <name> 只构建指定表单(src/forms/ 下的目录名)
198
198
  --only <list> 只构建指定模块,如 forms/customer,pages/dashboard
199
- --force 忽略增量缓存,强制重建
199
+ --force 忽略增量缓存,强制重建表单产物
200
200
  --dry-run 只打印增量计划,不构建
201
201
  --clean-cache 删除 .openxiangda/build-cache.json
202
202
  --no-runtime-cache 强制重建共享 runtime
@@ -237,11 +237,16 @@ import { App as AntdApp, ConfigProvider } from 'antd';
237
237
  import zhCN from 'antd/locale/zh_CN';
238
238
  import * as SyFormComponentsModule from 'openxiangda';
239
239
  import { antdTheme } from 'openxiangda/antd-theme';
240
+ import 'antd-mobile/es/global';
240
241
  import '../src/index.css';
241
242
 
242
243
  const runtimeVersion = '${runtimeVersionPlaceholder}';
243
244
  const roots = new WeakMap();
245
+ const portalContainerCleanups = new WeakMap();
244
246
  const { StandardFormPage, defineFormSchema } = SyFormComponentsModule;
247
+ const NAMESPACE_ROOT_CLASS = 'sy-app-workspace';
248
+ const PORTAL_CONTAINER_STACK_GLOBAL = '__OPENXIANGDA_PORTAL_CONTAINER_STACK__';
249
+ const PORTAL_CONTAINER_RESOLVER_GLOBAL = '${portalContainerResolverGlobal}';
245
250
 
246
251
  function getStyleContainer(el) {
247
252
  const rootNode = el.getRootNode?.();
@@ -250,58 +255,115 @@ function getStyleContainer(el) {
250
255
  : document.head;
251
256
  }
252
257
 
253
- function getNamespaceRoot(el) {
254
- return el.closest?.('.sy-app-workspace') || el;
255
- }
256
-
257
258
  function isInShadowRoot(el) {
258
259
  const rootNode = el.getRootNode?.();
259
260
  return typeof ShadowRoot !== 'undefined' && rootNode instanceof ShadowRoot;
260
261
  }
261
262
 
263
+ function getNamespaceRoot(el, triggerNode) {
264
+ if (isInShadowRoot(el)) return el;
265
+ const triggerRoot = triggerNode?.closest?.('.' + NAMESPACE_ROOT_CLASS);
266
+ return (
267
+ triggerRoot ||
268
+ el.closest?.('.' + NAMESPACE_ROOT_CLASS) ||
269
+ el.querySelector?.('.' + NAMESPACE_ROOT_CLASS) ||
270
+ el
271
+ );
272
+ }
273
+
262
274
  function getPopupContainer(el) {
263
- const inShadowRoot = isInShadowRoot(el);
264
- return (triggerNode) => {
265
- if (inShadowRoot) return el;
266
- return getNamespaceRoot(el) || triggerNode?.parentElement || document.body;
267
- };
275
+ return (triggerNode) => getNamespaceRoot(el, triggerNode);
268
276
  }
269
277
 
270
278
  function getTargetContainer(el) {
271
- return () => (isInShadowRoot(el) ? el : getNamespaceRoot(el) || document.body);
279
+ return () => getNamespaceRoot(el);
280
+ }
281
+
282
+ function createAntdConfig(el) {
283
+ return {
284
+ locale: zhCN,
285
+ prefixCls: 'sy-ant',
286
+ iconPrefixCls: 'sy-anticon',
287
+ theme: antdTheme,
288
+ getPopupContainer: getPopupContainer(el),
289
+ getTargetContainer: getTargetContainer(el),
290
+ };
291
+ }
292
+
293
+ function installRuntimePortalContainer(el) {
294
+ const stack = Array.isArray(globalThis[PORTAL_CONTAINER_STACK_GLOBAL])
295
+ ? globalThis[PORTAL_CONTAINER_STACK_GLOBAL]
296
+ : [];
297
+ stack.push(el);
298
+ globalThis[PORTAL_CONTAINER_STACK_GLOBAL] = stack;
299
+ globalThis[PORTAL_CONTAINER_RESOLVER_GLOBAL] = () => {
300
+ for (let index = stack.length - 1; index >= 0; index -= 1) {
301
+ const candidate = stack[index];
302
+ if (candidate?.isConnected) {
303
+ return getNamespaceRoot(candidate);
304
+ }
305
+ }
306
+ return document.querySelector('.' + NAMESPACE_ROOT_CLASS) || document.body;
307
+ };
308
+ return () => {
309
+ const position = stack.lastIndexOf(el);
310
+ if (position >= 0) stack.splice(position, 1);
311
+ };
312
+ }
313
+
314
+ function installAntdStaticHolder(el) {
315
+ ConfigProvider.config({
316
+ prefixCls: 'sy-ant',
317
+ iconPrefixCls: 'sy-anticon',
318
+ theme: antdTheme,
319
+ holderRender: (children) => {
320
+ if (!el.isConnected) {
321
+ return (
322
+ <ConfigProvider prefixCls="sy-ant" iconPrefixCls="sy-anticon" theme={antdTheme}>
323
+ {children}
324
+ </ConfigProvider>
325
+ );
326
+ }
327
+ return (
328
+ <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
329
+ <ConfigProvider {...createAntdConfig(el)}>{children}</ConfigProvider>
330
+ </StyleProvider>
331
+ );
332
+ },
333
+ });
272
334
  }
273
335
 
274
336
  function renderStandardForm(el, schemaInput, context = {}) {
275
337
  let root = roots.get(el);
338
+ el.classList.add(NAMESPACE_ROOT_CLASS);
339
+ if (!portalContainerCleanups.has(el)) {
340
+ portalContainerCleanups.set(el, installRuntimePortalContainer(el));
341
+ }
342
+ installAntdStaticHolder(el);
276
343
  if (!root) {
277
- if (!isInShadowRoot(el)) el.classList.add('sy-app-workspace');
278
344
  root = createRoot(el);
279
345
  roots.set(el, root);
280
346
  }
281
347
 
282
348
  const schema = defineFormSchema(schemaInput);
349
+ const antdConfig = createAntdConfig(el);
283
350
  root.render(
284
351
  <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
285
- <ConfigProvider
286
- locale={zhCN}
287
- prefixCls="sy-ant"
288
- iconPrefixCls="sy-anticon"
289
- theme={antdTheme}
290
- getPopupContainer={getPopupContainer(el)}
291
- getTargetContainer={getTargetContainer(el)}
292
- >
352
+ <ConfigProvider {...antdConfig}>
293
353
  <AntdApp>
294
- <StandardFormPage
295
- schema={schema}
296
- mode={context.mode || 'submit'}
297
- initialValues={context.initialValues}
298
- permissions={context.permissions}
299
- formUuid={context.formUuid}
300
- appType={context.appType}
301
- formInstanceId={context.formInstanceId}
302
- onSubmit={context.onSubmit}
303
- inDrawer={context.inDrawer}
304
- />
354
+ <div className="sy-app-workspace">
355
+ <StandardFormPage
356
+ schema={schema}
357
+ mode={context.mode || 'submit'}
358
+ initialValues={context.initialValues}
359
+ permissions={context.permissions}
360
+ formUuid={context.formUuid}
361
+ appType={context.appType}
362
+ formInstanceId={context.formInstanceId}
363
+ onSubmit={context.onSubmit}
364
+ inDrawer={context.inDrawer}
365
+ />
366
+ </div>
305
367
  </AntdApp>
306
368
  </ConfigProvider>
307
369
  </StyleProvider>
@@ -314,6 +376,11 @@ function unmountStandardForm(el) {
314
376
  root.unmount();
315
377
  roots.delete(el);
316
378
  }
379
+ const releasePortalContainer = portalContainerCleanups.get(el);
380
+ if (releasePortalContainer) {
381
+ releasePortalContainer();
382
+ portalContainerCleanups.delete(el);
383
+ }
317
384
  }
318
385
 
319
386
  export function createStandardFormModule(schemaInput) {
@@ -355,6 +422,24 @@ export default formRuntime;
355
422
  `;
356
423
  }
357
424
 
425
+ function createAntdMobilePortalPatchPlugin() {
426
+ const resolverExpression = `globalThis.${portalContainerResolverGlobal}?.() || document.body`;
427
+ return {
428
+ name: "openxiangda-antd-mobile-portal-container",
429
+ transform(code, id) {
430
+ if (!id.includes("/antd-mobile/") && !id.includes("\\\\antd-mobile\\\\")) {
431
+ return null;
432
+ }
433
+ const nextCode = code.replace(
434
+ /getContainer:\s*\(\)\s*=>\s*document\.body/g,
435
+ `getContainer: () => ${resolverExpression}`,
436
+ );
437
+ if (nextCode === code) return null;
438
+ return { code: nextCode, map: null };
439
+ },
440
+ };
441
+ }
442
+
358
443
  function createFormRuntimeProxyPlugin() {
359
444
  return {
360
445
  name: "sy-form-runtime-proxy",
@@ -546,7 +631,7 @@ async function buildSharedRuntime(options = {}) {
546
631
  },
547
632
  },
548
633
  },
549
- plugins: [reactPlugin],
634
+ plugins: [createAntdMobilePortalPatchPlugin(), reactPlugin],
550
635
  logLevel: "warn",
551
636
  });
552
637
 
@@ -688,7 +773,11 @@ async function buildForm(form) {
688
773
  },
689
774
  },
690
775
  },
691
- plugins: [createFormRuntimeProxyPlugin(), reactPlugin].filter(Boolean),
776
+ plugins: [
777
+ createAntdMobilePortalPatchPlugin(),
778
+ createFormRuntimeProxyPlugin(),
779
+ reactPlugin,
780
+ ].filter(Boolean),
692
781
  logLevel: "warn",
693
782
  });
694
783
 
@@ -751,9 +840,14 @@ async function main() {
751
840
  const startedAt = Date.now();
752
841
  console.log("[build] 构建表单页面");
753
842
  console.log("[build] 构建模式: shared runtime");
754
- const only = normalizeOnly(args.only).filter((item) => item.startsWith("forms/"));
755
- const filterForm = args.form || (only.length === 1 ? only[0].slice("forms/".length) : "");
756
- const forms = discoverForms(filterForm);
843
+ const onlyTargets = normalizeOnly(args.only);
844
+ const only = onlyTargets.filter((item) => item.startsWith("forms/"));
845
+ if (onlyTargets.length > 0 && only.length === 0) {
846
+ console.log("[build] forms: No form targets selected");
847
+ return;
848
+ }
849
+ const requested = args.form ? [`forms/${args.form}`] : only;
850
+ const forms = discoverForms("");
757
851
 
758
852
  if (forms.length === 0) {
759
853
  if (args.form) {
@@ -763,16 +857,24 @@ async function main() {
763
857
  }
764
858
  process.exit(1);
765
859
  }
860
+ const formKeys = new Set(forms.map((form) => form.key));
861
+ const missing = requested.filter((key) => !formKeys.has(key));
862
+ if (missing.length > 0) {
863
+ console.error(
864
+ `错误: 找不到表单 ${missing.map((key) => `"${key.slice("forms/".length)}"`).join(", ")}`,
865
+ );
866
+ process.exit(1);
867
+ }
766
868
 
767
869
  const plan = planIncrementalBuild(forms, {
768
870
  force: args.force,
769
- only: only.length ? only : undefined,
871
+ only: requested.length ? requested : undefined,
770
872
  });
771
873
  printPlan(plan, "forms");
772
874
  if (args.dryRun) return;
773
875
  if (plan.changed.length === 0) return;
774
876
 
775
- if (plan.fullRebuild && !args.form && only.length === 0 && fs.existsSync(distDir)) {
877
+ if (plan.fullRebuild && requested.length === 0 && fs.existsSync(distDir)) {
776
878
  fs.rmSync(distDir, { recursive: true, force: true });
777
879
  }
778
880
 
@@ -34,12 +34,14 @@ const tmpDir = path.join(rootDir, ".tmp");
34
34
  const runtimeDistDir = path.join(distRoot, "page-runtime");
35
35
  const runtimeVersionPlaceholder = "__SY_PAGE_RUNTIME_VERSION__";
36
36
  const runtimeCacheFileName = "build-cache.json";
37
+ const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
37
38
 
38
39
  const runtimePackages = [
39
40
  "react",
40
41
  "react-dom",
41
42
  "@ant-design/cssinjs",
42
43
  "antd",
44
+ "antd-mobile",
43
45
  "@ant-design/icons",
44
46
  "openxiangda",
45
47
  ];
@@ -163,7 +165,6 @@ function parseArgs(argv) {
163
165
  }
164
166
  if (arg === "--force") {
165
167
  result.force = true;
166
- result.runtimeCache = false;
167
168
  continue;
168
169
  }
169
170
  if (arg === "--dry-run") {
@@ -194,7 +195,7 @@ build-pages - 构建复杂代码页
194
195
  选项:
195
196
  --page <name> 只构建指定页面目录
196
197
  --only <list> 只构建指定模块,如 forms/customer,pages/dashboard
197
- --force 忽略增量缓存,强制重建
198
+ --force 忽略增量缓存,强制重建页面产物
198
199
  --dry-run 只打印增量计划,不构建
199
200
  --clean-cache 删除 .openxiangda/build-cache.json
200
201
  --no-runtime-cache 强制重建共享 runtime
@@ -339,6 +340,24 @@ async function createCssOptions() {
339
340
  };
340
341
  }
341
342
 
343
+ function createAntdMobilePortalPatchPlugin() {
344
+ const resolverExpression = `globalThis.${portalContainerResolverGlobal}?.() || document.body`;
345
+ return {
346
+ name: "openxiangda-antd-mobile-portal-container",
347
+ transform(code, id) {
348
+ if (!id.includes("/antd-mobile/") && !id.includes("\\\\antd-mobile\\\\")) {
349
+ return null;
350
+ }
351
+ const nextCode = code.replace(
352
+ /getContainer:\s*\(\)\s*=>\s*document\.body/g,
353
+ `getContainer: () => ${resolverExpression}`,
354
+ );
355
+ if (nextCode === code) return null;
356
+ return { code: nextCode, map: null };
357
+ },
358
+ };
359
+ }
360
+
342
361
  function createResolveAlias() {
343
362
  return [
344
363
  {
@@ -373,7 +392,7 @@ async function buildSharedRuntime(options = {}) {
373
392
  "process.env.NODE_ENV": JSON.stringify("production"),
374
393
  "process.env": JSON.stringify({ NODE_ENV: "production" }),
375
394
  },
376
- plugins: [react()],
395
+ plugins: [createAntdMobilePortalPatchPlugin(), react()],
377
396
  resolve: {
378
397
  alias: createResolveAlias(),
379
398
  dedupe: ["react", "react-dom", "antd", "@ant-design/cssinjs"],
@@ -655,7 +674,11 @@ async function buildPage(page) {
655
674
  "process.env.NODE_ENV": JSON.stringify("production"),
656
675
  "process.env": JSON.stringify({ NODE_ENV: "production" }),
657
676
  },
658
- plugins: [createSharedRuntimeProxyPlugin(), react()],
677
+ plugins: [
678
+ createAntdMobilePortalPatchPlugin(),
679
+ createSharedRuntimeProxyPlugin(),
680
+ react(),
681
+ ],
659
682
  resolve: {
660
683
  alias: createResolveAlias(),
661
684
  dedupe: ["react", "react-dom", "antd", "@ant-design/cssinjs"],
@@ -731,9 +754,14 @@ async function main() {
731
754
  return;
732
755
  }
733
756
 
734
- const only = normalizeOnly(args.only).filter((item) => item.startsWith("pages/"));
735
- const filterPage = args.page || (only.length === 1 ? only[0].slice("pages/".length) : "");
736
- const pages = (await discoverPages(filterPage)).map((page) => ({
757
+ const onlyTargets = normalizeOnly(args.only);
758
+ const only = onlyTargets.filter((item) => item.startsWith("pages/"));
759
+ if (onlyTargets.length > 0 && only.length === 0) {
760
+ console.log("[build] pages: No page targets selected");
761
+ return;
762
+ }
763
+ const requested = args.page ? [`pages/${args.page}`] : only;
764
+ const pages = (await discoverPages("")).map((page) => ({
737
765
  ...page,
738
766
  key: `pages/${page.dirName}`,
739
767
  dirPath: page.dirPath,
@@ -745,16 +773,23 @@ async function main() {
745
773
  console.log("未发现复杂代码页,跳过 pages 构建");
746
774
  return;
747
775
  }
776
+ const pageKeys = new Set(pages.map((page) => page.key));
777
+ const missing = requested.filter((key) => !pageKeys.has(key));
778
+ if (missing.length > 0) {
779
+ throw new Error(
780
+ `找不到代码页 ${missing.map((key) => `"${key.slice("pages/".length)}"`).join(", ")}`,
781
+ );
782
+ }
748
783
 
749
784
  const plan = planIncrementalBuild(pages, {
750
785
  force: args.force,
751
- only: only.length ? only : undefined,
786
+ only: requested.length ? requested : undefined,
752
787
  });
753
788
  printPlan(plan, "pages");
754
789
  if (args.dryRun) return;
755
790
  if (plan.changed.length === 0) return;
756
791
 
757
- if (plan.fullRebuild && !args.page && only.length === 0) {
792
+ if (plan.fullRebuild && requested.length === 0) {
758
793
  await fs.rm(path.join(distRoot, "pages"), { recursive: true, force: true });
759
794
  }
760
795
  await fs.mkdir(tmpDir, { recursive: true });
@@ -3,12 +3,14 @@ import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { rootDir } from "./utils/load-config.mjs";
6
+ import { normalizeOnly } from "./utils/incremental.mjs";
6
7
 
7
8
  const require = createRequire(import.meta.url);
8
9
  const scriptDir = path.dirname(fileURLToPath(import.meta.url));
9
10
  const tsxCli = require.resolve("tsx/cli");
10
11
  const args = process.argv.slice(2).filter((arg) => arg !== "--");
11
12
  const forwardedArgs = [];
13
+ const onlyValues = [];
12
14
 
13
15
  if (args.includes("--help") || args.includes("-h")) {
14
16
  console.log(`
@@ -35,13 +37,32 @@ for (let index = 0; index < args.length; index += 1) {
35
37
  }
36
38
  if (arg === "--only" && args[index + 1]) {
37
39
  forwardedArgs.push(arg, args[index + 1]);
40
+ onlyValues.push(args[index + 1]);
38
41
  index += 1;
39
42
  }
40
43
  if (arg.startsWith("--only=")) {
41
44
  forwardedArgs.push(arg);
45
+ onlyValues.push(arg.slice("--only=".length));
42
46
  }
43
47
  }
44
48
 
49
+ const onlyTargets = normalizeOnly(onlyValues);
50
+ const invalidOnlyTargets = onlyTargets.filter(
51
+ (item) => !item.startsWith("forms/") && !item.startsWith("pages/"),
52
+ );
53
+ if (invalidOnlyTargets.length > 0) {
54
+ console.error(
55
+ `[build] --only 目标必须以 forms/ 或 pages/ 开头: ${invalidOnlyTargets.join(", ")}`,
56
+ );
57
+ process.exit(1);
58
+ }
59
+
60
+ const hasOnlyTargets = onlyTargets.length > 0;
61
+ const shouldBuildForms =
62
+ !hasOnlyTargets || onlyTargets.some((item) => item.startsWith("forms/"));
63
+ const shouldBuildPages =
64
+ !hasOnlyTargets || onlyTargets.some((item) => item.startsWith("pages/"));
65
+
45
66
  const runScript = (scriptName, args) =>
46
67
  new Promise((resolve, reject) => {
47
68
  const child = spawn(process.execPath, [tsxCli, path.join(scriptDir, scriptName), ...args], {
@@ -60,5 +81,9 @@ const runScript = (scriptName, args) =>
60
81
  });
61
82
  });
62
83
 
63
- await runScript("build-forms.mjs", forwardedArgs);
64
- await runScript("build-pages.mjs", forwardedArgs);
84
+ if (shouldBuildForms) {
85
+ await runScript("build-forms.mjs", forwardedArgs);
86
+ }
87
+ if (shouldBuildPages) {
88
+ await runScript("build-pages.mjs", forwardedArgs);
89
+ }
@@ -172,6 +172,10 @@ export function commitIncrementalBuild(plan, builtModules) {
172
172
  const previous = loadBuildCache();
173
173
  const entries = { ...(previous?.entries || {}) };
174
174
  const now = new Date().toISOString();
175
+ const isPartialBuild = plan.selected.length !== plan.all.length;
176
+ const preserveGlobalSnapshot = Boolean(
177
+ previous && isPartialBuild && plan.fullRebuild,
178
+ );
175
179
  for (const item of builtModules) {
176
180
  entries[item.key] = {
177
181
  contentHash: plan.snapshot.moduleHashes[item.key],
@@ -185,9 +189,15 @@ export function commitIncrementalBuild(plan, builtModules) {
185
189
  `${JSON.stringify(
186
190
  {
187
191
  version: CACHE_VERSION,
188
- lockfileHash: plan.snapshot.lockfileHash,
189
- sharedHash: plan.snapshot.sharedHash,
190
- configHash: plan.snapshot.configHash,
192
+ lockfileHash: preserveGlobalSnapshot
193
+ ? previous.lockfileHash
194
+ : plan.snapshot.lockfileHash,
195
+ sharedHash: preserveGlobalSnapshot
196
+ ? previous.sharedHash
197
+ : plan.snapshot.sharedHash,
198
+ configHash: preserveGlobalSnapshot
199
+ ? previous.configHash
200
+ : plan.snapshot.configHash,
191
201
  entries,
192
202
  },
193
203
  null,
@@ -63,6 +63,34 @@ const ignoredDirs = new Set([
63
63
  const runtimePackages = ["openxiangda"];
64
64
  const runtimePackageRegistry =
65
65
  process.env.APP_WORKSPACE_NPM_REGISTRY || "https://registry.npmjs.org/";
66
+ const legacyTemplateTiptapOverrideVersion = "3.23.6";
67
+ const legacyTemplateTiptapOverrideKeys = new Set([
68
+ "@tiptap/core",
69
+ "@tiptap/pm",
70
+ "@tiptap/react",
71
+ "@tiptap/starter-kit",
72
+ "@tiptap/extensions",
73
+ "@tiptap/extension-list",
74
+ "@tiptap/extension-blockquote",
75
+ "@tiptap/extension-bold",
76
+ "@tiptap/extension-bubble-menu",
77
+ "@tiptap/extension-bullet-list",
78
+ "@tiptap/extension-character-count",
79
+ "@tiptap/extension-code",
80
+ "@tiptap/extension-document",
81
+ "@tiptap/extension-floating-menu",
82
+ "@tiptap/extension-hard-break",
83
+ "@tiptap/extension-heading",
84
+ "@tiptap/extension-horizontal-rule",
85
+ "@tiptap/extension-italic",
86
+ "@tiptap/extension-list-item",
87
+ "@tiptap/extension-list-keymap",
88
+ "@tiptap/extension-ordered-list",
89
+ "@tiptap/extension-paragraph",
90
+ "@tiptap/extension-placeholder",
91
+ "@tiptap/extension-strike",
92
+ "@tiptap/extension-text",
93
+ ]);
66
94
 
67
95
  function usage() {
68
96
  return `
@@ -150,6 +178,19 @@ function writeJson(path, value) {
150
178
  writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
151
179
  }
152
180
 
181
+ function getLegacyTemplateTiptapOverrideKeys(overrides = {}) {
182
+ const tiptapKeys = Object.keys(overrides).filter((key) =>
183
+ key.startsWith("@tiptap/"),
184
+ );
185
+ if (tiptapKeys.length === 0) return [];
186
+ const isLegacyTemplateSet = tiptapKeys.every(
187
+ (key) =>
188
+ legacyTemplateTiptapOverrideKeys.has(key) &&
189
+ overrides[key] === legacyTemplateTiptapOverrideVersion,
190
+ );
191
+ return isLegacyTemplateSet ? tiptapKeys : [];
192
+ }
193
+
153
194
  function escapeRegExp(value) {
154
195
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
155
196
  }
@@ -298,10 +339,8 @@ function updatePackageJson(workspaceRoot, channel) {
298
339
  }
299
340
  }
300
341
  if (pkg.pnpm?.overrides) {
301
- for (const key of Object.keys(pkg.pnpm.overrides)) {
302
- if (key.startsWith("@tiptap/")) {
303
- delete pkg.pnpm.overrides[key];
304
- }
342
+ for (const key of getLegacyTemplateTiptapOverrideKeys(pkg.pnpm.overrides)) {
343
+ delete pkg.pnpm.overrides[key];
305
344
  }
306
345
  if (Object.keys(pkg.pnpm.overrides).length === 0) {
307
346
  delete pkg.pnpm.overrides;