@wp-typia/project-tools 0.23.1 → 0.24.0
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.
- package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
- package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
- package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
- package/dist/runtime/cli-add-collision.js +8 -0
- package/dist/runtime/cli-add-help.js +10 -7
- package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
- package/dist/runtime/cli-add-kind-ids.js +1 -0
- package/dist/runtime/cli-add-types.d.ts +28 -1
- package/dist/runtime/cli-add-types.js +2 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
- package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -311
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +1 -1
- package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
- package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -232
- package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
- package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -145
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
- package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
- package/dist/runtime/cli-add-workspace-assets.js +6 -950
- package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
- package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
- package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
- package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-block-style.js +148 -0
- package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
- package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
- package/dist/runtime/cli-add-workspace-contract.js +1 -1
- package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
- package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
- package/dist/runtime/cli-add-workspace-integration-env.js +5 -345
- package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
- package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
- package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
- package/dist/runtime/cli-add-workspace-pattern.js +99 -0
- package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
- package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
- package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +6 -9
- package/dist/runtime/cli-add-workspace-rest-anchors.js +6 -466
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +5 -3
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +3 -16
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +1 -7
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +3 -322
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -99
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -663
- package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +3 -3
- package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-variation.js +162 -0
- package/dist/runtime/cli-add-workspace.d.ts +42 -107
- package/dist/runtime/cli-add-workspace.js +42 -674
- package/dist/runtime/cli-add.d.ts +3 -3
- package/dist/runtime/cli-add.js +2 -2
- package/dist/runtime/cli-core.d.ts +2 -1
- package/dist/runtime/cli-core.js +1 -1
- package/dist/runtime/cli-doctor-workspace-bindings.js +59 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +33 -5
- package/dist/runtime/cli-doctor.d.ts +2 -0
- package/dist/runtime/cli-doctor.js +13 -2
- package/dist/runtime/cli-help.js +6 -4
- package/dist/runtime/index.d.ts +5 -2
- package/dist/runtime/index.js +4 -2
- package/dist/runtime/local-dev-presets.js +2 -1
- package/dist/runtime/package-versions.d.ts +1 -0
- package/dist/runtime/package-versions.js +10 -2
- package/dist/runtime/pattern-catalog.d.ts +122 -0
- package/dist/runtime/pattern-catalog.js +471 -0
- package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
- package/dist/runtime/post-meta-binding-fields.js +135 -0
- package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
- package/dist/runtime/typia-llm-json-schema.js +33 -0
- package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
- package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
- package/dist/runtime/typia-llm-projection.d.ts +25 -0
- package/dist/runtime/typia-llm-projection.js +58 -0
- package/dist/runtime/typia-llm-render.d.ts +21 -0
- package/dist/runtime/typia-llm-render.js +252 -0
- package/dist/runtime/typia-llm-sync.d.ts +10 -0
- package/dist/runtime/typia-llm-sync.js +63 -0
- package/dist/runtime/typia-llm-types.d.ts +197 -0
- package/dist/runtime/typia-llm-types.js +1 -0
- package/dist/runtime/typia-llm.d.ts +9 -255
- package/dist/runtime/typia-llm.js +5 -634
- package/dist/runtime/workspace-inventory-mutations.js +13 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +9 -1
- package/dist/runtime/workspace-inventory-templates.d.ts +2 -2
- package/dist/runtime/workspace-inventory-templates.js +9 -1
- package/dist/runtime/workspace-inventory-types.d.ts +9 -1
- package/package.json +8 -3
- package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
- package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
- package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
- package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
|
@@ -1,469 +1,9 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
|
|
3
|
-
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
4
|
-
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
5
|
-
const REST_RESOURCE_SERVER_GLOB = "/inc/rest/*.php";
|
|
6
|
-
const REST_SCHEMA_HELPER_PATH = "/inc/rest-schema.php";
|
|
7
1
|
/**
|
|
8
|
-
*
|
|
2
|
+
* Compatibility facade for REST workspace anchor patchers.
|
|
9
3
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @throws When an existing loader does not reference `inc/rest-schema.php`.
|
|
4
|
+
* Keep the public runtime import path stable while bootstrap, contract sync,
|
|
5
|
+
* and REST resource sync patchers live in focused implementation modules.
|
|
13
6
|
*/
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let nextSource = source;
|
|
18
|
-
const loadFunctionName = `${workspace.workspace.phpPrefix}_load_rest_schema_helpers`;
|
|
19
|
-
const loadCall = `${loadFunctionName}();`;
|
|
20
|
-
const helperFunction = `
|
|
21
|
-
|
|
22
|
-
function ${loadFunctionName}() {
|
|
23
|
-
\t$helper_path = __DIR__ . '${REST_SCHEMA_HELPER_PATH}';
|
|
24
|
-
\tif ( is_readable( $helper_path ) ) {
|
|
25
|
-
\t\trequire_once $helper_path;
|
|
26
|
-
\t}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
${loadCall}
|
|
30
|
-
`;
|
|
31
|
-
if (!hasPhpFunctionDefinition(nextSource, loadFunctionName)) {
|
|
32
|
-
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, helperFunction);
|
|
33
|
-
}
|
|
34
|
-
else if (!nextSource.includes(REST_SCHEMA_HELPER_PATH)) {
|
|
35
|
-
throw new Error([
|
|
36
|
-
`Unable to patch ${path.basename(bootstrapPath)} in ensureRestSchemaHelperBootstrapAnchors.`,
|
|
37
|
-
`The existing ${loadFunctionName}() definition does not include ${REST_SCHEMA_HELPER_PATH}.`,
|
|
38
|
-
"Restore the generated bootstrap shape or load inc/rest-schema.php manually before retrying.",
|
|
39
|
-
].join(" "));
|
|
40
|
-
}
|
|
41
|
-
else if (!nextSource.includes(loadCall)) {
|
|
42
|
-
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, loadCall);
|
|
43
|
-
}
|
|
44
|
-
return nextSource;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
export async function ensureRestResourceBootstrapAnchors(workspace) {
|
|
48
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
49
|
-
await patchFile(bootstrapPath, (source) => {
|
|
50
|
-
let nextSource = source;
|
|
51
|
-
const registerFunctionName = `${workspace.workspace.phpPrefix}_register_rest_resources`;
|
|
52
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
53
|
-
const registerFunction = `
|
|
54
|
-
|
|
55
|
-
function ${registerFunctionName}() {
|
|
56
|
-
\tforeach ( glob( __DIR__ . '${REST_RESOURCE_SERVER_GLOB}' ) ?: array() as $rest_resource_module ) {
|
|
57
|
-
\t\trequire_once $rest_resource_module;
|
|
58
|
-
\t}
|
|
59
|
-
}
|
|
60
|
-
`;
|
|
61
|
-
if (!hasPhpFunctionDefinition(nextSource, registerFunctionName)) {
|
|
62
|
-
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, registerFunction);
|
|
63
|
-
}
|
|
64
|
-
else if (!nextSource.includes(REST_RESOURCE_SERVER_GLOB)) {
|
|
65
|
-
throw new Error([
|
|
66
|
-
`Unable to patch ${path.basename(bootstrapPath)} in ensureRestResourceBootstrapAnchors.`,
|
|
67
|
-
`The existing ${registerFunctionName}() definition does not include ${REST_RESOURCE_SERVER_GLOB}.`,
|
|
68
|
-
"Restore the generated bootstrap shape or wire the REST resource loader manually before retrying.",
|
|
69
|
-
].join(" "));
|
|
70
|
-
}
|
|
71
|
-
if (!nextSource.includes(registerHook)) {
|
|
72
|
-
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, registerHook);
|
|
73
|
-
}
|
|
74
|
-
return nextSource;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function assertSyncRestAnchor(nextSource, target, anchorDescription, hasAnchor, syncRestScriptPath) {
|
|
78
|
-
if (!nextSource.includes(target) && !hasAnchor) {
|
|
79
|
-
throw new Error([
|
|
80
|
-
`ensureRestResourceSyncScriptAnchors could not patch ${path.basename(syncRestScriptPath)}.`,
|
|
81
|
-
`Missing expected ${anchorDescription} anchor in scripts/sync-rest-contracts.ts.`,
|
|
82
|
-
"Restore the generated template or add the REST_RESOURCES wiring manually before retrying.",
|
|
83
|
-
].join(" "));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function replaceRequiredSyncRestSource(nextSource, target, anchor, replacement, anchorDescription, syncRestScriptPath) {
|
|
87
|
-
if (nextSource.includes(target)) {
|
|
88
|
-
return nextSource;
|
|
89
|
-
}
|
|
90
|
-
const hasAnchor = typeof anchor === "string" ? nextSource.includes(anchor) : anchor.test(nextSource);
|
|
91
|
-
assertSyncRestAnchor(nextSource, target, anchorDescription, hasAnchor, syncRestScriptPath);
|
|
92
|
-
return nextSource.replace(anchor, replacement);
|
|
93
|
-
}
|
|
94
|
-
function getSyncRestPatchErrorMessage(functionName, syncRestScriptPath, anchorDescription, subject) {
|
|
95
|
-
return [
|
|
96
|
-
`${functionName} could not patch ${path.basename(syncRestScriptPath)}.`,
|
|
97
|
-
`Missing expected ${anchorDescription} anchor in scripts/sync-rest-contracts.ts.`,
|
|
98
|
-
`Restore the generated template or add the ${subject} wiring manually before retrying.`,
|
|
99
|
-
].join(" ");
|
|
100
|
-
}
|
|
101
|
-
function replaceBlockConfigImportForContracts(nextSource, syncRestScriptPath) {
|
|
102
|
-
const importPatterns = [
|
|
103
|
-
/^import\s*\{\n(?:\t[^\n]*\n)+\} from ["']\.\/block-config["'];?$/mu,
|
|
104
|
-
/^import\s*\{[^\n]*\}\s*from\s*["']\.\/block-config["'];?$/mu,
|
|
105
|
-
];
|
|
106
|
-
const importMatch = importPatterns.map((pattern) => pattern.exec(nextSource)).find(Boolean) ??
|
|
107
|
-
null;
|
|
108
|
-
if (!importMatch) {
|
|
109
|
-
throw new Error(getSyncRestPatchErrorMessage("ensureContractSyncScriptAnchors", syncRestScriptPath, "block-config import", "CONTRACTS"));
|
|
110
|
-
}
|
|
111
|
-
const importSource = importMatch[0];
|
|
112
|
-
if (importSource.includes("CONTRACTS") &&
|
|
113
|
-
importSource.includes("WorkspaceContractConfig")) {
|
|
114
|
-
return nextSource;
|
|
115
|
-
}
|
|
116
|
-
if (!importSource.includes("BLOCKS") ||
|
|
117
|
-
!importSource.includes("WorkspaceBlockConfig")) {
|
|
118
|
-
throw new Error(getSyncRestPatchErrorMessage("ensureContractSyncScriptAnchors", syncRestScriptPath, "BLOCKS import", "CONTRACTS"));
|
|
119
|
-
}
|
|
120
|
-
const hasAiFeatures = importSource.includes("AI_FEATURES");
|
|
121
|
-
const hasAiFeatureConfig = importSource.includes("WorkspaceAiFeatureConfig");
|
|
122
|
-
const hasRestResources = importSource.includes("REST_RESOURCES");
|
|
123
|
-
const hasRestResourceConfig = importSource.includes("WorkspaceRestResourceConfig");
|
|
124
|
-
const hasPostMeta = importSource.includes("POST_META");
|
|
125
|
-
const hasPostMetaConfig = importSource.includes("WorkspacePostMetaConfig");
|
|
126
|
-
const replacement = [
|
|
127
|
-
"import {",
|
|
128
|
-
...(hasAiFeatures ? ["\tAI_FEATURES,"] : []),
|
|
129
|
-
"\tBLOCKS,",
|
|
130
|
-
"\tCONTRACTS,",
|
|
131
|
-
...(hasPostMeta ? ["\tPOST_META,"] : []),
|
|
132
|
-
...(hasRestResources ? ["\tREST_RESOURCES,"] : []),
|
|
133
|
-
...(hasAiFeatureConfig ? ["\ttype WorkspaceAiFeatureConfig,"] : []),
|
|
134
|
-
"\ttype WorkspaceBlockConfig,",
|
|
135
|
-
"\ttype WorkspaceContractConfig,",
|
|
136
|
-
...(hasPostMetaConfig ? ["\ttype WorkspacePostMetaConfig,"] : []),
|
|
137
|
-
...(hasRestResourceConfig ? ["\ttype WorkspaceRestResourceConfig,"] : []),
|
|
138
|
-
"} from './block-config';",
|
|
139
|
-
].join("\n");
|
|
140
|
-
return nextSource.replace(importSource, replacement);
|
|
141
|
-
}
|
|
142
|
-
function replaceBlockConfigImportForRestResources(nextSource, syncRestScriptPath) {
|
|
143
|
-
const importPatterns = [
|
|
144
|
-
/^import\s*\{\n(?:\t[^\n]*\n)+\} from ["']\.\/block-config["'];?$/mu,
|
|
145
|
-
/^import\s*\{[^\n]*\}\s*from\s*["']\.\/block-config["'];?$/mu,
|
|
146
|
-
];
|
|
147
|
-
const importMatch = importPatterns.map((pattern) => pattern.exec(nextSource)).find(Boolean) ??
|
|
148
|
-
null;
|
|
149
|
-
if (!importMatch) {
|
|
150
|
-
throw new Error(getSyncRestPatchErrorMessage("ensureRestResourceSyncScriptAnchors", syncRestScriptPath, "block-config import", "REST_RESOURCES"));
|
|
151
|
-
}
|
|
152
|
-
const importSource = importMatch[0];
|
|
153
|
-
if (importSource.includes("REST_RESOURCES") &&
|
|
154
|
-
importSource.includes("WorkspaceRestResourceConfig")) {
|
|
155
|
-
return nextSource;
|
|
156
|
-
}
|
|
157
|
-
if (!importSource.includes("BLOCKS") ||
|
|
158
|
-
!importSource.includes("WorkspaceBlockConfig")) {
|
|
159
|
-
throw new Error(getSyncRestPatchErrorMessage("ensureRestResourceSyncScriptAnchors", syncRestScriptPath, "BLOCKS import", "REST_RESOURCES"));
|
|
160
|
-
}
|
|
161
|
-
const hasAiFeatures = importSource.includes("AI_FEATURES");
|
|
162
|
-
const hasAiFeatureConfig = importSource.includes("WorkspaceAiFeatureConfig");
|
|
163
|
-
const hasContracts = importSource.includes("CONTRACTS");
|
|
164
|
-
const hasContractConfig = importSource.includes("WorkspaceContractConfig");
|
|
165
|
-
const hasPostMeta = importSource.includes("POST_META");
|
|
166
|
-
const hasPostMetaConfig = importSource.includes("WorkspacePostMetaConfig");
|
|
167
|
-
const replacement = [
|
|
168
|
-
"import {",
|
|
169
|
-
...(hasAiFeatures ? ["\tAI_FEATURES,"] : []),
|
|
170
|
-
"\tBLOCKS,",
|
|
171
|
-
...(hasContracts ? ["\tCONTRACTS,"] : []),
|
|
172
|
-
...(hasPostMeta ? ["\tPOST_META,"] : []),
|
|
173
|
-
"\tREST_RESOURCES,",
|
|
174
|
-
...(hasAiFeatureConfig ? ["\ttype WorkspaceAiFeatureConfig,"] : []),
|
|
175
|
-
"\ttype WorkspaceBlockConfig,",
|
|
176
|
-
...(hasContractConfig ? ["\ttype WorkspaceContractConfig,"] : []),
|
|
177
|
-
...(hasPostMetaConfig ? ["\ttype WorkspacePostMetaConfig,"] : []),
|
|
178
|
-
"\ttype WorkspaceRestResourceConfig,",
|
|
179
|
-
"} from './block-config';",
|
|
180
|
-
].join("\n");
|
|
181
|
-
return nextSource.replace(importSource, replacement);
|
|
182
|
-
}
|
|
183
|
-
function replaceRequiredContractSyncRestSource(nextSource, target, anchor, replacement, anchorDescription, syncRestScriptPath) {
|
|
184
|
-
if (nextSource.includes(target)) {
|
|
185
|
-
return nextSource;
|
|
186
|
-
}
|
|
187
|
-
const hasAnchor = typeof anchor === "string" ? nextSource.includes(anchor) : anchor.test(nextSource);
|
|
188
|
-
if (!hasAnchor) {
|
|
189
|
-
throw new Error(getSyncRestPatchErrorMessage("ensureContractSyncScriptAnchors", syncRestScriptPath, anchorDescription, "CONTRACTS"));
|
|
190
|
-
}
|
|
191
|
-
return nextSource.replace(anchor, replacement);
|
|
192
|
-
}
|
|
193
|
-
function formatNoResourcesSubject(subjects) {
|
|
194
|
-
if (subjects.length <= 2) {
|
|
195
|
-
return subjects.join(" or ");
|
|
196
|
-
}
|
|
197
|
-
const lastSubject = subjects[subjects.length - 1];
|
|
198
|
-
return `${subjects.slice(0, -1).join(", ")}, or ${lastSubject}`;
|
|
199
|
-
}
|
|
200
|
-
function buildContractNoResourcesGuard({ hasAiFeatures, hasPostMeta, hasRestResources, }) {
|
|
201
|
-
const condition = ["restBlocks.length === 0 &&", "standaloneContracts.length === 0"];
|
|
202
|
-
if (hasPostMeta) {
|
|
203
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
204
|
-
condition.push("postMetaContracts.length === 0");
|
|
205
|
-
}
|
|
206
|
-
if (hasRestResources) {
|
|
207
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
208
|
-
condition.push("restResources.length === 0");
|
|
209
|
-
}
|
|
210
|
-
if (hasAiFeatures) {
|
|
211
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
212
|
-
condition.push("aiFeatures.length === 0");
|
|
213
|
-
}
|
|
214
|
-
const noResourcesSubject = formatNoResourcesSubject([
|
|
215
|
-
"REST-enabled workspace blocks",
|
|
216
|
-
"standalone contracts",
|
|
217
|
-
...(hasPostMeta ? ["post meta contracts"] : []),
|
|
218
|
-
...(hasRestResources ? ["plugin-level REST resources"] : []),
|
|
219
|
-
...(hasAiFeatures ? ["AI features"] : []),
|
|
220
|
-
]);
|
|
221
|
-
return [
|
|
222
|
-
"if (",
|
|
223
|
-
...condition.map((line) => `\t\t${line}`),
|
|
224
|
-
"\t) {",
|
|
225
|
-
"\t\tconsole.log(",
|
|
226
|
-
"\t\t\toptions.check",
|
|
227
|
-
`\t\t\t\t? 'ℹ️ No ${noResourcesSubject} are registered yet. \`sync-rest --check\` is already clean.'`,
|
|
228
|
-
`\t\t\t\t: 'ℹ️ No ${noResourcesSubject} are registered yet.'`,
|
|
229
|
-
"\t\t);",
|
|
230
|
-
"\t\treturn;",
|
|
231
|
-
"\t}",
|
|
232
|
-
].join("\n");
|
|
233
|
-
}
|
|
234
|
-
const NO_RESOURCES_GUARD_PATTERN = /if \(\s*restBlocks\.length === 0(?:\s*&&\s*standaloneContracts\.length === 0)?(?:\s*&&\s*postMetaContracts\.length === 0)?(?:\s*&&\s*restResources\.length === 0)?(?:\s*&&\s*aiFeatures\.length === 0)?\s*\) \{[\s\S]*?\n\t\treturn;\n\t\}/u;
|
|
235
|
-
function replaceNoResourcesGuard(nextSource, replacement, functionName, syncRestScriptPath, subject) {
|
|
236
|
-
if (!NO_RESOURCES_GUARD_PATTERN.test(nextSource)) {
|
|
237
|
-
throw new Error(getSyncRestPatchErrorMessage(functionName, syncRestScriptPath, "no-resources guard", subject));
|
|
238
|
-
}
|
|
239
|
-
return nextSource.replace(NO_RESOURCES_GUARD_PATTERN, replacement);
|
|
240
|
-
}
|
|
241
|
-
function insertStandaloneContractFilter(nextSource, syncRestScriptPath) {
|
|
242
|
-
if (nextSource.includes("const standaloneContracts = CONTRACTS.filter")) {
|
|
243
|
-
return nextSource;
|
|
244
|
-
}
|
|
245
|
-
const restResourcesFilter = "const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );";
|
|
246
|
-
if (nextSource.includes(restResourcesFilter)) {
|
|
247
|
-
return nextSource.replace(restResourcesFilter, [
|
|
248
|
-
"const standaloneContracts = CONTRACTS.filter( isWorkspaceStandaloneContract );",
|
|
249
|
-
restResourcesFilter,
|
|
250
|
-
].join("\n\t"));
|
|
251
|
-
}
|
|
252
|
-
const restBlocksFilter = "const restBlocks = BLOCKS.filter( isRestEnabledBlock );";
|
|
253
|
-
return replaceRequiredContractSyncRestSource(nextSource, "const standaloneContracts = CONTRACTS.filter", restBlocksFilter, [
|
|
254
|
-
restBlocksFilter,
|
|
255
|
-
"const standaloneContracts = CONTRACTS.filter( isWorkspaceStandaloneContract );",
|
|
256
|
-
].join("\n\t"), "restBlocks filter", syncRestScriptPath);
|
|
257
|
-
}
|
|
258
|
-
function insertStandaloneContractNoResourcesGuard(nextSource, syncRestScriptPath) {
|
|
259
|
-
const hasRestResources = nextSource.includes("const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );");
|
|
260
|
-
const hasAiFeatures = nextSource.includes("const aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );");
|
|
261
|
-
const hasPostMeta = nextSource.includes("const postMetaContracts = POST_META.filter( isWorkspacePostMetaContract );");
|
|
262
|
-
return replaceNoResourcesGuard(nextSource, buildContractNoResourcesGuard({
|
|
263
|
-
hasAiFeatures,
|
|
264
|
-
hasPostMeta,
|
|
265
|
-
hasRestResources,
|
|
266
|
-
}), "ensureContractSyncScriptAnchors", syncRestScriptPath, "CONTRACTS");
|
|
267
|
-
}
|
|
268
|
-
function buildRestResourceNoResourcesGuard({ hasAiFeatures, hasPostMeta, hasStandaloneContracts, }) {
|
|
269
|
-
const condition = ["restBlocks.length === 0"];
|
|
270
|
-
if (hasStandaloneContracts) {
|
|
271
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
272
|
-
condition.push("standaloneContracts.length === 0");
|
|
273
|
-
}
|
|
274
|
-
if (hasPostMeta) {
|
|
275
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
276
|
-
condition.push("postMetaContracts.length === 0");
|
|
277
|
-
}
|
|
278
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
279
|
-
condition.push("restResources.length === 0");
|
|
280
|
-
if (hasAiFeatures) {
|
|
281
|
-
condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
|
|
282
|
-
condition.push("aiFeatures.length === 0");
|
|
283
|
-
}
|
|
284
|
-
const noResourcesSubject = formatNoResourcesSubject([
|
|
285
|
-
"REST-enabled workspace blocks",
|
|
286
|
-
...(hasStandaloneContracts ? ["standalone contracts"] : []),
|
|
287
|
-
...(hasPostMeta ? ["post meta contracts"] : []),
|
|
288
|
-
"plugin-level REST resources",
|
|
289
|
-
...(hasAiFeatures ? ["AI features"] : []),
|
|
290
|
-
]);
|
|
291
|
-
return [
|
|
292
|
-
"if (",
|
|
293
|
-
...condition.map((line) => `\t\t${line}`),
|
|
294
|
-
"\t) {",
|
|
295
|
-
"\t\tconsole.log(",
|
|
296
|
-
"\t\t\toptions.check",
|
|
297
|
-
`\t\t\t\t? 'ℹ️ No ${noResourcesSubject} are registered yet. \`sync-rest --check\` is already clean.'`,
|
|
298
|
-
`\t\t\t\t: 'ℹ️ No ${noResourcesSubject} are registered yet.'`,
|
|
299
|
-
"\t\t);",
|
|
300
|
-
"\t\treturn;",
|
|
301
|
-
"\t}",
|
|
302
|
-
].join("\n");
|
|
303
|
-
}
|
|
304
|
-
function insertRestResourceNoResourcesGuard(nextSource, syncRestScriptPath) {
|
|
305
|
-
const hasStandaloneContracts = nextSource.includes("const standaloneContracts = CONTRACTS.filter( isWorkspaceStandaloneContract );");
|
|
306
|
-
const hasAiFeatures = nextSource.includes("const aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );");
|
|
307
|
-
const hasPostMeta = nextSource.includes("const postMetaContracts = POST_META.filter( isWorkspacePostMetaContract );");
|
|
308
|
-
return replaceNoResourcesGuard(nextSource, buildRestResourceNoResourcesGuard({
|
|
309
|
-
hasAiFeatures,
|
|
310
|
-
hasPostMeta,
|
|
311
|
-
hasStandaloneContracts,
|
|
312
|
-
}), "ensureRestResourceSyncScriptAnchors", syncRestScriptPath, "REST_RESOURCES");
|
|
313
|
-
}
|
|
314
|
-
function insertStandaloneContractSyncLoop(nextSource, syncRestScriptPath) {
|
|
315
|
-
if (nextSource.includes("for ( const contract of standaloneContracts )")) {
|
|
316
|
-
return nextSource;
|
|
317
|
-
}
|
|
318
|
-
const loopSource = [
|
|
319
|
-
"\tfor ( const contract of standaloneContracts ) {",
|
|
320
|
-
"\t\tawait syncTypeSchemas(",
|
|
321
|
-
"\t\t\t{",
|
|
322
|
-
"\t\t\t\tjsonSchemaFile: contract.schemaFile,",
|
|
323
|
-
"\t\t\t\tsourceTypeName: contract.sourceTypeName,",
|
|
324
|
-
"\t\t\t\ttypesFile: contract.typesFile,",
|
|
325
|
-
"\t\t\t},",
|
|
326
|
-
"\t\t\t{",
|
|
327
|
-
"\t\t\t\tcheck: options.check,",
|
|
328
|
-
"\t\t\t}",
|
|
329
|
-
"\t\t);",
|
|
330
|
-
"\t}",
|
|
331
|
-
].join("\n");
|
|
332
|
-
const resourceLoopAnchor = "\n\tfor ( const resource of restResources ) {";
|
|
333
|
-
if (nextSource.includes(resourceLoopAnchor)) {
|
|
334
|
-
return nextSource.replace(resourceLoopAnchor, `\n${loopSource}\n${resourceLoopAnchor}`);
|
|
335
|
-
}
|
|
336
|
-
const consoleLogPattern = /\n\tconsole\.log\(\n\t\toptions\.check/u;
|
|
337
|
-
return replaceRequiredContractSyncRestSource(nextSource, "for ( const contract of standaloneContracts )", consoleLogPattern, [
|
|
338
|
-
"",
|
|
339
|
-
loopSource,
|
|
340
|
-
"",
|
|
341
|
-
"\tconsole.log(",
|
|
342
|
-
"\t\toptions.check",
|
|
343
|
-
].join("\n"), "success log insertion point", syncRestScriptPath);
|
|
344
|
-
}
|
|
345
|
-
export async function ensureContractSyncScriptAnchors(workspace) {
|
|
346
|
-
const syncRestScriptPath = path.join(workspace.projectDir, "scripts", "sync-rest-contracts.ts");
|
|
347
|
-
await patchFile(syncRestScriptPath, (source) => {
|
|
348
|
-
let nextSource = replaceBlockConfigImportForContracts(source, syncRestScriptPath);
|
|
349
|
-
const helperInsertionAnchor = "async function assertTypeArtifactsCurrent";
|
|
350
|
-
nextSource = replaceRequiredContractSyncRestSource(nextSource, "function isWorkspaceStandaloneContract(", helperInsertionAnchor, [
|
|
351
|
-
"function isWorkspaceStandaloneContract(",
|
|
352
|
-
"\tcontract: WorkspaceContractConfig",
|
|
353
|
-
"): contract is WorkspaceContractConfig & {",
|
|
354
|
-
"\tschemaFile: string;",
|
|
355
|
-
"\tsourceTypeName: string;",
|
|
356
|
-
"\ttypesFile: string;",
|
|
357
|
-
"} {",
|
|
358
|
-
"\treturn (",
|
|
359
|
-
"\t\ttypeof contract.schemaFile === 'string' &&",
|
|
360
|
-
"\t\ttypeof contract.sourceTypeName === 'string' &&",
|
|
361
|
-
"\t\ttypeof contract.typesFile === 'string'",
|
|
362
|
-
"\t);",
|
|
363
|
-
"}",
|
|
364
|
-
"",
|
|
365
|
-
"async function assertTypeArtifactsCurrent",
|
|
366
|
-
].join("\n"), "type artifact assertion helper", syncRestScriptPath);
|
|
367
|
-
nextSource = insertStandaloneContractFilter(nextSource, syncRestScriptPath);
|
|
368
|
-
nextSource = insertStandaloneContractNoResourcesGuard(nextSource, syncRestScriptPath);
|
|
369
|
-
nextSource = insertStandaloneContractSyncLoop(nextSource, syncRestScriptPath);
|
|
370
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date for workspace blocks and plugin-level resources!", "✅ REST contract schemas, standalone schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date for workspace blocks, standalone contracts, and plugin-level resources!");
|
|
371
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents generated for workspace blocks and plugin-level resources!", "✅ REST contract schemas, standalone schemas, portable API clients, and endpoint-aware OpenAPI documents generated for workspace blocks, standalone contracts, and plugin-level resources!");
|
|
372
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date with the TypeScript types!", "✅ REST contract schemas, standalone schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date with the TypeScript types!");
|
|
373
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents generated from TypeScript types!", "✅ REST contract schemas, standalone schemas, portable API clients, and endpoint-aware OpenAPI documents generated from TypeScript types!");
|
|
374
|
-
return nextSource;
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
export async function ensureRestResourceSyncScriptAnchors(workspace) {
|
|
378
|
-
const syncRestScriptPath = path.join(workspace.projectDir, "scripts", "sync-rest-contracts.ts");
|
|
379
|
-
await patchFile(syncRestScriptPath, (source) => {
|
|
380
|
-
let nextSource = replaceBlockConfigImportForRestResources(source, syncRestScriptPath);
|
|
381
|
-
const helperInsertionAnchor = "async function assertTypeArtifactsCurrent";
|
|
382
|
-
const restBlocksAnchor = "const restBlocks = BLOCKS.filter( isRestEnabledBlock );";
|
|
383
|
-
const consoleLogPattern = /\n\tconsole\.log\(\n\t\toptions\.check/u;
|
|
384
|
-
nextSource = replaceRequiredSyncRestSource(nextSource, "function isWorkspaceRestResource(", helperInsertionAnchor, [
|
|
385
|
-
"function isWorkspaceRestResource(",
|
|
386
|
-
"\tresource: WorkspaceRestResourceConfig",
|
|
387
|
-
"): resource is WorkspaceRestResourceConfig & {",
|
|
388
|
-
"\tclientFile: string;",
|
|
389
|
-
"\topenApiFile: string;",
|
|
390
|
-
"\trestManifest: NonNullable< WorkspaceRestResourceConfig[ 'restManifest' ] >;",
|
|
391
|
-
"\ttypesFile: string;",
|
|
392
|
-
"\tvalidatorsFile: string;",
|
|
393
|
-
"} {",
|
|
394
|
-
"\treturn (",
|
|
395
|
-
"\t\ttypeof resource.clientFile === 'string' &&",
|
|
396
|
-
"\t\ttypeof resource.openApiFile === 'string' &&",
|
|
397
|
-
"\t\ttypeof resource.typesFile === 'string' &&",
|
|
398
|
-
"\t\ttypeof resource.validatorsFile === 'string' &&",
|
|
399
|
-
"\t\ttypeof resource.restManifest === 'object' &&",
|
|
400
|
-
"\t\tresource.restManifest !== null",
|
|
401
|
-
"\t);",
|
|
402
|
-
"}",
|
|
403
|
-
"",
|
|
404
|
-
"async function assertTypeArtifactsCurrent",
|
|
405
|
-
].join("\n"), "type artifact assertion helper", syncRestScriptPath);
|
|
406
|
-
nextSource = replaceRequiredSyncRestSource(nextSource, "const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );", restBlocksAnchor, [
|
|
407
|
-
"const restBlocks = BLOCKS.filter( isRestEnabledBlock );",
|
|
408
|
-
"const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );",
|
|
409
|
-
].join("\n"), "restBlocks filter", syncRestScriptPath);
|
|
410
|
-
nextSource = insertRestResourceNoResourcesGuard(nextSource, syncRestScriptPath);
|
|
411
|
-
nextSource = replaceRequiredSyncRestSource(nextSource, "for ( const resource of restResources ) {", consoleLogPattern, [
|
|
412
|
-
"",
|
|
413
|
-
"\tfor ( const resource of restResources ) {",
|
|
414
|
-
"\t\tconst contracts = resource.restManifest.contracts;",
|
|
415
|
-
"",
|
|
416
|
-
"\t\tfor ( const [ baseName, contract ] of Object.entries( contracts ) ) {",
|
|
417
|
-
"\t\t\tawait syncTypeSchemas(",
|
|
418
|
-
"\t\t\t\t{",
|
|
419
|
-
"\t\t\t\t\tjsonSchemaFile: path.join(",
|
|
420
|
-
"\t\t\t\t\t\tpath.dirname( resource.typesFile ),",
|
|
421
|
-
"\t\t\t\t\t\t'api-schemas',",
|
|
422
|
-
"\t\t\t\t\t\t`${ baseName }.schema.json`",
|
|
423
|
-
"\t\t\t\t\t),",
|
|
424
|
-
"\t\t\t\t\topenApiFile: path.join(",
|
|
425
|
-
"\t\t\t\t\t\tpath.dirname( resource.typesFile ),",
|
|
426
|
-
"\t\t\t\t\t\t'api-schemas',",
|
|
427
|
-
"\t\t\t\t\t\t`${ baseName }.openapi.json`",
|
|
428
|
-
"\t\t\t\t\t),",
|
|
429
|
-
"\t\t\t\t\tsourceTypeName: contract.sourceTypeName,",
|
|
430
|
-
"\t\t\t\t\ttypesFile: resource.typesFile,",
|
|
431
|
-
"\t\t\t\t},",
|
|
432
|
-
"\t\t\t\t{",
|
|
433
|
-
"\t\t\t\t\tcheck: options.check,",
|
|
434
|
-
"\t\t\t\t}",
|
|
435
|
-
"\t\t\t);",
|
|
436
|
-
"\t\t}",
|
|
437
|
-
"",
|
|
438
|
-
"\t\tawait syncRestOpenApi(",
|
|
439
|
-
"\t\t\t{",
|
|
440
|
-
"\t\t\t\tmanifest: resource.restManifest,",
|
|
441
|
-
"\t\t\t\topenApiFile: resource.openApiFile,",
|
|
442
|
-
"\t\t\t\ttypesFile: resource.typesFile,",
|
|
443
|
-
"\t\t\t},",
|
|
444
|
-
"\t\t\t{",
|
|
445
|
-
"\t\t\t\tcheck: options.check,",
|
|
446
|
-
"\t\t\t}",
|
|
447
|
-
"\t\t);",
|
|
448
|
-
"",
|
|
449
|
-
"\t\tawait syncEndpointClient(",
|
|
450
|
-
"\t\t\t{",
|
|
451
|
-
"\t\t\t\tclientFile: resource.clientFile,",
|
|
452
|
-
"\t\t\t\tmanifest: resource.restManifest,",
|
|
453
|
-
"\t\t\t\ttypesFile: resource.typesFile,",
|
|
454
|
-
"\t\t\t\tvalidatorsFile: resource.validatorsFile,",
|
|
455
|
-
"\t\t\t},",
|
|
456
|
-
"\t\t\t{",
|
|
457
|
-
"\t\t\t\tcheck: options.check,",
|
|
458
|
-
"\t\t\t}",
|
|
459
|
-
"\t\t);",
|
|
460
|
-
"\t}",
|
|
461
|
-
"",
|
|
462
|
-
"\tconsole.log(",
|
|
463
|
-
"\t\toptions.check",
|
|
464
|
-
].join("\n"), "success log insertion point", syncRestScriptPath);
|
|
465
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date with the TypeScript types!", "✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date for workspace blocks and plugin-level resources!");
|
|
466
|
-
nextSource = nextSource.replace("✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents generated from TypeScript types!", "✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents generated for workspace blocks and plugin-level resources!");
|
|
467
|
-
return nextSource;
|
|
468
|
-
});
|
|
469
|
-
}
|
|
7
|
+
export { ensureRestResourceBootstrapAnchors, ensureRestSchemaHelperBootstrapAnchors, } from "./cli-add-workspace-rest-bootstrap-anchors.js";
|
|
8
|
+
export { ensureContractSyncScriptAnchors, } from "./cli-add-workspace-rest-contract-sync-anchors.js";
|
|
9
|
+
export { ensureRestResourceSyncScriptAnchors, } from "./cli-add-workspace-rest-resource-sync-anchors.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WorkspaceProject } from "./workspace-project.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ensure the workspace bootstrap loads the shared REST schema helper file.
|
|
4
|
+
*
|
|
5
|
+
* @param workspace Resolved workspace project metadata and PHP prefix.
|
|
6
|
+
* @returns A promise that resolves after the bootstrap is patched.
|
|
7
|
+
* @throws When an existing loader does not reference `inc/rest-schema.php`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureRestSchemaHelperBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Ensure the workspace bootstrap loads generated REST resource PHP modules.
|
|
12
|
+
*
|
|
13
|
+
* @param workspace Resolved workspace project metadata and PHP prefix.
|
|
14
|
+
* @returns A promise that resolves after the bootstrap is patched.
|
|
15
|
+
* @throws When an existing loader does not reference generated REST modules.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ensureRestResourceBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
|
|
3
|
+
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
4
|
+
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
5
|
+
const REST_RESOURCE_SERVER_GLOB = "/inc/rest/*.php";
|
|
6
|
+
const REST_SCHEMA_HELPER_PATH = "/inc/rest-schema.php";
|
|
7
|
+
function escapeRegex(value) {
|
|
8
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Check that an expected generated path appears inside the named PHP function.
|
|
12
|
+
*
|
|
13
|
+
* @param source Complete PHP bootstrap source.
|
|
14
|
+
* @param functionName PHP function name to inspect.
|
|
15
|
+
* @param needle Source fragment that must be present inside the function block.
|
|
16
|
+
* @returns True when the named function block contains the expected fragment.
|
|
17
|
+
*/
|
|
18
|
+
function phpFunctionBlockIncludes(source, functionName, needle) {
|
|
19
|
+
const functionMatch = new RegExp(`function\\s+${escapeRegex(functionName)}\\s*\\(`, "u").exec(source);
|
|
20
|
+
if (functionMatch === null) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const start = functionMatch.index;
|
|
24
|
+
const remainder = source.slice(start + 1);
|
|
25
|
+
const nextFunctionMatch = /\nfunction\s+/u.exec(remainder);
|
|
26
|
+
const nextFunction = nextFunctionMatch === null ? -1 : start + 1 + nextFunctionMatch.index;
|
|
27
|
+
const closingTag = source.indexOf("\n?>", start + 1);
|
|
28
|
+
const endCandidates = [nextFunction, closingTag].filter((index) => index !== -1);
|
|
29
|
+
const end = endCandidates.length > 0 ? Math.min(...endCandidates) : source.length;
|
|
30
|
+
return source.slice(start, end).includes(needle);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Ensure the workspace bootstrap loads the shared REST schema helper file.
|
|
34
|
+
*
|
|
35
|
+
* @param workspace Resolved workspace project metadata and PHP prefix.
|
|
36
|
+
* @returns A promise that resolves after the bootstrap is patched.
|
|
37
|
+
* @throws When an existing loader does not reference `inc/rest-schema.php`.
|
|
38
|
+
*/
|
|
39
|
+
export async function ensureRestSchemaHelperBootstrapAnchors(workspace) {
|
|
40
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
41
|
+
await patchFile(bootstrapPath, (source) => {
|
|
42
|
+
let nextSource = source;
|
|
43
|
+
const loadFunctionName = `${workspace.workspace.phpPrefix}_load_rest_schema_helpers`;
|
|
44
|
+
const loadCall = `${loadFunctionName}();`;
|
|
45
|
+
const helperFunction = `
|
|
46
|
+
|
|
47
|
+
function ${loadFunctionName}() {
|
|
48
|
+
\t$helper_path = __DIR__ . '${REST_SCHEMA_HELPER_PATH}';
|
|
49
|
+
\tif ( is_readable( $helper_path ) ) {
|
|
50
|
+
\t\trequire_once $helper_path;
|
|
51
|
+
\t}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
${loadCall}
|
|
55
|
+
`;
|
|
56
|
+
if (!hasPhpFunctionDefinition(nextSource, loadFunctionName)) {
|
|
57
|
+
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, helperFunction);
|
|
58
|
+
}
|
|
59
|
+
else if (!phpFunctionBlockIncludes(nextSource, loadFunctionName, REST_SCHEMA_HELPER_PATH)) {
|
|
60
|
+
throw new Error([
|
|
61
|
+
`Unable to patch ${path.basename(bootstrapPath)} in ensureRestSchemaHelperBootstrapAnchors.`,
|
|
62
|
+
`The existing ${loadFunctionName}() definition does not include ${REST_SCHEMA_HELPER_PATH}.`,
|
|
63
|
+
"Restore the generated bootstrap shape or load inc/rest-schema.php manually before retrying.",
|
|
64
|
+
].join(" "));
|
|
65
|
+
}
|
|
66
|
+
else if (!nextSource.includes(loadCall)) {
|
|
67
|
+
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, loadCall);
|
|
68
|
+
}
|
|
69
|
+
return nextSource;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ensure the workspace bootstrap loads generated REST resource PHP modules.
|
|
74
|
+
*
|
|
75
|
+
* @param workspace Resolved workspace project metadata and PHP prefix.
|
|
76
|
+
* @returns A promise that resolves after the bootstrap is patched.
|
|
77
|
+
* @throws When an existing loader does not reference generated REST modules.
|
|
78
|
+
*/
|
|
79
|
+
export async function ensureRestResourceBootstrapAnchors(workspace) {
|
|
80
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
81
|
+
await patchFile(bootstrapPath, (source) => {
|
|
82
|
+
let nextSource = source;
|
|
83
|
+
const registerFunctionName = `${workspace.workspace.phpPrefix}_register_rest_resources`;
|
|
84
|
+
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
85
|
+
const registerFunction = `
|
|
86
|
+
|
|
87
|
+
function ${registerFunctionName}() {
|
|
88
|
+
\tforeach ( glob( __DIR__ . '${REST_RESOURCE_SERVER_GLOB}' ) ?: array() as $rest_resource_module ) {
|
|
89
|
+
\t\trequire_once $rest_resource_module;
|
|
90
|
+
\t}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
if (!hasPhpFunctionDefinition(nextSource, registerFunctionName)) {
|
|
94
|
+
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, registerFunction);
|
|
95
|
+
}
|
|
96
|
+
else if (!phpFunctionBlockIncludes(nextSource, registerFunctionName, REST_RESOURCE_SERVER_GLOB)) {
|
|
97
|
+
throw new Error([
|
|
98
|
+
`Unable to patch ${path.basename(bootstrapPath)} in ensureRestResourceBootstrapAnchors.`,
|
|
99
|
+
`The existing ${registerFunctionName}() definition does not include ${REST_RESOURCE_SERVER_GLOB}.`,
|
|
100
|
+
"Restore the generated bootstrap shape or wire the REST resource loader manually before retrying.",
|
|
101
|
+
].join(" "));
|
|
102
|
+
}
|
|
103
|
+
if (!nextSource.includes(registerHook)) {
|
|
104
|
+
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, registerHook);
|
|
105
|
+
}
|
|
106
|
+
return nextSource;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WorkspaceProject } from "./workspace-project.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ensure sync-rest can repair and validate standalone workspace contracts.
|
|
4
|
+
*
|
|
5
|
+
* @param workspace Workspace project whose sync-rest script should be patched.
|
|
6
|
+
* @returns A promise that resolves after the sync-rest script is updated.
|
|
7
|
+
* @throws When the generated sync-rest anchors cannot be found.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureContractSyncScriptAnchors(workspace: WorkspaceProject): Promise<void>;
|