@wp-typia/project-tools 0.23.0 → 0.23.1
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/ai-feature-artifacts.js +4 -1
- package/dist/runtime/block-generator-service-spec.js +2 -1
- package/dist/runtime/cli-add-block-json.js +5 -1
- package/dist/runtime/cli-add-help.js +4 -3
- package/dist/runtime/cli-add-types.d.ts +18 -6
- package/dist/runtime/cli-add-validation.d.ts +7 -0
- package/dist/runtime/cli-add-validation.js +9 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +4 -1
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +5 -1
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +18 -27
- package/dist/runtime/cli-add-workspace-admin-view-templates.js +30 -1326
- package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -1
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +17 -1
- package/dist/runtime/cli-add-workspace-integration-env.d.ts +3 -1
- package/dist/runtime/cli-add-workspace-integration-env.js +42 -5
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.js +41 -0
- package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +158 -0
- package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +279 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +678 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +25 -4
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
- package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
- package/dist/runtime/cli-add-workspace-rest.d.ts +3 -20
- package/dist/runtime/cli-add-workspace-rest.js +33 -788
- package/dist/runtime/cli-core.d.ts +1 -1
- package/dist/runtime/cli-core.js +1 -1
- package/dist/runtime/cli-diagnostics.d.ts +3 -1
- package/dist/runtime/cli-diagnostics.js +17 -5
- package/dist/runtime/cli-doctor-workspace-bindings.js +4 -1
- package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +134 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
- package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
- package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
- package/dist/runtime/cli-doctor-workspace-features.js +14 -487
- package/dist/runtime/cli-doctor.d.ts +52 -3
- package/dist/runtime/cli-doctor.js +79 -8
- package/dist/runtime/cli-help.js +6 -3
- package/dist/runtime/cli-init-package-json.js +4 -2
- package/dist/runtime/cli-prompt.d.ts +16 -2
- package/dist/runtime/cli-prompt.js +29 -12
- package/dist/runtime/cli-scaffold.d.ts +2 -1
- package/dist/runtime/cli-scaffold.js +19 -10
- package/dist/runtime/external-template-guards.js +4 -6
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/json-utils.d.ts +62 -4
- package/dist/runtime/json-utils.js +78 -4
- package/dist/runtime/local-dev-presets.js +4 -1
- package/dist/runtime/migration-ui-capability.js +4 -1
- package/dist/runtime/migration-utils.js +4 -1
- package/dist/runtime/package-managers.js +6 -1
- package/dist/runtime/package-versions.js +6 -1
- package/dist/runtime/scaffold-bootstrap.js +7 -2
- package/dist/runtime/scaffold-package-manager-files.js +5 -1
- package/dist/runtime/scaffold-repository-reference.js +4 -2
- package/dist/runtime/scaffold-template-variables.js +2 -1
- package/dist/runtime/scaffold.d.ts +18 -1
- package/dist/runtime/scaffold.js +55 -2
- package/dist/runtime/temp-roots.js +4 -1
- package/dist/runtime/template-layers.js +4 -1
- package/dist/runtime/template-registry.js +9 -3
- package/dist/runtime/template-source-contracts.d.ts +2 -0
- package/dist/runtime/template-source-normalization.js +2 -1
- package/dist/runtime/template-source-remote.js +18 -5
- package/dist/runtime/template-source-seeds.js +10 -3
- package/dist/runtime/workspace-inventory-mutations.js +2 -1
- package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
- package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
- package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
- package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
- package/dist/runtime/workspace-inventory-parser.d.ts +3 -45
- package/dist/runtime/workspace-inventory-parser.js +3 -581
- package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +435 -0
- package/dist/runtime/workspace-inventory-templates.d.ts +1 -1
- package/dist/runtime/workspace-inventory-templates.js +1 -0
- package/dist/runtime/workspace-inventory-types.d.ts +1 -0
- package/dist/runtime/workspace-project.js +4 -6
- package/package.json +2 -2
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { getPackageVersions } from "./package-versions.js";
|
|
4
4
|
import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
|
|
5
5
|
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
6
|
+
import { readJsonFile } from "./json-utils.js";
|
|
6
7
|
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
7
8
|
const AI_FEATURE_SERVER_GLOB = "/inc/ai-features/*.php";
|
|
8
9
|
/**
|
|
@@ -43,7 +44,9 @@ function ${registerFunctionName}() {
|
|
|
43
44
|
*/
|
|
44
45
|
export async function ensureAiFeaturePackageScripts(workspace) {
|
|
45
46
|
const packageJsonPath = path.join(workspace.projectDir, "package.json");
|
|
46
|
-
const packageJson =
|
|
47
|
+
const packageJson = await readJsonFile(packageJsonPath, {
|
|
48
|
+
context: "workspace package manifest",
|
|
49
|
+
});
|
|
47
50
|
const nextScripts = {
|
|
48
51
|
...(packageJson.scripts ?? {}),
|
|
49
52
|
"sync-ai": packageJson.scripts?.["sync-ai"] ?? "tsx scripts/sync-ai-features.ts",
|
|
@@ -397,7 +397,23 @@ async function reconcileGeneratedArtifact( options: {
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
async function loadJsonDocument( filePath: string ) {
|
|
400
|
-
\
|
|
400
|
+
\tlet source: string;
|
|
401
|
+
\ttry {
|
|
402
|
+
\t\tsource = await readFile( filePath, 'utf8' );
|
|
403
|
+
\t} catch ( error ) {
|
|
404
|
+
\t\tthrow new Error(
|
|
405
|
+
\t\t\t\`Failed to read AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
|
|
406
|
+
\t\t);
|
|
407
|
+
\t}
|
|
408
|
+
|
|
409
|
+
\tlet decoded: unknown;
|
|
410
|
+
\ttry {
|
|
411
|
+
\t\tdecoded = JSON.parse( source ) as unknown;
|
|
412
|
+
\t} catch ( error ) {
|
|
413
|
+
\t\tthrow new Error(
|
|
414
|
+
\t\t\t\`Failed to parse AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
|
|
415
|
+
\t\t);
|
|
416
|
+
\t}
|
|
401
417
|
\tif ( ! decoded || typeof decoded !== 'object' || Array.isArray( decoded ) ) {
|
|
402
418
|
\t\tthrow new Error( \`Expected \${ filePath } to decode to a JSON object.\` );
|
|
403
419
|
\t}
|
|
@@ -8,6 +8,7 @@ import { type IntegrationEnvServiceId, type RunAddIntegrationEnvCommandOptions }
|
|
|
8
8
|
* @property service Canonical local service starter id selected for the scaffold.
|
|
9
9
|
* @property warnings Optional non-fatal preservation notices for existing files
|
|
10
10
|
* or scripts.
|
|
11
|
+
* @property withReleaseZip Whether release zip packaging scripts were added.
|
|
11
12
|
* @property withWpEnv Whether the generated scaffold included the wp-env preset.
|
|
12
13
|
*/
|
|
13
14
|
export interface RunAddIntegrationEnvCommandResult {
|
|
@@ -15,10 +16,11 @@ export interface RunAddIntegrationEnvCommandResult {
|
|
|
15
16
|
projectDir: string;
|
|
16
17
|
service: IntegrationEnvServiceId;
|
|
17
18
|
warnings?: string[];
|
|
19
|
+
withReleaseZip: boolean;
|
|
18
20
|
withWpEnv: boolean;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Add an opt-in local WordPress integration environment starter to an official
|
|
22
24
|
* workspace.
|
|
23
25
|
*/
|
|
24
|
-
export declare function runAddIntegrationEnvCommand({ cwd, integrationEnvName, service, withWpEnv, }: RunAddIntegrationEnvCommandOptions): Promise<RunAddIntegrationEnvCommandResult>;
|
|
26
|
+
export declare function runAddIntegrationEnvCommand({ cwd, integrationEnvName, service, withReleaseZip, withWpEnv, }: RunAddIntegrationEnvCommandOptions): Promise<RunAddIntegrationEnvCommandResult>;
|
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { assertValidGeneratedSlug, assertValidIntegrationEnvService, normalizeBlockSlug, } from "./cli-add-shared.js";
|
|
4
4
|
import { formatRunScript, } from "./package-managers.js";
|
|
5
5
|
import { pathExists, readOptionalUtf8File } from "./fs-async.js";
|
|
6
|
+
import { readJsonFile } from "./json-utils.js";
|
|
6
7
|
import { executeWorkspaceMutationPlan } from "./cli-add-workspace-mutation.js";
|
|
7
8
|
import { resolveWorkspaceProject } from "./workspace-project.js";
|
|
8
9
|
import { toTitleCase } from "./string-case.js";
|
|
@@ -136,6 +137,11 @@ const baseUrl = new URL(
|
|
|
136
137
|
);
|
|
137
138
|
const serviceUrl = getEnv("WP_TYPIA_SERVICE_URL", "").trim();
|
|
138
139
|
|
|
140
|
+
// Extend this starter with project-specific generated REST clients or schema
|
|
141
|
+
// checks as the workspace grows. For example, read JSON schemas under
|
|
142
|
+
// src/rest/<resource>/api-schemas or import TS clients through a tsx-powered
|
|
143
|
+
// smoke runner when you need authenticated route coverage.
|
|
144
|
+
|
|
139
145
|
await assertJsonEndpoint(
|
|
140
146
|
"WordPress REST index",
|
|
141
147
|
resolveEndpointUrl(baseUrl, "wp-json/"),
|
|
@@ -171,7 +177,7 @@ function buildEnvExampleSource(service) {
|
|
|
171
177
|
"",
|
|
172
178
|
].join("\n");
|
|
173
179
|
}
|
|
174
|
-
function buildIntegrationEnvReadmeSource({ integrationEnvSlug, service, withWpEnv, }) {
|
|
180
|
+
function buildIntegrationEnvReadmeSource({ integrationEnvSlug, service, withReleaseZip, withWpEnv, }) {
|
|
175
181
|
const title = toTitleCase(integrationEnvSlug);
|
|
176
182
|
const setupSteps = [
|
|
177
183
|
"Copy `.env.example` to `.env` and adjust the URLs or credentials for your local project.",
|
|
@@ -190,6 +196,11 @@ function buildIntegrationEnvReadmeSource({ integrationEnvSlug, service, withWpEn
|
|
|
190
196
|
"Set `WP_TYPIA_SERVICE_URL` only when your integration smoke needs a local service dependency.",
|
|
191
197
|
]),
|
|
192
198
|
`Run \`npm run smoke:${integrationEnvSlug}\` to execute the starter smoke check.`,
|
|
199
|
+
...(withReleaseZip
|
|
200
|
+
? [
|
|
201
|
+
"Run `npm run release:zip` after smoke checks pass to build a distributable plugin zip.",
|
|
202
|
+
]
|
|
203
|
+
: []),
|
|
193
204
|
];
|
|
194
205
|
return `# ${title} Integration Environment
|
|
195
206
|
|
|
@@ -211,6 +222,7 @@ ${setupSteps.map((step, index) => `${index + 1}. ${step}`).join("\n")}
|
|
|
211
222
|
emulator containers.
|
|
212
223
|
- Keep the smoke script focused on high-signal integration checks so CI and
|
|
213
224
|
local debugging stay fast.
|
|
225
|
+
${withReleaseZip ? "- Treat `release:zip:check` as a CI guard before packaging release artifacts.\n" : ""}
|
|
214
226
|
`;
|
|
215
227
|
}
|
|
216
228
|
async function appendMissingLines(filePath, lines) {
|
|
@@ -249,11 +261,13 @@ function addScriptIfMissing({ scriptName, scripts, scriptValue, warnings, }) {
|
|
|
249
261
|
}
|
|
250
262
|
async function mutatePackageJson(projectDir, mutate) {
|
|
251
263
|
const packageJsonPath = path.join(projectDir, "package.json");
|
|
252
|
-
const packageJson =
|
|
264
|
+
const packageJson = await readJsonFile(packageJsonPath, {
|
|
265
|
+
context: "integration env package manifest",
|
|
266
|
+
});
|
|
253
267
|
mutate(packageJson);
|
|
254
268
|
await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
|
|
255
269
|
}
|
|
256
|
-
function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManager, packageJson, service, warnings, withWpEnv, }) {
|
|
270
|
+
function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManager, packageJson, withReleaseZip, service, warnings, withWpEnv, }) {
|
|
257
271
|
const devDependencies = {
|
|
258
272
|
...(packageJson.devDependencies ?? {}),
|
|
259
273
|
};
|
|
@@ -296,6 +310,26 @@ function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManage
|
|
|
296
310
|
warnings,
|
|
297
311
|
});
|
|
298
312
|
}
|
|
313
|
+
if (withReleaseZip) {
|
|
314
|
+
addScriptIfMissing({
|
|
315
|
+
scriptName: "release:zip",
|
|
316
|
+
scriptValue: `${formatRunScript(packageManager, "sync-rest:package")} && ${formatRunScript(packageManager, "build")} && wp-scripts plugin-zip`,
|
|
317
|
+
scripts,
|
|
318
|
+
warnings,
|
|
319
|
+
});
|
|
320
|
+
addScriptIfMissing({
|
|
321
|
+
scriptName: "release:zip:check",
|
|
322
|
+
scriptValue: `${formatRunScript(packageManager, "sync-rest:package:check")} && ${formatRunScript(packageManager, "build")}`,
|
|
323
|
+
scripts,
|
|
324
|
+
warnings,
|
|
325
|
+
});
|
|
326
|
+
addScriptIfMissing({
|
|
327
|
+
scriptName: "qa:check",
|
|
328
|
+
scriptValue: `${formatRunScript(packageManager, "wp-typia:doctor:workspace")} && ${formatRunScript(packageManager, "release:zip:check")}`,
|
|
329
|
+
scripts,
|
|
330
|
+
warnings,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
299
333
|
if (service === "docker-compose") {
|
|
300
334
|
addScriptIfMissing({
|
|
301
335
|
scriptName: "service:start",
|
|
@@ -316,9 +350,9 @@ function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManage
|
|
|
316
350
|
* Add an opt-in local WordPress integration environment starter to an official
|
|
317
351
|
* workspace.
|
|
318
352
|
*/
|
|
319
|
-
export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integrationEnvName, service, withWpEnv = false, }) {
|
|
353
|
+
export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integrationEnvName, service, withReleaseZip = false, withWpEnv = false, }) {
|
|
320
354
|
const workspace = resolveWorkspaceProject(cwd);
|
|
321
|
-
const integrationEnvSlug = assertValidGeneratedSlug("Integration environment name", normalizeBlockSlug(integrationEnvName), "wp-typia add integration-env <name> [--wp-env]");
|
|
355
|
+
const integrationEnvSlug = assertValidGeneratedSlug("Integration environment name", normalizeBlockSlug(integrationEnvName), "wp-typia add integration-env <name> [--wp-env] [--release-zip]");
|
|
322
356
|
const serviceId = assertValidIntegrationEnvService(service);
|
|
323
357
|
const warnings = [];
|
|
324
358
|
const packageJsonPath = path.join(workspace.projectDir, "package.json");
|
|
@@ -351,6 +385,7 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
|
|
|
351
385
|
await writeNewScaffoldFile(docsPath, buildIntegrationEnvReadmeSource({
|
|
352
386
|
integrationEnvSlug,
|
|
353
387
|
service: serviceId,
|
|
388
|
+
withReleaseZip,
|
|
354
389
|
withWpEnv,
|
|
355
390
|
}));
|
|
356
391
|
await appendMissingLines(envExamplePath, [
|
|
@@ -376,6 +411,7 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
|
|
|
376
411
|
packageManager: workspace.packageManager,
|
|
377
412
|
packageJson,
|
|
378
413
|
service: serviceId,
|
|
414
|
+
withReleaseZip,
|
|
379
415
|
warnings,
|
|
380
416
|
withWpEnv,
|
|
381
417
|
}));
|
|
@@ -386,6 +422,7 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
|
|
|
386
422
|
projectDir: workspace.projectDir,
|
|
387
423
|
service: serviceId,
|
|
388
424
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
425
|
+
withReleaseZip,
|
|
389
426
|
withWpEnv,
|
|
390
427
|
};
|
|
391
428
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
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>;
|
|
2
10
|
export declare function ensureRestResourceBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
3
11
|
export declare function ensureContractSyncScriptAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
4
12
|
export declare function ensureRestResourceSyncScriptAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
@@ -3,6 +3,47 @@ import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
|
|
|
3
3
|
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
4
4
|
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
5
5
|
const REST_RESOURCE_SERVER_GLOB = "/inc/rest/*.php";
|
|
6
|
+
const REST_SCHEMA_HELPER_PATH = "/inc/rest-schema.php";
|
|
7
|
+
/**
|
|
8
|
+
* Ensure the workspace bootstrap loads the shared REST schema helper file.
|
|
9
|
+
*
|
|
10
|
+
* @param workspace Resolved workspace project metadata and PHP prefix.
|
|
11
|
+
* @returns A promise that resolves after the bootstrap is patched.
|
|
12
|
+
* @throws When an existing loader does not reference `inc/rest-schema.php`.
|
|
13
|
+
*/
|
|
14
|
+
export async function ensureRestSchemaHelperBootstrapAnchors(workspace) {
|
|
15
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
16
|
+
await patchFile(bootstrapPath, (source) => {
|
|
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
|
+
}
|
|
6
47
|
export async function ensureRestResourceBootstrapAnchors(workspace) {
|
|
7
48
|
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
8
49
|
await patchFile(bootstrapPath, (source) => {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GeneratedRestResourceScaffoldOptions, type RunAddRestResourceCommandResult } from "./cli-add-workspace-rest-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scaffold generated TypeScript, PHP, schema, and inventory files for a
|
|
4
|
+
* workspace-owned REST resource.
|
|
5
|
+
*
|
|
6
|
+
* @param options Resolved workspace and raw generated-mode command options.
|
|
7
|
+
* @returns Resolved scaffold metadata for the generated REST resource.
|
|
8
|
+
*/
|
|
9
|
+
export declare function scaffoldGeneratedRestResource({ controllerClass, controllerExtends, methods, namespace, permissionCallback, restResourceSlug, routePattern, workspace, }: GeneratedRestResourceScaffoldOptions): Promise<RunAddRestResourceCommandResult>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { promises as fsp } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureBlockConfigCanAddRestManifests } from "./cli-add-block-legacy-validator.js";
|
|
4
|
+
import { assertValidRestResourceMethods, getWorkspaceBootstrapPath, resolveGeneratedRestResourceRoutePattern, resolveOptionalPhpCallbackReference, resolveOptionalPhpClassReference, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
|
|
5
|
+
import { ensureRestResourceBootstrapAnchors, ensureRestSchemaHelperBootstrapAnchors, ensureRestResourceSyncScriptAnchors, } from "./cli-add-workspace-rest-anchors.js";
|
|
6
|
+
import { buildRestResourcePhpSource, buildWorkspaceRestSchemaHelperPhpSource, } from "./cli-add-workspace-rest-php-templates.js";
|
|
7
|
+
import { buildRestResourceApiSource, buildRestResourceConfigEntry, buildRestResourceDataSource, buildRestResourceTypesSource, buildRestResourceValidatorsSource, } from "./cli-add-workspace-rest-source-emitters.js";
|
|
8
|
+
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
9
|
+
import { syncRestResourceArtifacts } from "./rest-resource-artifacts.js";
|
|
10
|
+
import { toPascalCase, toTitleCase } from "./string-case.js";
|
|
11
|
+
import { appendWorkspaceInventoryEntries } from "./workspace-inventory.js";
|
|
12
|
+
async function ensureWorkspaceRestSchemaHelperFile(helperFilePath, phpPrefix) {
|
|
13
|
+
let currentSource = null;
|
|
14
|
+
try {
|
|
15
|
+
currentSource = await fsp.readFile(helperFilePath, "utf8");
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code !== "ENOENT") {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (currentSource === null) {
|
|
23
|
+
await fsp.mkdir(path.dirname(helperFilePath), { recursive: true });
|
|
24
|
+
await fsp.writeFile(helperFilePath, buildWorkspaceRestSchemaHelperPhpSource(phpPrefix), "utf8");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const requiredFunctions = [
|
|
28
|
+
`${phpPrefix}_load_rest_schema`,
|
|
29
|
+
`${phpPrefix}_prepare_rest_schema_for_wordpress`,
|
|
30
|
+
`${phpPrefix}_get_wordpress_rest_schema`,
|
|
31
|
+
`${phpPrefix}_validate_and_sanitize_rest_payload`,
|
|
32
|
+
];
|
|
33
|
+
const missingFunctions = requiredFunctions.filter((functionName) => !hasPhpFunctionDefinition(currentSource, functionName));
|
|
34
|
+
if (missingFunctions.length > 0) {
|
|
35
|
+
throw new Error([
|
|
36
|
+
`Existing ${path.relative(process.cwd(), helperFilePath)} is missing generated REST schema helper functions: ${missingFunctions.join(", ")}.`,
|
|
37
|
+
"Restore the generated inc/rest-schema.php helper or add these functions manually before retrying.",
|
|
38
|
+
].join(" "));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Scaffold generated TypeScript, PHP, schema, and inventory files for a
|
|
43
|
+
* workspace-owned REST resource.
|
|
44
|
+
*
|
|
45
|
+
* @param options Resolved workspace and raw generated-mode command options.
|
|
46
|
+
* @returns Resolved scaffold metadata for the generated REST resource.
|
|
47
|
+
*/
|
|
48
|
+
export async function scaffoldGeneratedRestResource({ controllerClass, controllerExtends, methods, namespace, permissionCallback, restResourceSlug, routePattern, workspace, }) {
|
|
49
|
+
const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
|
|
50
|
+
const syncRestScriptPath = path.join(workspace.projectDir, "scripts", "sync-rest-contracts.ts");
|
|
51
|
+
const restResourceDir = path.join(workspace.projectDir, "src", "rest", restResourceSlug);
|
|
52
|
+
const typesFilePath = path.join(restResourceDir, "api-types.ts");
|
|
53
|
+
const validatorsFilePath = path.join(restResourceDir, "api-validators.ts");
|
|
54
|
+
const apiFilePath = path.join(restResourceDir, "api.ts");
|
|
55
|
+
const resolvedMethods = assertValidRestResourceMethods(methods);
|
|
56
|
+
const resolvedRoutePattern = resolveGeneratedRestResourceRoutePattern(restResourceSlug, routePattern);
|
|
57
|
+
const hasCustomRoutePattern = typeof routePattern === "string" && routePattern.trim().length > 0;
|
|
58
|
+
const resolvedPermissionCallback = resolveOptionalPhpCallbackReference("Generated REST resource permission callback", permissionCallback);
|
|
59
|
+
const resolvedControllerClass = resolveOptionalPhpClassReference("Generated REST resource controller class", controllerClass);
|
|
60
|
+
const resolvedControllerExtends = resolveOptionalPhpClassReference("Generated REST resource controller base class", controllerExtends);
|
|
61
|
+
if (resolvedControllerExtends && !resolvedControllerClass) {
|
|
62
|
+
throw new Error("Generated REST resource controller base class requires --controller-class.");
|
|
63
|
+
}
|
|
64
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
65
|
+
const dataFilePath = path.join(restResourceDir, "data.ts");
|
|
66
|
+
const restSchemaHelperPath = path.join(workspace.projectDir, "inc", "rest-schema.php");
|
|
67
|
+
const phpFilePath = path.join(workspace.projectDir, "inc", "rest", `${restResourceSlug}.php`);
|
|
68
|
+
const mutationSnapshot = {
|
|
69
|
+
fileSources: await snapshotWorkspaceFiles([
|
|
70
|
+
blockConfigPath,
|
|
71
|
+
bootstrapPath,
|
|
72
|
+
restSchemaHelperPath,
|
|
73
|
+
syncRestScriptPath,
|
|
74
|
+
]),
|
|
75
|
+
snapshotDirs: [],
|
|
76
|
+
targetPaths: [restResourceDir, restSchemaHelperPath, phpFilePath],
|
|
77
|
+
};
|
|
78
|
+
try {
|
|
79
|
+
await fsp.mkdir(restResourceDir, { recursive: true });
|
|
80
|
+
await fsp.mkdir(path.dirname(phpFilePath), { recursive: true });
|
|
81
|
+
await ensureWorkspaceRestSchemaHelperFile(restSchemaHelperPath, workspace.workspace.phpPrefix);
|
|
82
|
+
await ensureRestSchemaHelperBootstrapAnchors(workspace);
|
|
83
|
+
await ensureRestResourceBootstrapAnchors(workspace);
|
|
84
|
+
await ensureRestResourceSyncScriptAnchors(workspace);
|
|
85
|
+
await fsp.writeFile(typesFilePath, buildRestResourceTypesSource(restResourceSlug, resolvedMethods), "utf8");
|
|
86
|
+
await fsp.writeFile(validatorsFilePath, buildRestResourceValidatorsSource(restResourceSlug, resolvedMethods), "utf8");
|
|
87
|
+
await fsp.writeFile(apiFilePath, buildRestResourceApiSource(restResourceSlug, resolvedMethods), "utf8");
|
|
88
|
+
await fsp.writeFile(dataFilePath, buildRestResourceDataSource(restResourceSlug, resolvedMethods), "utf8");
|
|
89
|
+
await fsp.writeFile(phpFilePath, buildRestResourcePhpSource(restResourceSlug, namespace, workspace.workspace.phpPrefix, resolvedMethods, {
|
|
90
|
+
...(resolvedControllerClass
|
|
91
|
+
? { controllerClass: resolvedControllerClass }
|
|
92
|
+
: {}),
|
|
93
|
+
...(resolvedControllerExtends
|
|
94
|
+
? { controllerExtends: resolvedControllerExtends }
|
|
95
|
+
: {}),
|
|
96
|
+
...(resolvedPermissionCallback
|
|
97
|
+
? { permissionCallback: resolvedPermissionCallback }
|
|
98
|
+
: {}),
|
|
99
|
+
routePattern: resolvedRoutePattern,
|
|
100
|
+
}), "utf8");
|
|
101
|
+
await syncRestResourceArtifacts({
|
|
102
|
+
clientFile: `src/rest/${restResourceSlug}/api-client.ts`,
|
|
103
|
+
methods: resolvedMethods,
|
|
104
|
+
outputDir: restResourceDir,
|
|
105
|
+
projectDir: workspace.projectDir,
|
|
106
|
+
typesFile: `src/rest/${restResourceSlug}/api-types.ts`,
|
|
107
|
+
validatorsFile: `src/rest/${restResourceSlug}/api-validators.ts`,
|
|
108
|
+
variables: {
|
|
109
|
+
namespace,
|
|
110
|
+
pascalCase: toPascalCase(restResourceSlug),
|
|
111
|
+
...(hasCustomRoutePattern ? { routePattern: resolvedRoutePattern } : {}),
|
|
112
|
+
slugKebabCase: restResourceSlug,
|
|
113
|
+
title: toTitleCase(restResourceSlug),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
await appendWorkspaceInventoryEntries(workspace.projectDir, {
|
|
117
|
+
restResourceEntries: [
|
|
118
|
+
buildRestResourceConfigEntry({
|
|
119
|
+
...(resolvedControllerClass
|
|
120
|
+
? { controllerClass: resolvedControllerClass }
|
|
121
|
+
: {}),
|
|
122
|
+
...(resolvedControllerExtends
|
|
123
|
+
? { controllerExtends: resolvedControllerExtends }
|
|
124
|
+
: {}),
|
|
125
|
+
methods: resolvedMethods,
|
|
126
|
+
namespace,
|
|
127
|
+
...(resolvedPermissionCallback
|
|
128
|
+
? { permissionCallback: resolvedPermissionCallback }
|
|
129
|
+
: {}),
|
|
130
|
+
restResourceSlug,
|
|
131
|
+
...(hasCustomRoutePattern ? { routePattern: resolvedRoutePattern } : {}),
|
|
132
|
+
}),
|
|
133
|
+
],
|
|
134
|
+
transformSource: ensureBlockConfigCanAddRestManifests,
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
...(resolvedControllerClass
|
|
138
|
+
? { controllerClass: resolvedControllerClass }
|
|
139
|
+
: {}),
|
|
140
|
+
...(resolvedControllerExtends
|
|
141
|
+
? { controllerExtends: resolvedControllerExtends }
|
|
142
|
+
: {}),
|
|
143
|
+
methods: resolvedMethods,
|
|
144
|
+
mode: "generated",
|
|
145
|
+
namespace,
|
|
146
|
+
...(resolvedPermissionCallback
|
|
147
|
+
? { permissionCallback: resolvedPermissionCallback }
|
|
148
|
+
: {}),
|
|
149
|
+
projectDir: workspace.projectDir,
|
|
150
|
+
restResourceSlug,
|
|
151
|
+
...(hasCustomRoutePattern ? { routePattern: resolvedRoutePattern } : {}),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ManualRestContractScaffoldOptions, type RunAddRestResourceCommandResult } from "./cli-add-workspace-rest-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scaffold a type-only external REST contract for workspace consumers.
|
|
4
|
+
*
|
|
5
|
+
* @param options Resolved workspace and raw manual-mode command options.
|
|
6
|
+
* @returns Resolved scaffold metadata for the manual REST contract.
|
|
7
|
+
*/
|
|
8
|
+
export declare function scaffoldManualRestContract({ auth, bodyTypeName, controllerClass, controllerExtends, method, namespace, pathPattern, permissionCallback, queryTypeName, responseTypeName, restResourceSlug, routePattern, secretFieldName, secretHasValueFieldName, secretMaskedResponseFieldName, secretPreserveOnEmpty, secretStateFieldName, workspace, }: ManualRestContractScaffoldOptions): Promise<RunAddRestResourceCommandResult>;
|