wp-typia 0.22.2 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/wp-typia.js +15 -1
- package/dist-bunli/.bunli/commands.gen.js +2574 -2213
- package/dist-bunli/{cli-6hcbjvym.js → cli-2mt6bvcj.js} +7 -7
- package/dist-bunli/{cli-sj5mtyzj.js → cli-6bhfzq5e.js} +41 -2
- package/dist-bunli/{cli-kww2sraq.js → cli-6ymn63t4.js} +142 -14
- package/dist-bunli/{cli-add-s0p4w1wz.js → cli-add-6s6kzf7x.js} +323 -355
- package/dist-bunli/{cli-pd5pqgre.js → cli-btbpt84c.js} +6 -11
- package/dist-bunli/{cli-doctor-6dchxz12.js → cli-doctor-70zd5m3b.js} +470 -474
- package/dist-bunli/{cli-n6hgvysz.js → cli-gsj6vyn5.js} +59 -9
- package/dist-bunli/{cli-gcbre1zs.js → cli-hb9vpsev.js} +6 -13
- package/dist-bunli/{cli-init-r6h1xchq.js → cli-init-kjjyky1y.js} +11 -11
- package/dist-bunli/{cli-smzkbfna.js → cli-qr2ek735.js} +1310 -1140
- package/dist-bunli/cli-rwjkqjhs.js +88 -0
- package/dist-bunli/{cli-scaffold-f023yxc5.js → cli-scaffold-f57ccf5v.js} +10 -10
- package/dist-bunli/cli.js +5 -3
- package/dist-bunli/{command-list-d3dcvzg2.js → command-list-wsaa4t2p.js} +144 -215
- package/dist-bunli/{migrations-pg5b9fh4.js → migrations-vw502qf9.js} +5 -5
- package/dist-bunli/node-cli.js +232 -226
- package/dist-bunli/{workspace-project-gxb499cp.js → workspace-project-7826tewa.js} +3 -2
- package/package.json +2 -2
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
hasExecutablePattern,
|
|
4
|
+
hasUncommentedPattern,
|
|
5
|
+
maskTypeScriptCommentsAndLiterals
|
|
6
|
+
} from "./cli-rwjkqjhs.js";
|
|
2
7
|
import {
|
|
3
8
|
getBuiltInTemplateLayerDirs,
|
|
4
9
|
isOmittableBuiltInTemplateLayerDir
|
|
@@ -16,7 +21,7 @@ import {
|
|
|
16
21
|
escapeRegex,
|
|
17
22
|
readWorkspaceInventory,
|
|
18
23
|
resolveEditorPluginSlotAlias
|
|
19
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-qr2ek735.js";
|
|
20
25
|
import"./cli-t73q5aqz.js";
|
|
21
26
|
import {
|
|
22
27
|
CLI_DIAGNOSTIC_CODES,
|
|
@@ -30,7 +35,8 @@ import {
|
|
|
30
35
|
getInvalidWorkspaceProjectReason,
|
|
31
36
|
parseWorkspacePackageJson,
|
|
32
37
|
tryResolveWorkspaceProject
|
|
33
|
-
} from "./cli-
|
|
38
|
+
} from "./cli-btbpt84c.js";
|
|
39
|
+
import"./cli-6bhfzq5e.js";
|
|
34
40
|
import"./cli-xnn9xjcy.js";
|
|
35
41
|
|
|
36
42
|
// ../wp-typia-project-tools/src/runtime/cli-doctor-environment.ts
|
|
@@ -129,12 +135,14 @@ async function getEnvironmentDoctorChecks(cwd) {
|
|
|
129
135
|
];
|
|
130
136
|
}
|
|
131
137
|
|
|
132
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
|
|
138
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-bindings.ts
|
|
139
|
+
import fs3 from "fs";
|
|
140
|
+
import path3 from "path";
|
|
141
|
+
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
142
|
+
|
|
143
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-shared.ts
|
|
133
144
|
import fs2 from "fs";
|
|
134
145
|
import path2 from "path";
|
|
135
|
-
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
136
|
-
var WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
137
|
-
var WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
|
|
138
146
|
var WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
139
147
|
var WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
140
148
|
var WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
@@ -158,6 +166,135 @@ var WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
|
158
166
|
"typia.openapi.json"
|
|
159
167
|
];
|
|
160
168
|
var WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
169
|
+
function createDoctorCheck2(label, status, detail, code) {
|
|
170
|
+
return code ? { code, detail, label, status } : { detail, label, status };
|
|
171
|
+
}
|
|
172
|
+
function createDoctorScopeCheck(status, detail) {
|
|
173
|
+
return createDoctorCheck2("Doctor scope", status, detail);
|
|
174
|
+
}
|
|
175
|
+
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
176
|
+
return `${packageName.split("/").pop() ?? packageName}.php`;
|
|
177
|
+
}
|
|
178
|
+
function checkExistingFiles(projectDir, label, filePaths) {
|
|
179
|
+
const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs2.existsSync(path2.join(projectDir, filePath)));
|
|
180
|
+
return createDoctorCheck2(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-bindings.ts
|
|
184
|
+
function checkWorkspaceBindingBootstrap(projectDir, packageName) {
|
|
185
|
+
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
186
|
+
const bootstrapPath = path3.join(projectDir, `${packageBaseName}.php`);
|
|
187
|
+
if (!fs3.existsSync(bootstrapPath)) {
|
|
188
|
+
return createDoctorCheck2("Binding bootstrap", "fail", `Missing ${path3.basename(bootstrapPath)}`);
|
|
189
|
+
}
|
|
190
|
+
const source = fs3.readFileSync(bootstrapPath, "utf8");
|
|
191
|
+
const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
|
|
192
|
+
const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
|
|
193
|
+
const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
|
|
194
|
+
const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
|
|
195
|
+
return createDoctorCheck2("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");
|
|
196
|
+
}
|
|
197
|
+
function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
|
|
198
|
+
const indexRelativePath = [path3.join("src", "bindings", "index.ts"), path3.join("src", "bindings", "index.js")].find((relativePath) => fs3.existsSync(path3.join(projectDir, relativePath)));
|
|
199
|
+
if (!indexRelativePath) {
|
|
200
|
+
return createDoctorCheck2("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
|
|
201
|
+
}
|
|
202
|
+
const indexPath = path3.join(projectDir, indexRelativePath);
|
|
203
|
+
const source = fs3.readFileSync(indexPath, "utf8");
|
|
204
|
+
const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
|
|
205
|
+
return createDoctorCheck2("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(", ")}`);
|
|
206
|
+
}
|
|
207
|
+
function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
|
|
208
|
+
const hasBlock = bindingSource.block !== undefined;
|
|
209
|
+
const hasAttribute = bindingSource.attribute !== undefined;
|
|
210
|
+
if (!hasBlock && !hasAttribute) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (!bindingSource.block || !bindingSource.attribute) {
|
|
214
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
|
|
215
|
+
}
|
|
216
|
+
if (!registeredBlockSlugs.has(bindingSource.block)) {
|
|
217
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
|
|
218
|
+
}
|
|
219
|
+
const blockJsonRelativePath = path3.join("src", "blocks", bindingSource.block, "block.json");
|
|
220
|
+
const blockJsonPath = path3.join(projectDir, blockJsonRelativePath);
|
|
221
|
+
const issues = [];
|
|
222
|
+
try {
|
|
223
|
+
const blockJson = parseScaffoldBlockMetadata(JSON.parse(fs3.readFileSync(blockJsonPath, "utf8")));
|
|
224
|
+
const attributes = blockJson.attributes;
|
|
225
|
+
if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) {
|
|
226
|
+
issues.push(`${blockJsonRelativePath} must define an attributes object`);
|
|
227
|
+
} else {
|
|
228
|
+
const attributeConfig = attributes[bindingSource.attribute];
|
|
229
|
+
if (!attributeConfig || typeof attributeConfig !== "object" || Array.isArray(attributeConfig)) {
|
|
230
|
+
issues.push(`${blockJsonRelativePath} must declare attribute "${bindingSource.attribute}"`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
issues.push(error instanceof Error ? `Unable to read ${blockJsonRelativePath}: ${error.message}` : `Unable to read ${blockJsonRelativePath}.`);
|
|
235
|
+
}
|
|
236
|
+
const serverPath = path3.join(projectDir, bindingSource.serverFile);
|
|
237
|
+
if (fs3.existsSync(serverPath)) {
|
|
238
|
+
const serverSource = fs3.readFileSync(serverPath, "utf8");
|
|
239
|
+
const supportedAttributesFilter = `block_bindings_supported_attributes_${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
240
|
+
if (!serverSource.includes(supportedAttributesFilter)) {
|
|
241
|
+
issues.push(`${bindingSource.serverFile} must register ${supportedAttributesFilter}`);
|
|
242
|
+
}
|
|
243
|
+
if (!new RegExp(`(['"])${escapeRegex(bindingSource.attribute)}\\1`, "u").test(serverSource)) {
|
|
244
|
+
issues.push(`${bindingSource.serverFile} must expose attribute "${bindingSource.attribute}"`);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
issues.push(`Missing ${bindingSource.serverFile}`);
|
|
248
|
+
}
|
|
249
|
+
const editorPath = path3.join(projectDir, bindingSource.editorFile);
|
|
250
|
+
if (fs3.existsSync(editorPath)) {
|
|
251
|
+
const editorSource = fs3.readFileSync(editorPath, "utf8");
|
|
252
|
+
const blockName = `${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
253
|
+
const bindingSourceTargetMatch = editorSource.match(/export\s+const\s+BINDING_SOURCE_TARGET\s*=\s*\{([\s\S]*?)\}\s+as\s+const\s*;/u);
|
|
254
|
+
if (!bindingSourceTargetMatch) {
|
|
255
|
+
issues.push(`${bindingSource.editorFile} must export BINDING_SOURCE_TARGET`);
|
|
256
|
+
} else {
|
|
257
|
+
const targetSource = bindingSourceTargetMatch[1] ?? "";
|
|
258
|
+
const attributePattern = new RegExp(`\\battribute\\s*:\\s*["']${escapeRegex(bindingSource.attribute)}["']`, "u");
|
|
259
|
+
const blockPattern = new RegExp(`\\bblock\\s*:\\s*["']${escapeRegex(blockName)}["']`, "u");
|
|
260
|
+
if (!attributePattern.test(targetSource)) {
|
|
261
|
+
issues.push(`${bindingSource.editorFile} must document target attribute "${bindingSource.attribute}"`);
|
|
262
|
+
}
|
|
263
|
+
if (!blockPattern.test(targetSource)) {
|
|
264
|
+
issues.push(`${bindingSource.editorFile} must document target block "${blockName}"`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
issues.push(`Missing ${bindingSource.editorFile}`);
|
|
269
|
+
}
|
|
270
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
|
|
271
|
+
}
|
|
272
|
+
function getWorkspaceBindingDoctorChecks(workspace, inventory) {
|
|
273
|
+
const checks = [];
|
|
274
|
+
if (inventory.bindingSources.length > 0) {
|
|
275
|
+
checks.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
|
|
276
|
+
checks.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
|
|
277
|
+
}
|
|
278
|
+
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
279
|
+
for (const bindingSource of inventory.bindingSources) {
|
|
280
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
|
|
281
|
+
bindingSource.serverFile,
|
|
282
|
+
bindingSource.editorFile
|
|
283
|
+
]));
|
|
284
|
+
const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
|
|
285
|
+
if (bindingTargetCheck) {
|
|
286
|
+
checks.push(bindingTargetCheck);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return checks;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-blocks.ts
|
|
293
|
+
import fs4 from "fs";
|
|
294
|
+
import path4 from "path";
|
|
295
|
+
import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata2 } from "@wp-typia/block-runtime/blocks";
|
|
296
|
+
var WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
297
|
+
var WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
|
|
161
298
|
var WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
|
|
162
299
|
var WORKSPACE_VARIATIONS_CALL_PATTERN = /registerWorkspaceVariations\s*\(\s*\)\s*;?/u;
|
|
163
300
|
var WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
|
|
@@ -193,75 +330,8 @@ var WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
|
|
|
193
330
|
];
|
|
194
331
|
var WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
|
|
195
332
|
var WORKSPACE_BLOCK_PROPS_PATTERN = /\buse(?:Block|InnerBlocks)Props(?:\.save)?\s*\(/u;
|
|
196
|
-
function createDoctorCheck2(label, status, detail, code) {
|
|
197
|
-
return code ? { code, detail, label, status } : { detail, label, status };
|
|
198
|
-
}
|
|
199
|
-
function createDoctorScopeCheck(status, detail) {
|
|
200
|
-
return createDoctorCheck2("Doctor scope", status, detail);
|
|
201
|
-
}
|
|
202
|
-
function maskSourceSegment(segment) {
|
|
203
|
-
return segment.replace(/[^\n\r]/gu, " ");
|
|
204
|
-
}
|
|
205
|
-
function maskTypeScriptComments(source) {
|
|
206
|
-
return source.replace(/\/\*[\s\S]*?\*\//gu, maskSourceSegment).replace(/\/\/[^\n\r]*/gu, maskSourceSegment);
|
|
207
|
-
}
|
|
208
|
-
function maskTypeScriptCommentsAndLiterals(source) {
|
|
209
|
-
let maskedSource = "";
|
|
210
|
-
let index = 0;
|
|
211
|
-
while (index < source.length) {
|
|
212
|
-
const current = source[index];
|
|
213
|
-
const next = source[index + 1];
|
|
214
|
-
if (current === "/" && next === "/") {
|
|
215
|
-
const start = index;
|
|
216
|
-
index += 2;
|
|
217
|
-
while (index < source.length && source[index] !== `
|
|
218
|
-
` && source[index] !== "\r") {
|
|
219
|
-
index += 1;
|
|
220
|
-
}
|
|
221
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
if (current === "/" && next === "*") {
|
|
225
|
-
const start = index;
|
|
226
|
-
index += 2;
|
|
227
|
-
while (index < source.length && !(source[index] === "*" && source[index + 1] === "/")) {
|
|
228
|
-
index += 1;
|
|
229
|
-
}
|
|
230
|
-
index = Math.min(index + 2, source.length);
|
|
231
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (current === "'" || current === '"' || current === "`") {
|
|
235
|
-
const start = index;
|
|
236
|
-
const quote = current;
|
|
237
|
-
index += 1;
|
|
238
|
-
while (index < source.length) {
|
|
239
|
-
const char = source[index];
|
|
240
|
-
if (char === "\\") {
|
|
241
|
-
index += 2;
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
index += 1;
|
|
245
|
-
if (char === quote) {
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
maskedSource += current;
|
|
253
|
-
index += 1;
|
|
254
|
-
}
|
|
255
|
-
return maskedSource;
|
|
256
|
-
}
|
|
257
|
-
function hasUncommentedPattern(source, pattern) {
|
|
258
|
-
return pattern.test(maskTypeScriptComments(source));
|
|
259
|
-
}
|
|
260
|
-
function hasExecutablePattern(source, pattern) {
|
|
261
|
-
return pattern.test(maskTypeScriptCommentsAndLiterals(source));
|
|
262
|
-
}
|
|
263
333
|
function normalizePathSeparators(relativePath) {
|
|
264
|
-
return relativePath.split(
|
|
334
|
+
return relativePath.split(path4.sep).join("/");
|
|
265
335
|
}
|
|
266
336
|
function hasRegisteredBlockAsset(value) {
|
|
267
337
|
if (typeof value === "string") {
|
|
@@ -273,25 +343,19 @@ function hasRegisteredBlockAsset(value) {
|
|
|
273
343
|
return false;
|
|
274
344
|
}
|
|
275
345
|
function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
|
|
276
|
-
const blockJsonRelativePath =
|
|
277
|
-
const blockJsonPath =
|
|
278
|
-
if (!
|
|
346
|
+
const blockJsonRelativePath = path4.join("src", "blocks", blockSlug, "block.json");
|
|
347
|
+
const blockJsonPath = path4.join(projectDir, blockJsonRelativePath);
|
|
348
|
+
if (!fs4.existsSync(blockJsonPath)) {
|
|
279
349
|
return {
|
|
280
350
|
blockJsonRelativePath,
|
|
281
351
|
error: `Missing ${blockJsonRelativePath}`
|
|
282
352
|
};
|
|
283
353
|
}
|
|
284
354
|
try {
|
|
285
|
-
const
|
|
286
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
287
|
-
return {
|
|
288
|
-
blockJsonRelativePath,
|
|
289
|
-
error: `${blockJsonRelativePath} must contain a JSON object`
|
|
290
|
-
};
|
|
291
|
-
}
|
|
355
|
+
const document = parseScaffoldBlockMetadata2(JSON.parse(fs4.readFileSync(blockJsonPath, "utf8")));
|
|
292
356
|
return {
|
|
293
357
|
blockJsonRelativePath,
|
|
294
|
-
document
|
|
358
|
+
document
|
|
295
359
|
};
|
|
296
360
|
} catch (error) {
|
|
297
361
|
return {
|
|
@@ -301,156 +365,126 @@ function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
|
|
|
301
365
|
}
|
|
302
366
|
}
|
|
303
367
|
function isWorkspaceBlockEditorSource(relativePath) {
|
|
304
|
-
|
|
305
|
-
const normalizedLowerPath = normalizedPath.toLowerCase();
|
|
306
|
-
if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(normalizedLowerPath) || /\.d\.[cm]?[jt]s$/u.test(normalizedLowerPath)) {
|
|
368
|
+
if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(relativePath)) {
|
|
307
369
|
return false;
|
|
308
370
|
}
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(
|
|
371
|
+
const normalizedRelativePath = normalizePathSeparators(relativePath);
|
|
372
|
+
const normalizedDirName = path4.posix.dirname(normalizedRelativePath);
|
|
373
|
+
const normalizedBaseName = path4.posix.basename(normalizedRelativePath, path4.posix.extname(normalizedRelativePath));
|
|
374
|
+
if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(normalizedBaseName)) {
|
|
313
375
|
return true;
|
|
314
376
|
}
|
|
315
|
-
|
|
377
|
+
const pathSegments = normalizedDirName.split("/");
|
|
378
|
+
return pathSegments.some((segment) => WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES.has(segment));
|
|
316
379
|
}
|
|
317
380
|
function isWorkspaceBlockSaveSource(relativePath) {
|
|
318
|
-
const
|
|
319
|
-
return
|
|
381
|
+
const normalizedBaseName = path4.basename(relativePath, path4.extname(relativePath));
|
|
382
|
+
return normalizedBaseName === "save";
|
|
320
383
|
}
|
|
321
384
|
function collectWorkspaceBlockEditorSources(projectDir, blockSlug) {
|
|
322
|
-
const blockDir =
|
|
323
|
-
if (!
|
|
385
|
+
const blockDir = path4.join(projectDir, "src", "blocks", blockSlug);
|
|
386
|
+
if (!fs4.existsSync(blockDir)) {
|
|
324
387
|
return [];
|
|
325
388
|
}
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
389
|
+
const collected = [];
|
|
390
|
+
const queue = [blockDir];
|
|
391
|
+
while (queue.length > 0) {
|
|
392
|
+
const currentDir = queue.pop();
|
|
393
|
+
if (!currentDir) {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
for (const entry of fs4.readdirSync(currentDir, { withFileTypes: true })) {
|
|
397
|
+
const absolutePath = path4.join(currentDir, entry.name);
|
|
330
398
|
if (entry.isDirectory()) {
|
|
331
|
-
|
|
399
|
+
queue.push(absolutePath);
|
|
332
400
|
continue;
|
|
333
401
|
}
|
|
334
402
|
if (!entry.isFile()) {
|
|
335
403
|
continue;
|
|
336
404
|
}
|
|
337
|
-
const relativePath =
|
|
338
|
-
|
|
339
|
-
if (!isWorkspaceBlockEditorSource(blockRelativePath)) {
|
|
405
|
+
const relativePath = path4.relative(projectDir, absolutePath);
|
|
406
|
+
if (!isWorkspaceBlockEditorSource(relativePath)) {
|
|
340
407
|
continue;
|
|
341
408
|
}
|
|
342
|
-
|
|
343
|
-
relativePath,
|
|
344
|
-
source:
|
|
409
|
+
collected.push({
|
|
410
|
+
relativePath: normalizePathSeparators(relativePath),
|
|
411
|
+
source: fs4.readFileSync(absolutePath, "utf8")
|
|
345
412
|
});
|
|
346
413
|
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return sources;
|
|
414
|
+
}
|
|
415
|
+
return collected.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
350
416
|
}
|
|
351
417
|
function getSourceLineNumber(source, index) {
|
|
352
|
-
let
|
|
418
|
+
let line = 1;
|
|
353
419
|
for (let cursor = 0;cursor < index; cursor += 1) {
|
|
354
420
|
if (source[cursor] === `
|
|
355
421
|
`) {
|
|
356
|
-
|
|
422
|
+
line += 1;
|
|
357
423
|
}
|
|
358
424
|
}
|
|
359
|
-
return
|
|
425
|
+
return line;
|
|
360
426
|
}
|
|
361
|
-
function isGlobalDomAccessCandidate(
|
|
362
|
-
|
|
363
|
-
|
|
427
|
+
function isGlobalDomAccessCandidate(source, index, identifier) {
|
|
428
|
+
const lineStart = source.lastIndexOf(`
|
|
429
|
+
`, index - 1) + 1;
|
|
430
|
+
const lineEndCandidate = source.indexOf(`
|
|
431
|
+
`, index);
|
|
432
|
+
const lineEnd = lineEndCandidate === -1 ? source.length : lineEndCandidate;
|
|
433
|
+
const lineSource = source.slice(lineStart, lineEnd);
|
|
434
|
+
const trimmedLine = lineSource.trimStart();
|
|
435
|
+
if (trimmedLine.startsWith("import ")) {
|
|
436
|
+
return false;
|
|
364
437
|
}
|
|
365
|
-
const
|
|
366
|
-
const after = maskedSource.slice(index + token.length);
|
|
367
|
-
const previousNonWhitespace = before.match(/\S(?=\s*$)/u)?.[0] ?? "";
|
|
368
|
-
const nextNonWhitespace = after.match(/^\s*(\S)/u)?.[1] ?? "";
|
|
369
|
-
if (previousNonWhitespace === "." || previousNonWhitespace === "{" || previousNonWhitespace === ",") {
|
|
438
|
+
if (trimmedLine.startsWith("const ") || trimmedLine.startsWith("let ") || trimmedLine.startsWith("var ")) {
|
|
370
439
|
return false;
|
|
371
440
|
}
|
|
372
|
-
if (
|
|
441
|
+
if (trimmedLine.startsWith("function ") || trimmedLine.startsWith("class ")) {
|
|
373
442
|
return false;
|
|
374
443
|
}
|
|
375
|
-
|
|
444
|
+
const precedingCharacter = index > 0 ? source[index - 1] : "";
|
|
445
|
+
if (precedingCharacter === "." || precedingCharacter === "'" || precedingCharacter === '"') {
|
|
376
446
|
return false;
|
|
377
447
|
}
|
|
378
|
-
return
|
|
448
|
+
return identifier === "document" || identifier === "window" || identifier === "parent" || identifier === "top";
|
|
379
449
|
}
|
|
380
|
-
function findWorkspaceBlockGlobalDomAccesses(
|
|
381
|
-
|
|
382
|
-
for (const { relativePath, source } of sources) {
|
|
450
|
+
function findWorkspaceBlockGlobalDomAccesses(editorSources) {
|
|
451
|
+
return editorSources.flatMap(({ relativePath, source }) => {
|
|
383
452
|
const maskedSource = maskTypeScriptCommentsAndLiterals(source);
|
|
384
453
|
const matches = maskedSource.matchAll(WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN);
|
|
454
|
+
const findings = [];
|
|
385
455
|
for (const match of matches) {
|
|
386
|
-
const
|
|
387
|
-
const
|
|
388
|
-
if (
|
|
456
|
+
const identifier = match[0];
|
|
457
|
+
const matchIndex = match.index ?? -1;
|
|
458
|
+
if (matchIndex < 0) {
|
|
389
459
|
continue;
|
|
390
460
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return findings;
|
|
461
|
+
if (!isGlobalDomAccessCandidate(source, matchIndex, identifier)) {
|
|
462
|
+
continue;
|
|
394
463
|
}
|
|
464
|
+
findings.push(`${relativePath}:${getSourceLineNumber(source, matchIndex)}`);
|
|
395
465
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
400
|
-
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
401
|
-
return `${packageBaseName}.php`;
|
|
402
|
-
}
|
|
403
|
-
function checkExistingFiles(projectDir, label, filePaths) {
|
|
404
|
-
const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs2.existsSync(path2.join(projectDir, filePath)));
|
|
405
|
-
return createDoctorCheck2(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
|
|
406
|
-
}
|
|
407
|
-
function checkWorkspacePackageMetadata(workspace, packageJson) {
|
|
408
|
-
const issues = [];
|
|
409
|
-
const packageName = packageJson.name;
|
|
410
|
-
const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
|
|
411
|
-
const wpTypia = packageJson.wpTypia;
|
|
412
|
-
if (typeof packageName !== "string" || packageName.length === 0) {
|
|
413
|
-
issues.push("package.json must define a string name for workspace bootstrap resolution");
|
|
414
|
-
}
|
|
415
|
-
if (wpTypia?.projectType !== "workspace") {
|
|
416
|
-
issues.push('wpTypia.projectType must be "workspace"');
|
|
417
|
-
}
|
|
418
|
-
if (wpTypia?.templatePackage !== WORKSPACE_TEMPLATE_PACKAGE) {
|
|
419
|
-
issues.push(`wpTypia.templatePackage must be "${WORKSPACE_TEMPLATE_PACKAGE}"`);
|
|
420
|
-
}
|
|
421
|
-
if (wpTypia?.namespace !== workspace.workspace.namespace) {
|
|
422
|
-
issues.push(`wpTypia.namespace must equal "${workspace.workspace.namespace}"`);
|
|
423
|
-
}
|
|
424
|
-
if (wpTypia?.textDomain !== workspace.workspace.textDomain) {
|
|
425
|
-
issues.push(`wpTypia.textDomain must equal "${workspace.workspace.textDomain}"`);
|
|
426
|
-
}
|
|
427
|
-
if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
|
|
428
|
-
issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
|
|
429
|
-
}
|
|
430
|
-
if (!fs2.existsSync(path2.join(workspace.projectDir, bootstrapRelativePath))) {
|
|
431
|
-
issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
|
|
432
|
-
}
|
|
433
|
-
return createDoctorCheck2("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${bootstrapRelativePath}` : issues.join("; "));
|
|
466
|
+
return findings;
|
|
467
|
+
});
|
|
434
468
|
}
|
|
435
469
|
function getWorkspaceBlockRequiredFiles(block) {
|
|
436
|
-
const blockDir =
|
|
470
|
+
const blockDir = path4.join("src", "blocks", block.slug);
|
|
437
471
|
return Array.from(new Set([
|
|
438
472
|
block.typesFile,
|
|
439
473
|
block.apiTypesFile,
|
|
440
474
|
block.openApiFile,
|
|
441
|
-
|
|
442
|
-
...WORKSPACE_GENERATED_BLOCK_ARTIFACTS.map((fileName) =>
|
|
475
|
+
path4.join(blockDir, "index.tsx"),
|
|
476
|
+
...WORKSPACE_GENERATED_BLOCK_ARTIFACTS.map((fileName) => path4.join(blockDir, fileName))
|
|
443
477
|
].filter((filePath) => typeof filePath === "string")));
|
|
444
478
|
}
|
|
445
479
|
function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
446
|
-
const blockJsonRelativePath =
|
|
447
|
-
const blockJsonPath =
|
|
448
|
-
if (!
|
|
480
|
+
const blockJsonRelativePath = path4.join("src", "blocks", block.slug, "block.json");
|
|
481
|
+
const blockJsonPath = path4.join(projectDir, blockJsonRelativePath);
|
|
482
|
+
if (!fs4.existsSync(blockJsonPath)) {
|
|
449
483
|
return createDoctorCheck2(`Block metadata ${block.slug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
450
484
|
}
|
|
451
485
|
let blockJson;
|
|
452
486
|
try {
|
|
453
|
-
blockJson =
|
|
487
|
+
blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs4.readFileSync(blockJsonPath, "utf8")));
|
|
454
488
|
} catch (error) {
|
|
455
489
|
return createDoctorCheck2(`Block metadata ${block.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
456
490
|
}
|
|
@@ -465,14 +499,14 @@ function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
|
465
499
|
return createDoctorCheck2(`Block metadata ${block.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `block.json matches ${expectedName} and ${workspace.workspace.textDomain}` : issues.join("; "));
|
|
466
500
|
}
|
|
467
501
|
function checkWorkspaceBlockHooks(projectDir, blockSlug) {
|
|
468
|
-
const blockJsonRelativePath =
|
|
469
|
-
const blockJsonPath =
|
|
470
|
-
if (!
|
|
502
|
+
const blockJsonRelativePath = path4.join("src", "blocks", blockSlug, "block.json");
|
|
503
|
+
const blockJsonPath = path4.join(projectDir, blockJsonRelativePath);
|
|
504
|
+
if (!fs4.existsSync(blockJsonPath)) {
|
|
471
505
|
return createDoctorCheck2(`Block hooks ${blockSlug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
472
506
|
}
|
|
473
507
|
let blockJson;
|
|
474
508
|
try {
|
|
475
|
-
blockJson =
|
|
509
|
+
blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs4.readFileSync(blockJsonPath, "utf8")));
|
|
476
510
|
} catch (error) {
|
|
477
511
|
return createDoctorCheck2(`Block hooks ${blockSlug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
478
512
|
}
|
|
@@ -488,12 +522,12 @@ function checkWorkspaceBlockHooks(projectDir, blockSlug) {
|
|
|
488
522
|
return createDoctorCheck2(`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(", ")}`);
|
|
489
523
|
}
|
|
490
524
|
function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
|
|
491
|
-
const entryRelativePath =
|
|
492
|
-
const entryPath =
|
|
493
|
-
if (!
|
|
525
|
+
const entryRelativePath = path4.join("src", "blocks", blockSlug, "index.tsx");
|
|
526
|
+
const entryPath = path4.join(projectDir, entryRelativePath);
|
|
527
|
+
if (!fs4.existsSync(entryPath)) {
|
|
494
528
|
return createDoctorCheck2(`Block collection ${blockSlug}`, "fail", `Missing ${entryRelativePath}`);
|
|
495
529
|
}
|
|
496
|
-
const source =
|
|
530
|
+
const source = fs4.readFileSync(entryPath, "utf8");
|
|
497
531
|
const hasCollectionImport = WORKSPACE_COLLECTION_IMPORT_PATTERN.test(source);
|
|
498
532
|
return createDoctorCheck2(`Block collection ${blockSlug}`, hasCollectionImport ? "pass" : "fail", hasCollectionImport ? "Shared block collection import is present" : `Missing a shared collection import like ${WORKSPACE_COLLECTION_IMPORT_LINE}`);
|
|
499
533
|
}
|
|
@@ -506,8 +540,8 @@ function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
|
|
|
506
540
|
}
|
|
507
541
|
const blockJson = metadataResult.document;
|
|
508
542
|
const apiVersion = typeof blockJson.apiVersion === "number" && Number.isFinite(blockJson.apiVersion) ? blockJson.apiVersion : null;
|
|
509
|
-
const blockDir =
|
|
510
|
-
const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) =>
|
|
543
|
+
const blockDir = path4.join(projectDir, "src", "blocks", blockSlug);
|
|
544
|
+
const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) => fs4.existsSync(path4.join(blockDir, fileName))).map((fileName) => normalizePathSeparators(path4.join("src", "blocks", blockSlug, fileName)));
|
|
511
545
|
const hasRegisteredEditorStyles = hasRegisteredBlockAsset(blockJson.style) || hasRegisteredBlockAsset(blockJson.editorStyle);
|
|
512
546
|
const editorSources = collectWorkspaceBlockEditorSources(projectDir, blockSlug);
|
|
513
547
|
const editorWrapperSources = editorSources.filter((source) => !isWorkspaceBlockSaveSource(source.relativePath));
|
|
@@ -525,103 +559,122 @@ function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
|
|
|
525
559
|
}
|
|
526
560
|
function checkWorkspacePatternBootstrap(projectDir, packageName) {
|
|
527
561
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
528
|
-
const bootstrapPath =
|
|
529
|
-
if (!
|
|
530
|
-
return createDoctorCheck2("Pattern bootstrap", "fail", `Missing ${
|
|
562
|
+
const bootstrapPath = path4.join(projectDir, `${packageBaseName}.php`);
|
|
563
|
+
if (!fs4.existsSync(bootstrapPath)) {
|
|
564
|
+
return createDoctorCheck2("Pattern bootstrap", "fail", `Missing ${path4.basename(bootstrapPath)}`);
|
|
531
565
|
}
|
|
532
|
-
const source =
|
|
566
|
+
const source = fs4.readFileSync(bootstrapPath, "utf8");
|
|
533
567
|
const hasCategoryAnchor = source.includes("register_block_pattern_category");
|
|
534
568
|
const hasPatternGlob = source.includes("/src/patterns/*.php");
|
|
535
569
|
return createDoctorCheck2("Pattern bootstrap", hasCategoryAnchor && hasPatternGlob ? "pass" : "fail", hasCategoryAnchor && hasPatternGlob ? "Pattern category and loader hooks are present" : "Missing pattern category registration or src/patterns loader hook");
|
|
536
570
|
}
|
|
537
|
-
function
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
return createDoctorCheck2("Binding bootstrap", "fail", `Missing ${path2.basename(bootstrapPath)}`);
|
|
571
|
+
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
572
|
+
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
573
|
+
if (!fs4.existsSync(entryPath)) {
|
|
574
|
+
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
542
575
|
}
|
|
543
|
-
const source =
|
|
544
|
-
const
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
|
|
548
|
-
return createDoctorCheck2("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");
|
|
576
|
+
const source = fs4.readFileSync(entryPath, "utf8");
|
|
577
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
|
|
578
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
|
|
579
|
+
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
549
580
|
}
|
|
550
|
-
function
|
|
551
|
-
const
|
|
552
|
-
if (!
|
|
553
|
-
return createDoctorCheck2(
|
|
581
|
+
function checkBlockStyleEntrypoint(projectDir, blockSlug) {
|
|
582
|
+
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
583
|
+
if (!fs4.existsSync(entryPath)) {
|
|
584
|
+
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
554
585
|
}
|
|
555
|
-
const
|
|
556
|
-
const
|
|
557
|
-
const
|
|
558
|
-
return createDoctorCheck2(
|
|
586
|
+
const source = fs4.readFileSync(entryPath, "utf8");
|
|
587
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
|
|
588
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
|
|
589
|
+
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
|
|
559
590
|
}
|
|
560
|
-
function
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
return;
|
|
591
|
+
function checkBlockTransformEntrypoint(projectDir, blockSlug) {
|
|
592
|
+
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
593
|
+
if (!fs4.existsSync(entryPath)) {
|
|
594
|
+
return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
565
595
|
}
|
|
566
|
-
|
|
567
|
-
|
|
596
|
+
const source = fs4.readFileSync(entryPath, "utf8");
|
|
597
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
|
|
598
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
|
|
599
|
+
return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block transform registration hook is present" : "Missing ./transforms import or applyWorkspaceBlockTransforms(registration.settings) call");
|
|
600
|
+
}
|
|
601
|
+
function checkBlockTransformConfig(workspace, transform) {
|
|
602
|
+
const expectedTo = `${workspace.workspace.namespace}/${transform.block}`;
|
|
603
|
+
const issues = [];
|
|
604
|
+
if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform.from)) {
|
|
605
|
+
issues.push("from must use full namespace/block format");
|
|
568
606
|
}
|
|
569
|
-
if (
|
|
570
|
-
|
|
607
|
+
if (transform.to !== expectedTo) {
|
|
608
|
+
issues.push(`to must equal "${expectedTo}" for workspace block "${transform.block}"`);
|
|
571
609
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
610
|
+
return createDoctorCheck2(`Block transform config ${transform.block}/${transform.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${transform.from} transforms into ${transform.to}` : issues.join("; "));
|
|
611
|
+
}
|
|
612
|
+
function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
613
|
+
const checks = [];
|
|
614
|
+
for (const block of inventory.blocks) {
|
|
615
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)));
|
|
616
|
+
checks.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
|
|
617
|
+
checks.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
|
|
618
|
+
checks.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
|
|
619
|
+
checks.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
|
|
620
|
+
}
|
|
621
|
+
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
622
|
+
const variationTargetBlocks = new Set;
|
|
623
|
+
for (const variation of inventory.variations) {
|
|
624
|
+
if (!registeredBlockSlugs.has(variation.block)) {
|
|
625
|
+
checks.push(createDoctorCheck2(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
|
|
626
|
+
continue;
|
|
585
627
|
}
|
|
586
|
-
|
|
587
|
-
|
|
628
|
+
variationTargetBlocks.add(variation.block);
|
|
629
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Variation ${variation.block}/${variation.slug}`, [variation.file]));
|
|
588
630
|
}
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
631
|
+
for (const blockSlug of variationTargetBlocks) {
|
|
632
|
+
checks.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
|
|
633
|
+
}
|
|
634
|
+
const blockStyleTargetBlocks = new Set;
|
|
635
|
+
for (const blockStyle of inventory.blockStyles) {
|
|
636
|
+
if (!registeredBlockSlugs.has(blockStyle.block)) {
|
|
637
|
+
checks.push(createDoctorCheck2(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
|
|
638
|
+
continue;
|
|
595
639
|
}
|
|
596
|
-
|
|
597
|
-
|
|
640
|
+
blockStyleTargetBlocks.add(blockStyle.block);
|
|
641
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
|
|
642
|
+
}
|
|
643
|
+
for (const blockSlug of blockStyleTargetBlocks) {
|
|
644
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
|
|
645
|
+
path4.join("src", "blocks", blockSlug, "styles", "index.ts")
|
|
646
|
+
]));
|
|
647
|
+
checks.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
|
|
648
|
+
}
|
|
649
|
+
const blockTransformTargetBlocks = new Set;
|
|
650
|
+
for (const blockTransform of inventory.blockTransforms) {
|
|
651
|
+
if (!registeredBlockSlugs.has(blockTransform.block)) {
|
|
652
|
+
checks.push(createDoctorCheck2(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
|
|
653
|
+
continue;
|
|
598
654
|
}
|
|
599
|
-
|
|
600
|
-
|
|
655
|
+
blockTransformTargetBlocks.add(blockTransform.block);
|
|
656
|
+
checks.push(checkBlockTransformConfig(workspace, blockTransform));
|
|
657
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
|
|
601
658
|
}
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
if (!bindingSourceTargetMatch) {
|
|
608
|
-
issues.push(`${bindingSource.editorFile} must export BINDING_SOURCE_TARGET`);
|
|
609
|
-
} else {
|
|
610
|
-
const targetSource = bindingSourceTargetMatch[1] ?? "";
|
|
611
|
-
const attributePattern = new RegExp(`\\battribute\\s*:\\s*["']${escapeRegex(bindingSource.attribute)}["']`, "u");
|
|
612
|
-
const blockPattern = new RegExp(`\\bblock\\s*:\\s*["']${escapeRegex(blockName)}["']`, "u");
|
|
613
|
-
if (!attributePattern.test(targetSource)) {
|
|
614
|
-
issues.push(`${bindingSource.editorFile} must document target attribute "${bindingSource.attribute}"`);
|
|
615
|
-
}
|
|
616
|
-
if (!blockPattern.test(targetSource)) {
|
|
617
|
-
issues.push(`${bindingSource.editorFile} must document target block "${blockName}"`);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
} else {
|
|
621
|
-
issues.push(`Missing ${bindingSource.editorFile}`);
|
|
659
|
+
for (const blockSlug of blockTransformTargetBlocks) {
|
|
660
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
|
|
661
|
+
path4.join("src", "blocks", blockSlug, "transforms", "index.ts")
|
|
662
|
+
]));
|
|
663
|
+
checks.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
|
|
622
664
|
}
|
|
623
|
-
|
|
665
|
+
const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs4.existsSync(path4.join(workspace.projectDir, "src", "patterns"));
|
|
666
|
+
if (shouldCheckPatternBootstrap) {
|
|
667
|
+
checks.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
|
|
668
|
+
}
|
|
669
|
+
for (const pattern of inventory.patterns) {
|
|
670
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [pattern.file]));
|
|
671
|
+
}
|
|
672
|
+
return checks;
|
|
624
673
|
}
|
|
674
|
+
|
|
675
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features.ts
|
|
676
|
+
import fs5 from "fs";
|
|
677
|
+
import path5 from "path";
|
|
625
678
|
function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
626
679
|
const schemaNames = new Set;
|
|
627
680
|
if (restResource.methods.includes("list")) {
|
|
@@ -647,7 +700,7 @@ function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
|
647
700
|
}
|
|
648
701
|
return Array.from(new Set([
|
|
649
702
|
restResource.apiFile,
|
|
650
|
-
...Array.from(schemaNames, (schemaName) =>
|
|
703
|
+
...Array.from(schemaNames, (schemaName) => path5.join(path5.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
651
704
|
restResource.clientFile,
|
|
652
705
|
restResource.dataFile,
|
|
653
706
|
restResource.openApiFile,
|
|
@@ -663,11 +716,11 @@ function checkWorkspaceRestResourceConfig(restResource) {
|
|
|
663
716
|
}
|
|
664
717
|
function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
|
|
665
718
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
666
|
-
const bootstrapPath =
|
|
667
|
-
if (!
|
|
668
|
-
return createDoctorCheck2("REST resource bootstrap", "fail", `Missing ${
|
|
719
|
+
const bootstrapPath = path5.join(projectDir, `${packageBaseName}.php`);
|
|
720
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
721
|
+
return createDoctorCheck2("REST resource bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
669
722
|
}
|
|
670
|
-
const source =
|
|
723
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
671
724
|
const registerFunctionName = `${phpPrefix}_register_rest_resources`;
|
|
672
725
|
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
673
726
|
const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
|
|
@@ -686,12 +739,12 @@ function getWorkspaceAbilityRequiredFiles(ability) {
|
|
|
686
739
|
]));
|
|
687
740
|
}
|
|
688
741
|
function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
689
|
-
const configPath =
|
|
690
|
-
if (!
|
|
742
|
+
const configPath = path5.join(projectDir, ability.configFile);
|
|
743
|
+
if (!fs5.existsSync(configPath)) {
|
|
691
744
|
return createDoctorCheck2(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
|
|
692
745
|
}
|
|
693
746
|
try {
|
|
694
|
-
const config = JSON.parse(
|
|
747
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf8"));
|
|
695
748
|
const abilityId = typeof config.abilityId === "string" ? config.abilityId.trim() : "";
|
|
696
749
|
const categorySlug = typeof config.category?.slug === "string" ? config.category.slug.trim() : "";
|
|
697
750
|
const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
|
|
@@ -703,11 +756,11 @@ function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
|
703
756
|
}
|
|
704
757
|
function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
705
758
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
706
|
-
const bootstrapPath =
|
|
707
|
-
if (!
|
|
708
|
-
return createDoctorCheck2("Ability bootstrap", "fail", `Missing ${
|
|
759
|
+
const bootstrapPath = path5.join(projectDir, `${packageBaseName}.php`);
|
|
760
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
761
|
+
return createDoctorCheck2("Ability bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
709
762
|
}
|
|
710
|
-
const source =
|
|
763
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
711
764
|
const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
|
|
712
765
|
const enqueueFunctionName = `${phpPrefix}_enqueue_workflow_abilities`;
|
|
713
766
|
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
@@ -724,14 +777,14 @@ function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
724
777
|
}
|
|
725
778
|
function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
726
779
|
const indexRelativePath = [
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
].find((relativePath) =>
|
|
780
|
+
path5.join("src", "abilities", "index.ts"),
|
|
781
|
+
path5.join("src", "abilities", "index.js")
|
|
782
|
+
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
730
783
|
if (!indexRelativePath) {
|
|
731
784
|
return createDoctorCheck2("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
|
|
732
785
|
}
|
|
733
|
-
const indexPath =
|
|
734
|
-
const source =
|
|
786
|
+
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
787
|
+
const source = fs5.readFileSync(indexPath, "utf8");
|
|
735
788
|
const missingExports = abilities.filter((ability) => {
|
|
736
789
|
const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex(ability.slug)}\\/client['"\`]`, "mu");
|
|
737
790
|
return !exportPattern.test(source);
|
|
@@ -742,9 +795,9 @@ function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
|
|
|
742
795
|
return Array.from(new Set([
|
|
743
796
|
aiFeature.aiSchemaFile,
|
|
744
797
|
aiFeature.apiFile,
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
798
|
+
path5.join(path5.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
|
|
799
|
+
path5.join(path5.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
|
|
800
|
+
path5.join(path5.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
|
|
748
801
|
aiFeature.clientFile,
|
|
749
802
|
aiFeature.dataFile,
|
|
750
803
|
aiFeature.openApiFile,
|
|
@@ -759,11 +812,11 @@ function checkWorkspaceAiFeatureConfig(aiFeature) {
|
|
|
759
812
|
}
|
|
760
813
|
function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
761
814
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
762
|
-
const bootstrapPath =
|
|
763
|
-
if (!
|
|
764
|
-
return createDoctorCheck2("AI feature bootstrap", "fail", `Missing ${
|
|
815
|
+
const bootstrapPath = path5.join(projectDir, `${packageBaseName}.php`);
|
|
816
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
817
|
+
return createDoctorCheck2("AI feature bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
765
818
|
}
|
|
766
|
-
const source =
|
|
819
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
767
820
|
const registerFunctionName = `${phpPrefix}_register_ai_features`;
|
|
768
821
|
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
769
822
|
const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
|
|
@@ -771,14 +824,14 @@ function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
771
824
|
return createDoctorCheck2("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");
|
|
772
825
|
}
|
|
773
826
|
function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
774
|
-
const editorPluginDir =
|
|
775
|
-
const surfaceFile = editorPlugin.slot === "PluginSidebar" ?
|
|
827
|
+
const editorPluginDir = path5.join("src", "editor-plugins", editorPlugin.slug);
|
|
828
|
+
const surfaceFile = editorPlugin.slot === "PluginSidebar" ? path5.join(editorPluginDir, "Sidebar.tsx") : path5.join(editorPluginDir, "Surface.tsx");
|
|
776
829
|
return Array.from(new Set([
|
|
777
830
|
editorPlugin.file,
|
|
778
831
|
surfaceFile,
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
832
|
+
path5.join(editorPluginDir, "data.ts"),
|
|
833
|
+
path5.join(editorPluginDir, "types.ts"),
|
|
834
|
+
path5.join(editorPluginDir, "style.scss")
|
|
782
835
|
]));
|
|
783
836
|
}
|
|
784
837
|
function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
@@ -788,11 +841,11 @@ function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
|
788
841
|
}
|
|
789
842
|
function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
|
|
790
843
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
791
|
-
const bootstrapPath =
|
|
792
|
-
if (!
|
|
793
|
-
return createDoctorCheck2("Editor plugin bootstrap", "fail", `Missing ${
|
|
844
|
+
const bootstrapPath = path5.join(projectDir, `${packageBaseName}.php`);
|
|
845
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
846
|
+
return createDoctorCheck2("Editor plugin bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
794
847
|
}
|
|
795
|
-
const source =
|
|
848
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
796
849
|
const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
|
|
797
850
|
const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
798
851
|
const hasEditorEnqueueHook = source.includes(enqueueHook);
|
|
@@ -803,14 +856,14 @@ function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix)
|
|
|
803
856
|
}
|
|
804
857
|
function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
805
858
|
const indexRelativePath = [
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
].find((relativePath) =>
|
|
859
|
+
path5.join("src", "editor-plugins", "index.ts"),
|
|
860
|
+
path5.join("src", "editor-plugins", "index.js")
|
|
861
|
+
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
809
862
|
if (!indexRelativePath) {
|
|
810
863
|
return createDoctorCheck2("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
|
|
811
864
|
}
|
|
812
|
-
const indexPath =
|
|
813
|
-
const source =
|
|
865
|
+
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
866
|
+
const source = fs5.readFileSync(indexPath, "utf8");
|
|
814
867
|
const missingImports = editorPlugins.filter((editorPlugin) => {
|
|
815
868
|
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
816
869
|
return !importPattern.test(source);
|
|
@@ -818,15 +871,15 @@ function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
|
818
871
|
return createDoctorCheck2("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(", ")}`);
|
|
819
872
|
}
|
|
820
873
|
function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
821
|
-
const adminViewDir =
|
|
874
|
+
const adminViewDir = path5.join("src", "admin-views", adminView.slug);
|
|
822
875
|
return Array.from(new Set([
|
|
823
876
|
adminView.file,
|
|
824
877
|
adminView.phpFile,
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
878
|
+
path5.join(adminViewDir, "Screen.tsx"),
|
|
879
|
+
path5.join(adminViewDir, "config.ts"),
|
|
880
|
+
path5.join(adminViewDir, "data.ts"),
|
|
881
|
+
path5.join(adminViewDir, "style.scss"),
|
|
882
|
+
path5.join(adminViewDir, "types.ts")
|
|
830
883
|
]));
|
|
831
884
|
}
|
|
832
885
|
function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
@@ -843,11 +896,11 @@ function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
|
843
896
|
}
|
|
844
897
|
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
845
898
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
846
|
-
const bootstrapPath =
|
|
847
|
-
if (!
|
|
848
|
-
return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${
|
|
899
|
+
const bootstrapPath = path5.join(projectDir, `${packageBaseName}.php`);
|
|
900
|
+
if (!fs5.existsSync(bootstrapPath)) {
|
|
901
|
+
return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${path5.basename(bootstrapPath)}`);
|
|
849
902
|
}
|
|
850
|
-
const source =
|
|
903
|
+
const source = fs5.readFileSync(bootstrapPath, "utf8");
|
|
851
904
|
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
852
905
|
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
853
906
|
const hasLoaderHook = source.includes(loadHook);
|
|
@@ -856,14 +909,14 @@ function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
856
909
|
}
|
|
857
910
|
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
858
911
|
const indexRelativePath = [
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
].find((relativePath) =>
|
|
912
|
+
path5.join("src", "admin-views", "index.ts"),
|
|
913
|
+
path5.join("src", "admin-views", "index.js")
|
|
914
|
+
].find((relativePath) => fs5.existsSync(path5.join(projectDir, relativePath)));
|
|
862
915
|
if (!indexRelativePath) {
|
|
863
916
|
return createDoctorCheck2("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
864
917
|
}
|
|
865
|
-
const indexPath =
|
|
866
|
-
const source =
|
|
918
|
+
const indexPath = path5.join(projectDir, indexRelativePath);
|
|
919
|
+
const source = fs5.readFileSync(indexPath, "utf8");
|
|
867
920
|
const missingImports = adminViews.filter((adminView) => {
|
|
868
921
|
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
869
922
|
return !importPattern.test(source);
|
|
@@ -871,11 +924,11 @@ function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
|
871
924
|
return createDoctorCheck2("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(", ")}`);
|
|
872
925
|
}
|
|
873
926
|
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
874
|
-
const phpPath =
|
|
875
|
-
if (!
|
|
927
|
+
const phpPath = path5.join(projectDir, adminView.phpFile);
|
|
928
|
+
if (!fs5.existsSync(phpPath)) {
|
|
876
929
|
return createDoctorCheck2(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
877
930
|
}
|
|
878
|
-
const source =
|
|
931
|
+
const source = fs5.readFileSync(phpPath, "utf8");
|
|
879
932
|
const hasAdminMenu = source.includes("add_submenu_page");
|
|
880
933
|
const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
|
|
881
934
|
const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
|
|
@@ -884,56 +937,107 @@ function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
|
884
937
|
const hasComponentsStyleDependency = source.includes("'wp-components'");
|
|
885
938
|
return createDoctorCheck2(`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");
|
|
886
939
|
}
|
|
887
|
-
function
|
|
888
|
-
const
|
|
889
|
-
if (
|
|
890
|
-
|
|
940
|
+
function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
|
|
941
|
+
const checks = [];
|
|
942
|
+
if (inventory.restResources.length > 0) {
|
|
943
|
+
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
891
944
|
}
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
896
|
-
}
|
|
897
|
-
function checkBlockStyleEntrypoint(projectDir, blockSlug) {
|
|
898
|
-
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
899
|
-
if (!fs2.existsSync(entryPath)) {
|
|
900
|
-
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
945
|
+
for (const restResource of inventory.restResources) {
|
|
946
|
+
checks.push(checkWorkspaceRestResourceConfig(restResource));
|
|
947
|
+
checks.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
|
|
901
948
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
|
|
906
|
-
}
|
|
907
|
-
function checkBlockTransformEntrypoint(projectDir, blockSlug) {
|
|
908
|
-
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
909
|
-
if (!fs2.existsSync(entryPath)) {
|
|
910
|
-
return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
949
|
+
if (inventory.abilities.length > 0) {
|
|
950
|
+
checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
951
|
+
checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
|
|
911
952
|
}
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
953
|
+
for (const ability of inventory.abilities) {
|
|
954
|
+
checks.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
|
|
955
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
|
|
956
|
+
}
|
|
957
|
+
if (inventory.aiFeatures.length > 0) {
|
|
958
|
+
checks.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
959
|
+
}
|
|
960
|
+
for (const aiFeature of inventory.aiFeatures) {
|
|
961
|
+
checks.push(checkWorkspaceAiFeatureConfig(aiFeature));
|
|
962
|
+
checks.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
|
|
963
|
+
}
|
|
964
|
+
if (inventory.editorPlugins.length > 0) {
|
|
965
|
+
checks.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
966
|
+
checks.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
|
|
967
|
+
}
|
|
968
|
+
for (const editorPlugin of inventory.editorPlugins) {
|
|
969
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
970
|
+
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
971
|
+
}
|
|
972
|
+
if (inventory.adminViews.length > 0) {
|
|
973
|
+
checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
974
|
+
checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
|
|
975
|
+
}
|
|
976
|
+
for (const adminView of inventory.adminViews) {
|
|
977
|
+
checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
|
|
978
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
|
|
979
|
+
checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
|
|
980
|
+
}
|
|
981
|
+
return checks;
|
|
916
982
|
}
|
|
917
|
-
|
|
918
|
-
|
|
983
|
+
|
|
984
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-package.ts
|
|
985
|
+
import fs6 from "fs";
|
|
986
|
+
import path6 from "path";
|
|
987
|
+
function getWorkspacePackageMetadataCheck(workspace, packageJson) {
|
|
919
988
|
const issues = [];
|
|
920
|
-
|
|
921
|
-
|
|
989
|
+
const packageName = packageJson.name;
|
|
990
|
+
const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
|
|
991
|
+
const wpTypia = packageJson.wpTypia;
|
|
992
|
+
if (typeof packageName !== "string" || packageName.length === 0) {
|
|
993
|
+
issues.push("package.json must define a string name for workspace bootstrap resolution");
|
|
922
994
|
}
|
|
923
|
-
if (
|
|
924
|
-
issues.push(
|
|
995
|
+
if (wpTypia?.projectType !== "workspace") {
|
|
996
|
+
issues.push('wpTypia.projectType must be "workspace"');
|
|
925
997
|
}
|
|
926
|
-
|
|
998
|
+
if (wpTypia?.templatePackage !== WORKSPACE_TEMPLATE_PACKAGE) {
|
|
999
|
+
issues.push(`wpTypia.templatePackage must be "${WORKSPACE_TEMPLATE_PACKAGE}"`);
|
|
1000
|
+
}
|
|
1001
|
+
if (wpTypia?.namespace !== workspace.workspace.namespace) {
|
|
1002
|
+
issues.push(`wpTypia.namespace must equal "${workspace.workspace.namespace}"`);
|
|
1003
|
+
}
|
|
1004
|
+
if (wpTypia?.textDomain !== workspace.workspace.textDomain) {
|
|
1005
|
+
issues.push(`wpTypia.textDomain must equal "${workspace.workspace.textDomain}"`);
|
|
1006
|
+
}
|
|
1007
|
+
if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
|
|
1008
|
+
issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
|
|
1009
|
+
}
|
|
1010
|
+
if (!fs6.existsSync(path6.join(workspace.projectDir, bootstrapRelativePath))) {
|
|
1011
|
+
issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
|
|
1012
|
+
}
|
|
1013
|
+
return createDoctorCheck2("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${bootstrapRelativePath}` : issues.join("; "));
|
|
927
1014
|
}
|
|
928
|
-
function
|
|
1015
|
+
function getMigrationWorkspaceHintCheck(workspace, packageJson) {
|
|
929
1016
|
const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
|
|
930
|
-
const migrationConfigRelativePath =
|
|
931
|
-
const hasMigrationConfig =
|
|
1017
|
+
const migrationConfigRelativePath = path6.join("src", "migrations", "config.ts");
|
|
1018
|
+
const hasMigrationConfig = fs6.existsSync(path6.join(workspace.projectDir, migrationConfigRelativePath));
|
|
932
1019
|
if (!hasMigrationScript && !hasMigrationConfig) {
|
|
933
1020
|
return null;
|
|
934
1021
|
}
|
|
935
1022
|
return createDoctorCheck2("Migration workspace", hasMigrationConfig ? "pass" : "fail", hasMigrationConfig ? "Run `wp-typia migrate doctor --all` for migration target, snapshot, fixture, and generated artifact checks" : `Missing ${migrationConfigRelativePath} for the configured migration workspace`);
|
|
936
1023
|
}
|
|
1024
|
+
|
|
1025
|
+
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
|
|
1026
|
+
function formatWorkspaceInventorySummary(inventory) {
|
|
1027
|
+
return [
|
|
1028
|
+
`${inventory.blocks.length} block(s)`,
|
|
1029
|
+
`${inventory.variations.length} variation(s)`,
|
|
1030
|
+
`${inventory.blockStyles.length} block style(s)`,
|
|
1031
|
+
`${inventory.blockTransforms.length} block transform(s)`,
|
|
1032
|
+
`${inventory.patterns.length} pattern(s)`,
|
|
1033
|
+
`${inventory.bindingSources.length} binding source(s)`,
|
|
1034
|
+
`${inventory.restResources.length} REST resource(s)`,
|
|
1035
|
+
`${inventory.abilities.length} ability scaffold(s)`,
|
|
1036
|
+
`${inventory.aiFeatures.length} AI feature(s)`,
|
|
1037
|
+
`${inventory.editorPlugins.length} editor plugin(s)`,
|
|
1038
|
+
`${inventory.adminViews.length} admin view(s)`
|
|
1039
|
+
].join(", ");
|
|
1040
|
+
}
|
|
937
1041
|
function getWorkspaceDoctorChecks(cwd) {
|
|
938
1042
|
const checks = [];
|
|
939
1043
|
let workspace = null;
|
|
@@ -963,122 +1067,14 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
963
1067
|
checks.push(createDoctorCheck2("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
|
|
964
1068
|
return checks;
|
|
965
1069
|
}
|
|
966
|
-
checks.push(
|
|
1070
|
+
checks.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson));
|
|
967
1071
|
try {
|
|
968
1072
|
const inventory = readWorkspaceInventory(workspace.projectDir);
|
|
969
|
-
checks.push(createDoctorCheck2("Workspace inventory", "pass",
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
checks.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
|
|
975
|
-
checks.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
|
|
976
|
-
}
|
|
977
|
-
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
978
|
-
const variationTargetBlocks = new Set;
|
|
979
|
-
for (const variation of inventory.variations) {
|
|
980
|
-
if (!registeredBlockSlugs.has(variation.block)) {
|
|
981
|
-
checks.push(createDoctorCheck2(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
|
|
982
|
-
continue;
|
|
983
|
-
}
|
|
984
|
-
variationTargetBlocks.add(variation.block);
|
|
985
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Variation ${variation.block}/${variation.slug}`, [variation.file]));
|
|
986
|
-
}
|
|
987
|
-
for (const blockSlug of variationTargetBlocks) {
|
|
988
|
-
checks.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
|
|
989
|
-
}
|
|
990
|
-
const blockStyleTargetBlocks = new Set;
|
|
991
|
-
for (const blockStyle of inventory.blockStyles) {
|
|
992
|
-
if (!registeredBlockSlugs.has(blockStyle.block)) {
|
|
993
|
-
checks.push(createDoctorCheck2(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
blockStyleTargetBlocks.add(blockStyle.block);
|
|
997
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
|
|
998
|
-
}
|
|
999
|
-
for (const blockSlug of blockStyleTargetBlocks) {
|
|
1000
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
|
|
1001
|
-
path2.join("src", "blocks", blockSlug, "styles", "index.ts")
|
|
1002
|
-
]));
|
|
1003
|
-
checks.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
|
|
1004
|
-
}
|
|
1005
|
-
const blockTransformTargetBlocks = new Set;
|
|
1006
|
-
for (const blockTransform of inventory.blockTransforms) {
|
|
1007
|
-
if (!registeredBlockSlugs.has(blockTransform.block)) {
|
|
1008
|
-
checks.push(createDoctorCheck2(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
|
|
1009
|
-
continue;
|
|
1010
|
-
}
|
|
1011
|
-
blockTransformTargetBlocks.add(blockTransform.block);
|
|
1012
|
-
checks.push(checkBlockTransformConfig(workspace, blockTransform));
|
|
1013
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
|
|
1014
|
-
}
|
|
1015
|
-
for (const blockSlug of blockTransformTargetBlocks) {
|
|
1016
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
|
|
1017
|
-
path2.join("src", "blocks", blockSlug, "transforms", "index.ts")
|
|
1018
|
-
]));
|
|
1019
|
-
checks.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
|
|
1020
|
-
}
|
|
1021
|
-
const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs2.existsSync(path2.join(workspace.projectDir, "src", "patterns"));
|
|
1022
|
-
if (shouldCheckPatternBootstrap) {
|
|
1023
|
-
checks.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
|
|
1024
|
-
}
|
|
1025
|
-
for (const pattern of inventory.patterns) {
|
|
1026
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [pattern.file]));
|
|
1027
|
-
}
|
|
1028
|
-
if (inventory.bindingSources.length > 0) {
|
|
1029
|
-
checks.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
|
|
1030
|
-
checks.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
|
|
1031
|
-
}
|
|
1032
|
-
for (const bindingSource of inventory.bindingSources) {
|
|
1033
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
|
|
1034
|
-
bindingSource.serverFile,
|
|
1035
|
-
bindingSource.editorFile
|
|
1036
|
-
]));
|
|
1037
|
-
const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
|
|
1038
|
-
if (bindingTargetCheck) {
|
|
1039
|
-
checks.push(bindingTargetCheck);
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
if (inventory.restResources.length > 0) {
|
|
1043
|
-
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1044
|
-
}
|
|
1045
|
-
for (const restResource of inventory.restResources) {
|
|
1046
|
-
checks.push(checkWorkspaceRestResourceConfig(restResource));
|
|
1047
|
-
checks.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
|
|
1048
|
-
}
|
|
1049
|
-
if (inventory.abilities.length > 0) {
|
|
1050
|
-
checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1051
|
-
checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
|
|
1052
|
-
}
|
|
1053
|
-
for (const ability of inventory.abilities) {
|
|
1054
|
-
checks.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
|
|
1055
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
|
|
1056
|
-
}
|
|
1057
|
-
if (inventory.aiFeatures.length > 0) {
|
|
1058
|
-
checks.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1059
|
-
}
|
|
1060
|
-
for (const aiFeature of inventory.aiFeatures) {
|
|
1061
|
-
checks.push(checkWorkspaceAiFeatureConfig(aiFeature));
|
|
1062
|
-
checks.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
|
|
1063
|
-
}
|
|
1064
|
-
if (inventory.editorPlugins.length > 0) {
|
|
1065
|
-
checks.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1066
|
-
checks.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
|
|
1067
|
-
}
|
|
1068
|
-
for (const editorPlugin of inventory.editorPlugins) {
|
|
1069
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
1070
|
-
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
1071
|
-
}
|
|
1072
|
-
if (inventory.adminViews.length > 0) {
|
|
1073
|
-
checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1074
|
-
checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
|
|
1075
|
-
}
|
|
1076
|
-
for (const adminView of inventory.adminViews) {
|
|
1077
|
-
checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
|
|
1078
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
|
|
1079
|
-
checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
|
|
1080
|
-
}
|
|
1081
|
-
const migrationWorkspaceCheck = checkMigrationWorkspaceHint(workspace, workspacePackageJson);
|
|
1073
|
+
checks.push(createDoctorCheck2("Workspace inventory", "pass", formatWorkspaceInventorySummary(inventory)));
|
|
1074
|
+
checks.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
|
|
1075
|
+
checks.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
|
|
1076
|
+
checks.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
|
|
1077
|
+
const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspace, workspacePackageJson);
|
|
1082
1078
|
if (migrationWorkspaceCheck) {
|
|
1083
1079
|
checks.push(migrationWorkspaceCheck);
|
|
1084
1080
|
}
|
|
@@ -1121,4 +1117,4 @@ export {
|
|
|
1121
1117
|
getDoctorChecks
|
|
1122
1118
|
};
|
|
1123
1119
|
|
|
1124
|
-
//# debugId=
|
|
1120
|
+
//# debugId=08A020B4B453391764756E2164756E21
|