wp-typia 0.22.2 → 0.22.4

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.
@@ -21,7 +21,7 @@ import {
21
21
  scaffoldProject,
22
22
  syncPersistenceRestArtifacts,
23
23
  updatePluginHeaderCompatibility
24
- } from "./cli-kww2sraq.js";
24
+ } from "./cli-6ymn63t4.js";
25
25
  import {
26
26
  DEFAULT_WORDPRESS_ABILITIES_VERSION,
27
27
  DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION,
@@ -34,17 +34,20 @@ import {
34
34
  } from "./cli-1sm60g1z.js";
35
35
  import {
36
36
  snapshotProjectVersion
37
- } from "./cli-6hcbjvym.js";
37
+ } from "./cli-2mt6bvcj.js";
38
38
  import {
39
39
  ensureMigrationDirectories,
40
40
  parseMigrationConfig,
41
41
  writeInitialMigrationScaffold,
42
42
  writeMigrationConfig
43
- } from "./cli-gcbre1zs.js";
43
+ } from "./cli-hb9vpsev.js";
44
44
  import"./cli-bq2v559b.js";
45
45
  import {
46
- formatInstallCommand
47
- } from "./cli-sj5mtyzj.js";
46
+ findExecutablePatternMatch,
47
+ hasExecutablePattern,
48
+ hasUncommentedPattern,
49
+ maskTypeScriptCommentsAndLiterals
50
+ } from "./cli-rwjkqjhs.js";
48
51
  import"./cli-10pe4mf8.js";
49
52
  import {
50
53
  SHARED_WORKSPACE_TEMPLATE_ROOT
@@ -58,6 +61,8 @@ import {
58
61
  assertAdminViewDoesNotExist,
59
62
  assertAiFeatureDoesNotExist,
60
63
  assertBindingSourceDoesNotExist,
64
+ assertBlockStyleDoesNotExist,
65
+ assertBlockTransformDoesNotExist,
61
66
  assertEditorPluginDoesNotExist,
62
67
  assertPatternDoesNotExist,
63
68
  assertRestResourceDoesNotExist,
@@ -95,7 +100,7 @@ import {
95
100
  toPascalCase,
96
101
  toSnakeCase,
97
102
  toTitleCase
98
- } from "./cli-smzkbfna.js";
103
+ } from "./cli-qr2ek735.js";
99
104
  import {
100
105
  createManagedTempRoot
101
106
  } from "./cli-t73q5aqz.js";
@@ -105,7 +110,10 @@ import {
105
110
  } from "./cli-p95wr1q8.js";
106
111
  import {
107
112
  resolveWorkspaceProject
108
- } from "./cli-pd5pqgre.js";
113
+ } from "./cli-btbpt84c.js";
114
+ import {
115
+ formatInstallCommand
116
+ } from "./cli-6bhfzq5e.js";
109
117
  import {
110
118
  __reExport,
111
119
  __toESM
@@ -1863,6 +1871,67 @@ add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );
1863
1871
  `;
1864
1872
  }
1865
1873
 
1874
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-mutation.ts
1875
+ var DEFAULT_PHP_SNIPPET_INSERTION_ANCHORS = [
1876
+ /add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
1877
+ /\?>\s*$/u
1878
+ ];
1879
+
1880
+ class WorkspaceMutationRollbackError extends Error {
1881
+ mutationError;
1882
+ rollbackError;
1883
+ constructor(mutationError, rollbackError) {
1884
+ super("Workspace mutation failed and rollback also failed.");
1885
+ this.name = "WorkspaceMutationRollbackError";
1886
+ this.mutationError = mutationError;
1887
+ this.rollbackError = rollbackError;
1888
+ }
1889
+ }
1890
+ async function executeWorkspaceMutationPlan({
1891
+ filePaths,
1892
+ run,
1893
+ snapshotDirs = [],
1894
+ targetPaths = []
1895
+ }) {
1896
+ const mutationSnapshot = {
1897
+ fileSources: await snapshotWorkspaceFiles(filePaths),
1898
+ snapshotDirs: [...snapshotDirs],
1899
+ targetPaths: [...targetPaths]
1900
+ };
1901
+ try {
1902
+ return await run();
1903
+ } catch (error) {
1904
+ try {
1905
+ await rollbackWorkspaceMutation(mutationSnapshot);
1906
+ } catch (rollbackError) {
1907
+ throw new WorkspaceMutationRollbackError(error, rollbackError);
1908
+ }
1909
+ throw error;
1910
+ }
1911
+ }
1912
+ function insertPhpSnippetBeforeWorkspaceAnchors(source, snippet) {
1913
+ for (const anchor of DEFAULT_PHP_SNIPPET_INSERTION_ANCHORS) {
1914
+ const candidate = source.replace(anchor, (match) => `${snippet}
1915
+ ${match}`);
1916
+ if (candidate !== source) {
1917
+ return candidate;
1918
+ }
1919
+ }
1920
+ return `${source.trimEnd()}
1921
+ ${snippet}
1922
+ `;
1923
+ }
1924
+ function appendPhpSnippetBeforeClosingTag(source, snippet) {
1925
+ const closingTagPattern = /\?>\s*$/u;
1926
+ if (closingTagPattern.test(source)) {
1927
+ return source.replace(closingTagPattern, `${snippet}
1928
+ ?>`);
1929
+ }
1930
+ return `${source.trimEnd()}
1931
+ ${snippet}
1932
+ `;
1933
+ }
1934
+
1866
1935
  // ../wp-typia-project-tools/src/runtime/cli-add-workspace-admin-view-scaffold.ts
1867
1936
  function detectJsonIndent(source) {
1868
1937
  const indentMatch = /\n([ \t]+)"/u.exec(source);
@@ -1926,36 +1995,8 @@ function ${loadFunctionName}() {
1926
1995
  }
1927
1996
  }
1928
1997
  `;
1929
- const insertionAnchors = [
1930
- /add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
1931
- /\?>\s*$/u
1932
- ];
1933
- const insertPhpSnippet = (snippet) => {
1934
- for (const anchor of insertionAnchors) {
1935
- const candidate = nextSource.replace(anchor, (match) => `${snippet}
1936
- ${match}`);
1937
- if (candidate !== nextSource) {
1938
- nextSource = candidate;
1939
- return;
1940
- }
1941
- }
1942
- nextSource = `${nextSource.trimEnd()}
1943
- ${snippet}
1944
- `;
1945
- };
1946
- const appendPhpSnippet = (snippet) => {
1947
- const closingTagPattern = /\?>\s*$/u;
1948
- if (closingTagPattern.test(nextSource)) {
1949
- nextSource = nextSource.replace(closingTagPattern, `${snippet}
1950
- ?>`);
1951
- return;
1952
- }
1953
- nextSource = `${nextSource.trimEnd()}
1954
- ${snippet}
1955
- `;
1956
- };
1957
1998
  if (!hasPhpFunctionDefinition(nextSource, loadFunctionName)) {
1958
- insertPhpSnippet(loadFunction);
1999
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, loadFunction);
1959
2000
  } else {
1960
2001
  const functionRange = findPhpFunctionRange(nextSource, loadFunctionName);
1961
2002
  const functionSource = functionRange ? nextSource.slice(functionRange.start, functionRange.end) : "";
@@ -1968,7 +2009,7 @@ ${snippet}
1968
2009
  }
1969
2010
  }
1970
2011
  if (!loadHookPattern.test(nextSource)) {
1971
- appendPhpSnippet(loadHook);
2012
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, loadHook);
1972
2013
  }
1973
2014
  return nextSource;
1974
2015
  });
@@ -2091,42 +2132,38 @@ async function scaffoldAdminViewWorkspace(options) {
2091
2132
  const adminViewsIndexPath = resolveAdminViewRegistryPath(workspace.projectDir);
2092
2133
  const adminViewDir = path5.join(workspace.projectDir, "src", "admin-views", adminViewSlug);
2093
2134
  const adminViewPhpPath = path5.join(workspace.projectDir, "inc", "admin-views", `${adminViewSlug}.php`);
2094
- const mutationSnapshot = {
2095
- fileSources: await snapshotWorkspaceFiles([
2135
+ await executeWorkspaceMutationPlan({
2136
+ filePaths: [
2096
2137
  adminViewsIndexPath,
2097
2138
  blockConfigPath,
2098
2139
  bootstrapPath,
2099
2140
  buildScriptPath,
2100
2141
  packageJsonPath,
2101
2142
  webpackConfigPath
2102
- ]),
2103
- snapshotDirs: [],
2104
- targetPaths: [adminViewDir, adminViewPhpPath]
2105
- };
2106
- try {
2107
- await fsp3.mkdir(adminViewDir, { recursive: true });
2108
- await fsp3.mkdir(path5.dirname(adminViewPhpPath), { recursive: true });
2109
- await ensureAdminViewPackageDependencies(workspace, parsedSource);
2110
- await ensureAdminViewBootstrapAnchors(workspace);
2111
- await ensureAdminViewBuildScriptAnchors(workspace);
2112
- await ensureAdminViewWebpackAnchors(workspace);
2113
- await fsp3.writeFile(path5.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource), "utf8");
2114
- await fsp3.writeFile(path5.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, parsedSource, restResource), "utf8");
2115
- await fsp3.writeFile(path5.join(adminViewDir, "data.ts"), coreDataSource ? buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) : restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
2116
- await fsp3.writeFile(path5.join(adminViewDir, "Screen.tsx"), coreDataSource ? buildCoreDataAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain) : buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
2117
- await fsp3.writeFile(path5.join(adminViewDir, "index.tsx"), buildAdminViewEntrySource(adminViewSlug), "utf8");
2118
- await fsp3.writeFile(path5.join(adminViewDir, "style.scss"), buildAdminViewStyleSource(), "utf8");
2119
- await fsp3.writeFile(adminViewPhpPath, buildAdminViewPhpSource(adminViewSlug, workspace), "utf8");
2120
- await writeAdminViewRegistry(workspace.projectDir, adminViewSlug);
2121
- await appendWorkspaceInventoryEntries(workspace.projectDir, {
2122
- adminViewEntries: [
2123
- buildAdminViewConfigEntry(adminViewSlug, parsedSource)
2124
- ]
2125
- });
2126
- } catch (error) {
2127
- await rollbackWorkspaceMutation(mutationSnapshot);
2128
- throw error;
2129
- }
2143
+ ],
2144
+ targetPaths: [adminViewDir, adminViewPhpPath],
2145
+ run: async () => {
2146
+ await fsp3.mkdir(adminViewDir, { recursive: true });
2147
+ await fsp3.mkdir(path5.dirname(adminViewPhpPath), { recursive: true });
2148
+ await ensureAdminViewPackageDependencies(workspace, parsedSource);
2149
+ await ensureAdminViewBootstrapAnchors(workspace);
2150
+ await ensureAdminViewBuildScriptAnchors(workspace);
2151
+ await ensureAdminViewWebpackAnchors(workspace);
2152
+ await fsp3.writeFile(path5.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource), "utf8");
2153
+ await fsp3.writeFile(path5.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, parsedSource, restResource), "utf8");
2154
+ await fsp3.writeFile(path5.join(adminViewDir, "data.ts"), coreDataSource ? buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) : restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
2155
+ await fsp3.writeFile(path5.join(adminViewDir, "Screen.tsx"), coreDataSource ? buildCoreDataAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain) : buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
2156
+ await fsp3.writeFile(path5.join(adminViewDir, "index.tsx"), buildAdminViewEntrySource(adminViewSlug), "utf8");
2157
+ await fsp3.writeFile(path5.join(adminViewDir, "style.scss"), buildAdminViewStyleSource(), "utf8");
2158
+ await fsp3.writeFile(adminViewPhpPath, buildAdminViewPhpSource(adminViewSlug, workspace), "utf8");
2159
+ await writeAdminViewRegistry(workspace.projectDir, adminViewSlug);
2160
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
2161
+ adminViewEntries: [
2162
+ buildAdminViewConfigEntry(adminViewSlug, parsedSource)
2163
+ ]
2164
+ });
2165
+ }
2166
+ });
2130
2167
  }
2131
2168
 
2132
2169
  // ../wp-typia-project-tools/src/runtime/cli-add-workspace-admin-view.ts
@@ -2377,8 +2414,10 @@ registerBlockBindingsSource( {
2377
2414
  `;
2378
2415
  }
2379
2416
  function resolveBindingTarget(options, namespace) {
2380
- const hasBlock = options.blockName !== undefined && options.blockName.trim().length > 0;
2381
- const hasAttribute = options.attributeName !== undefined && options.attributeName.trim().length > 0;
2417
+ const blockName = normalizeOptionalCliString(options.blockName);
2418
+ const attributeName = normalizeOptionalCliString(options.attributeName);
2419
+ const hasBlock = blockName !== undefined;
2420
+ const hasAttribute = attributeName !== undefined;
2382
2421
  if (!hasBlock && !hasAttribute) {
2383
2422
  return;
2384
2423
  }
@@ -2386,8 +2425,8 @@ function resolveBindingTarget(options, namespace) {
2386
2425
  throw new Error("`wp-typia add binding-source` requires --block and --attribute to be provided together.");
2387
2426
  }
2388
2427
  return {
2389
- attributeName: assertValidBindingAttributeName(options.attributeName ?? ""),
2390
- blockSlug: resolveBindingTargetBlockSlug(options.blockName ?? "", namespace)
2428
+ attributeName: assertValidBindingAttributeName(attributeName ?? ""),
2429
+ blockSlug: resolveBindingTargetBlockSlug(blockName ?? "", namespace)
2391
2430
  };
2392
2431
  }
2393
2432
  function formatBindingAttributeTypeMember(attributeName) {
@@ -4367,12 +4406,14 @@ async function runAddRestResourceCommand({
4367
4406
  throw error;
4368
4407
  }
4369
4408
  }
4370
- // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability.ts
4409
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-scaffold.ts
4371
4410
  var import_semver = __toESM(require_semver(), 1);
4372
4411
  import fs5 from "fs";
4373
4412
  import { promises as fsp6 } from "fs";
4374
4413
  import path10 from "path";
4375
4414
  import { syncTypeSchemas as syncTypeSchemas2 } from "@wp-typia/block-runtime/metadata-core";
4415
+
4416
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-types.ts
4376
4417
  var ABILITY_SERVER_GLOB = "/inc/abilities/*.php";
4377
4418
  var ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
4378
4419
  var ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
@@ -4380,17 +4421,8 @@ var ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end";
4380
4421
  var ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start";
4381
4422
  var WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities";
4382
4423
  var WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
4383
- function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
4384
- if (!existingVersion) {
4385
- return requiredVersion;
4386
- }
4387
- const existingMinimum = import_semver.default.minVersion(existingVersion);
4388
- const requiredMinimum = import_semver.default.minVersion(requiredVersion);
4389
- if (!existingMinimum || !requiredMinimum) {
4390
- return requiredVersion;
4391
- }
4392
- return import_semver.default.gte(existingMinimum, requiredMinimum) ? existingVersion : requiredVersion;
4393
- }
4424
+
4425
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-templates.ts
4394
4426
  function toAbilityCategorySlug(workspaceNamespace) {
4395
4427
  const normalizedNamespace = workspaceNamespace.replace(/[^a-z0-9-]+/gu, "-").replace(/-{2,}/gu, "-").replace(/^-|-$/gu, "");
4396
4428
  return `${normalizedNamespace || "workspace"}-workflows`;
@@ -4855,6 +4887,19 @@ function buildAbilityRegistrySource(abilitySlugs) {
4855
4887
  `).concat(`
4856
4888
  `);
4857
4889
  }
4890
+
4891
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-scaffold.ts
4892
+ function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
4893
+ if (!existingVersion) {
4894
+ return requiredVersion;
4895
+ }
4896
+ const existingMinimum = import_semver.default.minVersion(existingVersion);
4897
+ const requiredMinimum = import_semver.default.minVersion(requiredVersion);
4898
+ if (!existingMinimum || !requiredMinimum) {
4899
+ return requiredVersion;
4900
+ }
4901
+ return import_semver.default.gte(existingMinimum, requiredMinimum) ? existingVersion : requiredVersion;
4902
+ }
4858
4903
  function resolveAbilityRegistryPath(projectDir) {
4859
4904
  const abilitiesDir = path10.join(projectDir, "src", "abilities");
4860
4905
  return [path10.join(abilitiesDir, "index.ts"), path10.join(abilitiesDir, "index.js")].find((candidatePath) => fs5.existsSync(candidatePath)) ?? path10.join(abilitiesDir, "index.ts");
@@ -4950,50 +4995,22 @@ function ${enqueueFunctionName}() {
4950
4995
  );
4951
4996
  }
4952
4997
  `;
4953
- const insertionAnchors = [
4954
- /add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
4955
- /\?>\s*$/u
4956
- ];
4957
- const insertPhpSnippet = (snippet) => {
4958
- for (const anchor of insertionAnchors) {
4959
- const candidate = nextSource.replace(anchor, (match) => `${snippet}
4960
- ${match}`);
4961
- if (candidate !== nextSource) {
4962
- nextSource = candidate;
4963
- return;
4964
- }
4965
- }
4966
- nextSource = `${nextSource.trimEnd()}
4967
- ${snippet}
4968
- `;
4969
- };
4970
- const appendPhpSnippet = (snippet) => {
4971
- const closingTagPattern = /\?>\s*$/u;
4972
- if (closingTagPattern.test(nextSource)) {
4973
- nextSource = nextSource.replace(closingTagPattern, `${snippet}
4974
- ?>`);
4975
- return;
4976
- }
4977
- nextSource = `${nextSource.trimEnd()}
4978
- ${snippet}
4979
- `;
4980
- };
4981
4998
  if (!hasPhpFunctionDefinition(nextSource, loadFunctionName)) {
4982
- insertPhpSnippet(loadFunction);
4999
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, loadFunction);
4983
5000
  }
4984
5001
  if (!hasPhpFunctionDefinition(nextSource, enqueueFunctionName)) {
4985
- insertPhpSnippet(enqueueFunction);
5002
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, enqueueFunction);
4986
5003
  } else if (!findPhpFunctionRange(nextSource, enqueueFunctionName)?.source.includes("wp_enqueue_script_module")) {
4987
5004
  nextSource = replacePhpFunctionDefinition(nextSource, enqueueFunctionName, enqueueFunction, { trimReplacementStart: true }) ?? nextSource;
4988
5005
  }
4989
5006
  if (!nextSource.includes(loadHook)) {
4990
- appendPhpSnippet(loadHook);
5007
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, loadHook);
4991
5008
  }
4992
5009
  if (!nextSource.includes(adminEnqueueHook)) {
4993
- appendPhpSnippet(adminEnqueueHook);
5010
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, adminEnqueueHook);
4994
5011
  }
4995
5012
  if (!nextSource.includes(editorEnqueueHook)) {
4996
- appendPhpSnippet(editorEnqueueHook);
5013
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, editorEnqueueHook);
4997
5014
  }
4998
5015
  return nextSource;
4999
5016
  });
@@ -5066,21 +5083,29 @@ async function ensureAbilityBuildScriptAnchors(workspace) {
5066
5083
  }
5067
5084
  const sharedEntriesPattern = /(for\s*\(\s*const\s+relativePath\s+of\s+\[)([\s\S]*?)(\]\s*\)\s*\{)/u;
5068
5085
  const match = nextSource.match(sharedEntriesPattern);
5069
- if (!match || !match[2].includes("src/bindings/index.ts") || !match[2].includes("src/editor-plugins/index.ts")) {
5086
+ if (!match || !/['"]src\/bindings\/index\.(?:ts|js)['"]/u.test(match[2]) || !/['"]src\/editor-plugins\/index\.(?:tsx|ts|js)['"]/u.test(match[2])) {
5070
5087
  throw new Error([
5071
5088
  `ensureAbilityBuildScriptAnchors could not patch ${path10.basename(buildScriptPath)}.`,
5072
5089
  "Missing the expected shared editor entries array in scripts/build-workspace.mjs.",
5073
5090
  "Restore the generated template or wire abilities/index manually before retrying."
5074
5091
  ].join(" "));
5075
5092
  }
5076
- nextSource = nextSource.replace(sharedEntriesPattern, `$1
5077
- 'src/bindings/index.ts',
5078
- 'src/bindings/index.js',
5079
- 'src/editor-plugins/index.ts',
5080
- 'src/editor-plugins/index.js',
5081
- 'src/abilities/index.ts',
5082
- 'src/abilities/index.js',
5083
- $3`);
5093
+ nextSource = nextSource.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
5094
+ const missingAbilityEntries = [
5095
+ "'src/abilities/index.ts'",
5096
+ "'src/abilities/index.js'"
5097
+ ].filter((entry) => !sharedEntries.includes(entry));
5098
+ if (missingAbilityEntries.length === 0) {
5099
+ return fullMatch;
5100
+ }
5101
+ const itemIndent = sharedEntries.match(/\n([ \t]*)['"]/u)?.[1] ?? "\t\t";
5102
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
5103
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
5104
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
5105
+ const nextEntries = `${trimmedEntries}${separator}` + missingAbilityEntries.map((entry) => `
5106
+ ${itemIndent}${entry},`).join("") + trailingWhitespace;
5107
+ return fullMatch.replace(sharedEntries, nextEntries);
5108
+ });
5084
5109
  return nextSource;
5085
5110
  });
5086
5111
  }
@@ -5109,8 +5134,7 @@ async function ensureAbilityWebpackAnchors(workspace) {
5109
5134
  entries.push( [ entryName, entryPath ] );
5110
5135
  break;
5111
5136
  }
5112
- }
5113
- $2`);
5137
+ }$2`);
5114
5138
  }
5115
5139
  const sharedEntriesPattern = /for\s*\(\s*const\s+\[\s*entryName\s*,\s*candidates\s*\]\s+of\s+\[([\s\S]*?)\]\s*\)\s*\{/u;
5116
5140
  const match = source.match(sharedEntriesPattern);
@@ -5121,31 +5145,33 @@ $2`);
5121
5145
  "Restore the generated template or wire abilities/index manually before retrying."
5122
5146
  ].join(" "));
5123
5147
  }
5124
- return source.replace(sharedEntriesPattern, `for ( const [ entryName, candidates ] of [
5125
- [
5126
- 'bindings/index',
5127
- [ 'src/bindings/index.ts', 'src/bindings/index.js' ],
5128
- ],
5129
- [
5130
- 'editor-plugins/index',
5131
- [ 'src/editor-plugins/index.ts', 'src/editor-plugins/index.js' ],
5132
- ],
5133
- [
5134
- 'abilities/index',
5135
- [ 'src/abilities/index.ts', 'src/abilities/index.js' ],
5136
- ],
5137
- ] ) {`);
5148
+ return source.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
5149
+ if (/['"]abilities\/index['"]/u.test(sharedEntries)) {
5150
+ return fullMatch;
5151
+ }
5152
+ const tupleIndent = sharedEntries.match(/\n([ \t]*)\[/u)?.[1] ?? "\t\t";
5153
+ const nestedIndent = `${tupleIndent} `;
5154
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
5155
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
5156
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
5157
+ const abilityTuple = [
5158
+ `${tupleIndent}[`,
5159
+ `${nestedIndent}'abilities/index',`,
5160
+ `${nestedIndent}[ 'src/abilities/index.ts', 'src/abilities/index.js' ],`,
5161
+ `${tupleIndent}],`
5162
+ ].join(`
5163
+ `);
5164
+ const nextEntries = `${trimmedEntries}${separator}
5165
+ ${abilityTuple}` + trailingWhitespace;
5166
+ return fullMatch.replace(sharedEntries, nextEntries);
5167
+ });
5138
5168
  });
5139
5169
  }
5140
- async function runAddAbilityCommand({
5141
- abilityName,
5142
- cwd = process.cwd()
5170
+ async function scaffoldAbilityWorkspace({
5171
+ abilitySlug,
5172
+ compatibilityPolicy,
5173
+ workspace
5143
5174
  }) {
5144
- const workspace = resolveWorkspaceProject(cwd);
5145
- const abilitySlug = assertValidGeneratedSlug("Ability name", normalizeBlockSlug(abilityName), "wp-typia add ability <name>");
5146
- const inventory = readWorkspaceInventory(workspace.projectDir);
5147
- assertAbilityDoesNotExist(workspace.projectDir, abilitySlug, inventory);
5148
- const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY);
5149
5175
  const blockConfigPath = path10.join(workspace.projectDir, "scripts", "block-config.ts");
5150
5176
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
5151
5177
  const buildScriptPath = path10.join(workspace.projectDir, "scripts", "build-workspace.mjs");
@@ -5160,8 +5186,8 @@ async function runAddAbilityCommand({
5160
5186
  const dataFilePath = path10.join(abilityDir, "data.ts");
5161
5187
  const clientFilePath = path10.join(abilityDir, "client.ts");
5162
5188
  const phpFilePath = path10.join(workspace.projectDir, "inc", "abilities", `${abilitySlug}.php`);
5163
- const mutationSnapshot = {
5164
- fileSources: await snapshotWorkspaceFiles([
5189
+ await executeWorkspaceMutationPlan({
5190
+ filePaths: [
5165
5191
  blockConfigPath,
5166
5192
  bootstrapPath,
5167
5193
  buildScriptPath,
@@ -5170,52 +5196,67 @@ async function runAddAbilityCommand({
5170
5196
  syncProjectScriptPath,
5171
5197
  webpackConfigPath,
5172
5198
  abilitiesIndexPath
5173
- ]),
5174
- snapshotDirs: [],
5175
- targetPaths: [abilityDir, phpFilePath, syncAbilitiesScriptPath]
5199
+ ],
5200
+ targetPaths: [abilityDir, phpFilePath, syncAbilitiesScriptPath],
5201
+ run: async () => {
5202
+ await fsp6.mkdir(abilityDir, { recursive: true });
5203
+ await fsp6.mkdir(path10.dirname(phpFilePath), { recursive: true });
5204
+ await ensureAbilityBootstrapAnchors(workspace);
5205
+ await patchFile(bootstrapPath, (source) => updatePluginHeaderCompatibility(source, compatibilityPolicy));
5206
+ await ensureAbilityPackageScripts(workspace);
5207
+ await ensureAbilitySyncProjectAnchors(workspace);
5208
+ await ensureAbilityBuildScriptAnchors(workspace);
5209
+ await ensureAbilityWebpackAnchors(workspace);
5210
+ await fsp6.writeFile(syncAbilitiesScriptPath, buildAbilitySyncScriptSource(), "utf8");
5211
+ await fsp6.writeFile(configFilePath, buildAbilityConfigSource(abilitySlug, workspace.workspace.namespace), "utf8");
5212
+ await fsp6.writeFile(typesFilePath, buildAbilityTypesSource(abilitySlug), "utf8");
5213
+ await fsp6.writeFile(dataFilePath, buildAbilityDataSource(abilitySlug), "utf8");
5214
+ await fsp6.writeFile(clientFilePath, buildAbilityClientSource(abilitySlug), "utf8");
5215
+ await fsp6.writeFile(phpFilePath, buildAbilityPhpSource(abilitySlug, workspace), "utf8");
5216
+ const pascalCase = toPascalCase(abilitySlug);
5217
+ await syncTypeSchemas2({
5218
+ jsonSchemaFile: `src/abilities/${abilitySlug}/input.schema.json`,
5219
+ projectRoot: workspace.projectDir,
5220
+ sourceTypeName: `${pascalCase}AbilityInput`,
5221
+ typesFile: `src/abilities/${abilitySlug}/types.ts`
5222
+ });
5223
+ await syncTypeSchemas2({
5224
+ jsonSchemaFile: `src/abilities/${abilitySlug}/output.schema.json`,
5225
+ projectRoot: workspace.projectDir,
5226
+ sourceTypeName: `${pascalCase}AbilityOutput`,
5227
+ typesFile: `src/abilities/${abilitySlug}/types.ts`
5228
+ });
5229
+ await writeAbilityRegistry(workspace.projectDir, abilitySlug);
5230
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
5231
+ abilityEntries: [
5232
+ buildAbilityConfigEntry(abilitySlug, compatibilityPolicy)
5233
+ ]
5234
+ });
5235
+ }
5236
+ });
5237
+ }
5238
+
5239
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability.ts
5240
+ async function runAddAbilityCommand({
5241
+ abilityName,
5242
+ cwd = process.cwd()
5243
+ }) {
5244
+ const workspace = resolveWorkspaceProject(cwd);
5245
+ const abilitySlug = assertValidGeneratedSlug("Ability name", normalizeBlockSlug(abilityName), "wp-typia add ability <name>");
5246
+ const inventory = readWorkspaceInventory(workspace.projectDir);
5247
+ assertAbilityDoesNotExist(workspace.projectDir, abilitySlug, inventory);
5248
+ const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY);
5249
+ await scaffoldAbilityWorkspace({
5250
+ abilitySlug,
5251
+ compatibilityPolicy,
5252
+ workspace
5253
+ });
5254
+ return {
5255
+ abilitySlug,
5256
+ projectDir: workspace.projectDir
5176
5257
  };
5177
- try {
5178
- await fsp6.mkdir(abilityDir, { recursive: true });
5179
- await fsp6.mkdir(path10.dirname(phpFilePath), { recursive: true });
5180
- await ensureAbilityBootstrapAnchors(workspace);
5181
- await patchFile(bootstrapPath, (source) => updatePluginHeaderCompatibility(source, compatibilityPolicy));
5182
- await ensureAbilityPackageScripts(workspace);
5183
- await ensureAbilitySyncProjectAnchors(workspace);
5184
- await ensureAbilityBuildScriptAnchors(workspace);
5185
- await ensureAbilityWebpackAnchors(workspace);
5186
- await fsp6.writeFile(syncAbilitiesScriptPath, buildAbilitySyncScriptSource(), "utf8");
5187
- await fsp6.writeFile(configFilePath, buildAbilityConfigSource(abilitySlug, workspace.workspace.namespace), "utf8");
5188
- await fsp6.writeFile(typesFilePath, buildAbilityTypesSource(abilitySlug), "utf8");
5189
- await fsp6.writeFile(dataFilePath, buildAbilityDataSource(abilitySlug), "utf8");
5190
- await fsp6.writeFile(clientFilePath, buildAbilityClientSource(abilitySlug), "utf8");
5191
- await fsp6.writeFile(phpFilePath, buildAbilityPhpSource(abilitySlug, workspace), "utf8");
5192
- const pascalCase = toPascalCase(abilitySlug);
5193
- await syncTypeSchemas2({
5194
- jsonSchemaFile: `src/abilities/${abilitySlug}/input.schema.json`,
5195
- projectRoot: workspace.projectDir,
5196
- sourceTypeName: `${pascalCase}AbilityInput`,
5197
- typesFile: `src/abilities/${abilitySlug}/types.ts`
5198
- });
5199
- await syncTypeSchemas2({
5200
- jsonSchemaFile: `src/abilities/${abilitySlug}/output.schema.json`,
5201
- projectRoot: workspace.projectDir,
5202
- sourceTypeName: `${pascalCase}AbilityOutput`,
5203
- typesFile: `src/abilities/${abilitySlug}/types.ts`
5204
- });
5205
- await writeAbilityRegistry(workspace.projectDir, abilitySlug);
5206
- await appendWorkspaceInventoryEntries(workspace.projectDir, {
5207
- abilityEntries: [buildAbilityConfigEntry(abilitySlug, compatibilityPolicy)]
5208
- });
5209
- return {
5210
- abilitySlug,
5211
- projectDir: workspace.projectDir
5212
- };
5213
- } catch (error) {
5214
- await rollbackWorkspaceMutation(mutationSnapshot);
5215
- throw error;
5216
- }
5217
5258
  }
5218
- // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai.ts
5259
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai-scaffold.ts
5219
5260
  import { promises as fsp8 } from "fs";
5220
5261
  import path13 from "path";
5221
5262
 
@@ -6072,7 +6113,7 @@ async function ensureAiFeatureSyncRestAnchors(workspace) {
6072
6113
  });
6073
6114
  }
6074
6115
 
6075
- // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai.ts
6116
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai-templates.ts
6076
6117
  function buildAiFeaturePhpSource(aiFeatureSlug, namespace, phpPrefix, textDomain) {
6077
6118
  const aiFeatureTitle = toTitleCase(aiFeatureSlug);
6078
6119
  const aiFeaturePhpId = aiFeatureSlug.replace(/-/g, "_");
@@ -6113,6 +6154,8 @@ if ( ! defined( 'ABSPATH' ) ) {
6113
6154
  * - ${quotePhpString(adminNoticeMessageFilterHook)} filters the wp-admin notice shown when AI support is unavailable.
6114
6155
  * - ${quotePhpString(unavailableMessageFilterHook)} filters REST-facing unavailable messages by reason code.
6115
6156
  * - ${quotePhpString(telemetryFilterHook)} filters the response telemetry array before schema validation. Return a schema-compatible array.
6157
+ *
6158
+ * Compatibility note: this server-only endpoint avoids WordPress script-module enqueue APIs so older sites can load the generated feature file safely.
6116
6159
  */
6117
6160
 
6118
6161
  if ( ! function_exists( '${loadSchemaFunctionName}' ) ) {
@@ -6673,17 +6716,14 @@ add_action( 'admin_notices', '${adminNoticeFunctionName}' );
6673
6716
  add_action( 'rest_api_init', '${registerRoutesFunctionName}' );
6674
6717
  `;
6675
6718
  }
6676
- async function runAddAiFeatureCommand({
6677
- aiFeatureName,
6678
- cwd = process.cwd(),
6679
- namespace
6719
+
6720
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai-scaffold.ts
6721
+ async function scaffoldAiFeatureWorkspace({
6722
+ aiFeatureSlug,
6723
+ compatibilityPolicy,
6724
+ namespace,
6725
+ workspace
6680
6726
  }) {
6681
- const workspace = resolveWorkspaceProject(cwd);
6682
- const aiFeatureSlug = assertValidGeneratedSlug("AI feature name", normalizeBlockSlug(aiFeatureName), "wp-typia add ai-feature <name> [--namespace <vendor/v1>]");
6683
- const resolvedNamespace = resolveRestResourceNamespace(workspace.workspace.namespace, namespace);
6684
- const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY);
6685
- const inventory = readWorkspaceInventory(workspace.projectDir);
6686
- assertAiFeatureDoesNotExist(workspace.projectDir, aiFeatureSlug, inventory);
6687
6727
  const blockConfigPath = path13.join(workspace.projectDir, "scripts", "block-config.ts");
6688
6728
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
6689
6729
  const packageJsonPath = path13.join(workspace.projectDir, "package.json");
@@ -6696,69 +6736,88 @@ async function runAddAiFeatureCommand({
6696
6736
  const apiFilePath = path13.join(aiFeatureDir, "api.ts");
6697
6737
  const dataFilePath = path13.join(aiFeatureDir, "data.ts");
6698
6738
  const phpFilePath = path13.join(workspace.projectDir, "inc", "ai-features", `${aiFeatureSlug}.php`);
6699
- const mutationSnapshot = {
6700
- fileSources: await snapshotWorkspaceFiles([
6739
+ return executeWorkspaceMutationPlan({
6740
+ filePaths: [
6701
6741
  blockConfigPath,
6702
6742
  bootstrapPath,
6703
6743
  packageJsonPath,
6704
6744
  syncAiScriptPath,
6705
6745
  syncProjectScriptPath,
6706
6746
  syncRestScriptPath
6707
- ]),
6708
- snapshotDirs: [],
6709
- targetPaths: [aiFeatureDir, phpFilePath, syncAiScriptPath]
6747
+ ],
6748
+ targetPaths: [aiFeatureDir, phpFilePath, syncAiScriptPath],
6749
+ run: async () => {
6750
+ await fsp8.mkdir(aiFeatureDir, { recursive: true });
6751
+ await fsp8.mkdir(path13.dirname(phpFilePath), { recursive: true });
6752
+ await ensureAiFeatureBootstrapAnchors(workspace);
6753
+ await patchFile(bootstrapPath, (source) => updatePluginHeaderCompatibility(source, compatibilityPolicy));
6754
+ const packageScriptChanges = await ensureAiFeaturePackageScripts(workspace);
6755
+ await ensureAiFeatureSyncProjectAnchors(workspace);
6756
+ await ensureAiFeatureSyncRestAnchors(workspace);
6757
+ await fsp8.writeFile(syncAiScriptPath, buildAiFeatureSyncScriptSource(), "utf8");
6758
+ await fsp8.writeFile(typesFilePath, buildAiFeatureTypesSource(aiFeatureSlug), "utf8");
6759
+ await fsp8.writeFile(validatorsFilePath, buildAiFeatureValidatorsSource(aiFeatureSlug), "utf8");
6760
+ await fsp8.writeFile(apiFilePath, buildAiFeatureApiSource(aiFeatureSlug), "utf8");
6761
+ await fsp8.writeFile(dataFilePath, buildAiFeatureDataSource(aiFeatureSlug), "utf8");
6762
+ await fsp8.writeFile(phpFilePath, buildAiFeaturePhpSource(aiFeatureSlug, namespace, workspace.workspace.phpPrefix, workspace.workspace.textDomain), "utf8");
6763
+ const pascalCase = toPascalCase(aiFeatureSlug);
6764
+ await syncAiFeatureRestArtifacts({
6765
+ clientFile: `src/ai-features/${aiFeatureSlug}/api-client.ts`,
6766
+ outputDir: path13.join("src", "ai-features", aiFeatureSlug),
6767
+ projectDir: workspace.projectDir,
6768
+ typesFile: `src/ai-features/${aiFeatureSlug}/api-types.ts`,
6769
+ validatorsFile: `src/ai-features/${aiFeatureSlug}/api-validators.ts`,
6770
+ variables: {
6771
+ namespace,
6772
+ pascalCase,
6773
+ slugKebabCase: aiFeatureSlug,
6774
+ title: toTitleCase(aiFeatureSlug)
6775
+ }
6776
+ });
6777
+ await syncAiFeatureSchemaArtifact({
6778
+ aiSchemaFile: `src/ai-features/${aiFeatureSlug}/ai-schemas/feature-result.ai.schema.json`,
6779
+ outputDir: path13.join("src", "ai-features", aiFeatureSlug),
6780
+ projectDir: workspace.projectDir
6781
+ });
6782
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
6783
+ aiFeatureEntries: [
6784
+ buildAiFeatureConfigEntry(aiFeatureSlug, namespace)
6785
+ ],
6786
+ transformSource: ensureBlockConfigCanAddRestManifests
6787
+ });
6788
+ return {
6789
+ warnings: packageScriptChanges.addedProjectToolsDependency ? [
6790
+ "Added `@wp-typia/project-tools` to devDependencies for `sync-ai`. If this workspace was already installed, rerun your package manager install command before the first `wp-typia sync ai`."
6791
+ ] : []
6792
+ };
6793
+ }
6794
+ });
6795
+ }
6796
+
6797
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai.ts
6798
+ async function runAddAiFeatureCommand({
6799
+ aiFeatureName,
6800
+ cwd = process.cwd(),
6801
+ namespace
6802
+ }) {
6803
+ const workspace = resolveWorkspaceProject(cwd);
6804
+ const aiFeatureSlug = assertValidGeneratedSlug("AI feature name", normalizeBlockSlug(aiFeatureName), "wp-typia add ai-feature <name> [--namespace <vendor/v1>]");
6805
+ const resolvedNamespace = resolveRestResourceNamespace(workspace.workspace.namespace, namespace);
6806
+ const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY);
6807
+ const inventory = readWorkspaceInventory(workspace.projectDir);
6808
+ assertAiFeatureDoesNotExist(workspace.projectDir, aiFeatureSlug, inventory);
6809
+ const scaffoldResult = await scaffoldAiFeatureWorkspace({
6810
+ aiFeatureSlug,
6811
+ compatibilityPolicy,
6812
+ namespace: resolvedNamespace,
6813
+ workspace
6814
+ });
6815
+ return {
6816
+ aiFeatureSlug,
6817
+ namespace: resolvedNamespace,
6818
+ projectDir: workspace.projectDir,
6819
+ warnings: scaffoldResult.warnings
6710
6820
  };
6711
- try {
6712
- await fsp8.mkdir(aiFeatureDir, { recursive: true });
6713
- await fsp8.mkdir(path13.dirname(phpFilePath), { recursive: true });
6714
- await ensureAiFeatureBootstrapAnchors(workspace);
6715
- await patchFile(bootstrapPath, (source) => updatePluginHeaderCompatibility(source, compatibilityPolicy));
6716
- const packageScriptChanges = await ensureAiFeaturePackageScripts(workspace);
6717
- await ensureAiFeatureSyncProjectAnchors(workspace);
6718
- await ensureAiFeatureSyncRestAnchors(workspace);
6719
- await fsp8.writeFile(syncAiScriptPath, buildAiFeatureSyncScriptSource(), "utf8");
6720
- await fsp8.writeFile(typesFilePath, buildAiFeatureTypesSource(aiFeatureSlug), "utf8");
6721
- await fsp8.writeFile(validatorsFilePath, buildAiFeatureValidatorsSource(aiFeatureSlug), "utf8");
6722
- await fsp8.writeFile(apiFilePath, buildAiFeatureApiSource(aiFeatureSlug), "utf8");
6723
- await fsp8.writeFile(dataFilePath, buildAiFeatureDataSource(aiFeatureSlug), "utf8");
6724
- await fsp8.writeFile(phpFilePath, buildAiFeaturePhpSource(aiFeatureSlug, resolvedNamespace, workspace.workspace.phpPrefix, workspace.workspace.textDomain), "utf8");
6725
- const pascalCase = toPascalCase(aiFeatureSlug);
6726
- await syncAiFeatureRestArtifacts({
6727
- clientFile: `src/ai-features/${aiFeatureSlug}/api-client.ts`,
6728
- outputDir: path13.join("src", "ai-features", aiFeatureSlug),
6729
- projectDir: workspace.projectDir,
6730
- typesFile: `src/ai-features/${aiFeatureSlug}/api-types.ts`,
6731
- validatorsFile: `src/ai-features/${aiFeatureSlug}/api-validators.ts`,
6732
- variables: {
6733
- namespace: resolvedNamespace,
6734
- pascalCase,
6735
- slugKebabCase: aiFeatureSlug,
6736
- title: toTitleCase(aiFeatureSlug)
6737
- }
6738
- });
6739
- await syncAiFeatureSchemaArtifact({
6740
- aiSchemaFile: `src/ai-features/${aiFeatureSlug}/ai-schemas/feature-result.ai.schema.json`,
6741
- outputDir: path13.join("src", "ai-features", aiFeatureSlug),
6742
- projectDir: workspace.projectDir
6743
- });
6744
- await appendWorkspaceInventoryEntries(workspace.projectDir, {
6745
- aiFeatureEntries: [
6746
- buildAiFeatureConfigEntry(aiFeatureSlug, resolvedNamespace)
6747
- ],
6748
- transformSource: ensureBlockConfigCanAddRestManifests
6749
- });
6750
- return {
6751
- aiFeatureSlug,
6752
- namespace: resolvedNamespace,
6753
- projectDir: workspace.projectDir,
6754
- warnings: packageScriptChanges.addedProjectToolsDependency ? [
6755
- "Added `@wp-typia/project-tools` to devDependencies for `sync-ai`. If this workspace was already installed, rerun your package manager install command before the first `wp-typia sync ai`."
6756
- ] : []
6757
- };
6758
- } catch (error) {
6759
- await rollbackWorkspaceMutation(mutationSnapshot);
6760
- throw error;
6761
- }
6762
6821
  }
6763
6822
 
6764
6823
  // ../wp-typia-project-tools/src/runtime/cli-add-workspace.ts
@@ -6776,80 +6835,6 @@ var BLOCK_TRANSFORMS_CALL_LINE = "applyWorkspaceBlockTransforms(registration.set
6776
6835
  var BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
6777
6836
  var SCAFFOLD_REGISTRATION_SETTINGS_CALL_PATTERN = /registerScaffoldBlockType\s*\(\s*registration\s*\.\s*name\s*,\s*registration\s*\.\s*settings\s*\)\s*;?/u;
6778
6837
  var FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
6779
- function maskSourceSegment(segment) {
6780
- return segment.replace(/[^\n\r]/gu, " ");
6781
- }
6782
- function maskTypeScriptComments(source) {
6783
- return source.replace(/\/\*[\s\S]*?\*\//gu, maskSourceSegment).replace(/\/\/[^\n\r]*/gu, maskSourceSegment);
6784
- }
6785
- function maskTypeScriptCommentsAndLiterals(source) {
6786
- let maskedSource = "";
6787
- let index = 0;
6788
- while (index < source.length) {
6789
- const current = source[index];
6790
- const next = source[index + 1];
6791
- if (current === "/" && next === "/") {
6792
- const start = index;
6793
- index += 2;
6794
- while (index < source.length && source[index] !== `
6795
- ` && source[index] !== "\r") {
6796
- index += 1;
6797
- }
6798
- maskedSource += maskSourceSegment(source.slice(start, index));
6799
- continue;
6800
- }
6801
- if (current === "/" && next === "*") {
6802
- const start = index;
6803
- index += 2;
6804
- while (index < source.length && !(source[index] === "*" && source[index + 1] === "/")) {
6805
- index += 1;
6806
- }
6807
- index = Math.min(index + 2, source.length);
6808
- maskedSource += maskSourceSegment(source.slice(start, index));
6809
- continue;
6810
- }
6811
- if (current === "'" || current === '"' || current === "`") {
6812
- const start = index;
6813
- const quote = current;
6814
- index += 1;
6815
- while (index < source.length) {
6816
- const char = source[index];
6817
- if (char === "\\") {
6818
- index += 2;
6819
- continue;
6820
- }
6821
- index += 1;
6822
- if (char === quote) {
6823
- break;
6824
- }
6825
- }
6826
- maskedSource += maskSourceSegment(source.slice(start, index));
6827
- continue;
6828
- }
6829
- maskedSource += current;
6830
- index += 1;
6831
- }
6832
- return maskedSource;
6833
- }
6834
- function hasExecutablePattern(source, pattern) {
6835
- return pattern.test(maskTypeScriptCommentsAndLiterals(source));
6836
- }
6837
- function hasUncommentedPattern(source, pattern) {
6838
- return pattern.test(maskTypeScriptComments(source));
6839
- }
6840
- function findExecutablePatternMatch(source, patterns) {
6841
- const maskedSource = maskTypeScriptCommentsAndLiterals(source);
6842
- for (const pattern of patterns) {
6843
- const match = pattern.exec(maskedSource);
6844
- if (match && match.index !== undefined) {
6845
- return {
6846
- end: match.index + match[0].length,
6847
- start: match.index
6848
- };
6849
- }
6850
- }
6851
- return;
6852
- }
6853
6838
  function isIdentifierBoundary(source, index) {
6854
6839
  if (index < 0 || index >= source.length) {
6855
6840
  return true;
@@ -7242,24 +7227,6 @@ async function writeBlockTransformRegistry(projectDir, blockSlug, transformSlug)
7242
7227
  const nextTransformSlugs = Array.from(new Set([...existingTransformSlugs, transformSlug])).sort();
7243
7228
  await fsp9.writeFile(transformsIndexPath, buildBlockTransformIndexSource(nextTransformSlugs), "utf8");
7244
7229
  }
7245
- function assertBlockStyleDoesNotExist(projectDir, blockSlug, styleSlug, inventory) {
7246
- const stylePath = path14.join(projectDir, "src", "blocks", blockSlug, "styles", `${styleSlug}.ts`);
7247
- if (fs6.existsSync(stylePath)) {
7248
- throw new Error(`A block style already exists at ${path14.relative(projectDir, stylePath)}. Choose a different name.`);
7249
- }
7250
- if (inventory.blockStyles.some((entry) => entry.block === blockSlug && entry.slug === styleSlug)) {
7251
- throw new Error(`A block style inventory entry already exists for ${blockSlug}/${styleSlug}. Choose a different name.`);
7252
- }
7253
- }
7254
- function assertBlockTransformDoesNotExist(projectDir, blockSlug, transformSlug, inventory) {
7255
- const transformPath = path14.join(projectDir, "src", "blocks", blockSlug, "transforms", `${transformSlug}.ts`);
7256
- if (fs6.existsSync(transformPath)) {
7257
- throw new Error(`A block transform already exists at ${path14.relative(projectDir, transformPath)}. Choose a different name.`);
7258
- }
7259
- if (inventory.blockTransforms.some((entry) => entry.block === blockSlug && entry.slug === transformSlug)) {
7260
- throw new Error(`A block transform inventory entry already exists for ${blockSlug}/${transformSlug}. Choose a different name.`);
7261
- }
7262
- }
7263
7230
  function assertFullBlockName(blockName, flagName) {
7264
7231
  const trimmed = blockName.trim();
7265
7232
  if (!trimmed) {
@@ -7500,6 +7467,7 @@ export {
7500
7467
  runAddAiFeatureCommand,
7501
7468
  runAddAdminViewCommand,
7502
7469
  runAddAbilityCommand,
7470
+ isAddBlockTemplateId,
7503
7471
  getWorkspaceBlockSelectOptions,
7504
7472
  formatAddHelpText,
7505
7473
  EDITOR_PLUGIN_SLOT_IDS,
@@ -7507,4 +7475,4 @@ export {
7507
7475
  ADD_BLOCK_TEMPLATE_IDS
7508
7476
  };
7509
7477
 
7510
- //# debugId=FE993C1947A36DF464756E2164756E21
7478
+ //# debugId=851894DA0B69BA4964756E2164756E21