wp-typia 0.20.4 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bin/argv-walker.d.ts +19 -0
- package/bin/argv-walker.js +53 -0
- package/bin/routing-metadata.generated.d.ts +1 -1
- package/bin/routing-metadata.generated.js +38 -38
- package/bin/wp-typia.js +75 -87
- package/dist-bunli/.bunli/commands.gen.js +4940 -1246
- package/dist-bunli/{cli-68145vb5.js → cli-9x01fjna.js} +346 -41
- package/dist-bunli/{cli-add-a27wjrk4.js → cli-add-93945fc2.js} +1900 -385
- package/dist-bunli/{cli-diagnostics-db6kxv83.js → cli-diagnostics-5dvztm7q.js} +8 -2
- package/dist-bunli/{cli-doctor-31djnnxs.js → cli-doctor-zsndr5sw.js} +492 -20
- package/dist-bunli/{cli-3w3qxq9w.js → cli-hx88xwr4.js} +257 -25
- package/dist-bunli/cli-init-6xxc0snz.js +844 -0
- package/dist-bunli/{cli-2rev5hqm.js → cli-jfj54qej.js} +1 -1
- package/dist-bunli/{cli-jcd4wgam.js → cli-p95wr1q8.js} +77 -5
- package/dist-bunli/{cli-c5021kqy.js → cli-pav309dt.js} +896 -286
- package/dist-bunli/{cli-scaffold-r0yxfhbq.js → cli-scaffold-d2vtf740.js} +6 -5
- package/dist-bunli/{cli-tesygdnr.js → cli-syg9qpxw.js} +22 -1
- package/dist-bunli/cli.js +31 -117
- package/dist-bunli/{command-list-kx7q3f18.js → command-list-p452y8td.js} +561 -319
- package/dist-bunli/{migrations-1p6mbkyw.js → migrations-aj1rv3h8.js} +2 -2
- package/dist-bunli/node-cli.js +1035 -555
- package/package.json +5 -3
- package/dist-bunli/cli-init-gdyp9enw.js +0 -341
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CLI_DIAGNOSTIC_CODES,
|
|
4
|
+
CLI_DIAGNOSTIC_CODE_METADATA,
|
|
4
5
|
CliDiagnosticError,
|
|
5
6
|
createCliCommandError,
|
|
7
|
+
createCliDiagnosticCodeError,
|
|
6
8
|
formatCliDiagnosticError,
|
|
7
9
|
formatDoctorCheckLine,
|
|
8
10
|
formatDoctorSummaryLine,
|
|
11
|
+
getCliDiagnosticCodeMetadata,
|
|
9
12
|
getDoctorFailureDetailLines,
|
|
10
13
|
getFailingDoctorChecks,
|
|
11
14
|
isCliDiagnosticError,
|
|
12
15
|
serializeCliDiagnosticError
|
|
13
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-p95wr1q8.js";
|
|
14
17
|
import"./cli-xnn9xjcy.js";
|
|
15
18
|
export {
|
|
16
19
|
serializeCliDiagnosticError,
|
|
17
20
|
isCliDiagnosticError,
|
|
18
21
|
getFailingDoctorChecks,
|
|
19
22
|
getDoctorFailureDetailLines,
|
|
23
|
+
getCliDiagnosticCodeMetadata,
|
|
20
24
|
formatDoctorSummaryLine,
|
|
21
25
|
formatDoctorCheckLine,
|
|
22
26
|
formatCliDiagnosticError,
|
|
27
|
+
createCliDiagnosticCodeError,
|
|
23
28
|
createCliCommandError,
|
|
24
29
|
CliDiagnosticError,
|
|
30
|
+
CLI_DIAGNOSTIC_CODE_METADATA,
|
|
25
31
|
CLI_DIAGNOSTIC_CODES
|
|
26
32
|
};
|
|
27
33
|
|
|
28
|
-
//# debugId=
|
|
34
|
+
//# debugId=C0BB65021DB87CDD64756E2164756E21
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
createCliCommandError,
|
|
4
|
-
formatDoctorCheckLine,
|
|
5
|
-
formatDoctorSummaryLine,
|
|
6
|
-
getDoctorFailureDetailLines
|
|
7
|
-
} from "./cli-jcd4wgam.js";
|
|
8
2
|
import {
|
|
9
3
|
getBuiltInTemplateLayerDirs,
|
|
10
4
|
isOmittableBuiltInTemplateLayerDir
|
|
@@ -19,9 +13,18 @@ import {
|
|
|
19
13
|
HOOKED_BLOCK_POSITION_SET,
|
|
20
14
|
REST_RESOURCE_METHOD_IDS,
|
|
21
15
|
REST_RESOURCE_NAMESPACE_PATTERN,
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
escapeRegex,
|
|
17
|
+
readWorkspaceInventory,
|
|
18
|
+
resolveEditorPluginSlotAlias
|
|
19
|
+
} from "./cli-hx88xwr4.js";
|
|
24
20
|
import"./cli-t73q5aqz.js";
|
|
21
|
+
import {
|
|
22
|
+
CLI_DIAGNOSTIC_CODES,
|
|
23
|
+
createCliCommandError,
|
|
24
|
+
formatDoctorCheckLine,
|
|
25
|
+
formatDoctorSummaryLine,
|
|
26
|
+
getDoctorFailureDetailLines
|
|
27
|
+
} from "./cli-p95wr1q8.js";
|
|
25
28
|
import {
|
|
26
29
|
WORKSPACE_TEMPLATE_PACKAGE,
|
|
27
30
|
getInvalidWorkspaceProjectReason,
|
|
@@ -140,6 +143,10 @@ var WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
|
|
|
140
143
|
var WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
|
|
141
144
|
var WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
|
|
142
145
|
var WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php";
|
|
146
|
+
var WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php";
|
|
147
|
+
var WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js";
|
|
148
|
+
var WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php";
|
|
149
|
+
var WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css";
|
|
143
150
|
var WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js";
|
|
144
151
|
var WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php";
|
|
145
152
|
var WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css";
|
|
@@ -150,14 +157,244 @@ var WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
|
150
157
|
"typia-validator.php",
|
|
151
158
|
"typia.openapi.json"
|
|
152
159
|
];
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
var WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
161
|
+
var WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
|
|
162
|
+
var WORKSPACE_VARIATIONS_CALL_PATTERN = /registerWorkspaceVariations\s*\(\s*\)\s*;?/u;
|
|
163
|
+
var WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
|
|
164
|
+
var WORKSPACE_BLOCK_STYLES_CALL_PATTERN = /registerWorkspaceBlockStyles\s*\(\s*\)\s*;?/u;
|
|
165
|
+
var WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN = /^\s*import\s*\{\s*applyWorkspaceBlockTransforms\s*\}\s*from\s*["']\.\/transforms["']\s*;?\s*$/mu;
|
|
166
|
+
var WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
|
|
167
|
+
var WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL = "https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/block-migration-for-iframe-editor-compatibility/";
|
|
168
|
+
var WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES = {
|
|
169
|
+
API_VERSION: "wp-typia.workspace.block.iframe.api-version",
|
|
170
|
+
BLOCK_PROPS: "wp-typia.workspace.block.iframe.block-props",
|
|
171
|
+
EDITOR_GLOBALS: "wp-typia.workspace.block.iframe.editor-globals",
|
|
172
|
+
EDITOR_STYLES: "wp-typia.workspace.block.iframe.editor-styles"
|
|
173
|
+
};
|
|
174
|
+
var WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/u;
|
|
175
|
+
var WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES = new Set([
|
|
176
|
+
"edit",
|
|
177
|
+
"editor",
|
|
178
|
+
"index",
|
|
179
|
+
"save"
|
|
180
|
+
]);
|
|
181
|
+
var WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES = new Set([
|
|
182
|
+
"components",
|
|
183
|
+
"controls",
|
|
184
|
+
"editor",
|
|
185
|
+
"inspector"
|
|
186
|
+
]);
|
|
187
|
+
var WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
|
|
188
|
+
"editor.css",
|
|
189
|
+
"editor.scss",
|
|
190
|
+
"index.css",
|
|
191
|
+
"style.css",
|
|
192
|
+
"style.scss"
|
|
193
|
+
];
|
|
194
|
+
var WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
|
|
195
|
+
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 };
|
|
155
198
|
}
|
|
156
199
|
function createDoctorScopeCheck(status, detail) {
|
|
157
200
|
return createDoctorCheck2("Doctor scope", status, detail);
|
|
158
201
|
}
|
|
159
|
-
function
|
|
160
|
-
return
|
|
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
|
+
function normalizePathSeparators(relativePath) {
|
|
264
|
+
return relativePath.split(path2.sep).join("/");
|
|
265
|
+
}
|
|
266
|
+
function hasRegisteredBlockAsset(value) {
|
|
267
|
+
if (typeof value === "string") {
|
|
268
|
+
return value.trim().length > 0;
|
|
269
|
+
}
|
|
270
|
+
if (Array.isArray(value)) {
|
|
271
|
+
return value.some((entry) => hasRegisteredBlockAsset(entry));
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
|
|
276
|
+
const blockJsonRelativePath = path2.join("src", "blocks", blockSlug, "block.json");
|
|
277
|
+
const blockJsonPath = path2.join(projectDir, blockJsonRelativePath);
|
|
278
|
+
if (!fs2.existsSync(blockJsonPath)) {
|
|
279
|
+
return {
|
|
280
|
+
blockJsonRelativePath,
|
|
281
|
+
error: `Missing ${blockJsonRelativePath}`
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const parsed = JSON.parse(fs2.readFileSync(blockJsonPath, "utf8"));
|
|
286
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
287
|
+
return {
|
|
288
|
+
blockJsonRelativePath,
|
|
289
|
+
error: `${blockJsonRelativePath} must contain a JSON object`
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
blockJsonRelativePath,
|
|
294
|
+
document: parsed
|
|
295
|
+
};
|
|
296
|
+
} catch (error) {
|
|
297
|
+
return {
|
|
298
|
+
blockJsonRelativePath,
|
|
299
|
+
error: error instanceof Error ? error.message : String(error)
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function isWorkspaceBlockEditorSource(relativePath) {
|
|
304
|
+
const normalizedPath = normalizePathSeparators(relativePath);
|
|
305
|
+
const normalizedLowerPath = normalizedPath.toLowerCase();
|
|
306
|
+
if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(normalizedLowerPath) || /\.d\.[cm]?[jt]s$/u.test(normalizedLowerPath)) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
const segments = normalizedLowerPath.split("/");
|
|
310
|
+
const fileName = segments[segments.length - 1] ?? "";
|
|
311
|
+
const baseName = fileName.replace(/\.[^.]+$/u, "");
|
|
312
|
+
if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(baseName)) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
return segments.slice(0, -1).some((segment) => WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES.has(segment));
|
|
316
|
+
}
|
|
317
|
+
function isWorkspaceBlockSaveSource(relativePath) {
|
|
318
|
+
const fileName = normalizePathSeparators(relativePath).split("/").pop() ?? "";
|
|
319
|
+
return fileName.replace(/\.[^.]+$/u, "").toLowerCase() === "save";
|
|
320
|
+
}
|
|
321
|
+
function collectWorkspaceBlockEditorSources(projectDir, blockSlug) {
|
|
322
|
+
const blockDir = path2.join(projectDir, "src", "blocks", blockSlug);
|
|
323
|
+
if (!fs2.existsSync(blockDir)) {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
const sources = [];
|
|
327
|
+
const visitDirectory = (directory) => {
|
|
328
|
+
for (const entry of fs2.readdirSync(directory, { withFileTypes: true })) {
|
|
329
|
+
const entryPath = path2.join(directory, entry.name);
|
|
330
|
+
if (entry.isDirectory()) {
|
|
331
|
+
visitDirectory(entryPath);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (!entry.isFile()) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const relativePath = normalizePathSeparators(path2.relative(projectDir, entryPath));
|
|
338
|
+
const blockRelativePath = path2.relative(blockDir, entryPath);
|
|
339
|
+
if (!isWorkspaceBlockEditorSource(blockRelativePath)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
sources.push({
|
|
343
|
+
relativePath,
|
|
344
|
+
source: fs2.readFileSync(entryPath, "utf8")
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
visitDirectory(blockDir);
|
|
349
|
+
return sources;
|
|
350
|
+
}
|
|
351
|
+
function getSourceLineNumber(source, index) {
|
|
352
|
+
let lineNumber = 1;
|
|
353
|
+
for (let cursor = 0;cursor < index; cursor += 1) {
|
|
354
|
+
if (source[cursor] === `
|
|
355
|
+
`) {
|
|
356
|
+
lineNumber += 1;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return lineNumber;
|
|
360
|
+
}
|
|
361
|
+
function isGlobalDomAccessCandidate(maskedSource, index, token) {
|
|
362
|
+
if (token === "document" || token === "window") {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
const before = maskedSource.slice(0, index);
|
|
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 === ",") {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
if (nextNonWhitespace === ":") {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
if (/\b(?:const|function|let|var)\s+$/u.test(before)) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
function findWorkspaceBlockGlobalDomAccesses(sources) {
|
|
381
|
+
const findings = [];
|
|
382
|
+
for (const { relativePath, source } of sources) {
|
|
383
|
+
const maskedSource = maskTypeScriptCommentsAndLiterals(source);
|
|
384
|
+
const matches = maskedSource.matchAll(WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN);
|
|
385
|
+
for (const match of matches) {
|
|
386
|
+
const index = match.index ?? 0;
|
|
387
|
+
const matchedToken = match[0].replace(/\W+/gu, "");
|
|
388
|
+
if (!isGlobalDomAccessCandidate(maskedSource, index, matchedToken)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
findings.push(`${relativePath}:${getSourceLineNumber(source, index)} (${matchedToken})`);
|
|
392
|
+
if (findings.length >= 5) {
|
|
393
|
+
return findings;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return findings;
|
|
161
398
|
}
|
|
162
399
|
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
163
400
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
@@ -260,6 +497,32 @@ function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
|
|
|
260
497
|
const hasCollectionImport = WORKSPACE_COLLECTION_IMPORT_PATTERN.test(source);
|
|
261
498
|
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}`);
|
|
262
499
|
}
|
|
500
|
+
function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
|
|
501
|
+
const metadataResult = readWorkspaceBlockIframeMetadata(projectDir, blockSlug);
|
|
502
|
+
if (!metadataResult.document) {
|
|
503
|
+
return [
|
|
504
|
+
createDoctorCheck2(`Block iframe/API v3 ${blockSlug}`, "warn", metadataResult.error ?? `Unable to inspect ${metadataResult.blockJsonRelativePath}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION)
|
|
505
|
+
];
|
|
506
|
+
}
|
|
507
|
+
const blockJson = metadataResult.document;
|
|
508
|
+
const apiVersion = typeof blockJson.apiVersion === "number" && Number.isFinite(blockJson.apiVersion) ? blockJson.apiVersion : null;
|
|
509
|
+
const blockDir = path2.join(projectDir, "src", "blocks", blockSlug);
|
|
510
|
+
const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) => fs2.existsSync(path2.join(blockDir, fileName))).map((fileName) => normalizePathSeparators(path2.join("src", "blocks", blockSlug, fileName)));
|
|
511
|
+
const hasRegisteredEditorStyles = hasRegisteredBlockAsset(blockJson.style) || hasRegisteredBlockAsset(blockJson.editorStyle);
|
|
512
|
+
const editorSources = collectWorkspaceBlockEditorSources(projectDir, blockSlug);
|
|
513
|
+
const editorWrapperSources = editorSources.filter((source) => !isWorkspaceBlockSaveSource(source.relativePath));
|
|
514
|
+
const globalDomAccesses = findWorkspaceBlockGlobalDomAccesses(editorSources);
|
|
515
|
+
const hasBlockPropsUsage = editorSources.some(({ source }) => hasExecutablePattern(source, WORKSPACE_BLOCK_PROPS_PATTERN));
|
|
516
|
+
const hasEditorBlockPropsUsage = editorWrapperSources.some(({ source }) => hasExecutablePattern(source, WORKSPACE_BLOCK_PROPS_PATTERN));
|
|
517
|
+
const blockWrapperStatus = editorWrapperSources.length === 0 || hasEditorBlockPropsUsage ? "pass" : "warn";
|
|
518
|
+
const blockWrapperDetail = editorSources.length === 0 ? "No editor-facing block source files found; general file checks will report missing entrypoints" : editorWrapperSources.length === 0 ? "No editor wrapper source files found; general file checks will report missing entrypoints" : hasEditorBlockPropsUsage ? "Editor-facing sources use block wrapper props" : hasBlockPropsUsage ? "Only save-facing useBlockProps.save() usage was detected. Confirm the editor wrapper also receives useBlockProps() or useInnerBlocksProps() before relying on iframe editor rendering." : "No useBlockProps(), useBlockProps.save(), or useInnerBlocksProps() usage was detected in editor-facing sources. Confirm the block wrapper receives WordPress block editor props before relying on iframe editor rendering.";
|
|
519
|
+
return [
|
|
520
|
+
createDoctorCheck2(`Block iframe API version ${blockSlug}`, apiVersion !== null && apiVersion >= 3 ? "pass" : "warn", apiVersion !== null && apiVersion >= 3 ? "block.json declares apiVersion 3 for iframe editor readiness" : `Set ${metadataResult.blockJsonRelativePath} apiVersion to 3 after testing the block in iframe-enabled Post Editor and Site Editor contexts. WordPress recommends API v3 for iframe editor compatibility. See ${WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION),
|
|
521
|
+
createDoctorCheck2(`Block iframe styles ${blockSlug}`, localStyleFiles.length === 0 || hasRegisteredEditorStyles ? "pass" : "warn", localStyleFiles.length === 0 ? "No local block stylesheet source files found to register" : hasRegisteredEditorStyles ? "block.json registers block styles for iframe editor loading" : `Found stylesheet source files (${localStyleFiles.join(", ")}) but block.json does not declare style or editorStyle. Register block content styles so iframe editors do not depend on parent admin styles.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_STYLES),
|
|
522
|
+
createDoctorCheck2(`Block iframe globals ${blockSlug}`, globalDomAccesses.length === 0 ? "pass" : "warn", globalDomAccesses.length === 0 ? "No direct window/document/parent DOM access detected in editor-facing block sources" : `Direct global DOM access detected at ${globalDomAccesses.join(", ")}. Prefer element.ownerDocument/defaultView via refs or useRefEffect for iframe editor content.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_GLOBALS),
|
|
523
|
+
createDoctorCheck2(`Block iframe wrapper ${blockSlug}`, blockWrapperStatus, blockWrapperDetail, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.BLOCK_PROPS)
|
|
524
|
+
];
|
|
525
|
+
}
|
|
263
526
|
function checkWorkspacePatternBootstrap(projectDir, packageName) {
|
|
264
527
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
265
528
|
const bootstrapPath = path2.join(projectDir, `${packageBaseName}.php`);
|
|
@@ -294,6 +557,71 @@ function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
|
|
|
294
557
|
const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
|
|
295
558
|
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(", ")}`);
|
|
296
559
|
}
|
|
560
|
+
function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
|
|
561
|
+
const hasBlock = bindingSource.block !== undefined;
|
|
562
|
+
const hasAttribute = bindingSource.attribute !== undefined;
|
|
563
|
+
if (!hasBlock && !hasAttribute) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
if (!bindingSource.block || !bindingSource.attribute) {
|
|
567
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
|
|
568
|
+
}
|
|
569
|
+
if (!registeredBlockSlugs.has(bindingSource.block)) {
|
|
570
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
|
|
571
|
+
}
|
|
572
|
+
const blockJsonRelativePath = path2.join("src", "blocks", bindingSource.block, "block.json");
|
|
573
|
+
const blockJsonPath = path2.join(projectDir, blockJsonRelativePath);
|
|
574
|
+
const issues = [];
|
|
575
|
+
try {
|
|
576
|
+
const blockJson = parseScaffoldBlockMetadata(JSON.parse(fs2.readFileSync(blockJsonPath, "utf8")));
|
|
577
|
+
const attributes = blockJson.attributes;
|
|
578
|
+
if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) {
|
|
579
|
+
issues.push(`${blockJsonRelativePath} must define an attributes object`);
|
|
580
|
+
} else {
|
|
581
|
+
const attributeConfig = attributes[bindingSource.attribute];
|
|
582
|
+
if (!attributeConfig || typeof attributeConfig !== "object" || Array.isArray(attributeConfig)) {
|
|
583
|
+
issues.push(`${blockJsonRelativePath} must declare attribute "${bindingSource.attribute}"`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
} catch (error) {
|
|
587
|
+
issues.push(error instanceof Error ? `Unable to read ${blockJsonRelativePath}: ${error.message}` : `Unable to read ${blockJsonRelativePath}.`);
|
|
588
|
+
}
|
|
589
|
+
const serverPath = path2.join(projectDir, bindingSource.serverFile);
|
|
590
|
+
if (fs2.existsSync(serverPath)) {
|
|
591
|
+
const serverSource = fs2.readFileSync(serverPath, "utf8");
|
|
592
|
+
const supportedAttributesFilter = `block_bindings_supported_attributes_${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
593
|
+
if (!serverSource.includes(supportedAttributesFilter)) {
|
|
594
|
+
issues.push(`${bindingSource.serverFile} must register ${supportedAttributesFilter}`);
|
|
595
|
+
}
|
|
596
|
+
if (!new RegExp(`'${escapeRegex(bindingSource.attribute)}'`, "u").test(serverSource)) {
|
|
597
|
+
issues.push(`${bindingSource.serverFile} must expose attribute "${bindingSource.attribute}"`);
|
|
598
|
+
}
|
|
599
|
+
} else {
|
|
600
|
+
issues.push(`Missing ${bindingSource.serverFile}`);
|
|
601
|
+
}
|
|
602
|
+
const editorPath = path2.join(projectDir, bindingSource.editorFile);
|
|
603
|
+
if (fs2.existsSync(editorPath)) {
|
|
604
|
+
const editorSource = fs2.readFileSync(editorPath, "utf8");
|
|
605
|
+
const blockName = `${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
606
|
+
const bindingSourceTargetMatch = editorSource.match(/export\s+const\s+BINDING_SOURCE_TARGET\s*=\s*\{([\s\S]*?)\}\s+as\s+const\s*;/u);
|
|
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}`);
|
|
622
|
+
}
|
|
623
|
+
return createDoctorCheck2(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
|
|
624
|
+
}
|
|
297
625
|
function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
298
626
|
const schemaNames = new Set;
|
|
299
627
|
if (restResource.methods.includes("list")) {
|
|
@@ -444,18 +772,19 @@ function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
444
772
|
}
|
|
445
773
|
function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
446
774
|
const editorPluginDir = path2.join("src", "editor-plugins", editorPlugin.slug);
|
|
775
|
+
const surfaceFile = editorPlugin.slot === "PluginSidebar" ? path2.join(editorPluginDir, "Sidebar.tsx") : path2.join(editorPluginDir, "Surface.tsx");
|
|
447
776
|
return Array.from(new Set([
|
|
448
777
|
editorPlugin.file,
|
|
449
|
-
|
|
778
|
+
surfaceFile,
|
|
450
779
|
path2.join(editorPluginDir, "data.ts"),
|
|
451
780
|
path2.join(editorPluginDir, "types.ts"),
|
|
452
781
|
path2.join(editorPluginDir, "style.scss")
|
|
453
782
|
]));
|
|
454
783
|
}
|
|
455
784
|
function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
456
|
-
const
|
|
457
|
-
const isValidSlot =
|
|
458
|
-
return createDoctorCheck2(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot ? `Editor plugin slot ${editorPlugin.slot} is supported` : `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")}
|
|
785
|
+
const normalizedSlot = resolveEditorPluginSlotAlias(editorPlugin.slot);
|
|
786
|
+
const isValidSlot = Boolean(normalizedSlot);
|
|
787
|
+
return createDoctorCheck2(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot ? `Editor plugin slot ${editorPlugin.slot} is supported as ${normalizedSlot}` : `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")} or legacy aliases PluginSidebar, PluginDocumentSettingPanel.`);
|
|
459
788
|
}
|
|
460
789
|
function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
|
|
461
790
|
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
@@ -488,16 +817,113 @@ function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
|
488
817
|
});
|
|
489
818
|
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(", ")}`);
|
|
490
819
|
}
|
|
820
|
+
function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
821
|
+
const adminViewDir = path2.join("src", "admin-views", adminView.slug);
|
|
822
|
+
return Array.from(new Set([
|
|
823
|
+
adminView.file,
|
|
824
|
+
adminView.phpFile,
|
|
825
|
+
path2.join(adminViewDir, "Screen.tsx"),
|
|
826
|
+
path2.join(adminViewDir, "config.ts"),
|
|
827
|
+
path2.join(adminViewDir, "data.ts"),
|
|
828
|
+
path2.join(adminViewDir, "style.scss"),
|
|
829
|
+
path2.join(adminViewDir, "types.ts")
|
|
830
|
+
]));
|
|
831
|
+
}
|
|
832
|
+
function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
833
|
+
if (adminView.source === undefined) {
|
|
834
|
+
return createDoctorCheck2(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
|
|
835
|
+
}
|
|
836
|
+
const source = adminView.source.trim();
|
|
837
|
+
const sourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
|
|
838
|
+
const restResourceSlug = sourceMatch?.[1];
|
|
839
|
+
const restResource = restResourceSlug ? inventory.restResources.find((entry) => entry.slug === restResourceSlug) : undefined;
|
|
840
|
+
const isValid = Boolean(restResource?.methods.includes("list"));
|
|
841
|
+
return createDoctorCheck2(`Admin view config ${adminView.slug}`, isValid ? "pass" : "fail", isValid ? `Admin view source ${source} is list-capable` : "Admin view source must use rest-resource:<slug> and reference a list-capable REST resource");
|
|
842
|
+
}
|
|
843
|
+
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
844
|
+
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
845
|
+
const bootstrapPath = path2.join(projectDir, `${packageBaseName}.php`);
|
|
846
|
+
if (!fs2.existsSync(bootstrapPath)) {
|
|
847
|
+
return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${path2.basename(bootstrapPath)}`);
|
|
848
|
+
}
|
|
849
|
+
const source = fs2.readFileSync(bootstrapPath, "utf8");
|
|
850
|
+
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
851
|
+
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
852
|
+
const hasLoaderHook = source.includes(loadHook);
|
|
853
|
+
const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
|
|
854
|
+
return createDoctorCheck2("Admin view bootstrap", hasLoaderHook && hasServerGlob ? "pass" : "fail", hasLoaderHook && hasServerGlob ? "Admin view PHP loader hook is present" : "Missing admin view PHP require glob or plugins_loaded hook");
|
|
855
|
+
}
|
|
856
|
+
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
857
|
+
const indexRelativePath = [
|
|
858
|
+
path2.join("src", "admin-views", "index.ts"),
|
|
859
|
+
path2.join("src", "admin-views", "index.js")
|
|
860
|
+
].find((relativePath) => fs2.existsSync(path2.join(projectDir, relativePath)));
|
|
861
|
+
if (!indexRelativePath) {
|
|
862
|
+
return createDoctorCheck2("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
863
|
+
}
|
|
864
|
+
const indexPath = path2.join(projectDir, indexRelativePath);
|
|
865
|
+
const source = fs2.readFileSync(indexPath, "utf8");
|
|
866
|
+
const missingImports = adminViews.filter((adminView) => {
|
|
867
|
+
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
868
|
+
return !importPattern.test(source);
|
|
869
|
+
});
|
|
870
|
+
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(", ")}`);
|
|
871
|
+
}
|
|
872
|
+
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
873
|
+
const phpPath = path2.join(projectDir, adminView.phpFile);
|
|
874
|
+
if (!fs2.existsSync(phpPath)) {
|
|
875
|
+
return createDoctorCheck2(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
876
|
+
}
|
|
877
|
+
const source = fs2.readFileSync(phpPath, "utf8");
|
|
878
|
+
const hasAdminMenu = source.includes("add_submenu_page");
|
|
879
|
+
const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
|
|
880
|
+
const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
|
|
881
|
+
const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
|
|
882
|
+
const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
|
|
883
|
+
const hasComponentsStyleDependency = source.includes("'wp-components'");
|
|
884
|
+
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");
|
|
885
|
+
}
|
|
491
886
|
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
492
887
|
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
493
888
|
if (!fs2.existsSync(entryPath)) {
|
|
494
889
|
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
495
890
|
}
|
|
496
891
|
const source = fs2.readFileSync(entryPath, "utf8");
|
|
497
|
-
const hasImport = source
|
|
498
|
-
const hasCall = source
|
|
892
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
|
|
893
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
|
|
499
894
|
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
500
895
|
}
|
|
896
|
+
function checkBlockStyleEntrypoint(projectDir, blockSlug) {
|
|
897
|
+
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
898
|
+
if (!fs2.existsSync(entryPath)) {
|
|
899
|
+
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
900
|
+
}
|
|
901
|
+
const source = fs2.readFileSync(entryPath, "utf8");
|
|
902
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
|
|
903
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
|
|
904
|
+
return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
|
|
905
|
+
}
|
|
906
|
+
function checkBlockTransformEntrypoint(projectDir, blockSlug) {
|
|
907
|
+
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
908
|
+
if (!fs2.existsSync(entryPath)) {
|
|
909
|
+
return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
910
|
+
}
|
|
911
|
+
const source = fs2.readFileSync(entryPath, "utf8");
|
|
912
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
|
|
913
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
|
|
914
|
+
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");
|
|
915
|
+
}
|
|
916
|
+
function checkBlockTransformConfig(workspace, transform) {
|
|
917
|
+
const expectedTo = `${workspace.workspace.namespace}/${transform.block}`;
|
|
918
|
+
const issues = [];
|
|
919
|
+
if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform.from)) {
|
|
920
|
+
issues.push("from must use full namespace/block format");
|
|
921
|
+
}
|
|
922
|
+
if (transform.to !== expectedTo) {
|
|
923
|
+
issues.push(`to must equal "${expectedTo}" for workspace block "${transform.block}"`);
|
|
924
|
+
}
|
|
925
|
+
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("; "));
|
|
926
|
+
}
|
|
501
927
|
function checkMigrationWorkspaceHint(workspace, packageJson) {
|
|
502
928
|
const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
|
|
503
929
|
const migrationConfigRelativePath = path2.join("src", "migrations", "config.ts");
|
|
@@ -539,12 +965,13 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
539
965
|
checks.push(checkWorkspacePackageMetadata(workspace, workspacePackageJson));
|
|
540
966
|
try {
|
|
541
967
|
const inventory = readWorkspaceInventory(workspace.projectDir);
|
|
542
|
-
checks.push(createDoctorCheck2("Workspace inventory", "pass", `${inventory.blocks.length} block(s), ${inventory.variations.length} variation(s), ${inventory.patterns.length} pattern(s), ${inventory.bindingSources.length} binding source(s), ${inventory.restResources.length} REST resource(s), ${inventory.abilities.length} ability scaffold(s), ${inventory.aiFeatures.length} AI feature(s), ${inventory.editorPlugins.length} editor plugin(s)`));
|
|
968
|
+
checks.push(createDoctorCheck2("Workspace inventory", "pass", `${inventory.blocks.length} block(s), ${inventory.variations.length} variation(s), ${inventory.blockStyles.length} block style(s), ${inventory.blockTransforms.length} block transform(s), ${inventory.patterns.length} pattern(s), ${inventory.bindingSources.length} binding source(s), ${inventory.restResources.length} REST resource(s), ${inventory.abilities.length} ability scaffold(s), ${inventory.aiFeatures.length} AI feature(s), ${inventory.editorPlugins.length} editor plugin(s), ${inventory.adminViews.length} admin view(s)`));
|
|
543
969
|
for (const block of inventory.blocks) {
|
|
544
970
|
checks.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)));
|
|
545
971
|
checks.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
|
|
546
972
|
checks.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
|
|
547
973
|
checks.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
|
|
974
|
+
checks.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
|
|
548
975
|
}
|
|
549
976
|
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
550
977
|
const variationTargetBlocks = new Set;
|
|
@@ -559,6 +986,37 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
559
986
|
for (const blockSlug of variationTargetBlocks) {
|
|
560
987
|
checks.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
|
|
561
988
|
}
|
|
989
|
+
const blockStyleTargetBlocks = new Set;
|
|
990
|
+
for (const blockStyle of inventory.blockStyles) {
|
|
991
|
+
if (!registeredBlockSlugs.has(blockStyle.block)) {
|
|
992
|
+
checks.push(createDoctorCheck2(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
blockStyleTargetBlocks.add(blockStyle.block);
|
|
996
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
|
|
997
|
+
}
|
|
998
|
+
for (const blockSlug of blockStyleTargetBlocks) {
|
|
999
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
|
|
1000
|
+
path2.join("src", "blocks", blockSlug, "styles", "index.ts")
|
|
1001
|
+
]));
|
|
1002
|
+
checks.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
|
|
1003
|
+
}
|
|
1004
|
+
const blockTransformTargetBlocks = new Set;
|
|
1005
|
+
for (const blockTransform of inventory.blockTransforms) {
|
|
1006
|
+
if (!registeredBlockSlugs.has(blockTransform.block)) {
|
|
1007
|
+
checks.push(createDoctorCheck2(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
blockTransformTargetBlocks.add(blockTransform.block);
|
|
1011
|
+
checks.push(checkBlockTransformConfig(workspace, blockTransform));
|
|
1012
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
|
|
1013
|
+
}
|
|
1014
|
+
for (const blockSlug of blockTransformTargetBlocks) {
|
|
1015
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
|
|
1016
|
+
path2.join("src", "blocks", blockSlug, "transforms", "index.ts")
|
|
1017
|
+
]));
|
|
1018
|
+
checks.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
|
|
1019
|
+
}
|
|
562
1020
|
const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs2.existsSync(path2.join(workspace.projectDir, "src", "patterns"));
|
|
563
1021
|
if (shouldCheckPatternBootstrap) {
|
|
564
1022
|
checks.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
|
|
@@ -575,6 +1033,10 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
575
1033
|
bindingSource.serverFile,
|
|
576
1034
|
bindingSource.editorFile
|
|
577
1035
|
]));
|
|
1036
|
+
const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
|
|
1037
|
+
if (bindingTargetCheck) {
|
|
1038
|
+
checks.push(bindingTargetCheck);
|
|
1039
|
+
}
|
|
578
1040
|
}
|
|
579
1041
|
if (inventory.restResources.length > 0) {
|
|
580
1042
|
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
@@ -606,6 +1068,15 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
606
1068
|
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
607
1069
|
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
608
1070
|
}
|
|
1071
|
+
if (inventory.adminViews.length > 0) {
|
|
1072
|
+
checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1073
|
+
checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
|
|
1074
|
+
}
|
|
1075
|
+
for (const adminView of inventory.adminViews) {
|
|
1076
|
+
checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
|
|
1077
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
|
|
1078
|
+
checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
|
|
1079
|
+
}
|
|
609
1080
|
const migrationWorkspaceCheck = checkMigrationWorkspaceHint(workspace, workspacePackageJson);
|
|
610
1081
|
if (migrationWorkspaceCheck) {
|
|
611
1082
|
checks.push(migrationWorkspaceCheck);
|
|
@@ -636,6 +1107,7 @@ async function runDoctor(cwd, options = {}) {
|
|
|
636
1107
|
const failureDetailLines = getDoctorFailureDetailLines(checks);
|
|
637
1108
|
if (failureDetailLines.length > 0) {
|
|
638
1109
|
throw createCliCommandError({
|
|
1110
|
+
code: CLI_DIAGNOSTIC_CODES.DOCTOR_CHECK_FAILED,
|
|
639
1111
|
command: "doctor",
|
|
640
1112
|
detailLines: failureDetailLines,
|
|
641
1113
|
summary: "One or more doctor checks failed."
|
|
@@ -648,4 +1120,4 @@ export {
|
|
|
648
1120
|
getDoctorChecks
|
|
649
1121
|
};
|
|
650
1122
|
|
|
651
|
-
//# debugId=
|
|
1123
|
+
//# debugId=7C95CE3500DB32DC64756E2164756E21
|