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