wp-typia 0.22.9 → 0.23.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/README.md +5 -0
- package/bin/routing-metadata.generated.js +16 -0
- package/dist-bunli/.bunli/commands.gen.js +7312 -3829
- package/dist-bunli/{cli-2pnk64h0.js → cli-1meywwsy.js} +148 -124
- package/dist-bunli/{cli-fys8vm2t.js → cli-43mx1vfb.js} +4 -1
- package/dist-bunli/{cli-ag722tzm.js → cli-9npd9was.js} +9 -5
- package/dist-bunli/{cli-add-6dn9h94t.js → cli-add-21bvpfgw.js} +4591 -2319
- package/dist-bunli/{cli-arz4rcye.js → cli-agywa5n6.js} +6 -6
- package/dist-bunli/{cli-xw1wbxf3.js → cli-c2acv5dv.js} +1 -1
- package/dist-bunli/{cli-doctor-564c43ay.js → cli-doctor-wy2yjsge.js} +245 -146
- package/dist-bunli/{cli-init-znhqp8tr.js → cli-init-xnsbxncv.js} +16 -6
- package/dist-bunli/{cli-rwjkqjhs.js → cli-j8et6jvr.js} +37 -2
- package/dist-bunli/{cli-scaffold-6trxyyk6.js → cli-scaffold-zhp2ym8z.js} +9 -9
- package/dist-bunli/{cli-regw5384.js → cli-ts9thts5.js} +1568 -1035
- package/dist-bunli/{cli-y934dq2k.js → cli-z5qkx2pn.js} +197 -100
- package/dist-bunli/cli.js +3 -3
- package/dist-bunli/{command-list-g3qhb3y4.js → command-list-aqrkx021.js} +881 -505
- package/dist-bunli/{migrations-qc1r0yqe.js → migrations-bx0yvc2v.js} +4 -4
- package/dist-bunli/node-cli.js +1173 -693
- package/package.json +2 -2
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
+
hasAdminViewManualSettingsRouteParameters,
|
|
3
4
|
hasExecutablePattern,
|
|
4
5
|
hasUncommentedPattern,
|
|
6
|
+
isAdminViewManualSettingsRestResource,
|
|
5
7
|
maskTypeScriptCommentsAndLiterals
|
|
6
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-j8et6jvr.js";
|
|
7
9
|
import {
|
|
8
10
|
getBuiltInTemplateLayerDirs,
|
|
9
11
|
isOmittableBuiltInTemplateLayerDir
|
|
10
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-c2acv5dv.js";
|
|
11
13
|
import {
|
|
12
14
|
isBuiltInTemplateId,
|
|
13
15
|
listTemplates
|
|
@@ -16,15 +18,20 @@ import {
|
|
|
16
18
|
EDITOR_PLUGIN_SLOT_IDS,
|
|
17
19
|
HOOKED_BLOCK_ANCHOR_PATTERN,
|
|
18
20
|
HOOKED_BLOCK_POSITION_SET,
|
|
21
|
+
MANUAL_REST_CONTRACT_AUTH_IDS,
|
|
22
|
+
MANUAL_REST_CONTRACT_HTTP_METHOD_IDS,
|
|
19
23
|
REST_RESOURCE_METHOD_IDS,
|
|
20
24
|
REST_RESOURCE_NAMESPACE_PATTERN,
|
|
25
|
+
assertValidPostMetaPostType,
|
|
21
26
|
escapeRegex,
|
|
22
|
-
|
|
27
|
+
isGeneratedRestResourceRoutePatternCompatible,
|
|
28
|
+
pathExists,
|
|
29
|
+
readWorkspaceInventoryAsync,
|
|
23
30
|
resolveEditorPluginSlotAlias
|
|
24
|
-
} from "./cli-
|
|
31
|
+
} from "./cli-ts9thts5.js";
|
|
25
32
|
import"./cli-cvxvcw7c.js";
|
|
26
33
|
import"./cli-t73q5aqz.js";
|
|
27
|
-
import"./cli-
|
|
34
|
+
import"./cli-43mx1vfb.js";
|
|
28
35
|
import {
|
|
29
36
|
CLI_DIAGNOSTIC_CODES,
|
|
30
37
|
createCliCommandError,
|
|
@@ -44,9 +51,55 @@ import"./cli-xnn9xjcy.js";
|
|
|
44
51
|
// ../wp-typia-project-tools/src/runtime/cli-doctor-environment.ts
|
|
45
52
|
import { execFileSync } from "child_process";
|
|
46
53
|
import { access, constants as fsConstants, rm, writeFile } from "fs/promises";
|
|
47
|
-
import
|
|
54
|
+
import fs2 from "fs";
|
|
48
55
|
import os from "os";
|
|
56
|
+
import path2 from "path";
|
|
57
|
+
|
|
58
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-shared.ts
|
|
59
|
+
import fs from "fs";
|
|
49
60
|
import path from "path";
|
|
61
|
+
var WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
62
|
+
var WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
63
|
+
var WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
64
|
+
var WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php";
|
|
65
|
+
var WORKSPACE_POST_META_GLOB = "/inc/post-meta/*.php";
|
|
66
|
+
var WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
|
|
67
|
+
var WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
|
|
68
|
+
var WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
|
|
69
|
+
var WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php";
|
|
70
|
+
var WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php";
|
|
71
|
+
var WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js";
|
|
72
|
+
var WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php";
|
|
73
|
+
var WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css";
|
|
74
|
+
var WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js";
|
|
75
|
+
var WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php";
|
|
76
|
+
var WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css";
|
|
77
|
+
var WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
78
|
+
"block.json",
|
|
79
|
+
"typia.manifest.json",
|
|
80
|
+
"typia.schema.json",
|
|
81
|
+
"typia-validator.php",
|
|
82
|
+
"typia.openapi.json"
|
|
83
|
+
];
|
|
84
|
+
var WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
85
|
+
function createDoctorCheck(label, status, detail, code) {
|
|
86
|
+
return code ? { code, detail, label, status } : { detail, label, status };
|
|
87
|
+
}
|
|
88
|
+
function createDoctorScopeCheck(status, detail) {
|
|
89
|
+
return createDoctorCheck("Doctor scope", status, detail);
|
|
90
|
+
}
|
|
91
|
+
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
92
|
+
return `${packageName.split("/").pop() ?? packageName}.php`;
|
|
93
|
+
}
|
|
94
|
+
function resolveWorkspaceBootstrapPath(projectDir, packageName) {
|
|
95
|
+
return path.join(projectDir, getWorkspaceBootstrapRelativePath(packageName));
|
|
96
|
+
}
|
|
97
|
+
function checkExistingFiles(projectDir, label, filePaths) {
|
|
98
|
+
const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs.existsSync(path.join(projectDir, filePath)));
|
|
99
|
+
return createDoctorCheck(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-environment.ts
|
|
50
103
|
function readCommandVersion(command, args = ["--version"]) {
|
|
51
104
|
try {
|
|
52
105
|
return execFileSync(command, args, {
|
|
@@ -70,7 +123,7 @@ async function checkWritableDirectory(directory) {
|
|
|
70
123
|
}
|
|
71
124
|
}
|
|
72
125
|
async function checkTempDirectory() {
|
|
73
|
-
const tempFile =
|
|
126
|
+
const tempFile = path2.join(os.tmpdir(), `wp-typia-${Date.now()}.tmp`);
|
|
74
127
|
try {
|
|
75
128
|
await writeFile(tempFile, "ok", "utf8");
|
|
76
129
|
await rm(tempFile, { force: true });
|
|
@@ -79,15 +132,12 @@ async function checkTempDirectory() {
|
|
|
79
132
|
return false;
|
|
80
133
|
}
|
|
81
134
|
}
|
|
82
|
-
function createDoctorCheck(label, status, detail) {
|
|
83
|
-
return { detail, label, status };
|
|
84
|
-
}
|
|
85
135
|
function getTemplateDoctorChecks() {
|
|
86
136
|
const checks = [];
|
|
87
137
|
for (const template of listTemplates()) {
|
|
88
138
|
if (!isBuiltInTemplateId(template.id)) {
|
|
89
|
-
const templateDirExists =
|
|
90
|
-
const hasAssets2 = templateDirExists &&
|
|
139
|
+
const templateDirExists = fs2.existsSync(template.templateDir);
|
|
140
|
+
const hasAssets2 = templateDirExists && fs2.existsSync(path2.join(template.templateDir, "package.json.mustache"));
|
|
91
141
|
checks.push({
|
|
92
142
|
status: !templateDirExists || hasAssets2 ? "pass" : "fail",
|
|
93
143
|
label: `Template ${template.id}`,
|
|
@@ -110,9 +160,9 @@ function getTemplateDoctorChecks() {
|
|
|
110
160
|
persistencePolicy: "public"
|
|
111
161
|
})
|
|
112
162
|
])) : getBuiltInTemplateLayerDirs(builtInTemplateId);
|
|
113
|
-
const missingRequiredLayer = layerDirs.some((layerDir) => !
|
|
114
|
-
const existingLayerDirs = layerDirs.filter((layerDir) =>
|
|
115
|
-
const hasAssets = !missingRequiredLayer && existingLayerDirs.some((layerDir) =>
|
|
163
|
+
const missingRequiredLayer = layerDirs.some((layerDir) => !fs2.existsSync(layerDir) && !isOmittableBuiltInTemplateLayerDir(builtInTemplateId, layerDir));
|
|
164
|
+
const existingLayerDirs = layerDirs.filter((layerDir) => fs2.existsSync(layerDir));
|
|
165
|
+
const hasAssets = !missingRequiredLayer && existingLayerDirs.some((layerDir) => fs2.existsSync(path2.join(layerDir, "package.json.mustache"))) && existingLayerDirs.some((layerDir) => fs2.existsSync(path2.join(layerDir, "src")));
|
|
116
166
|
checks.push({
|
|
117
167
|
status: hasAssets ? "pass" : "fail",
|
|
118
168
|
label: `Template ${template.id}`,
|
|
@@ -141,72 +191,27 @@ async function getEnvironmentDoctorChecks(cwd) {
|
|
|
141
191
|
import fs3 from "fs";
|
|
142
192
|
import path3 from "path";
|
|
143
193
|
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
144
|
-
|
|
145
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-shared.ts
|
|
146
|
-
import fs2 from "fs";
|
|
147
|
-
import path2 from "path";
|
|
148
|
-
var WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
149
|
-
var WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
150
|
-
var WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
151
|
-
var WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php";
|
|
152
|
-
var WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
|
|
153
|
-
var WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
|
|
154
|
-
var WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
|
|
155
|
-
var WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php";
|
|
156
|
-
var WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php";
|
|
157
|
-
var WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js";
|
|
158
|
-
var WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php";
|
|
159
|
-
var WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css";
|
|
160
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js";
|
|
161
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php";
|
|
162
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css";
|
|
163
|
-
var WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
164
|
-
"block.json",
|
|
165
|
-
"typia.manifest.json",
|
|
166
|
-
"typia.schema.json",
|
|
167
|
-
"typia-validator.php",
|
|
168
|
-
"typia.openapi.json"
|
|
169
|
-
];
|
|
170
|
-
var WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
171
|
-
function createDoctorCheck2(label, status, detail, code) {
|
|
172
|
-
return code ? { code, detail, label, status } : { detail, label, status };
|
|
173
|
-
}
|
|
174
|
-
function createDoctorScopeCheck(status, detail) {
|
|
175
|
-
return createDoctorCheck2("Doctor scope", status, detail);
|
|
176
|
-
}
|
|
177
|
-
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
178
|
-
return `${packageName.split("/").pop() ?? packageName}.php`;
|
|
179
|
-
}
|
|
180
|
-
function resolveWorkspaceBootstrapPath(projectDir, packageName) {
|
|
181
|
-
return path2.join(projectDir, getWorkspaceBootstrapRelativePath(packageName));
|
|
182
|
-
}
|
|
183
|
-
function checkExistingFiles(projectDir, label, filePaths) {
|
|
184
|
-
const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs2.existsSync(path2.join(projectDir, filePath)));
|
|
185
|
-
return createDoctorCheck2(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-bindings.ts
|
|
189
194
|
function checkWorkspaceBindingBootstrap(projectDir, packageName) {
|
|
190
195
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
191
196
|
if (!fs3.existsSync(bootstrapPath)) {
|
|
192
|
-
return
|
|
197
|
+
return createDoctorCheck("Binding bootstrap", "fail", `Missing ${path3.basename(bootstrapPath)}`);
|
|
193
198
|
}
|
|
194
199
|
const source = fs3.readFileSync(bootstrapPath, "utf8");
|
|
195
200
|
const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
|
|
196
201
|
const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
|
|
197
202
|
const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
|
|
198
203
|
const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
|
|
199
|
-
return
|
|
204
|
+
return createDoctorCheck("Binding bootstrap", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "pass" : "fail", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "Binding source PHP and editor bootstrap hooks are present" : "Missing binding source PHP require glob or editor enqueue hook");
|
|
200
205
|
}
|
|
201
206
|
function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
|
|
202
207
|
const indexRelativePath = [path3.join("src", "bindings", "index.ts"), path3.join("src", "bindings", "index.js")].find((relativePath) => fs3.existsSync(path3.join(projectDir, relativePath)));
|
|
203
208
|
if (!indexRelativePath) {
|
|
204
|
-
return
|
|
209
|
+
return createDoctorCheck("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
|
|
205
210
|
}
|
|
206
211
|
const indexPath = path3.join(projectDir, indexRelativePath);
|
|
207
212
|
const source = fs3.readFileSync(indexPath, "utf8");
|
|
208
213
|
const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
|
|
209
|
-
return
|
|
214
|
+
return createDoctorCheck("Binding sources index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Binding source editor registrations are aggregated" : `Missing editor imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
210
215
|
}
|
|
211
216
|
function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
|
|
212
217
|
const hasBlock = bindingSource.block !== undefined;
|
|
@@ -215,10 +220,10 @@ function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs
|
|
|
215
220
|
return;
|
|
216
221
|
}
|
|
217
222
|
if (!bindingSource.block || !bindingSource.attribute) {
|
|
218
|
-
return
|
|
223
|
+
return createDoctorCheck(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
|
|
219
224
|
}
|
|
220
225
|
if (!registeredBlockSlugs.has(bindingSource.block)) {
|
|
221
|
-
return
|
|
226
|
+
return createDoctorCheck(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
|
|
222
227
|
}
|
|
223
228
|
const blockJsonRelativePath = path3.join("src", "blocks", bindingSource.block, "block.json");
|
|
224
229
|
const blockJsonPath = path3.join(projectDir, blockJsonRelativePath);
|
|
@@ -271,7 +276,7 @@ function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs
|
|
|
271
276
|
} else {
|
|
272
277
|
issues.push(`Missing ${bindingSource.editorFile}`);
|
|
273
278
|
}
|
|
274
|
-
return
|
|
279
|
+
return createDoctorCheck(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
|
|
275
280
|
}
|
|
276
281
|
function getWorkspaceBindingDoctorChecks(workspace, inventory) {
|
|
277
282
|
const checks = [];
|
|
@@ -484,13 +489,13 @@ function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
|
484
489
|
const blockJsonRelativePath = path4.join("src", "blocks", block.slug, "block.json");
|
|
485
490
|
const blockJsonPath = path4.join(projectDir, blockJsonRelativePath);
|
|
486
491
|
if (!fs4.existsSync(blockJsonPath)) {
|
|
487
|
-
return
|
|
492
|
+
return createDoctorCheck(`Block metadata ${block.slug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
488
493
|
}
|
|
489
494
|
let blockJson;
|
|
490
495
|
try {
|
|
491
496
|
blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs4.readFileSync(blockJsonPath, "utf8")));
|
|
492
497
|
} catch (error) {
|
|
493
|
-
return
|
|
498
|
+
return createDoctorCheck(`Block metadata ${block.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
494
499
|
}
|
|
495
500
|
const expectedName = `${workspace.workspace.namespace}/${block.slug}`;
|
|
496
501
|
const issues = [];
|
|
@@ -500,46 +505,46 @@ function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
|
500
505
|
if (blockJson.textdomain !== workspace.workspace.textDomain) {
|
|
501
506
|
issues.push(`block.json textdomain must equal "${workspace.workspace.textDomain}"`);
|
|
502
507
|
}
|
|
503
|
-
return
|
|
508
|
+
return createDoctorCheck(`Block metadata ${block.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `block.json matches ${expectedName} and ${workspace.workspace.textDomain}` : issues.join("; "));
|
|
504
509
|
}
|
|
505
510
|
function checkWorkspaceBlockHooks(projectDir, blockSlug) {
|
|
506
511
|
const blockJsonRelativePath = path4.join("src", "blocks", blockSlug, "block.json");
|
|
507
512
|
const blockJsonPath = path4.join(projectDir, blockJsonRelativePath);
|
|
508
513
|
if (!fs4.existsSync(blockJsonPath)) {
|
|
509
|
-
return
|
|
514
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
510
515
|
}
|
|
511
516
|
let blockJson;
|
|
512
517
|
try {
|
|
513
518
|
blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs4.readFileSync(blockJsonPath, "utf8")));
|
|
514
519
|
} catch (error) {
|
|
515
|
-
return
|
|
520
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
516
521
|
}
|
|
517
522
|
const blockHooks = blockJson.blockHooks;
|
|
518
523
|
if (blockHooks === undefined) {
|
|
519
|
-
return
|
|
524
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "pass", "No blockHooks metadata configured");
|
|
520
525
|
}
|
|
521
526
|
if (!blockHooks || typeof blockHooks !== "object" || Array.isArray(blockHooks)) {
|
|
522
|
-
return
|
|
527
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `${blockJsonRelativePath} must define blockHooks as an object when present.`);
|
|
523
528
|
}
|
|
524
529
|
const blockName = typeof blockJson.name === "string" && blockJson.name.trim().length > 0 ? blockJson.name.trim() : null;
|
|
525
530
|
const invalidEntries = Object.entries(blockHooks).filter(([anchor, position]) => blockName !== null && anchor.trim() === blockName || anchor.trim().length === 0 || anchor !== anchor.trim() || !HOOKED_BLOCK_ANCHOR_PATTERN.test(anchor) || typeof position !== "string" || !HOOKED_BLOCK_POSITION_SET.has(position));
|
|
526
|
-
return
|
|
531
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, invalidEntries.length === 0 ? "pass" : "fail", invalidEntries.length === 0 ? `blockHooks metadata is valid${Object.keys(blockHooks).length > 0 ? ` (${Object.keys(blockHooks).join(", ")})` : ""}` : `Invalid blockHooks entries: ${invalidEntries.map(([anchor, position]) => `${anchor || "<empty>"} => ${String(position)}`).join(", ")}`);
|
|
527
532
|
}
|
|
528
533
|
function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
|
|
529
534
|
const entryRelativePath = path4.join("src", "blocks", blockSlug, "index.tsx");
|
|
530
535
|
const entryPath = path4.join(projectDir, entryRelativePath);
|
|
531
536
|
if (!fs4.existsSync(entryPath)) {
|
|
532
|
-
return
|
|
537
|
+
return createDoctorCheck(`Block collection ${blockSlug}`, "fail", `Missing ${entryRelativePath}`);
|
|
533
538
|
}
|
|
534
539
|
const source = fs4.readFileSync(entryPath, "utf8");
|
|
535
540
|
const hasCollectionImport = WORKSPACE_COLLECTION_IMPORT_PATTERN.test(source);
|
|
536
|
-
return
|
|
541
|
+
return createDoctorCheck(`Block collection ${blockSlug}`, hasCollectionImport ? "pass" : "fail", hasCollectionImport ? "Shared block collection import is present" : `Missing a shared collection import like ${WORKSPACE_COLLECTION_IMPORT_LINE}`);
|
|
537
542
|
}
|
|
538
543
|
function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
|
|
539
544
|
const metadataResult = readWorkspaceBlockIframeMetadata(projectDir, blockSlug);
|
|
540
545
|
if (!metadataResult.document) {
|
|
541
546
|
return [
|
|
542
|
-
|
|
547
|
+
createDoctorCheck(`Block iframe/API v3 ${blockSlug}`, "warn", metadataResult.error ?? `Unable to inspect ${metadataResult.blockJsonRelativePath}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION)
|
|
543
548
|
];
|
|
544
549
|
}
|
|
545
550
|
const blockJson = metadataResult.document;
|
|
@@ -555,51 +560,51 @@ function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
|
|
|
555
560
|
const blockWrapperStatus = editorWrapperSources.length === 0 || hasEditorBlockPropsUsage ? "pass" : "warn";
|
|
556
561
|
const blockWrapperDetail = editorSources.length === 0 ? "No editor-facing block source files found; general file checks will report missing entrypoints" : editorWrapperSources.length === 0 ? "No editor wrapper source files found; general file checks will report missing entrypoints" : hasEditorBlockPropsUsage ? "Editor-facing sources use block wrapper props" : hasBlockPropsUsage ? "Only save-facing useBlockProps.save() usage was detected. Confirm the editor wrapper also receives useBlockProps() or useInnerBlocksProps() before relying on iframe editor rendering." : "No useBlockProps(), useBlockProps.save(), or useInnerBlocksProps() usage was detected in editor-facing sources. Confirm the block wrapper receives WordPress block editor props before relying on iframe editor rendering.";
|
|
557
562
|
return [
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
563
|
+
createDoctorCheck(`Block iframe API version ${blockSlug}`, apiVersion !== null && apiVersion >= 3 ? "pass" : "warn", apiVersion !== null && apiVersion >= 3 ? "block.json declares apiVersion 3 for iframe editor readiness" : `Set ${metadataResult.blockJsonRelativePath} apiVersion to 3 after testing the block in iframe-enabled Post Editor and Site Editor contexts. WordPress recommends API v3 for iframe editor compatibility. See ${WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION),
|
|
564
|
+
createDoctorCheck(`Block iframe styles ${blockSlug}`, localStyleFiles.length === 0 || hasRegisteredEditorStyles ? "pass" : "warn", localStyleFiles.length === 0 ? "No local block stylesheet source files found to register" : hasRegisteredEditorStyles ? "block.json registers block styles for iframe editor loading" : `Found stylesheet source files (${localStyleFiles.join(", ")}) but block.json does not declare style or editorStyle. Register block content styles so iframe editors do not depend on parent admin styles.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_STYLES),
|
|
565
|
+
createDoctorCheck(`Block iframe globals ${blockSlug}`, globalDomAccesses.length === 0 ? "pass" : "warn", globalDomAccesses.length === 0 ? "No direct window/document/parent DOM access detected in editor-facing block sources" : `Direct global DOM access detected at ${globalDomAccesses.join(", ")}. Prefer element.ownerDocument/defaultView via refs or useRefEffect for iframe editor content.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_GLOBALS),
|
|
566
|
+
createDoctorCheck(`Block iframe wrapper ${blockSlug}`, blockWrapperStatus, blockWrapperDetail, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.BLOCK_PROPS)
|
|
562
567
|
];
|
|
563
568
|
}
|
|
564
569
|
function checkWorkspacePatternBootstrap(projectDir, packageName) {
|
|
565
570
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
566
571
|
if (!fs4.existsSync(bootstrapPath)) {
|
|
567
|
-
return
|
|
572
|
+
return createDoctorCheck("Pattern bootstrap", "fail", `Missing ${path4.basename(bootstrapPath)}`);
|
|
568
573
|
}
|
|
569
574
|
const source = fs4.readFileSync(bootstrapPath, "utf8");
|
|
570
575
|
const hasCategoryAnchor = source.includes("register_block_pattern_category");
|
|
571
576
|
const hasPatternGlob = source.includes("/src/patterns/*.php");
|
|
572
|
-
return
|
|
577
|
+
return createDoctorCheck("Pattern bootstrap", hasCategoryAnchor && hasPatternGlob ? "pass" : "fail", hasCategoryAnchor && hasPatternGlob ? "Pattern category and loader hooks are present" : "Missing pattern category registration or src/patterns loader hook");
|
|
573
578
|
}
|
|
574
579
|
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
575
580
|
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
576
581
|
if (!fs4.existsSync(entryPath)) {
|
|
577
|
-
return
|
|
582
|
+
return createDoctorCheck(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
578
583
|
}
|
|
579
584
|
const source = fs4.readFileSync(entryPath, "utf8");
|
|
580
585
|
const hasImport = hasUncommentedPattern(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
|
|
581
586
|
const hasCall = hasExecutablePattern(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
|
|
582
|
-
return
|
|
587
|
+
return createDoctorCheck(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
583
588
|
}
|
|
584
589
|
function checkBlockStyleEntrypoint(projectDir, blockSlug) {
|
|
585
590
|
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
586
591
|
if (!fs4.existsSync(entryPath)) {
|
|
587
|
-
return
|
|
592
|
+
return createDoctorCheck(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
588
593
|
}
|
|
589
594
|
const source = fs4.readFileSync(entryPath, "utf8");
|
|
590
595
|
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
|
|
591
596
|
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
|
|
592
|
-
return
|
|
597
|
+
return createDoctorCheck(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
|
|
593
598
|
}
|
|
594
599
|
function checkBlockTransformEntrypoint(projectDir, blockSlug) {
|
|
595
600
|
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
596
601
|
if (!fs4.existsSync(entryPath)) {
|
|
597
|
-
return
|
|
602
|
+
return createDoctorCheck(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
598
603
|
}
|
|
599
604
|
const source = fs4.readFileSync(entryPath, "utf8");
|
|
600
605
|
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
|
|
601
606
|
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
|
|
602
|
-
return
|
|
607
|
+
return createDoctorCheck(`Block transform entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block transform registration hook is present" : "Missing ./transforms import or applyWorkspaceBlockTransforms(registration.settings) call");
|
|
603
608
|
}
|
|
604
609
|
function checkBlockTransformConfig(workspace, transform) {
|
|
605
610
|
const expectedTo = `${workspace.workspace.namespace}/${transform.block}`;
|
|
@@ -610,7 +615,7 @@ function checkBlockTransformConfig(workspace, transform) {
|
|
|
610
615
|
if (transform.to !== expectedTo) {
|
|
611
616
|
issues.push(`to must equal "${expectedTo}" for workspace block "${transform.block}"`);
|
|
612
617
|
}
|
|
613
|
-
return
|
|
618
|
+
return createDoctorCheck(`Block transform config ${transform.block}/${transform.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${transform.from} transforms into ${transform.to}` : issues.join("; "));
|
|
614
619
|
}
|
|
615
620
|
function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
616
621
|
const checks = [];
|
|
@@ -625,7 +630,7 @@ function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
|
625
630
|
const variationTargetBlocks = new Set;
|
|
626
631
|
for (const variation of inventory.variations) {
|
|
627
632
|
if (!registeredBlockSlugs.has(variation.block)) {
|
|
628
|
-
checks.push(
|
|
633
|
+
checks.push(createDoctorCheck(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
|
|
629
634
|
continue;
|
|
630
635
|
}
|
|
631
636
|
variationTargetBlocks.add(variation.block);
|
|
@@ -637,7 +642,7 @@ function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
|
637
642
|
const blockStyleTargetBlocks = new Set;
|
|
638
643
|
for (const blockStyle of inventory.blockStyles) {
|
|
639
644
|
if (!registeredBlockSlugs.has(blockStyle.block)) {
|
|
640
|
-
checks.push(
|
|
645
|
+
checks.push(createDoctorCheck(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
|
|
641
646
|
continue;
|
|
642
647
|
}
|
|
643
648
|
blockStyleTargetBlocks.add(blockStyle.block);
|
|
@@ -652,7 +657,7 @@ function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
|
652
657
|
const blockTransformTargetBlocks = new Set;
|
|
653
658
|
for (const blockTransform of inventory.blockTransforms) {
|
|
654
659
|
if (!registeredBlockSlugs.has(blockTransform.block)) {
|
|
655
|
-
checks.push(
|
|
660
|
+
checks.push(createDoctorCheck(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
|
|
656
661
|
continue;
|
|
657
662
|
}
|
|
658
663
|
blockTransformTargetBlocks.add(blockTransform.block);
|
|
@@ -678,8 +683,26 @@ function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
|
678
683
|
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features.ts
|
|
679
684
|
import fs5 from "fs";
|
|
680
685
|
import path5 from "path";
|
|
686
|
+
function isManualRestResource(restResource) {
|
|
687
|
+
return restResource.mode === "manual";
|
|
688
|
+
}
|
|
681
689
|
function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
682
690
|
const schemaNames = new Set;
|
|
691
|
+
if (isManualRestResource(restResource)) {
|
|
692
|
+
schemaNames.add("query");
|
|
693
|
+
if (restResource.bodyTypeName) {
|
|
694
|
+
schemaNames.add("request");
|
|
695
|
+
}
|
|
696
|
+
schemaNames.add("response");
|
|
697
|
+
return Array.from(new Set([
|
|
698
|
+
restResource.apiFile,
|
|
699
|
+
...Array.from(schemaNames, (schemaName) => path5.join(path5.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
700
|
+
restResource.clientFile,
|
|
701
|
+
restResource.openApiFile,
|
|
702
|
+
restResource.typesFile,
|
|
703
|
+
restResource.validatorsFile
|
|
704
|
+
]));
|
|
705
|
+
}
|
|
683
706
|
if (restResource.methods.includes("list")) {
|
|
684
707
|
schemaNames.add("list-query");
|
|
685
708
|
schemaNames.add("list-response");
|
|
@@ -705,29 +728,80 @@ function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
|
705
728
|
restResource.apiFile,
|
|
706
729
|
...Array.from(schemaNames, (schemaName) => path5.join(path5.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
707
730
|
restResource.clientFile,
|
|
708
|
-
restResource.dataFile,
|
|
731
|
+
...restResource.dataFile ? [restResource.dataFile] : [],
|
|
709
732
|
restResource.openApiFile,
|
|
710
|
-
restResource.phpFile,
|
|
733
|
+
...restResource.phpFile ? [restResource.phpFile] : [],
|
|
711
734
|
restResource.typesFile,
|
|
712
735
|
restResource.validatorsFile
|
|
713
736
|
]));
|
|
714
737
|
}
|
|
715
738
|
function checkWorkspaceRestResourceConfig(restResource) {
|
|
716
739
|
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(restResource.namespace);
|
|
740
|
+
if (isManualRestResource(restResource)) {
|
|
741
|
+
const hasAuth = restResource.auth == null || MANUAL_REST_CONTRACT_AUTH_IDS.includes(restResource.auth);
|
|
742
|
+
const hasMethod = typeof restResource.method === "string" && MANUAL_REST_CONTRACT_HTTP_METHOD_IDS.includes(restResource.method);
|
|
743
|
+
const hasPathPattern = typeof restResource.pathPattern === "string" && restResource.pathPattern.startsWith("/") && restResource.pathPattern.length > 1;
|
|
744
|
+
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasAuth && hasMethod && hasPathPattern ? "pass" : "fail", hasNamespace && hasAuth && hasMethod && hasPathPattern ? `Manual REST contract ${restResource.method} /${restResource.namespace}${restResource.pathPattern}` : "Manual REST contract namespace, auth, method, or path pattern is invalid");
|
|
745
|
+
}
|
|
717
746
|
const hasMethods = restResource.methods.length > 0 && restResource.methods.every((method) => REST_RESOURCE_METHOD_IDS.includes(method));
|
|
718
|
-
|
|
747
|
+
const hasGeneratedFiles = typeof restResource.dataFile === "string" && restResource.dataFile.length > 0 && typeof restResource.phpFile === "string" && restResource.phpFile.length > 0;
|
|
748
|
+
const hasRoutePattern = restResource.routePattern == null || typeof restResource.routePattern === "string" && restResource.routePattern.startsWith("/") && restResource.routePattern.length > 1 && !/\s/u.test(restResource.routePattern) && isGeneratedRestResourceRoutePatternCompatible(restResource.routePattern);
|
|
749
|
+
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern ? "pass" : "fail", hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern ? `REST resource namespace ${restResource.namespace} with methods ${restResource.methods.join(", ")}` : "REST resource namespace, methods, dataFile, phpFile, or routePattern are invalid");
|
|
719
750
|
}
|
|
720
751
|
function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
|
|
721
752
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
722
753
|
if (!fs5.existsSync(bootstrapPath)) {
|
|
723
|
-
return
|
|
754
|
+
return createDoctorCheck("REST resource bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
724
755
|
}
|
|
725
756
|
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
726
757
|
const registerFunctionName = `${phpPrefix}_register_rest_resources`;
|
|
727
758
|
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
728
759
|
const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
|
|
729
760
|
const hasRegisterHook = source.includes(registerHook);
|
|
730
|
-
return
|
|
761
|
+
return createDoctorCheck("REST resource bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "REST resource PHP loader hook is present" : "Missing REST resource PHP require glob or init hook");
|
|
762
|
+
}
|
|
763
|
+
function getWorkspacePostMetaRequiredFiles(postMeta) {
|
|
764
|
+
return Array.from(new Set([
|
|
765
|
+
postMeta.phpFile,
|
|
766
|
+
postMeta.schemaFile,
|
|
767
|
+
postMeta.typesFile
|
|
768
|
+
]));
|
|
769
|
+
}
|
|
770
|
+
function checkWorkspacePostMetaConfig(postMeta) {
|
|
771
|
+
let hasPostType = false;
|
|
772
|
+
try {
|
|
773
|
+
hasPostType = assertValidPostMetaPostType(postMeta.postType) === postMeta.postType;
|
|
774
|
+
} catch {
|
|
775
|
+
hasPostType = false;
|
|
776
|
+
}
|
|
777
|
+
const hasMetaKey = typeof postMeta.metaKey === "string" && postMeta.metaKey.trim().length > 0 && !/\s/u.test(postMeta.metaKey);
|
|
778
|
+
const hasRestExposure = typeof postMeta.showInRest === "boolean";
|
|
779
|
+
return createDoctorCheck(`Post meta config ${postMeta.slug}`, hasPostType && hasMetaKey && hasRestExposure ? "pass" : "fail", hasPostType && hasMetaKey && hasRestExposure ? `Post meta ${postMeta.metaKey} targets ${postMeta.postType}` : "Post meta postType, metaKey, or showInRest configuration is invalid");
|
|
780
|
+
}
|
|
781
|
+
function checkWorkspacePostMetaBootstrap(projectDir, packageName, phpPrefix) {
|
|
782
|
+
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
783
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
784
|
+
return createDoctorCheck("Post meta bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
785
|
+
}
|
|
786
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
787
|
+
const registerFunctionName = `${phpPrefix}_register_post_meta_contracts`;
|
|
788
|
+
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
789
|
+
const hasServerGlob = source.includes(WORKSPACE_POST_META_GLOB);
|
|
790
|
+
const hasRegisterHook = source.includes(registerHook);
|
|
791
|
+
return createDoctorCheck("Post meta bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "Post meta PHP loader hook is present" : "Missing post meta PHP require glob or init hook");
|
|
792
|
+
}
|
|
793
|
+
function checkWorkspacePostMetaPhp(projectDir, postMeta) {
|
|
794
|
+
const phpPath = path5.join(projectDir, postMeta.phpFile);
|
|
795
|
+
if (!fs5.existsSync(phpPath)) {
|
|
796
|
+
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, "fail", `Missing ${postMeta.phpFile}`);
|
|
797
|
+
}
|
|
798
|
+
const source = fs5.readFileSync(phpPath, "utf8");
|
|
799
|
+
const hasRegisterPostMeta = source.includes("register_post_meta");
|
|
800
|
+
const hasPostType = source.includes(postMeta.postType);
|
|
801
|
+
const hasMetaKey = source.includes(postMeta.metaKey);
|
|
802
|
+
const hasSchemaFile = source.includes(postMeta.schemaFile);
|
|
803
|
+
const hasRestExposure = source.includes("'show_in_rest'");
|
|
804
|
+
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure ? "pass" : "fail", hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure ? "Post meta registration, schema path, and REST exposure flag are wired" : "Missing register_post_meta, post type, meta key, schema path, or show_in_rest wiring");
|
|
731
805
|
}
|
|
732
806
|
function getWorkspaceAbilityRequiredFiles(ability) {
|
|
733
807
|
return Array.from(new Set([
|
|
@@ -743,7 +817,7 @@ function getWorkspaceAbilityRequiredFiles(ability) {
|
|
|
743
817
|
function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
744
818
|
const configPath = path5.join(projectDir, ability.configFile);
|
|
745
819
|
if (!fs5.existsSync(configPath)) {
|
|
746
|
-
return
|
|
820
|
+
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
|
|
747
821
|
}
|
|
748
822
|
try {
|
|
749
823
|
const config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
|
|
@@ -751,15 +825,15 @@ function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
|
751
825
|
const categorySlug = typeof config.category?.slug === "string" ? config.category.slug.trim() : "";
|
|
752
826
|
const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
|
|
753
827
|
const hasValidCategorySlug = /^[a-z0-9-]+$/u.test(categorySlug);
|
|
754
|
-
return
|
|
828
|
+
return createDoctorCheck(`Ability config ${ability.slug}`, hasValidAbilityId && hasValidCategorySlug ? "pass" : "fail", hasValidAbilityId && hasValidCategorySlug ? `Ability id ${abilityId} in category ${categorySlug} is valid` : "Ability config must define a valid abilityId (`namespace/ability-name`) and category.slug.");
|
|
755
829
|
} catch (error) {
|
|
756
|
-
return
|
|
830
|
+
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
757
831
|
}
|
|
758
832
|
}
|
|
759
833
|
function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
760
834
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
761
835
|
if (!fs5.existsSync(bootstrapPath)) {
|
|
762
|
-
return
|
|
836
|
+
return createDoctorCheck("Ability bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
763
837
|
}
|
|
764
838
|
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
765
839
|
const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
|
|
@@ -774,7 +848,7 @@ function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
774
848
|
const hasEditorScript = source.includes(WORKSPACE_ABILITY_EDITOR_SCRIPT);
|
|
775
849
|
const hasEditorAsset = source.includes(WORKSPACE_ABILITY_EDITOR_ASSET);
|
|
776
850
|
const hasScriptModuleEnqueue = source.includes("wp_enqueue_script_module");
|
|
777
|
-
return
|
|
851
|
+
return createDoctorCheck("Ability bootstrap", hasLoaderHook && hasAdminEnqueueHook && hasEditorEnqueueHook && hasServerGlob && hasEditorScript && hasEditorAsset && hasScriptModuleEnqueue ? "pass" : "fail", hasLoaderHook && hasAdminEnqueueHook && hasEditorEnqueueHook && hasServerGlob && hasEditorScript && hasEditorAsset && hasScriptModuleEnqueue ? "Ability loader and admin/editor script-module bootstrap hooks are present" : "Missing ability loader hook, script-module enqueue, or build/abilities asset references");
|
|
778
852
|
}
|
|
779
853
|
function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
780
854
|
const indexRelativePath = [
|
|
@@ -782,7 +856,7 @@ function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
|
782
856
|
path5.join("src", "abilities", "index.js")
|
|
783
857
|
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
784
858
|
if (!indexRelativePath) {
|
|
785
|
-
return
|
|
859
|
+
return createDoctorCheck("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
|
|
786
860
|
}
|
|
787
861
|
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
788
862
|
const source = fs5.readFileSync(indexPath, "utf8");
|
|
@@ -790,7 +864,7 @@ function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
|
790
864
|
const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex(ability.slug)}\\/client['"\`]`, "mu");
|
|
791
865
|
return !exportPattern.test(source);
|
|
792
866
|
});
|
|
793
|
-
return
|
|
867
|
+
return createDoctorCheck("Abilities index", missingExports.length === 0 ? "pass" : "fail", missingExports.length === 0 ? "Ability client helpers are aggregated" : `Missing ability exports for: ${missingExports.map((entry) => entry.slug).join(", ")}`);
|
|
794
868
|
}
|
|
795
869
|
function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
|
|
796
870
|
return Array.from(new Set([
|
|
@@ -809,19 +883,19 @@ function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
|
|
|
809
883
|
}
|
|
810
884
|
function checkWorkspaceAiFeatureConfig(aiFeature) {
|
|
811
885
|
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(aiFeature.namespace);
|
|
812
|
-
return
|
|
886
|
+
return createDoctorCheck(`AI feature config ${aiFeature.slug}`, hasNamespace ? "pass" : "fail", hasNamespace ? `AI feature namespace ${aiFeature.namespace} is valid` : "AI feature namespace is invalid");
|
|
813
887
|
}
|
|
814
888
|
function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
815
889
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
816
890
|
if (!fs5.existsSync(bootstrapPath)) {
|
|
817
|
-
return
|
|
891
|
+
return createDoctorCheck("AI feature bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
818
892
|
}
|
|
819
893
|
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
820
894
|
const registerFunctionName = `${phpPrefix}_register_ai_features`;
|
|
821
895
|
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
822
896
|
const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
|
|
823
897
|
const hasRegisterHook = source.includes(registerHook);
|
|
824
|
-
return
|
|
898
|
+
return createDoctorCheck("AI feature bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "AI feature PHP loader hook is present" : "Missing AI feature PHP require glob or init hook");
|
|
825
899
|
}
|
|
826
900
|
function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
827
901
|
const editorPluginDir = path5.join("src", "editor-plugins", editorPlugin.slug);
|
|
@@ -837,12 +911,12 @@ function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
|
837
911
|
function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
838
912
|
const normalizedSlot = resolveEditorPluginSlotAlias(editorPlugin.slot);
|
|
839
913
|
const isValidSlot = Boolean(normalizedSlot);
|
|
840
|
-
return
|
|
914
|
+
return createDoctorCheck(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot ? `Editor plugin slot ${editorPlugin.slot} is supported as ${normalizedSlot}` : `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")} or legacy aliases PluginSidebar, PluginDocumentSettingPanel.`);
|
|
841
915
|
}
|
|
842
916
|
function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
|
|
843
917
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
844
918
|
if (!fs5.existsSync(bootstrapPath)) {
|
|
845
|
-
return
|
|
919
|
+
return createDoctorCheck("Editor plugin bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
846
920
|
}
|
|
847
921
|
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
848
922
|
const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
|
|
@@ -851,7 +925,7 @@ function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix)
|
|
|
851
925
|
const hasEditorScript = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT);
|
|
852
926
|
const hasEditorAsset = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET);
|
|
853
927
|
const hasEditorStyle = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE);
|
|
854
|
-
return
|
|
928
|
+
return createDoctorCheck("Editor plugin bootstrap", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "pass" : "fail", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "Editor plugin enqueue hook is present" : "Missing editor plugin enqueue hook or build/editor-plugins script/style asset references");
|
|
855
929
|
}
|
|
856
930
|
function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
857
931
|
const indexRelativePath = [
|
|
@@ -859,7 +933,7 @@ function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
|
859
933
|
path5.join("src", "editor-plugins", "index.js")
|
|
860
934
|
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
861
935
|
if (!indexRelativePath) {
|
|
862
|
-
return
|
|
936
|
+
return createDoctorCheck("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
|
|
863
937
|
}
|
|
864
938
|
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
865
939
|
const source = fs5.readFileSync(indexPath, "utf8");
|
|
@@ -867,7 +941,7 @@ function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
|
867
941
|
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
868
942
|
return !importPattern.test(source);
|
|
869
943
|
});
|
|
870
|
-
return
|
|
944
|
+
return createDoctorCheck("Editor plugins index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Editor plugin registrations are aggregated" : `Missing editor plugin imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
871
945
|
}
|
|
872
946
|
function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
873
947
|
const adminViewDir = path5.join("src", "admin-views", adminView.slug);
|
|
@@ -883,27 +957,31 @@ function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
|
883
957
|
}
|
|
884
958
|
function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
885
959
|
if (adminView.source === undefined) {
|
|
886
|
-
return
|
|
960
|
+
return createDoctorCheck(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
|
|
887
961
|
}
|
|
888
962
|
const source = adminView.source.trim();
|
|
889
963
|
const restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
|
|
890
964
|
const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
|
|
891
965
|
const restResourceSlug = restSourceMatch?.[1];
|
|
892
966
|
const restResource = restResourceSlug ? inventory.restResources.find((entry) => entry.slug === restResourceSlug) : undefined;
|
|
893
|
-
const
|
|
894
|
-
|
|
967
|
+
const isListCapableRestResource = Boolean(restResource?.methods.includes("list"));
|
|
968
|
+
const isManualSettingsRestResource = isAdminViewManualSettingsRestResource(restResource);
|
|
969
|
+
const hasManualSettingsRouteParameters = isManualSettingsRestResource && hasAdminViewManualSettingsRouteParameters(restResource);
|
|
970
|
+
const isValid = isListCapableRestResource || isManualSettingsRestResource && !hasManualSettingsRouteParameters || Boolean(coreDataSourceMatch);
|
|
971
|
+
const failDetail = hasManualSettingsRouteParameters ? `Admin view source ${source} uses route parameters or regex groups and cannot scaffold a singleton settings form` : "Admin view source must use rest-resource:<slug> with a list-capable REST resource, a manual settings contract with a body type, or core-data:<postType|taxonomy>/<name>";
|
|
972
|
+
return createDoctorCheck(`Admin view config ${adminView.slug}`, isValid ? "pass" : "fail", isValid ? `Admin view source ${source} is ${isManualSettingsRestResource ? "settings-form capable" : coreDataSourceMatch ? "core-data capable" : "list-capable"}` : failDetail);
|
|
895
973
|
}
|
|
896
974
|
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
897
975
|
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
898
976
|
if (!fs5.existsSync(bootstrapPath)) {
|
|
899
|
-
return
|
|
977
|
+
return createDoctorCheck("Admin view bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
900
978
|
}
|
|
901
979
|
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
902
980
|
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
903
981
|
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
904
982
|
const hasLoaderHook = source.includes(loadHook);
|
|
905
983
|
const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
|
|
906
|
-
return
|
|
984
|
+
return createDoctorCheck("Admin view bootstrap", hasLoaderHook && hasServerGlob ? "pass" : "fail", hasLoaderHook && hasServerGlob ? "Admin view PHP loader hook is present" : "Missing admin view PHP require glob or plugins_loaded hook");
|
|
907
985
|
}
|
|
908
986
|
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
909
987
|
const indexRelativePath = [
|
|
@@ -911,7 +989,7 @@ function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
|
911
989
|
path5.join("src", "admin-views", "index.js")
|
|
912
990
|
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
913
991
|
if (!indexRelativePath) {
|
|
914
|
-
return
|
|
992
|
+
return createDoctorCheck("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
915
993
|
}
|
|
916
994
|
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
917
995
|
const source = fs5.readFileSync(indexPath, "utf8");
|
|
@@ -919,12 +997,12 @@ function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
|
919
997
|
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
920
998
|
return !importPattern.test(source);
|
|
921
999
|
});
|
|
922
|
-
return
|
|
1000
|
+
return createDoctorCheck("Admin views index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Admin view registrations are aggregated" : `Missing admin view imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
923
1001
|
}
|
|
924
1002
|
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
925
1003
|
const phpPath = path5.join(projectDir, adminView.phpFile);
|
|
926
1004
|
if (!fs5.existsSync(phpPath)) {
|
|
927
|
-
return
|
|
1005
|
+
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
928
1006
|
}
|
|
929
1007
|
const source = fs5.readFileSync(phpPath, "utf8");
|
|
930
1008
|
const hasAdminMenu = source.includes("add_submenu_page");
|
|
@@ -933,17 +1011,25 @@ function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
|
933
1011
|
const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
|
|
934
1012
|
const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
|
|
935
1013
|
const hasComponentsStyleDependency = source.includes("'wp-components'");
|
|
936
|
-
return
|
|
1014
|
+
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "pass" : "fail", hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "Admin menu, script, style, and wp-components style dependency are wired" : "Missing admin menu, enqueue hook, build/admin-views asset reference, or wp-components style dependency");
|
|
937
1015
|
}
|
|
938
1016
|
function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
|
|
939
1017
|
const checks = [];
|
|
940
|
-
if (inventory.restResources.
|
|
1018
|
+
if (inventory.restResources.some((restResource) => !isManualRestResource(restResource))) {
|
|
941
1019
|
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
942
1020
|
}
|
|
943
1021
|
for (const restResource of inventory.restResources) {
|
|
944
1022
|
checks.push(checkWorkspaceRestResourceConfig(restResource));
|
|
945
1023
|
checks.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
|
|
946
1024
|
}
|
|
1025
|
+
if (inventory.postMeta.length > 0) {
|
|
1026
|
+
checks.push(checkWorkspacePostMetaBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1027
|
+
}
|
|
1028
|
+
for (const postMeta of inventory.postMeta) {
|
|
1029
|
+
checks.push(checkWorkspacePostMetaConfig(postMeta));
|
|
1030
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Post meta ${postMeta.slug}`, getWorkspacePostMetaRequiredFiles(postMeta)));
|
|
1031
|
+
checks.push(checkWorkspacePostMetaPhp(workspace.projectDir, postMeta));
|
|
1032
|
+
}
|
|
947
1033
|
if (inventory.abilities.length > 0) {
|
|
948
1034
|
checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
949
1035
|
checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
|
|
@@ -980,12 +1066,25 @@ function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
|
|
|
980
1066
|
}
|
|
981
1067
|
|
|
982
1068
|
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-package.ts
|
|
983
|
-
import fs6 from "fs";
|
|
984
1069
|
import path6 from "path";
|
|
985
|
-
function
|
|
986
|
-
const issues = [];
|
|
1070
|
+
async function prepareWorkspacePackageDoctorSnapshot(workspace, packageJson) {
|
|
987
1071
|
const packageName = packageJson.name;
|
|
988
1072
|
const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
|
|
1073
|
+
const migrationConfigRelativePath = path6.join("src", "migrations", "config.ts");
|
|
1074
|
+
const [bootstrapExists, migrationConfigExists] = await Promise.all([
|
|
1075
|
+
pathExists(path6.join(workspace.projectDir, bootstrapRelativePath)),
|
|
1076
|
+
pathExists(path6.join(workspace.projectDir, migrationConfigRelativePath))
|
|
1077
|
+
]);
|
|
1078
|
+
return {
|
|
1079
|
+
bootstrapExists,
|
|
1080
|
+
bootstrapRelativePath,
|
|
1081
|
+
migrationConfigExists,
|
|
1082
|
+
migrationConfigRelativePath
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function getWorkspacePackageMetadataCheck(workspace, packageJson, snapshot) {
|
|
1086
|
+
const issues = [];
|
|
1087
|
+
const packageName = packageJson.name;
|
|
989
1088
|
const wpTypia = packageJson.wpTypia;
|
|
990
1089
|
if (typeof packageName !== "string" || packageName.length === 0) {
|
|
991
1090
|
issues.push("package.json must define a string name for workspace bootstrap resolution");
|
|
@@ -1005,19 +1104,17 @@ function getWorkspacePackageMetadataCheck(workspace, packageJson) {
|
|
|
1005
1104
|
if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
|
|
1006
1105
|
issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
|
|
1007
1106
|
}
|
|
1008
|
-
if (!
|
|
1009
|
-
issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
|
|
1107
|
+
if (!snapshot.bootstrapExists) {
|
|
1108
|
+
issues.push(`Missing bootstrap file ${snapshot.bootstrapRelativePath}`);
|
|
1010
1109
|
}
|
|
1011
|
-
return
|
|
1110
|
+
return createDoctorCheck("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${snapshot.bootstrapRelativePath}` : issues.join("; "));
|
|
1012
1111
|
}
|
|
1013
|
-
function getMigrationWorkspaceHintCheck(
|
|
1112
|
+
function getMigrationWorkspaceHintCheck(packageJson, snapshot) {
|
|
1014
1113
|
const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
|
|
1015
|
-
|
|
1016
|
-
const hasMigrationConfig = fs6.existsSync(path6.join(workspace.projectDir, migrationConfigRelativePath));
|
|
1017
|
-
if (!hasMigrationScript && !hasMigrationConfig) {
|
|
1114
|
+
if (!hasMigrationScript && !snapshot.migrationConfigExists) {
|
|
1018
1115
|
return null;
|
|
1019
1116
|
}
|
|
1020
|
-
return
|
|
1117
|
+
return createDoctorCheck("Migration workspace", snapshot.migrationConfigExists ? "pass" : "fail", snapshot.migrationConfigExists ? "Run `wp-typia migrate doctor --all` for migration target, snapshot, fixture, and generated artifact checks" : `Missing ${snapshot.migrationConfigRelativePath} for the configured migration workspace`);
|
|
1021
1118
|
}
|
|
1022
1119
|
|
|
1023
1120
|
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
|
|
@@ -1030,13 +1127,14 @@ function formatWorkspaceInventorySummary(inventory) {
|
|
|
1030
1127
|
`${inventory.patterns.length} pattern(s)`,
|
|
1031
1128
|
`${inventory.bindingSources.length} binding source(s)`,
|
|
1032
1129
|
`${inventory.restResources.length} REST resource(s)`,
|
|
1130
|
+
`${inventory.postMeta.length} post meta contract(s)`,
|
|
1033
1131
|
`${inventory.abilities.length} ability scaffold(s)`,
|
|
1034
1132
|
`${inventory.aiFeatures.length} AI feature(s)`,
|
|
1035
1133
|
`${inventory.editorPlugins.length} editor plugin(s)`,
|
|
1036
1134
|
`${inventory.adminViews.length} admin view(s)`
|
|
1037
1135
|
].join(", ");
|
|
1038
1136
|
}
|
|
1039
|
-
function getWorkspaceDoctorChecks(cwd) {
|
|
1137
|
+
async function getWorkspaceDoctorChecks(cwd) {
|
|
1040
1138
|
const checks = [];
|
|
1041
1139
|
let workspace = null;
|
|
1042
1140
|
let invalidWorkspaceReason = null;
|
|
@@ -1045,13 +1143,13 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
1045
1143
|
workspace = tryResolveWorkspaceProject(cwd);
|
|
1046
1144
|
} catch (error) {
|
|
1047
1145
|
checks.push(createDoctorScopeCheck("fail", "Scope: blocked before workspace checks. Environment checks ran, but workspace discovery could not continue. Fix the nearby workspace package metadata and rerun `wp-typia doctor`."));
|
|
1048
|
-
checks.push(
|
|
1146
|
+
checks.push(createDoctorCheck("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
|
|
1049
1147
|
return checks;
|
|
1050
1148
|
}
|
|
1051
1149
|
if (!workspace) {
|
|
1052
1150
|
if (invalidWorkspaceReason) {
|
|
1053
1151
|
checks.push(createDoctorScopeCheck("fail", "Scope: blocked before workspace checks. Environment checks ran, but workspace diagnostics could not continue because a nearby wp-typia workspace candidate is invalid. Fix the workspace package metadata and rerun `wp-typia doctor`."));
|
|
1054
|
-
checks.push(
|
|
1152
|
+
checks.push(createDoctorCheck("Workspace package metadata", "fail", invalidWorkspaceReason));
|
|
1055
1153
|
} else {
|
|
1056
1154
|
checks.push(createDoctorScopeCheck("pass", "Scope: environment-only. No official wp-typia workspace root was detected, so this run only covered environment readiness. Re-run `wp-typia doctor` from a workspace root if you expected package metadata, inventory, or generated artifact checks."));
|
|
1057
1155
|
}
|
|
@@ -1062,22 +1160,23 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
1062
1160
|
try {
|
|
1063
1161
|
workspacePackageJson = parseWorkspacePackageJson(workspace.projectDir);
|
|
1064
1162
|
} catch (error) {
|
|
1065
|
-
checks.push(
|
|
1163
|
+
checks.push(createDoctorCheck("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
|
|
1066
1164
|
return checks;
|
|
1067
1165
|
}
|
|
1068
|
-
|
|
1166
|
+
const packageDoctorSnapshot = await prepareWorkspacePackageDoctorSnapshot(workspace, workspacePackageJson);
|
|
1167
|
+
checks.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson, packageDoctorSnapshot));
|
|
1069
1168
|
try {
|
|
1070
|
-
const inventory =
|
|
1071
|
-
checks.push(
|
|
1169
|
+
const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
|
|
1170
|
+
checks.push(createDoctorCheck("Workspace inventory", "pass", formatWorkspaceInventorySummary(inventory)));
|
|
1072
1171
|
checks.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
|
|
1073
1172
|
checks.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
|
|
1074
1173
|
checks.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
|
|
1075
|
-
const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(
|
|
1174
|
+
const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspacePackageJson, packageDoctorSnapshot);
|
|
1076
1175
|
if (migrationWorkspaceCheck) {
|
|
1077
1176
|
checks.push(migrationWorkspaceCheck);
|
|
1078
1177
|
}
|
|
1079
1178
|
} catch (error) {
|
|
1080
|
-
checks.push(
|
|
1179
|
+
checks.push(createDoctorCheck("Workspace inventory", "fail", error instanceof Error ? error.message : String(error)));
|
|
1081
1180
|
}
|
|
1082
1181
|
return checks;
|
|
1083
1182
|
}
|
|
@@ -1086,7 +1185,7 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
1086
1185
|
async function getDoctorChecks(cwd) {
|
|
1087
1186
|
return [
|
|
1088
1187
|
...await getEnvironmentDoctorChecks(cwd),
|
|
1089
|
-
...getWorkspaceDoctorChecks(cwd)
|
|
1188
|
+
...await getWorkspaceDoctorChecks(cwd)
|
|
1090
1189
|
];
|
|
1091
1190
|
}
|
|
1092
1191
|
async function runDoctor(cwd, options = {}) {
|
|
@@ -1115,4 +1214,4 @@ export {
|
|
|
1115
1214
|
getDoctorChecks
|
|
1116
1215
|
};
|
|
1117
1216
|
|
|
1118
|
-
//# debugId=
|
|
1217
|
+
//# debugId=A0E15D6F99F87A7464756E2164756E21
|