wp-typia 0.20.5 → 0.22.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 +3 -1
- package/bin/routing-metadata.generated.js +57 -37
- package/bin/runtime-routing.d.ts +34 -0
- package/bin/runtime-routing.js +124 -0
- package/bin/wp-typia.js +97 -90
- package/dist-bunli/.bunli/commands.gen.js +5705 -1385
- package/dist-bunli/{cli-j1tyw390.js → cli-1w5vkye4.js} +989 -266
- package/dist-bunli/{cli-tesygdnr.js → cli-39er8888.js} +29 -2
- package/dist-bunli/{cli-add-6byyahb8.js → cli-add-kjhghdqq.js} +2488 -479
- package/dist-bunli/{cli-diagnostics-zecc6w1f.js → cli-diagnostics-5dvztm7q.js} +8 -2
- package/dist-bunli/{cli-doctor-2bc4sq7v.js → cli-doctor-p3jxvn0k.js} +493 -20
- package/dist-bunli/{cli-2rev5hqm.js → cli-e623rs7g.js} +1 -1
- package/dist-bunli/cli-init-djhwr245.js +844 -0
- package/dist-bunli/{cli-3w3qxq9w.js → cli-j180bk07.js} +260 -25
- package/dist-bunli/{cli-xnh2s5kz.js → cli-ktp869eh.js} +350 -41
- package/dist-bunli/{cli-xxzpb58s.js → cli-p95wr1q8.js} +72 -4
- package/dist-bunli/{cli-scaffold-19gyvxxt.js → cli-scaffold-376yw891.js} +6 -5
- package/dist-bunli/cli.js +31 -117
- package/dist-bunli/{command-list-pztcgga5.js → command-list-jt1a1w7r.js} +587 -320
- package/dist-bunli/{migrations-1p6mbkyw.js → migrations-nwas5bwt.js} +2 -2
- package/dist-bunli/node-cli.js +1063 -556
- 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-xxzpb58s.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-j180bk07.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,114 @@ 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 restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
|
|
838
|
+
const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
|
|
839
|
+
const restResourceSlug = restSourceMatch?.[1];
|
|
840
|
+
const restResource = restResourceSlug ? inventory.restResources.find((entry) => entry.slug === restResourceSlug) : undefined;
|
|
841
|
+
const isValid = Boolean(restResource?.methods.includes("list")) || Boolean(coreDataSourceMatch);
|
|
842
|
+
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> with a list-capable REST resource or core-data:<postType|taxonomy>/<name>");
|
|
843
|
+
}
|
|
844
|
+
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
845
|
+
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
846
|
+
const bootstrapPath = path2.join(projectDir, `${packageBaseName}.php`);
|
|
847
|
+
if (!fs2.existsSync(bootstrapPath)) {
|
|
848
|
+
return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${path2.basename(bootstrapPath)}`);
|
|
849
|
+
}
|
|
850
|
+
const source = fs2.readFileSync(bootstrapPath, "utf8");
|
|
851
|
+
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
852
|
+
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
853
|
+
const hasLoaderHook = source.includes(loadHook);
|
|
854
|
+
const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
|
|
855
|
+
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");
|
|
856
|
+
}
|
|
857
|
+
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
858
|
+
const indexRelativePath = [
|
|
859
|
+
path2.join("src", "admin-views", "index.ts"),
|
|
860
|
+
path2.join("src", "admin-views", "index.js")
|
|
861
|
+
].find((relativePath) => fs2.existsSync(path2.join(projectDir, relativePath)));
|
|
862
|
+
if (!indexRelativePath) {
|
|
863
|
+
return createDoctorCheck2("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
864
|
+
}
|
|
865
|
+
const indexPath = path2.join(projectDir, indexRelativePath);
|
|
866
|
+
const source = fs2.readFileSync(indexPath, "utf8");
|
|
867
|
+
const missingImports = adminViews.filter((adminView) => {
|
|
868
|
+
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
869
|
+
return !importPattern.test(source);
|
|
870
|
+
});
|
|
871
|
+
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
|
+
}
|
|
873
|
+
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
874
|
+
const phpPath = path2.join(projectDir, adminView.phpFile);
|
|
875
|
+
if (!fs2.existsSync(phpPath)) {
|
|
876
|
+
return createDoctorCheck2(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
877
|
+
}
|
|
878
|
+
const source = fs2.readFileSync(phpPath, "utf8");
|
|
879
|
+
const hasAdminMenu = source.includes("add_submenu_page");
|
|
880
|
+
const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
|
|
881
|
+
const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
|
|
882
|
+
const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
|
|
883
|
+
const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
|
|
884
|
+
const hasComponentsStyleDependency = source.includes("'wp-components'");
|
|
885
|
+
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
|
+
}
|
|
491
887
|
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
492
888
|
const entryPath = path2.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
493
889
|
if (!fs2.existsSync(entryPath)) {
|
|
494
890
|
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path2.relative(projectDir, entryPath)}`);
|
|
495
891
|
}
|
|
496
892
|
const source = fs2.readFileSync(entryPath, "utf8");
|
|
497
|
-
const hasImport = source
|
|
498
|
-
const hasCall = source
|
|
893
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
|
|
894
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
|
|
499
895
|
return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
500
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)}`);
|
|
901
|
+
}
|
|
902
|
+
const source = fs2.readFileSync(entryPath, "utf8");
|
|
903
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
|
|
904
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
|
|
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)}`);
|
|
911
|
+
}
|
|
912
|
+
const source = fs2.readFileSync(entryPath, "utf8");
|
|
913
|
+
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
|
|
914
|
+
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
|
|
915
|
+
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");
|
|
916
|
+
}
|
|
917
|
+
function checkBlockTransformConfig(workspace, transform) {
|
|
918
|
+
const expectedTo = `${workspace.workspace.namespace}/${transform.block}`;
|
|
919
|
+
const issues = [];
|
|
920
|
+
if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform.from)) {
|
|
921
|
+
issues.push("from must use full namespace/block format");
|
|
922
|
+
}
|
|
923
|
+
if (transform.to !== expectedTo) {
|
|
924
|
+
issues.push(`to must equal "${expectedTo}" for workspace block "${transform.block}"`);
|
|
925
|
+
}
|
|
926
|
+
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("; "));
|
|
927
|
+
}
|
|
501
928
|
function checkMigrationWorkspaceHint(workspace, packageJson) {
|
|
502
929
|
const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
|
|
503
930
|
const migrationConfigRelativePath = path2.join("src", "migrations", "config.ts");
|
|
@@ -539,12 +966,13 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
539
966
|
checks.push(checkWorkspacePackageMetadata(workspace, workspacePackageJson));
|
|
540
967
|
try {
|
|
541
968
|
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)`));
|
|
969
|
+
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
970
|
for (const block of inventory.blocks) {
|
|
544
971
|
checks.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)));
|
|
545
972
|
checks.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
|
|
546
973
|
checks.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
|
|
547
974
|
checks.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
|
|
975
|
+
checks.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
|
|
548
976
|
}
|
|
549
977
|
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
550
978
|
const variationTargetBlocks = new Set;
|
|
@@ -559,6 +987,37 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
559
987
|
for (const blockSlug of variationTargetBlocks) {
|
|
560
988
|
checks.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
|
|
561
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
|
+
}
|
|
562
1021
|
const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs2.existsSync(path2.join(workspace.projectDir, "src", "patterns"));
|
|
563
1022
|
if (shouldCheckPatternBootstrap) {
|
|
564
1023
|
checks.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
|
|
@@ -575,6 +1034,10 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
575
1034
|
bindingSource.serverFile,
|
|
576
1035
|
bindingSource.editorFile
|
|
577
1036
|
]));
|
|
1037
|
+
const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
|
|
1038
|
+
if (bindingTargetCheck) {
|
|
1039
|
+
checks.push(bindingTargetCheck);
|
|
1040
|
+
}
|
|
578
1041
|
}
|
|
579
1042
|
if (inventory.restResources.length > 0) {
|
|
580
1043
|
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
@@ -606,6 +1069,15 @@ function getWorkspaceDoctorChecks(cwd) {
|
|
|
606
1069
|
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
607
1070
|
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
608
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
|
+
}
|
|
609
1081
|
const migrationWorkspaceCheck = checkMigrationWorkspaceHint(workspace, workspacePackageJson);
|
|
610
1082
|
if (migrationWorkspaceCheck) {
|
|
611
1083
|
checks.push(migrationWorkspaceCheck);
|
|
@@ -636,6 +1108,7 @@ async function runDoctor(cwd, options = {}) {
|
|
|
636
1108
|
const failureDetailLines = getDoctorFailureDetailLines(checks);
|
|
637
1109
|
if (failureDetailLines.length > 0) {
|
|
638
1110
|
throw createCliCommandError({
|
|
1111
|
+
code: CLI_DIAGNOSTIC_CODES.DOCTOR_CHECK_FAILED,
|
|
639
1112
|
command: "doctor",
|
|
640
1113
|
detailLines: failureDetailLines,
|
|
641
1114
|
summary: "One or more doctor checks failed."
|
|
@@ -648,4 +1121,4 @@ export {
|
|
|
648
1121
|
getDoctorChecks
|
|
649
1122
|
};
|
|
650
1123
|
|
|
651
|
-
//# debugId=
|
|
1124
|
+
//# debugId=0A56FB55109F0ECC64756E2164756E21
|