wp-typia 0.24.4 → 0.24.6
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 +8 -6
- package/bin/wp-typia.js +24 -103
- package/{dist-bunli/node-cli.js → dist/cli.js} +5086 -3693
- package/package.json +9 -36
- package/bin/routing-metadata.generated.d.ts +0 -8
- package/bin/routing-metadata.generated.js +0 -93
- package/bin/runtime-routing.d.ts +0 -34
- package/bin/runtime-routing.js +0 -124
- package/dist-bunli/.bunli/commands.gen.js +0 -304441
- package/dist-bunli/.bunli/highlights-eq9cgrbb.scm +0 -604
- package/dist-bunli/.bunli/highlights-ghv9g403.scm +0 -205
- package/dist-bunli/.bunli/highlights-hk7bwhj4.scm +0 -284
- package/dist-bunli/.bunli/highlights-r812a2qc.scm +0 -150
- package/dist-bunli/.bunli/highlights-x6tmsnaa.scm +0 -115
- package/dist-bunli/.bunli/injections-73j83es3.scm +0 -27
- package/dist-bunli/.bunli/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/dist-bunli/.bunli/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/dist-bunli/.bunli/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/dist-bunli/.bunli/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/dist-bunli/.bunli/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/dist-bunli/agents-91fpdyyt.js +0 -12
- package/dist-bunli/chunk-bdqvmfwv-f5qmzmxg.js +0 -16825
- package/dist-bunli/cli-03j0axbt.js +0 -163
- package/dist-bunli/cli-1170yyve.js +0 -106
- package/dist-bunli/cli-368d4cgy.js +0 -1235
- package/dist-bunli/cli-377p86mf.js +0 -191
- package/dist-bunli/cli-6v0pcxw6.js +0 -314
- package/dist-bunli/cli-84c7wff4.js +0 -198
- package/dist-bunli/cli-8hxf9qw6.js +0 -198
- package/dist-bunli/cli-9fx0qgb7.js +0 -3680
- package/dist-bunli/cli-ac2ebaf8.js +0 -3
- package/dist-bunli/cli-add-qjd3ba8j.js +0 -10671
- package/dist-bunli/cli-am5x7tb4.js +0 -192
- package/dist-bunli/cli-bajwv85z.js +0 -24
- package/dist-bunli/cli-ccax7s0s.js +0 -34
- package/dist-bunli/cli-cvxvcw7c.js +0 -46
- package/dist-bunli/cli-diagnostics-10drxh34.js +0 -34
- package/dist-bunli/cli-doctor-6fyxq940.js +0 -1446
- package/dist-bunli/cli-e4bwd81c.js +0 -1260
- package/dist-bunli/cli-fv4h3ydt.js +0 -173823
- package/dist-bunli/cli-hv2yedw2.js +0 -74591
- package/dist-bunli/cli-init-7avk42dh.js +0 -880
- package/dist-bunli/cli-kfm9mm68.js +0 -14679
- package/dist-bunli/cli-prompt-ncyg68rn.js +0 -12
- package/dist-bunli/cli-rdcga1bd.js +0 -135
- package/dist-bunli/cli-scaffold-0bb6pr3w.js +0 -538
- package/dist-bunli/cli-t73q5aqz.js +0 -103
- package/dist-bunli/cli-templates-g8t4fm11.js +0 -167
- package/dist-bunli/cli-tj7ajdvf.js +0 -2612
- package/dist-bunli/cli-tq730sqt.js +0 -344
- package/dist-bunli/cli-xnn9xjcy.js +0 -68
- package/dist-bunli/cli-z48frc8t.js +0 -229
- package/dist-bunli/cli.js +0 -2523
- package/dist-bunli/command-list-y3g7e9rb.js +0 -4013
- package/dist-bunli/create-template-validation-4fr851vg.js +0 -16
- package/dist-bunli/migrations-3vngdy51.js +0 -47
- package/dist-bunli/sync-k2k8svyc.js +0 -13
- package/dist-bunli/workspace-project-gmv2a71z.js +0 -22
|
@@ -1,1446 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import {
|
|
3
|
-
assertPostMetaBindingPath,
|
|
4
|
-
hasAdminViewManualSettingsRouteParameters,
|
|
5
|
-
hasExecutablePattern,
|
|
6
|
-
hasUncommentedPattern,
|
|
7
|
-
isAdminViewManualSettingsRestResource,
|
|
8
|
-
loadPostMetaBindingFieldsSync,
|
|
9
|
-
maskTypeScriptCommentsAndLiterals
|
|
10
|
-
} from "./cli-z48frc8t.js";
|
|
11
|
-
import {
|
|
12
|
-
getBuiltInTemplateLayerDirs,
|
|
13
|
-
isOmittableBuiltInTemplateLayerDir
|
|
14
|
-
} from "./cli-377p86mf.js";
|
|
15
|
-
import {
|
|
16
|
-
isBuiltInTemplateId,
|
|
17
|
-
listTemplates
|
|
18
|
-
} from "./cli-8hxf9qw6.js";
|
|
19
|
-
import {
|
|
20
|
-
EDITOR_PLUGIN_SLOT_IDS,
|
|
21
|
-
HOOKED_BLOCK_ANCHOR_PATTERN,
|
|
22
|
-
HOOKED_BLOCK_POSITION_SET,
|
|
23
|
-
MANUAL_REST_CONTRACT_AUTH_IDS,
|
|
24
|
-
MANUAL_REST_CONTRACT_HTTP_METHOD_IDS,
|
|
25
|
-
REST_RESOURCE_METHOD_IDS,
|
|
26
|
-
REST_RESOURCE_NAMESPACE_PATTERN,
|
|
27
|
-
assertValidPostMetaPostType,
|
|
28
|
-
escapeRegex,
|
|
29
|
-
formatPatternCatalogDiagnostics,
|
|
30
|
-
isGeneratedRestResourceRoutePatternCompatible,
|
|
31
|
-
pathExists,
|
|
32
|
-
readWorkspaceInventoryAsync,
|
|
33
|
-
resolveEditorPluginSlotAlias,
|
|
34
|
-
resolvePatternCatalogContentFile,
|
|
35
|
-
validatePatternCatalog
|
|
36
|
-
} from "./cli-fv4h3ydt.js";
|
|
37
|
-
import"./cli-cvxvcw7c.js";
|
|
38
|
-
import"./cli-t73q5aqz.js";
|
|
39
|
-
import"./cli-bajwv85z.js";
|
|
40
|
-
import {
|
|
41
|
-
CLI_DIAGNOSTIC_CODES,
|
|
42
|
-
createCliCommandError,
|
|
43
|
-
formatDoctorCheckLine,
|
|
44
|
-
formatDoctorSummaryLine
|
|
45
|
-
} from "./cli-tq730sqt.js";
|
|
46
|
-
import {
|
|
47
|
-
WORKSPACE_TEMPLATE_PACKAGE,
|
|
48
|
-
getInvalidWorkspaceProjectReason,
|
|
49
|
-
parseWorkspacePackageJson,
|
|
50
|
-
tryResolveWorkspaceProject
|
|
51
|
-
} from "./cli-1170yyve.js";
|
|
52
|
-
import"./cli-am5x7tb4.js";
|
|
53
|
-
import {
|
|
54
|
-
readJsonFileSync
|
|
55
|
-
} from "./cli-ccax7s0s.js";
|
|
56
|
-
import"./cli-xnn9xjcy.js";
|
|
57
|
-
|
|
58
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-environment.ts
|
|
59
|
-
import { execFileSync } from "child_process";
|
|
60
|
-
import { access, constants as fsConstants, rm, writeFile } from "fs/promises";
|
|
61
|
-
import fs2 from "fs";
|
|
62
|
-
import os from "os";
|
|
63
|
-
import path2 from "path";
|
|
64
|
-
|
|
65
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-shared.ts
|
|
66
|
-
import fs from "fs";
|
|
67
|
-
import path from "path";
|
|
68
|
-
var WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
69
|
-
var WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
70
|
-
var WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
71
|
-
var WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php";
|
|
72
|
-
var WORKSPACE_POST_META_GLOB = "/inc/post-meta/*.php";
|
|
73
|
-
var WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
|
|
74
|
-
var WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
|
|
75
|
-
var WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
|
|
76
|
-
var WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php";
|
|
77
|
-
var WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php";
|
|
78
|
-
var WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js";
|
|
79
|
-
var WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php";
|
|
80
|
-
var WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css";
|
|
81
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js";
|
|
82
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php";
|
|
83
|
-
var WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css";
|
|
84
|
-
var WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
85
|
-
"block.json",
|
|
86
|
-
"typia.manifest.json",
|
|
87
|
-
"typia.schema.json",
|
|
88
|
-
"typia-validator.php",
|
|
89
|
-
"typia.openapi.json"
|
|
90
|
-
];
|
|
91
|
-
var WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
92
|
-
function createDoctorCheck(label, status, detail, code) {
|
|
93
|
-
return code ? { code, detail, label, status } : { detail, label, status };
|
|
94
|
-
}
|
|
95
|
-
function createDoctorScopeCheck(status, detail) {
|
|
96
|
-
return createDoctorCheck("Doctor scope", status, detail);
|
|
97
|
-
}
|
|
98
|
-
function getWorkspaceBootstrapRelativePath(packageName) {
|
|
99
|
-
return `${packageName.split("/").pop() ?? packageName}.php`;
|
|
100
|
-
}
|
|
101
|
-
function resolveWorkspaceBootstrapPath(projectDir, packageName) {
|
|
102
|
-
return path.join(projectDir, getWorkspaceBootstrapRelativePath(packageName));
|
|
103
|
-
}
|
|
104
|
-
function checkExistingFiles(projectDir, label, filePaths) {
|
|
105
|
-
const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs.existsSync(path.join(projectDir, filePath)));
|
|
106
|
-
return createDoctorCheck(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-environment.ts
|
|
110
|
-
function readCommandVersion(command, args = ["--version"]) {
|
|
111
|
-
try {
|
|
112
|
-
return execFileSync(command, args, {
|
|
113
|
-
encoding: "utf8",
|
|
114
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
115
|
-
}).trim();
|
|
116
|
-
} catch {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function compareMajorVersion(actualVersion, minimumMajor) {
|
|
121
|
-
const parsed = Number.parseInt(actualVersion.replace(/^v/, "").split(".")[0] ?? "", 10);
|
|
122
|
-
return Number.isFinite(parsed) && parsed >= minimumMajor;
|
|
123
|
-
}
|
|
124
|
-
async function checkWritableDirectory(directory) {
|
|
125
|
-
try {
|
|
126
|
-
await access(directory, fsConstants.W_OK);
|
|
127
|
-
return true;
|
|
128
|
-
} catch {
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async function checkTempDirectory() {
|
|
133
|
-
const tempFile = path2.join(os.tmpdir(), `wp-typia-${Date.now()}.tmp`);
|
|
134
|
-
try {
|
|
135
|
-
await writeFile(tempFile, "ok", "utf8");
|
|
136
|
-
await rm(tempFile, { force: true });
|
|
137
|
-
return true;
|
|
138
|
-
} catch {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
function getTemplateDoctorChecks() {
|
|
143
|
-
const checks = [];
|
|
144
|
-
for (const template of listTemplates()) {
|
|
145
|
-
if (!isBuiltInTemplateId(template.id)) {
|
|
146
|
-
const templateDirExists = fs2.existsSync(template.templateDir);
|
|
147
|
-
const hasAssets2 = templateDirExists && fs2.existsSync(path2.join(template.templateDir, "package.json.mustache"));
|
|
148
|
-
checks.push({
|
|
149
|
-
status: !templateDirExists || hasAssets2 ? "pass" : "fail",
|
|
150
|
-
label: `Template ${template.id}`,
|
|
151
|
-
detail: !templateDirExists ? "External template metadata only; local overlay package is not installed." : hasAssets2 ? template.templateDir : "Missing core template assets"
|
|
152
|
-
});
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
const builtInTemplateId = template.id;
|
|
156
|
-
const layerDirs = builtInTemplateId === "persistence" ? Array.from(new Set([
|
|
157
|
-
...getBuiltInTemplateLayerDirs(builtInTemplateId, { persistencePolicy: "authenticated" }),
|
|
158
|
-
...getBuiltInTemplateLayerDirs(builtInTemplateId, { persistencePolicy: "public" })
|
|
159
|
-
])) : builtInTemplateId === "compound" ? Array.from(new Set([
|
|
160
|
-
...getBuiltInTemplateLayerDirs(builtInTemplateId),
|
|
161
|
-
...getBuiltInTemplateLayerDirs(builtInTemplateId, {
|
|
162
|
-
persistenceEnabled: true,
|
|
163
|
-
persistencePolicy: "authenticated"
|
|
164
|
-
}),
|
|
165
|
-
...getBuiltInTemplateLayerDirs(builtInTemplateId, {
|
|
166
|
-
persistenceEnabled: true,
|
|
167
|
-
persistencePolicy: "public"
|
|
168
|
-
})
|
|
169
|
-
])) : getBuiltInTemplateLayerDirs(builtInTemplateId);
|
|
170
|
-
const missingRequiredLayer = layerDirs.some((layerDir) => !fs2.existsSync(layerDir) && !isOmittableBuiltInTemplateLayerDir(builtInTemplateId, layerDir));
|
|
171
|
-
const existingLayerDirs = layerDirs.filter((layerDir) => fs2.existsSync(layerDir));
|
|
172
|
-
const hasAssets = !missingRequiredLayer && existingLayerDirs.some((layerDir) => fs2.existsSync(path2.join(layerDir, "package.json.mustache"))) && existingLayerDirs.some((layerDir) => fs2.existsSync(path2.join(layerDir, "src")));
|
|
173
|
-
checks.push({
|
|
174
|
-
status: hasAssets ? "pass" : "fail",
|
|
175
|
-
label: `Template ${template.id}`,
|
|
176
|
-
detail: hasAssets ? existingLayerDirs.join(" + ") : "Missing core template assets"
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
return checks;
|
|
180
|
-
}
|
|
181
|
-
async function getEnvironmentDoctorChecks(cwd) {
|
|
182
|
-
const bunVersion = readCommandVersion("bun");
|
|
183
|
-
const nodeVersion = readCommandVersion("node");
|
|
184
|
-
const gitVersion = readCommandVersion("git");
|
|
185
|
-
const cwdWritable = await checkWritableDirectory(cwd);
|
|
186
|
-
const tempWritable = await checkTempDirectory();
|
|
187
|
-
return [
|
|
188
|
-
createDoctorCheck("Bun", bunVersion && compareMajorVersion(bunVersion, 1) ? "pass" : "fail", bunVersion ? `Detected ${bunVersion}` : "Not available"),
|
|
189
|
-
createDoctorCheck("Node", nodeVersion && compareMajorVersion(nodeVersion, 20) ? "pass" : "fail", nodeVersion ? `Detected ${nodeVersion}` : "Not available"),
|
|
190
|
-
createDoctorCheck("git", gitVersion ? "pass" : "fail", gitVersion ?? "Not available"),
|
|
191
|
-
createDoctorCheck("Current directory", cwdWritable ? "pass" : "fail", cwdWritable ? "Writable" : "Not writable"),
|
|
192
|
-
createDoctorCheck("Temp directory", tempWritable ? "pass" : "fail", tempWritable ? "Writable" : "Not writable"),
|
|
193
|
-
...getTemplateDoctorChecks()
|
|
194
|
-
];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-bindings.ts
|
|
198
|
-
import fs3 from "fs";
|
|
199
|
-
import path3 from "path";
|
|
200
|
-
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
201
|
-
function checkWorkspaceBindingBootstrap(projectDir, packageName) {
|
|
202
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
203
|
-
if (!fs3.existsSync(bootstrapPath)) {
|
|
204
|
-
return createDoctorCheck("Binding bootstrap", "fail", `Missing ${path3.basename(bootstrapPath)}`);
|
|
205
|
-
}
|
|
206
|
-
const source = fs3.readFileSync(bootstrapPath, "utf8");
|
|
207
|
-
const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
|
|
208
|
-
const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
|
|
209
|
-
const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
|
|
210
|
-
const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
|
|
211
|
-
return createDoctorCheck("Binding bootstrap", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "pass" : "fail", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "Binding source PHP and editor bootstrap hooks are present" : "Missing binding source PHP require glob or editor enqueue hook");
|
|
212
|
-
}
|
|
213
|
-
function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
|
|
214
|
-
const indexRelativePath = [path3.join("src", "bindings", "index.ts"), path3.join("src", "bindings", "index.js")].find((relativePath) => fs3.existsSync(path3.join(projectDir, relativePath)));
|
|
215
|
-
if (!indexRelativePath) {
|
|
216
|
-
return createDoctorCheck("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
|
|
217
|
-
}
|
|
218
|
-
const indexPath = path3.join(projectDir, indexRelativePath);
|
|
219
|
-
const source = fs3.readFileSync(indexPath, "utf8");
|
|
220
|
-
const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
|
|
221
|
-
return createDoctorCheck("Binding sources index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Binding source editor registrations are aggregated" : `Missing editor imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
222
|
-
}
|
|
223
|
-
function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
|
|
224
|
-
const hasBlock = bindingSource.block !== undefined;
|
|
225
|
-
const hasAttribute = bindingSource.attribute !== undefined;
|
|
226
|
-
if (!hasBlock && !hasAttribute) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
if (!bindingSource.block || !bindingSource.attribute) {
|
|
230
|
-
return createDoctorCheck(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
|
|
231
|
-
}
|
|
232
|
-
if (!registeredBlockSlugs.has(bindingSource.block)) {
|
|
233
|
-
return createDoctorCheck(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
|
|
234
|
-
}
|
|
235
|
-
const blockJsonRelativePath = path3.join("src", "blocks", bindingSource.block, "block.json");
|
|
236
|
-
const blockJsonPath = path3.join(projectDir, blockJsonRelativePath);
|
|
237
|
-
const issues = [];
|
|
238
|
-
try {
|
|
239
|
-
const blockJson = parseScaffoldBlockMetadata(readJsonFileSync(blockJsonPath, {
|
|
240
|
-
context: "workspace block metadata"
|
|
241
|
-
}));
|
|
242
|
-
const attributes = blockJson.attributes;
|
|
243
|
-
if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) {
|
|
244
|
-
issues.push(`${blockJsonRelativePath} must define an attributes object`);
|
|
245
|
-
} else {
|
|
246
|
-
const attributeConfig = attributes[bindingSource.attribute];
|
|
247
|
-
if (!attributeConfig || typeof attributeConfig !== "object" || Array.isArray(attributeConfig)) {
|
|
248
|
-
issues.push(`${blockJsonRelativePath} must declare attribute "${bindingSource.attribute}"`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} catch (error) {
|
|
252
|
-
issues.push(error instanceof Error ? `Unable to read ${blockJsonRelativePath}: ${error.message}` : `Unable to read ${blockJsonRelativePath}.`);
|
|
253
|
-
}
|
|
254
|
-
const serverPath = path3.join(projectDir, bindingSource.serverFile);
|
|
255
|
-
if (fs3.existsSync(serverPath)) {
|
|
256
|
-
const serverSource = fs3.readFileSync(serverPath, "utf8");
|
|
257
|
-
const supportedAttributesFilter = `block_bindings_supported_attributes_${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
258
|
-
if (!serverSource.includes(supportedAttributesFilter)) {
|
|
259
|
-
issues.push(`${bindingSource.serverFile} must register ${supportedAttributesFilter}`);
|
|
260
|
-
}
|
|
261
|
-
if (!new RegExp(`(['"])${escapeRegex(bindingSource.attribute)}\\1`, "u").test(serverSource)) {
|
|
262
|
-
issues.push(`${bindingSource.serverFile} must expose attribute "${bindingSource.attribute}"`);
|
|
263
|
-
}
|
|
264
|
-
} else {
|
|
265
|
-
issues.push(`Missing ${bindingSource.serverFile}`);
|
|
266
|
-
}
|
|
267
|
-
const editorPath = path3.join(projectDir, bindingSource.editorFile);
|
|
268
|
-
if (fs3.existsSync(editorPath)) {
|
|
269
|
-
const editorSource = fs3.readFileSync(editorPath, "utf8");
|
|
270
|
-
const blockName = `${workspace.workspace.namespace}/${bindingSource.block}`;
|
|
271
|
-
const bindingSourceTargetMatch = editorSource.match(/export\s+const\s+BINDING_SOURCE_TARGET\s*=\s*\{([\s\S]*?)\}\s+as\s+const\s*;/u);
|
|
272
|
-
if (!bindingSourceTargetMatch) {
|
|
273
|
-
issues.push(`${bindingSource.editorFile} must export BINDING_SOURCE_TARGET`);
|
|
274
|
-
} else {
|
|
275
|
-
const targetSource = bindingSourceTargetMatch[1] ?? "";
|
|
276
|
-
const attributePattern = new RegExp(`\\battribute\\s*:\\s*["']${escapeRegex(bindingSource.attribute)}["']`, "u");
|
|
277
|
-
const blockPattern = new RegExp(`\\bblock\\s*:\\s*["']${escapeRegex(blockName)}["']`, "u");
|
|
278
|
-
if (!attributePattern.test(targetSource)) {
|
|
279
|
-
issues.push(`${bindingSource.editorFile} must document target attribute "${bindingSource.attribute}"`);
|
|
280
|
-
}
|
|
281
|
-
if (!blockPattern.test(targetSource)) {
|
|
282
|
-
issues.push(`${bindingSource.editorFile} must document target block "${blockName}"`);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
} else {
|
|
286
|
-
issues.push(`Missing ${bindingSource.editorFile}`);
|
|
287
|
-
}
|
|
288
|
-
return createDoctorCheck(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
|
|
289
|
-
}
|
|
290
|
-
function checkWorkspaceBindingPostMeta(projectDir, inventory, bindingSource) {
|
|
291
|
-
if (!bindingSource.postMeta) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
const postMeta = inventory.postMeta.find((entry) => entry.slug === bindingSource.postMeta);
|
|
295
|
-
if (!postMeta) {
|
|
296
|
-
return createDoctorCheck(`Binding post meta ${bindingSource.slug}`, "fail", `Binding source references unknown post meta contract "${bindingSource.postMeta}".`);
|
|
297
|
-
}
|
|
298
|
-
const issues = [];
|
|
299
|
-
try {
|
|
300
|
-
const fields = loadPostMetaBindingFieldsSync(projectDir, postMeta);
|
|
301
|
-
if (bindingSource.metaPath) {
|
|
302
|
-
assertPostMetaBindingPath(fields, postMeta.slug, bindingSource.metaPath);
|
|
303
|
-
}
|
|
304
|
-
} catch (error) {
|
|
305
|
-
issues.push(error instanceof Error ? error.message : String(error));
|
|
306
|
-
}
|
|
307
|
-
const serverPath = path3.join(projectDir, bindingSource.serverFile);
|
|
308
|
-
if (fs3.existsSync(serverPath)) {
|
|
309
|
-
const serverSource = fs3.readFileSync(serverPath, "utf8");
|
|
310
|
-
if (!serverSource.includes("get_post_meta")) {
|
|
311
|
-
issues.push(`${bindingSource.serverFile} must read post meta values`);
|
|
312
|
-
}
|
|
313
|
-
if (!serverSource.includes(postMeta.metaKey)) {
|
|
314
|
-
issues.push(`${bindingSource.serverFile} must reference ${postMeta.metaKey}`);
|
|
315
|
-
}
|
|
316
|
-
if (!serverSource.includes(postMeta.schemaFile)) {
|
|
317
|
-
issues.push(`${bindingSource.serverFile} must reference ${postMeta.schemaFile}`);
|
|
318
|
-
}
|
|
319
|
-
} else {
|
|
320
|
-
issues.push(`Missing ${bindingSource.serverFile}`);
|
|
321
|
-
}
|
|
322
|
-
const editorPath = path3.join(projectDir, bindingSource.editorFile);
|
|
323
|
-
if (fs3.existsSync(editorPath)) {
|
|
324
|
-
const editorSource = fs3.readFileSync(editorPath, "utf8");
|
|
325
|
-
if (!editorSource.includes("POST_META_BINDING_FIELDS")) {
|
|
326
|
-
issues.push(`${bindingSource.editorFile} must define post meta binding fields`);
|
|
327
|
-
}
|
|
328
|
-
if (!editorSource.includes(postMeta.schemaFile)) {
|
|
329
|
-
issues.push(`${bindingSource.editorFile} must reference ${postMeta.schemaFile}`);
|
|
330
|
-
}
|
|
331
|
-
if (bindingSource.metaPath && !editorSource.includes(bindingSource.metaPath)) {
|
|
332
|
-
issues.push(`${bindingSource.editorFile} must reference default meta path "${bindingSource.metaPath}"`);
|
|
333
|
-
}
|
|
334
|
-
} else {
|
|
335
|
-
issues.push(`Missing ${bindingSource.editorFile}`);
|
|
336
|
-
}
|
|
337
|
-
return createDoctorCheck(`Binding post meta ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.slug} reads ${postMeta.slug} via ${postMeta.schemaFile}` : issues.join("; "));
|
|
338
|
-
}
|
|
339
|
-
function getWorkspaceBindingDoctorChecks(workspace, inventory) {
|
|
340
|
-
const checks = [];
|
|
341
|
-
if (inventory.bindingSources.length > 0) {
|
|
342
|
-
checks.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
|
|
343
|
-
checks.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
|
|
344
|
-
}
|
|
345
|
-
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
346
|
-
for (const bindingSource of inventory.bindingSources) {
|
|
347
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
|
|
348
|
-
bindingSource.serverFile,
|
|
349
|
-
bindingSource.editorFile
|
|
350
|
-
]));
|
|
351
|
-
const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
|
|
352
|
-
if (bindingTargetCheck) {
|
|
353
|
-
checks.push(bindingTargetCheck);
|
|
354
|
-
}
|
|
355
|
-
const bindingPostMetaCheck = checkWorkspaceBindingPostMeta(workspace.projectDir, inventory, bindingSource);
|
|
356
|
-
if (bindingPostMetaCheck) {
|
|
357
|
-
checks.push(bindingPostMetaCheck);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return checks;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-block-addons.ts
|
|
364
|
-
import fs4 from "fs";
|
|
365
|
-
import path4 from "path";
|
|
366
|
-
var WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
|
|
367
|
-
var WORKSPACE_VARIATIONS_CALL_PATTERN = /registerWorkspaceVariations\s*\(\s*\)\s*;?/u;
|
|
368
|
-
var WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
|
|
369
|
-
var WORKSPACE_BLOCK_STYLES_CALL_PATTERN = /registerWorkspaceBlockStyles\s*\(\s*\)\s*;?/u;
|
|
370
|
-
var WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN = /^\s*import\s*\{\s*applyWorkspaceBlockTransforms\s*\}\s*from\s*["']\.\/transforms["']\s*;?\s*$/mu;
|
|
371
|
-
var WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
|
|
372
|
-
function isNestedPatternContentFile(patternFile) {
|
|
373
|
-
if (!patternFile) {
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
const normalizedPath = patternFile.replace(/\\/gu, "/");
|
|
377
|
-
return normalizedPath.startsWith("src/patterns/") && normalizedPath.slice("src/patterns/".length).includes("/");
|
|
378
|
-
}
|
|
379
|
-
function checkWorkspacePatternBootstrap(projectDir, packageName, requiresNestedPatternGlob) {
|
|
380
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
381
|
-
if (!fs4.existsSync(bootstrapPath)) {
|
|
382
|
-
return createDoctorCheck("Pattern bootstrap", "fail", `Missing ${path4.basename(bootstrapPath)}`);
|
|
383
|
-
}
|
|
384
|
-
const source = fs4.readFileSync(bootstrapPath, "utf8");
|
|
385
|
-
const hasCategoryAnchor = source.includes("register_block_pattern_category");
|
|
386
|
-
const hasPatternGlob = source.includes("/src/patterns/*.php");
|
|
387
|
-
const hasNestedPatternGlob = source.includes("/src/patterns/*/*.php");
|
|
388
|
-
const hasRequiredPatternGlobs = hasPatternGlob && (!requiresNestedPatternGlob || hasNestedPatternGlob);
|
|
389
|
-
return createDoctorCheck("Pattern bootstrap", hasCategoryAnchor && hasRequiredPatternGlobs ? "pass" : "fail", hasCategoryAnchor && hasRequiredPatternGlobs ? "Pattern category and loader hooks are present" : requiresNestedPatternGlob ? "Missing pattern category registration or nested src/patterns loader hook" : "Missing pattern category registration or src/patterns loader hook");
|
|
390
|
-
}
|
|
391
|
-
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
392
|
-
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
393
|
-
if (!fs4.existsSync(entryPath)) {
|
|
394
|
-
return createDoctorCheck(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
395
|
-
}
|
|
396
|
-
const source = fs4.readFileSync(entryPath, "utf8");
|
|
397
|
-
const hasImport = hasUncommentedPattern(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
|
|
398
|
-
const hasCall = hasExecutablePattern(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
|
|
399
|
-
return createDoctorCheck(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
|
|
400
|
-
}
|
|
401
|
-
function checkBlockStyleEntrypoint(projectDir, blockSlug) {
|
|
402
|
-
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
403
|
-
if (!fs4.existsSync(entryPath)) {
|
|
404
|
-
return createDoctorCheck(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
405
|
-
}
|
|
406
|
-
const source = fs4.readFileSync(entryPath, "utf8");
|
|
407
|
-
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
|
|
408
|
-
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
|
|
409
|
-
return createDoctorCheck(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
|
|
410
|
-
}
|
|
411
|
-
function checkBlockTransformEntrypoint(projectDir, blockSlug) {
|
|
412
|
-
const entryPath = path4.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
413
|
-
if (!fs4.existsSync(entryPath)) {
|
|
414
|
-
return createDoctorCheck(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path4.relative(projectDir, entryPath)}`);
|
|
415
|
-
}
|
|
416
|
-
const source = fs4.readFileSync(entryPath, "utf8");
|
|
417
|
-
const hasImport = hasUncommentedPattern(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
|
|
418
|
-
const hasCall = hasExecutablePattern(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
|
|
419
|
-
return createDoctorCheck(`Block transform entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block transform registration hook is present" : "Missing ./transforms import or applyWorkspaceBlockTransforms(registration.settings) call");
|
|
420
|
-
}
|
|
421
|
-
function checkBlockTransformConfig(workspace, transform) {
|
|
422
|
-
const expectedTo = `${workspace.workspace.namespace}/${transform.block}`;
|
|
423
|
-
const issues = [];
|
|
424
|
-
if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform.from)) {
|
|
425
|
-
issues.push("from must use full namespace/block format");
|
|
426
|
-
}
|
|
427
|
-
if (transform.to !== expectedTo) {
|
|
428
|
-
issues.push(`to must equal "${expectedTo}" for workspace block "${transform.block}"`);
|
|
429
|
-
}
|
|
430
|
-
return createDoctorCheck(`Block transform config ${transform.block}/${transform.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${transform.from} transforms into ${transform.to}` : issues.join("; "));
|
|
431
|
-
}
|
|
432
|
-
function getWorkspaceBlockAddonDoctorChecks(workspace, inventory, registeredBlockSlugs) {
|
|
433
|
-
const checks = [];
|
|
434
|
-
const variationTargetBlocks = new Set;
|
|
435
|
-
for (const variation of inventory.variations) {
|
|
436
|
-
if (!registeredBlockSlugs.has(variation.block)) {
|
|
437
|
-
checks.push(createDoctorCheck(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
|
|
438
|
-
continue;
|
|
439
|
-
}
|
|
440
|
-
variationTargetBlocks.add(variation.block);
|
|
441
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Variation ${variation.block}/${variation.slug}`, [variation.file]));
|
|
442
|
-
}
|
|
443
|
-
for (const blockSlug of variationTargetBlocks) {
|
|
444
|
-
checks.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
|
|
445
|
-
}
|
|
446
|
-
const blockStyleTargetBlocks = new Set;
|
|
447
|
-
for (const blockStyle of inventory.blockStyles) {
|
|
448
|
-
if (!registeredBlockSlugs.has(blockStyle.block)) {
|
|
449
|
-
checks.push(createDoctorCheck(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
blockStyleTargetBlocks.add(blockStyle.block);
|
|
453
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
|
|
454
|
-
}
|
|
455
|
-
for (const blockSlug of blockStyleTargetBlocks) {
|
|
456
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
|
|
457
|
-
path4.join("src", "blocks", blockSlug, "styles", "index.ts")
|
|
458
|
-
]));
|
|
459
|
-
checks.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
|
|
460
|
-
}
|
|
461
|
-
const blockTransformTargetBlocks = new Set;
|
|
462
|
-
for (const blockTransform of inventory.blockTransforms) {
|
|
463
|
-
if (!registeredBlockSlugs.has(blockTransform.block)) {
|
|
464
|
-
checks.push(createDoctorCheck(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
blockTransformTargetBlocks.add(blockTransform.block);
|
|
468
|
-
checks.push(checkBlockTransformConfig(workspace, blockTransform));
|
|
469
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
|
|
470
|
-
}
|
|
471
|
-
for (const blockSlug of blockTransformTargetBlocks) {
|
|
472
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
|
|
473
|
-
path4.join("src", "blocks", blockSlug, "transforms", "index.ts")
|
|
474
|
-
]));
|
|
475
|
-
checks.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
|
|
476
|
-
}
|
|
477
|
-
const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs4.existsSync(path4.join(workspace.projectDir, "src", "patterns"));
|
|
478
|
-
if (shouldCheckPatternBootstrap) {
|
|
479
|
-
const requiresNestedPatternGlob = inventory.patterns.some((pattern) => isNestedPatternContentFile(resolvePatternCatalogContentFile(pattern)));
|
|
480
|
-
checks.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName, requiresNestedPatternGlob));
|
|
481
|
-
}
|
|
482
|
-
if (inventory.patterns.length > 0) {
|
|
483
|
-
const catalogValidation = validatePatternCatalog(inventory.patterns, {
|
|
484
|
-
projectDir: workspace.projectDir
|
|
485
|
-
});
|
|
486
|
-
checks.push(createDoctorCheck("Pattern catalog", catalogValidation.errors.length > 0 ? "fail" : catalogValidation.warnings.length > 0 ? "warn" : "pass", catalogValidation.diagnostics.length > 0 ? formatPatternCatalogDiagnostics(catalogValidation.diagnostics) : "Pattern catalog metadata is valid"));
|
|
487
|
-
}
|
|
488
|
-
for (const pattern of inventory.patterns) {
|
|
489
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [
|
|
490
|
-
resolvePatternCatalogContentFile(pattern)
|
|
491
|
-
]));
|
|
492
|
-
}
|
|
493
|
-
return checks;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-block-iframe.ts
|
|
497
|
-
import fs5 from "fs";
|
|
498
|
-
import path5 from "path";
|
|
499
|
-
import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata2 } from "@wp-typia/block-runtime/blocks";
|
|
500
|
-
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/";
|
|
501
|
-
var WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES = {
|
|
502
|
-
API_VERSION: "wp-typia.workspace.block.iframe.api-version",
|
|
503
|
-
BLOCK_PROPS: "wp-typia.workspace.block.iframe.block-props",
|
|
504
|
-
EDITOR_GLOBALS: "wp-typia.workspace.block.iframe.editor-globals",
|
|
505
|
-
EDITOR_STYLES: "wp-typia.workspace.block.iframe.editor-styles"
|
|
506
|
-
};
|
|
507
|
-
var WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/u;
|
|
508
|
-
var WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES = new Set([
|
|
509
|
-
"edit",
|
|
510
|
-
"editor",
|
|
511
|
-
"index",
|
|
512
|
-
"save"
|
|
513
|
-
]);
|
|
514
|
-
var WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES = new Set([
|
|
515
|
-
"components",
|
|
516
|
-
"controls",
|
|
517
|
-
"editor",
|
|
518
|
-
"inspector"
|
|
519
|
-
]);
|
|
520
|
-
var WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
|
|
521
|
-
"editor.css",
|
|
522
|
-
"editor.scss",
|
|
523
|
-
"index.css",
|
|
524
|
-
"style.css",
|
|
525
|
-
"style.scss"
|
|
526
|
-
];
|
|
527
|
-
var WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
|
|
528
|
-
var WORKSPACE_BLOCK_PROPS_PATTERN = /\buse(?:Block|InnerBlocks)Props(?:\.save)?\s*\(/u;
|
|
529
|
-
function normalizePathSeparators(relativePath) {
|
|
530
|
-
return relativePath.split(path5.sep).join("/");
|
|
531
|
-
}
|
|
532
|
-
function hasRegisteredBlockAsset(value) {
|
|
533
|
-
if (typeof value === "string") {
|
|
534
|
-
return value.trim().length > 0;
|
|
535
|
-
}
|
|
536
|
-
if (Array.isArray(value)) {
|
|
537
|
-
return value.some((entry) => hasRegisteredBlockAsset(entry));
|
|
538
|
-
}
|
|
539
|
-
return false;
|
|
540
|
-
}
|
|
541
|
-
function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
|
|
542
|
-
const blockJsonRelativePath = path5.join("src", "blocks", blockSlug, "block.json");
|
|
543
|
-
const blockJsonPath = path5.join(projectDir, blockJsonRelativePath);
|
|
544
|
-
if (!fs5.existsSync(blockJsonPath)) {
|
|
545
|
-
return {
|
|
546
|
-
blockJsonRelativePath,
|
|
547
|
-
error: `Missing ${blockJsonRelativePath}`
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
try {
|
|
551
|
-
const document = parseScaffoldBlockMetadata2(readJsonFileSync(blockJsonPath, {
|
|
552
|
-
context: "workspace block metadata"
|
|
553
|
-
}));
|
|
554
|
-
return {
|
|
555
|
-
blockJsonRelativePath,
|
|
556
|
-
document
|
|
557
|
-
};
|
|
558
|
-
} catch (error) {
|
|
559
|
-
return {
|
|
560
|
-
blockJsonRelativePath,
|
|
561
|
-
error: error instanceof Error ? error.message : String(error)
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
function isWorkspaceBlockEditorSource(relativePath) {
|
|
566
|
-
if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(relativePath)) {
|
|
567
|
-
return false;
|
|
568
|
-
}
|
|
569
|
-
const normalizedRelativePath = normalizePathSeparators(relativePath);
|
|
570
|
-
const normalizedDirName = path5.posix.dirname(normalizedRelativePath);
|
|
571
|
-
const normalizedBaseName = path5.posix.basename(normalizedRelativePath, path5.posix.extname(normalizedRelativePath));
|
|
572
|
-
if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(normalizedBaseName)) {
|
|
573
|
-
return true;
|
|
574
|
-
}
|
|
575
|
-
const pathSegments = normalizedDirName.split("/");
|
|
576
|
-
return pathSegments.some((segment) => WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES.has(segment));
|
|
577
|
-
}
|
|
578
|
-
function isWorkspaceBlockSaveSource(relativePath) {
|
|
579
|
-
const normalizedBaseName = path5.basename(relativePath, path5.extname(relativePath));
|
|
580
|
-
return normalizedBaseName === "save";
|
|
581
|
-
}
|
|
582
|
-
function collectWorkspaceBlockEditorSources(projectDir, blockSlug) {
|
|
583
|
-
const blockDir = path5.join(projectDir, "src", "blocks", blockSlug);
|
|
584
|
-
if (!fs5.existsSync(blockDir)) {
|
|
585
|
-
return [];
|
|
586
|
-
}
|
|
587
|
-
const collected = [];
|
|
588
|
-
const queue = [blockDir];
|
|
589
|
-
while (queue.length > 0) {
|
|
590
|
-
const currentDir = queue.pop();
|
|
591
|
-
if (!currentDir) {
|
|
592
|
-
continue;
|
|
593
|
-
}
|
|
594
|
-
for (const entry of fs5.readdirSync(currentDir, { withFileTypes: true })) {
|
|
595
|
-
const absolutePath = path5.join(currentDir, entry.name);
|
|
596
|
-
if (entry.isDirectory()) {
|
|
597
|
-
queue.push(absolutePath);
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
if (!entry.isFile()) {
|
|
601
|
-
continue;
|
|
602
|
-
}
|
|
603
|
-
const relativePath = path5.relative(projectDir, absolutePath);
|
|
604
|
-
if (!isWorkspaceBlockEditorSource(relativePath)) {
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
collected.push({
|
|
608
|
-
relativePath: normalizePathSeparators(relativePath),
|
|
609
|
-
source: fs5.readFileSync(absolutePath, "utf8")
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
return collected.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
614
|
-
}
|
|
615
|
-
function getSourceLineNumber(source, index) {
|
|
616
|
-
let line = 1;
|
|
617
|
-
for (let cursor = 0;cursor < index; cursor += 1) {
|
|
618
|
-
if (source[cursor] === `
|
|
619
|
-
`) {
|
|
620
|
-
line += 1;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return line;
|
|
624
|
-
}
|
|
625
|
-
function isGlobalDomAccessCandidate(source, index, identifier) {
|
|
626
|
-
const lineStart = source.lastIndexOf(`
|
|
627
|
-
`, index - 1) + 1;
|
|
628
|
-
const lineEndCandidate = source.indexOf(`
|
|
629
|
-
`, index);
|
|
630
|
-
const lineEnd = lineEndCandidate === -1 ? source.length : lineEndCandidate;
|
|
631
|
-
const lineSource = source.slice(lineStart, lineEnd);
|
|
632
|
-
const trimmedLine = lineSource.trimStart();
|
|
633
|
-
if (trimmedLine.startsWith("import ")) {
|
|
634
|
-
return false;
|
|
635
|
-
}
|
|
636
|
-
if (trimmedLine.startsWith("const ") || trimmedLine.startsWith("let ") || trimmedLine.startsWith("var ")) {
|
|
637
|
-
return false;
|
|
638
|
-
}
|
|
639
|
-
if (trimmedLine.startsWith("function ") || trimmedLine.startsWith("class ")) {
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
const precedingCharacter = index > 0 ? source[index - 1] : "";
|
|
643
|
-
if (precedingCharacter === "." || precedingCharacter === "'" || precedingCharacter === '"') {
|
|
644
|
-
return false;
|
|
645
|
-
}
|
|
646
|
-
return identifier === "document" || identifier === "window" || identifier === "parent" || identifier === "top";
|
|
647
|
-
}
|
|
648
|
-
function findWorkspaceBlockGlobalDomAccesses(editorSources) {
|
|
649
|
-
return editorSources.flatMap(({ relativePath, source }) => {
|
|
650
|
-
const maskedSource = maskTypeScriptCommentsAndLiterals(source);
|
|
651
|
-
const matches = maskedSource.matchAll(WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN);
|
|
652
|
-
const findings = [];
|
|
653
|
-
for (const match of matches) {
|
|
654
|
-
const identifier = match[0];
|
|
655
|
-
const matchIndex = match.index ?? -1;
|
|
656
|
-
if (matchIndex < 0) {
|
|
657
|
-
continue;
|
|
658
|
-
}
|
|
659
|
-
if (!isGlobalDomAccessCandidate(source, matchIndex, identifier)) {
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
findings.push(`${relativePath}:${getSourceLineNumber(source, matchIndex)}`);
|
|
663
|
-
}
|
|
664
|
-
return findings;
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
function getWorkspaceBlockIframeCompatibilityChecks(projectDir, blockSlug) {
|
|
668
|
-
const metadataResult = readWorkspaceBlockIframeMetadata(projectDir, blockSlug);
|
|
669
|
-
if (!metadataResult.document) {
|
|
670
|
-
return [
|
|
671
|
-
createDoctorCheck(`Block iframe/API v3 ${blockSlug}`, "warn", metadataResult.error ?? `Unable to inspect ${metadataResult.blockJsonRelativePath}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION)
|
|
672
|
-
];
|
|
673
|
-
}
|
|
674
|
-
const blockJson = metadataResult.document;
|
|
675
|
-
const apiVersion = typeof blockJson.apiVersion === "number" && Number.isFinite(blockJson.apiVersion) ? blockJson.apiVersion : null;
|
|
676
|
-
const blockDir = path5.join(projectDir, "src", "blocks", blockSlug);
|
|
677
|
-
const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) => fs5.existsSync(path5.join(blockDir, fileName))).map((fileName) => normalizePathSeparators(path5.join("src", "blocks", blockSlug, fileName)));
|
|
678
|
-
const hasRegisteredEditorStyles = hasRegisteredBlockAsset(blockJson.style) || hasRegisteredBlockAsset(blockJson.editorStyle);
|
|
679
|
-
const editorSources = collectWorkspaceBlockEditorSources(projectDir, blockSlug);
|
|
680
|
-
const editorWrapperSources = editorSources.filter((source) => !isWorkspaceBlockSaveSource(source.relativePath));
|
|
681
|
-
const globalDomAccesses = findWorkspaceBlockGlobalDomAccesses(editorSources);
|
|
682
|
-
const hasBlockPropsUsage = editorSources.some(({ source }) => hasExecutablePattern(source, WORKSPACE_BLOCK_PROPS_PATTERN));
|
|
683
|
-
const hasEditorBlockPropsUsage = editorWrapperSources.some(({ source }) => hasExecutablePattern(source, WORKSPACE_BLOCK_PROPS_PATTERN));
|
|
684
|
-
const blockWrapperStatus = editorWrapperSources.length === 0 || hasEditorBlockPropsUsage ? "pass" : "warn";
|
|
685
|
-
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.";
|
|
686
|
-
return [
|
|
687
|
-
createDoctorCheck(`Block iframe API version ${blockSlug}`, apiVersion !== null && apiVersion >= 3 ? "pass" : "warn", apiVersion !== null && apiVersion >= 3 ? "block.json declares apiVersion 3 for iframe editor readiness" : `Set ${metadataResult.blockJsonRelativePath} apiVersion to 3 after testing the block in iframe-enabled Post Editor and Site Editor contexts. WordPress recommends API v3 for iframe editor compatibility. See ${WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL}`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.API_VERSION),
|
|
688
|
-
createDoctorCheck(`Block iframe styles ${blockSlug}`, localStyleFiles.length === 0 || hasRegisteredEditorStyles ? "pass" : "warn", localStyleFiles.length === 0 ? "No local block stylesheet source files found to register" : hasRegisteredEditorStyles ? "block.json registers block styles for iframe editor loading" : `Found stylesheet source files (${localStyleFiles.join(", ")}) but block.json does not declare style or editorStyle. Register block content styles so iframe editors do not depend on parent admin styles.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_STYLES),
|
|
689
|
-
createDoctorCheck(`Block iframe globals ${blockSlug}`, globalDomAccesses.length === 0 ? "pass" : "warn", globalDomAccesses.length === 0 ? "No direct window/document/parent DOM access detected in editor-facing block sources" : `Direct global DOM access detected at ${globalDomAccesses.join(", ")}. Prefer element.ownerDocument/defaultView via refs or useRefEffect for iframe editor content.`, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.EDITOR_GLOBALS),
|
|
690
|
-
createDoctorCheck(`Block iframe wrapper ${blockSlug}`, blockWrapperStatus, blockWrapperDetail, WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES.BLOCK_PROPS)
|
|
691
|
-
];
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-block-metadata.ts
|
|
695
|
-
import fs6 from "fs";
|
|
696
|
-
import path6 from "path";
|
|
697
|
-
import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata3 } from "@wp-typia/block-runtime/blocks";
|
|
698
|
-
var WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
699
|
-
var WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
|
|
700
|
-
function getWorkspaceBlockRequiredFiles(block) {
|
|
701
|
-
const blockDir = path6.join("src", "blocks", block.slug);
|
|
702
|
-
return Array.from(new Set([
|
|
703
|
-
block.typesFile,
|
|
704
|
-
block.apiTypesFile,
|
|
705
|
-
block.openApiFile,
|
|
706
|
-
path6.join(blockDir, "index.tsx"),
|
|
707
|
-
...WORKSPACE_GENERATED_BLOCK_ARTIFACTS.map((fileName) => path6.join(blockDir, fileName))
|
|
708
|
-
].filter((filePath) => typeof filePath === "string")));
|
|
709
|
-
}
|
|
710
|
-
function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
711
|
-
const blockJsonRelativePath = path6.join("src", "blocks", block.slug, "block.json");
|
|
712
|
-
const blockJsonPath = path6.join(projectDir, blockJsonRelativePath);
|
|
713
|
-
if (!fs6.existsSync(blockJsonPath)) {
|
|
714
|
-
return createDoctorCheck(`Block metadata ${block.slug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
715
|
-
}
|
|
716
|
-
let blockJson;
|
|
717
|
-
try {
|
|
718
|
-
blockJson = parseScaffoldBlockMetadata3(readJsonFileSync(blockJsonPath, {
|
|
719
|
-
context: "workspace block metadata"
|
|
720
|
-
}));
|
|
721
|
-
} catch (error) {
|
|
722
|
-
return createDoctorCheck(`Block metadata ${block.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
723
|
-
}
|
|
724
|
-
const expectedName = `${workspace.workspace.namespace}/${block.slug}`;
|
|
725
|
-
const issues = [];
|
|
726
|
-
if (blockJson.name !== expectedName) {
|
|
727
|
-
issues.push(`block.json name must equal "${expectedName}"`);
|
|
728
|
-
}
|
|
729
|
-
if (blockJson.textdomain !== workspace.workspace.textDomain) {
|
|
730
|
-
issues.push(`block.json textdomain must equal "${workspace.workspace.textDomain}"`);
|
|
731
|
-
}
|
|
732
|
-
return createDoctorCheck(`Block metadata ${block.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `block.json matches ${expectedName} and ${workspace.workspace.textDomain}` : issues.join("; "));
|
|
733
|
-
}
|
|
734
|
-
function checkWorkspaceBlockHooks(projectDir, blockSlug) {
|
|
735
|
-
const blockJsonRelativePath = path6.join("src", "blocks", blockSlug, "block.json");
|
|
736
|
-
const blockJsonPath = path6.join(projectDir, blockJsonRelativePath);
|
|
737
|
-
if (!fs6.existsSync(blockJsonPath)) {
|
|
738
|
-
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
739
|
-
}
|
|
740
|
-
let blockJson;
|
|
741
|
-
try {
|
|
742
|
-
blockJson = parseScaffoldBlockMetadata3(readJsonFileSync(blockJsonPath, {
|
|
743
|
-
context: "workspace block metadata"
|
|
744
|
-
}));
|
|
745
|
-
} catch (error) {
|
|
746
|
-
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
747
|
-
}
|
|
748
|
-
const blockHooks = blockJson.blockHooks;
|
|
749
|
-
if (blockHooks === undefined) {
|
|
750
|
-
return createDoctorCheck(`Block hooks ${blockSlug}`, "pass", "No blockHooks metadata configured");
|
|
751
|
-
}
|
|
752
|
-
if (!blockHooks || typeof blockHooks !== "object" || Array.isArray(blockHooks)) {
|
|
753
|
-
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `${blockJsonRelativePath} must define blockHooks as an object when present.`);
|
|
754
|
-
}
|
|
755
|
-
const blockName = typeof blockJson.name === "string" && blockJson.name.trim().length > 0 ? blockJson.name.trim() : null;
|
|
756
|
-
const invalidEntries = Object.entries(blockHooks).filter(([anchor, position]) => blockName !== null && anchor.trim() === blockName || anchor.trim().length === 0 || anchor !== anchor.trim() || !HOOKED_BLOCK_ANCHOR_PATTERN.test(anchor) || typeof position !== "string" || !HOOKED_BLOCK_POSITION_SET.has(position));
|
|
757
|
-
return createDoctorCheck(`Block hooks ${blockSlug}`, invalidEntries.length === 0 ? "pass" : "fail", invalidEntries.length === 0 ? `blockHooks metadata is valid${Object.keys(blockHooks).length > 0 ? ` (${Object.keys(blockHooks).join(", ")})` : ""}` : `Invalid blockHooks entries: ${invalidEntries.map(([anchor, position]) => `${anchor || "<empty>"} => ${String(position)}`).join(", ")}`);
|
|
758
|
-
}
|
|
759
|
-
function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
|
|
760
|
-
const entryRelativePath = path6.join("src", "blocks", blockSlug, "index.tsx");
|
|
761
|
-
const entryPath = path6.join(projectDir, entryRelativePath);
|
|
762
|
-
if (!fs6.existsSync(entryPath)) {
|
|
763
|
-
return createDoctorCheck(`Block collection ${blockSlug}`, "fail", `Missing ${entryRelativePath}`);
|
|
764
|
-
}
|
|
765
|
-
const source = fs6.readFileSync(entryPath, "utf8");
|
|
766
|
-
const hasCollectionImport = WORKSPACE_COLLECTION_IMPORT_PATTERN.test(source);
|
|
767
|
-
return createDoctorCheck(`Block collection ${blockSlug}`, hasCollectionImport ? "pass" : "fail", hasCollectionImport ? "Shared block collection import is present" : `Missing a shared collection import like ${WORKSPACE_COLLECTION_IMPORT_LINE}`);
|
|
768
|
-
}
|
|
769
|
-
function getWorkspaceBlockCoreDoctorChecks(workspace, block) {
|
|
770
|
-
return [
|
|
771
|
-
checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)),
|
|
772
|
-
checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block),
|
|
773
|
-
checkWorkspaceBlockHooks(workspace.projectDir, block.slug),
|
|
774
|
-
checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug)
|
|
775
|
-
];
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-blocks.ts
|
|
779
|
-
function getWorkspaceBlockDoctorChecks(workspace, inventory) {
|
|
780
|
-
const checks = [];
|
|
781
|
-
for (const block of inventory.blocks) {
|
|
782
|
-
checks.push(...getWorkspaceBlockCoreDoctorChecks(workspace, block));
|
|
783
|
-
checks.push(...getWorkspaceBlockIframeCompatibilityChecks(workspace.projectDir, block.slug));
|
|
784
|
-
}
|
|
785
|
-
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
786
|
-
checks.push(...getWorkspaceBlockAddonDoctorChecks(workspace, inventory, registeredBlockSlugs));
|
|
787
|
-
return checks;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-abilities.ts
|
|
791
|
-
import fs7 from "fs";
|
|
792
|
-
import path7 from "path";
|
|
793
|
-
function getWorkspaceAbilityRequiredFiles(ability) {
|
|
794
|
-
return Array.from(new Set([
|
|
795
|
-
ability.clientFile,
|
|
796
|
-
ability.configFile,
|
|
797
|
-
ability.dataFile,
|
|
798
|
-
ability.inputSchemaFile,
|
|
799
|
-
ability.outputSchemaFile,
|
|
800
|
-
ability.phpFile,
|
|
801
|
-
ability.typesFile
|
|
802
|
-
]));
|
|
803
|
-
}
|
|
804
|
-
function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
805
|
-
const configPath = path7.join(projectDir, ability.configFile);
|
|
806
|
-
if (!fs7.existsSync(configPath)) {
|
|
807
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
|
|
808
|
-
}
|
|
809
|
-
try {
|
|
810
|
-
const config = readJsonFileSync(configPath, {
|
|
811
|
-
context: "workspace ability config"
|
|
812
|
-
});
|
|
813
|
-
const abilityId = typeof config.abilityId === "string" ? config.abilityId.trim() : "";
|
|
814
|
-
const categorySlug = typeof config.category?.slug === "string" ? config.category.slug.trim() : "";
|
|
815
|
-
const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
|
|
816
|
-
const hasValidCategorySlug = /^[a-z0-9-]+$/u.test(categorySlug);
|
|
817
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, hasValidAbilityId && hasValidCategorySlug ? "pass" : "fail", hasValidAbilityId && hasValidCategorySlug ? `Ability id ${abilityId} in category ${categorySlug} is valid` : "Ability config must define a valid abilityId (`namespace/ability-name`) and category.slug.");
|
|
818
|
-
} catch (error) {
|
|
819
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
823
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
824
|
-
if (!fs7.existsSync(bootstrapPath)) {
|
|
825
|
-
return createDoctorCheck("Ability bootstrap", "fail", `Missing ${path7.basename(bootstrapPath)}`);
|
|
826
|
-
}
|
|
827
|
-
const source = fs7.readFileSync(bootstrapPath, "utf8");
|
|
828
|
-
const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
|
|
829
|
-
const enqueueFunctionName = `${phpPrefix}_enqueue_workflow_abilities`;
|
|
830
|
-
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
831
|
-
const adminEnqueueHook = `add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );`;
|
|
832
|
-
const editorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
833
|
-
const hasLoaderHook = source.includes(loadHook);
|
|
834
|
-
const hasAdminEnqueueHook = source.includes(adminEnqueueHook);
|
|
835
|
-
const hasEditorEnqueueHook = source.includes(editorEnqueueHook);
|
|
836
|
-
const hasServerGlob = source.includes(WORKSPACE_ABILITY_GLOB);
|
|
837
|
-
const hasEditorScript = source.includes(WORKSPACE_ABILITY_EDITOR_SCRIPT);
|
|
838
|
-
const hasEditorAsset = source.includes(WORKSPACE_ABILITY_EDITOR_ASSET);
|
|
839
|
-
const hasScriptModuleEnqueue = source.includes("wp_enqueue_script_module");
|
|
840
|
-
return createDoctorCheck("Ability bootstrap", hasLoaderHook && hasAdminEnqueueHook && hasEditorEnqueueHook && hasServerGlob && hasEditorScript && hasEditorAsset && hasScriptModuleEnqueue ? "pass" : "fail", hasLoaderHook && hasAdminEnqueueHook && hasEditorEnqueueHook && hasServerGlob && hasEditorScript && hasEditorAsset && hasScriptModuleEnqueue ? "Ability loader and admin/editor script-module bootstrap hooks are present" : "Missing ability loader hook, script-module enqueue, or build/abilities asset references");
|
|
841
|
-
}
|
|
842
|
-
function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
843
|
-
const indexRelativePath = [
|
|
844
|
-
path7.join("src", "abilities", "index.ts"),
|
|
845
|
-
path7.join("src", "abilities", "index.js")
|
|
846
|
-
].find((relativePath) => fs7.existsSync(path7.join(projectDir, relativePath)));
|
|
847
|
-
if (!indexRelativePath) {
|
|
848
|
-
return createDoctorCheck("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
|
|
849
|
-
}
|
|
850
|
-
const indexPath = path7.join(projectDir, indexRelativePath);
|
|
851
|
-
const source = fs7.readFileSync(indexPath, "utf8");
|
|
852
|
-
const missingExports = abilities.filter((ability) => {
|
|
853
|
-
const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex(ability.slug)}\\/client['"\`]`, "mu");
|
|
854
|
-
return !exportPattern.test(source);
|
|
855
|
-
});
|
|
856
|
-
return createDoctorCheck("Abilities index", missingExports.length === 0 ? "pass" : "fail", missingExports.length === 0 ? "Ability client helpers are aggregated" : `Missing ability exports for: ${missingExports.map((entry) => entry.slug).join(", ")}`);
|
|
857
|
-
}
|
|
858
|
-
function getWorkspaceAbilityDoctorChecks(workspace, abilities) {
|
|
859
|
-
const checks = [];
|
|
860
|
-
if (abilities.length > 0) {
|
|
861
|
-
checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
862
|
-
checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, abilities));
|
|
863
|
-
}
|
|
864
|
-
for (const ability of abilities) {
|
|
865
|
-
checks.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
|
|
866
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
|
|
867
|
-
}
|
|
868
|
-
return checks;
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-admin-views.ts
|
|
872
|
-
import fs8 from "fs";
|
|
873
|
-
import path8 from "path";
|
|
874
|
-
function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
875
|
-
const adminViewDir = path8.join("src", "admin-views", adminView.slug);
|
|
876
|
-
return Array.from(new Set([
|
|
877
|
-
adminView.file,
|
|
878
|
-
adminView.phpFile,
|
|
879
|
-
path8.join(adminViewDir, "Screen.tsx"),
|
|
880
|
-
path8.join(adminViewDir, "config.ts"),
|
|
881
|
-
path8.join(adminViewDir, "data.ts"),
|
|
882
|
-
path8.join(adminViewDir, "style.scss"),
|
|
883
|
-
path8.join(adminViewDir, "types.ts")
|
|
884
|
-
]));
|
|
885
|
-
}
|
|
886
|
-
function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
887
|
-
if (adminView.source === undefined) {
|
|
888
|
-
return createDoctorCheck(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
|
|
889
|
-
}
|
|
890
|
-
const source = adminView.source.trim();
|
|
891
|
-
const restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
|
|
892
|
-
const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
|
|
893
|
-
const restResourceSlug = restSourceMatch?.[1];
|
|
894
|
-
const restResource = restResourceSlug ? inventory.restResources.find((entry) => entry.slug === restResourceSlug) : undefined;
|
|
895
|
-
const isListCapableRestResource = Boolean(restResource?.methods.includes("list"));
|
|
896
|
-
const isManualSettingsRestResource = isAdminViewManualSettingsRestResource(restResource);
|
|
897
|
-
const hasManualSettingsRouteParameters = isManualSettingsRestResource && hasAdminViewManualSettingsRouteParameters(restResource);
|
|
898
|
-
const isValid = isListCapableRestResource || isManualSettingsRestResource && !hasManualSettingsRouteParameters || Boolean(coreDataSourceMatch);
|
|
899
|
-
const failDetail = hasManualSettingsRouteParameters ? `Admin view source ${source} uses route parameters or regex groups and cannot scaffold a singleton settings form` : "Admin view source must use rest-resource:<slug> with a list-capable REST resource, a manual settings contract with a body type, or core-data:<postType|taxonomy>/<name>";
|
|
900
|
-
return createDoctorCheck(`Admin view config ${adminView.slug}`, isValid ? "pass" : "fail", isValid ? `Admin view source ${source} is ${isManualSettingsRestResource ? "settings-form capable" : coreDataSourceMatch ? "core-data capable" : "list-capable"}` : failDetail);
|
|
901
|
-
}
|
|
902
|
-
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
903
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
904
|
-
if (!fs8.existsSync(bootstrapPath)) {
|
|
905
|
-
return createDoctorCheck("Admin view bootstrap", "fail", `Missing ${path8.basename(bootstrapPath)}`);
|
|
906
|
-
}
|
|
907
|
-
const source = fs8.readFileSync(bootstrapPath, "utf8");
|
|
908
|
-
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
909
|
-
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
910
|
-
const hasLoaderHook = source.includes(loadHook);
|
|
911
|
-
const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
|
|
912
|
-
return createDoctorCheck("Admin view bootstrap", hasLoaderHook && hasServerGlob ? "pass" : "fail", hasLoaderHook && hasServerGlob ? "Admin view PHP loader hook is present" : "Missing admin view PHP require glob or plugins_loaded hook");
|
|
913
|
-
}
|
|
914
|
-
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
915
|
-
const indexRelativePath = [
|
|
916
|
-
path8.join("src", "admin-views", "index.ts"),
|
|
917
|
-
path8.join("src", "admin-views", "index.js")
|
|
918
|
-
].find((relativePath) => fs8.existsSync(path8.join(projectDir, relativePath)));
|
|
919
|
-
if (!indexRelativePath) {
|
|
920
|
-
return createDoctorCheck("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
921
|
-
}
|
|
922
|
-
const indexPath = path8.join(projectDir, indexRelativePath);
|
|
923
|
-
const source = fs8.readFileSync(indexPath, "utf8");
|
|
924
|
-
const missingImports = adminViews.filter((adminView) => {
|
|
925
|
-
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
926
|
-
return !importPattern.test(source);
|
|
927
|
-
});
|
|
928
|
-
return createDoctorCheck("Admin views index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Admin view registrations are aggregated" : `Missing admin view imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
929
|
-
}
|
|
930
|
-
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
931
|
-
const phpPath = path8.join(projectDir, adminView.phpFile);
|
|
932
|
-
if (!fs8.existsSync(phpPath)) {
|
|
933
|
-
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
934
|
-
}
|
|
935
|
-
const source = fs8.readFileSync(phpPath, "utf8");
|
|
936
|
-
const hasAdminMenu = source.includes("add_submenu_page");
|
|
937
|
-
const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
|
|
938
|
-
const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
|
|
939
|
-
const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
|
|
940
|
-
const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
|
|
941
|
-
const hasComponentsStyleDependency = /['"]wp-components['"]/u.test(source);
|
|
942
|
-
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "pass" : "fail", hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "Admin menu, script, style, and wp-components style dependency are wired" : "Missing admin menu, enqueue hook, build/admin-views asset reference, or wp-components style dependency");
|
|
943
|
-
}
|
|
944
|
-
function getWorkspaceAdminViewDoctorChecks(workspace, inventory) {
|
|
945
|
-
const checks = [];
|
|
946
|
-
if (inventory.adminViews.length > 0) {
|
|
947
|
-
checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
948
|
-
checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
|
|
949
|
-
}
|
|
950
|
-
for (const adminView of inventory.adminViews) {
|
|
951
|
-
checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
|
|
952
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
|
|
953
|
-
checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
|
|
954
|
-
}
|
|
955
|
-
return checks;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-ai.ts
|
|
959
|
-
import fs9 from "fs";
|
|
960
|
-
import path9 from "path";
|
|
961
|
-
function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
|
|
962
|
-
return Array.from(new Set([
|
|
963
|
-
aiFeature.aiSchemaFile,
|
|
964
|
-
aiFeature.apiFile,
|
|
965
|
-
path9.join(path9.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
|
|
966
|
-
path9.join(path9.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
|
|
967
|
-
path9.join(path9.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
|
|
968
|
-
aiFeature.clientFile,
|
|
969
|
-
aiFeature.dataFile,
|
|
970
|
-
aiFeature.openApiFile,
|
|
971
|
-
aiFeature.phpFile,
|
|
972
|
-
aiFeature.typesFile,
|
|
973
|
-
aiFeature.validatorsFile
|
|
974
|
-
]));
|
|
975
|
-
}
|
|
976
|
-
function checkWorkspaceAiFeatureConfig(aiFeature) {
|
|
977
|
-
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(aiFeature.namespace);
|
|
978
|
-
return createDoctorCheck(`AI feature config ${aiFeature.slug}`, hasNamespace ? "pass" : "fail", hasNamespace ? `AI feature namespace ${aiFeature.namespace} is valid` : "AI feature namespace is invalid");
|
|
979
|
-
}
|
|
980
|
-
function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
981
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
982
|
-
if (!fs9.existsSync(bootstrapPath)) {
|
|
983
|
-
return createDoctorCheck("AI feature bootstrap", "fail", `Missing ${path9.basename(bootstrapPath)}`);
|
|
984
|
-
}
|
|
985
|
-
const source = fs9.readFileSync(bootstrapPath, "utf8");
|
|
986
|
-
const registerFunctionName = `${phpPrefix}_register_ai_features`;
|
|
987
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
988
|
-
const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
|
|
989
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
990
|
-
return createDoctorCheck("AI feature bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "AI feature PHP loader hook is present" : "Missing AI feature PHP require glob or init hook");
|
|
991
|
-
}
|
|
992
|
-
function getWorkspaceAiFeatureDoctorChecks(workspace, aiFeatures) {
|
|
993
|
-
const checks = [];
|
|
994
|
-
if (aiFeatures.length > 0) {
|
|
995
|
-
checks.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
996
|
-
}
|
|
997
|
-
for (const aiFeature of aiFeatures) {
|
|
998
|
-
checks.push(checkWorkspaceAiFeatureConfig(aiFeature));
|
|
999
|
-
checks.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
|
|
1000
|
-
}
|
|
1001
|
-
return checks;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-editor-plugins.ts
|
|
1005
|
-
import fs10 from "fs";
|
|
1006
|
-
import path10 from "path";
|
|
1007
|
-
function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
1008
|
-
const editorPluginDir = path10.join("src", "editor-plugins", editorPlugin.slug);
|
|
1009
|
-
const surfaceFile = editorPlugin.slot === "PluginSidebar" ? path10.join(editorPluginDir, "Sidebar.tsx") : path10.join(editorPluginDir, "Surface.tsx");
|
|
1010
|
-
return Array.from(new Set([
|
|
1011
|
-
editorPlugin.file,
|
|
1012
|
-
surfaceFile,
|
|
1013
|
-
path10.join(editorPluginDir, "data.ts"),
|
|
1014
|
-
path10.join(editorPluginDir, "types.ts"),
|
|
1015
|
-
path10.join(editorPluginDir, "style.scss")
|
|
1016
|
-
]));
|
|
1017
|
-
}
|
|
1018
|
-
function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
1019
|
-
const normalizedSlot = resolveEditorPluginSlotAlias(editorPlugin.slot);
|
|
1020
|
-
const isValidSlot = Boolean(normalizedSlot);
|
|
1021
|
-
return createDoctorCheck(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot ? `Editor plugin slot ${editorPlugin.slot} is supported as ${normalizedSlot}` : `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")} or legacy aliases PluginSidebar, PluginDocumentSettingPanel.`);
|
|
1022
|
-
}
|
|
1023
|
-
function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
|
|
1024
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
1025
|
-
if (!fs10.existsSync(bootstrapPath)) {
|
|
1026
|
-
return createDoctorCheck("Editor plugin bootstrap", "fail", `Missing ${path10.basename(bootstrapPath)}`);
|
|
1027
|
-
}
|
|
1028
|
-
const source = fs10.readFileSync(bootstrapPath, "utf8");
|
|
1029
|
-
const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
|
|
1030
|
-
const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
1031
|
-
const hasEditorEnqueueHook = source.includes(enqueueHook);
|
|
1032
|
-
const hasEditorScript = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT);
|
|
1033
|
-
const hasEditorAsset = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET);
|
|
1034
|
-
const hasEditorStyle = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE);
|
|
1035
|
-
return createDoctorCheck("Editor plugin bootstrap", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "pass" : "fail", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "Editor plugin enqueue hook is present" : "Missing editor plugin enqueue hook or build/editor-plugins script/style asset references");
|
|
1036
|
-
}
|
|
1037
|
-
function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
1038
|
-
const indexRelativePath = [
|
|
1039
|
-
path10.join("src", "editor-plugins", "index.ts"),
|
|
1040
|
-
path10.join("src", "editor-plugins", "index.js")
|
|
1041
|
-
].find((relativePath) => fs10.existsSync(path10.join(projectDir, relativePath)));
|
|
1042
|
-
if (!indexRelativePath) {
|
|
1043
|
-
return createDoctorCheck("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
|
|
1044
|
-
}
|
|
1045
|
-
const indexPath = path10.join(projectDir, indexRelativePath);
|
|
1046
|
-
const source = fs10.readFileSync(indexPath, "utf8");
|
|
1047
|
-
const missingImports = editorPlugins.filter((editorPlugin) => {
|
|
1048
|
-
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
1049
|
-
return !importPattern.test(source);
|
|
1050
|
-
});
|
|
1051
|
-
return createDoctorCheck("Editor plugins index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Editor plugin registrations are aggregated" : `Missing editor plugin imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
1052
|
-
}
|
|
1053
|
-
function getWorkspaceEditorPluginDoctorChecks(workspace, editorPlugins) {
|
|
1054
|
-
const checks = [];
|
|
1055
|
-
if (editorPlugins.length > 0) {
|
|
1056
|
-
checks.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1057
|
-
checks.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, editorPlugins));
|
|
1058
|
-
}
|
|
1059
|
-
for (const editorPlugin of editorPlugins) {
|
|
1060
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
1061
|
-
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
1062
|
-
}
|
|
1063
|
-
return checks;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-post-meta.ts
|
|
1067
|
-
import fs11 from "fs";
|
|
1068
|
-
import path11 from "path";
|
|
1069
|
-
function getWorkspacePostMetaRequiredFiles(postMeta) {
|
|
1070
|
-
return Array.from(new Set([
|
|
1071
|
-
postMeta.phpFile,
|
|
1072
|
-
postMeta.schemaFile,
|
|
1073
|
-
postMeta.typesFile
|
|
1074
|
-
]));
|
|
1075
|
-
}
|
|
1076
|
-
function checkWorkspacePostMetaConfig(postMeta) {
|
|
1077
|
-
let hasPostType = false;
|
|
1078
|
-
try {
|
|
1079
|
-
hasPostType = assertValidPostMetaPostType(postMeta.postType) === postMeta.postType;
|
|
1080
|
-
} catch {
|
|
1081
|
-
hasPostType = false;
|
|
1082
|
-
}
|
|
1083
|
-
const hasMetaKey = typeof postMeta.metaKey === "string" && postMeta.metaKey.trim().length > 0 && !/\s/u.test(postMeta.metaKey);
|
|
1084
|
-
const hasRestExposure = typeof postMeta.showInRest === "boolean";
|
|
1085
|
-
return createDoctorCheck(`Post meta config ${postMeta.slug}`, hasPostType && hasMetaKey && hasRestExposure ? "pass" : "fail", hasPostType && hasMetaKey && hasRestExposure ? `Post meta ${postMeta.metaKey} targets ${postMeta.postType}` : "Post meta postType, metaKey, or showInRest configuration is invalid");
|
|
1086
|
-
}
|
|
1087
|
-
function checkWorkspacePostMetaBootstrap(projectDir, packageName, phpPrefix) {
|
|
1088
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
1089
|
-
if (!fs11.existsSync(bootstrapPath)) {
|
|
1090
|
-
return createDoctorCheck("Post meta bootstrap", "fail", `Missing ${path11.basename(bootstrapPath)}`);
|
|
1091
|
-
}
|
|
1092
|
-
const source = fs11.readFileSync(bootstrapPath, "utf8");
|
|
1093
|
-
const registerFunctionName = `${phpPrefix}_register_post_meta_contracts`;
|
|
1094
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
1095
|
-
const hasServerGlob = source.includes(WORKSPACE_POST_META_GLOB);
|
|
1096
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
1097
|
-
return createDoctorCheck("Post meta bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "Post meta PHP loader hook is present" : "Missing post meta PHP require glob or init hook");
|
|
1098
|
-
}
|
|
1099
|
-
function checkWorkspacePostMetaPhp(projectDir, postMeta) {
|
|
1100
|
-
const phpPath = path11.join(projectDir, postMeta.phpFile);
|
|
1101
|
-
if (!fs11.existsSync(phpPath)) {
|
|
1102
|
-
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, "fail", `Missing ${postMeta.phpFile}`);
|
|
1103
|
-
}
|
|
1104
|
-
const source = fs11.readFileSync(phpPath, "utf8");
|
|
1105
|
-
const hasRegisterPostMeta = source.includes("register_post_meta");
|
|
1106
|
-
const hasPostType = source.includes(postMeta.postType);
|
|
1107
|
-
const hasMetaKey = source.includes(postMeta.metaKey);
|
|
1108
|
-
const hasSchemaFile = source.includes(postMeta.schemaFile);
|
|
1109
|
-
const hasRestExposure = source.includes("'show_in_rest'");
|
|
1110
|
-
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure ? "pass" : "fail", hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure ? "Post meta registration, schema path, and REST exposure flag are wired" : "Missing register_post_meta, post type, meta key, schema path, or show_in_rest wiring");
|
|
1111
|
-
}
|
|
1112
|
-
function getWorkspacePostMetaDoctorChecks(workspace, postMetaEntries) {
|
|
1113
|
-
const checks = [];
|
|
1114
|
-
if (postMetaEntries.length > 0) {
|
|
1115
|
-
checks.push(checkWorkspacePostMetaBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1116
|
-
}
|
|
1117
|
-
for (const postMeta of postMetaEntries) {
|
|
1118
|
-
checks.push(checkWorkspacePostMetaConfig(postMeta));
|
|
1119
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Post meta ${postMeta.slug}`, getWorkspacePostMetaRequiredFiles(postMeta)));
|
|
1120
|
-
checks.push(checkWorkspacePostMetaPhp(workspace.projectDir, postMeta));
|
|
1121
|
-
}
|
|
1122
|
-
return checks;
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features-rest.ts
|
|
1126
|
-
import fs12 from "fs";
|
|
1127
|
-
import path12 from "path";
|
|
1128
|
-
function isManualRestResource(restResource) {
|
|
1129
|
-
return restResource.mode === "manual";
|
|
1130
|
-
}
|
|
1131
|
-
function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
1132
|
-
const schemaNames = new Set;
|
|
1133
|
-
if (isManualRestResource(restResource)) {
|
|
1134
|
-
schemaNames.add("query");
|
|
1135
|
-
if (restResource.bodyTypeName) {
|
|
1136
|
-
schemaNames.add("request");
|
|
1137
|
-
}
|
|
1138
|
-
schemaNames.add("response");
|
|
1139
|
-
return Array.from(new Set([
|
|
1140
|
-
restResource.apiFile,
|
|
1141
|
-
...Array.from(schemaNames, (schemaName) => path12.join(path12.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
1142
|
-
restResource.clientFile,
|
|
1143
|
-
restResource.openApiFile,
|
|
1144
|
-
restResource.typesFile,
|
|
1145
|
-
restResource.validatorsFile
|
|
1146
|
-
]));
|
|
1147
|
-
}
|
|
1148
|
-
if (restResource.methods.includes("list")) {
|
|
1149
|
-
schemaNames.add("list-query");
|
|
1150
|
-
schemaNames.add("list-response");
|
|
1151
|
-
}
|
|
1152
|
-
if (restResource.methods.includes("read")) {
|
|
1153
|
-
schemaNames.add("read-query");
|
|
1154
|
-
schemaNames.add("read-response");
|
|
1155
|
-
}
|
|
1156
|
-
if (restResource.methods.includes("create")) {
|
|
1157
|
-
schemaNames.add("create-request");
|
|
1158
|
-
schemaNames.add("create-response");
|
|
1159
|
-
}
|
|
1160
|
-
if (restResource.methods.includes("update")) {
|
|
1161
|
-
schemaNames.add("update-query");
|
|
1162
|
-
schemaNames.add("update-request");
|
|
1163
|
-
schemaNames.add("update-response");
|
|
1164
|
-
}
|
|
1165
|
-
if (restResource.methods.includes("delete")) {
|
|
1166
|
-
schemaNames.add("delete-query");
|
|
1167
|
-
schemaNames.add("delete-response");
|
|
1168
|
-
}
|
|
1169
|
-
return Array.from(new Set([
|
|
1170
|
-
restResource.apiFile,
|
|
1171
|
-
...Array.from(schemaNames, (schemaName) => path12.join(path12.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
1172
|
-
restResource.clientFile,
|
|
1173
|
-
...restResource.dataFile ? [restResource.dataFile] : [],
|
|
1174
|
-
restResource.openApiFile,
|
|
1175
|
-
...restResource.phpFile ? [restResource.phpFile] : [],
|
|
1176
|
-
restResource.typesFile,
|
|
1177
|
-
restResource.validatorsFile
|
|
1178
|
-
]));
|
|
1179
|
-
}
|
|
1180
|
-
function checkWorkspaceRestResourceConfig(restResource) {
|
|
1181
|
-
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(restResource.namespace);
|
|
1182
|
-
if (isManualRestResource(restResource)) {
|
|
1183
|
-
const hasAuth = restResource.auth == null || MANUAL_REST_CONTRACT_AUTH_IDS.includes(restResource.auth);
|
|
1184
|
-
const hasMethod = typeof restResource.method === "string" && MANUAL_REST_CONTRACT_HTTP_METHOD_IDS.includes(restResource.method);
|
|
1185
|
-
const hasPathPattern = typeof restResource.pathPattern === "string" && restResource.pathPattern.startsWith("/") && restResource.pathPattern.length > 1;
|
|
1186
|
-
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasAuth && hasMethod && hasPathPattern ? "pass" : "fail", hasNamespace && hasAuth && hasMethod && hasPathPattern ? `Manual REST contract ${restResource.method} /${restResource.namespace}${restResource.pathPattern}` : "Manual REST contract namespace, auth, method, or path pattern is invalid");
|
|
1187
|
-
}
|
|
1188
|
-
const hasMethods = restResource.methods.length > 0 && restResource.methods.every((method) => REST_RESOURCE_METHOD_IDS.includes(method));
|
|
1189
|
-
const hasGeneratedFiles = typeof restResource.dataFile === "string" && restResource.dataFile.length > 0 && typeof restResource.phpFile === "string" && restResource.phpFile.length > 0;
|
|
1190
|
-
const hasRoutePattern = restResource.routePattern == null || typeof restResource.routePattern === "string" && restResource.routePattern.startsWith("/") && restResource.routePattern.length > 1 && !/\s/u.test(restResource.routePattern) && isGeneratedRestResourceRoutePatternCompatible(restResource.routePattern);
|
|
1191
|
-
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern ? "pass" : "fail", hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern ? `REST resource namespace ${restResource.namespace} with methods ${restResource.methods.join(", ")}` : "REST resource namespace, methods, dataFile, phpFile, or routePattern are invalid");
|
|
1192
|
-
}
|
|
1193
|
-
function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
|
|
1194
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
1195
|
-
if (!fs12.existsSync(bootstrapPath)) {
|
|
1196
|
-
return createDoctorCheck("REST resource bootstrap", "fail", `Missing ${path12.basename(bootstrapPath)}`);
|
|
1197
|
-
}
|
|
1198
|
-
const source = fs12.readFileSync(bootstrapPath, "utf8");
|
|
1199
|
-
const registerFunctionName = `${phpPrefix}_register_rest_resources`;
|
|
1200
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
1201
|
-
const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
|
|
1202
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
1203
|
-
return createDoctorCheck("REST resource bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "REST resource PHP loader hook is present" : "Missing REST resource PHP require glob or init hook");
|
|
1204
|
-
}
|
|
1205
|
-
function getWorkspaceRestResourceDoctorChecks(workspace, restResources) {
|
|
1206
|
-
const checks = [];
|
|
1207
|
-
if (restResources.some((restResource) => !isManualRestResource(restResource))) {
|
|
1208
|
-
checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
1209
|
-
}
|
|
1210
|
-
for (const restResource of restResources) {
|
|
1211
|
-
checks.push(checkWorkspaceRestResourceConfig(restResource));
|
|
1212
|
-
checks.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
|
|
1213
|
-
}
|
|
1214
|
-
return checks;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features.ts
|
|
1218
|
-
function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
|
|
1219
|
-
return [
|
|
1220
|
-
...getWorkspaceRestResourceDoctorChecks(workspace, inventory.restResources),
|
|
1221
|
-
...getWorkspacePostMetaDoctorChecks(workspace, inventory.postMeta),
|
|
1222
|
-
...getWorkspaceAbilityDoctorChecks(workspace, inventory.abilities),
|
|
1223
|
-
...getWorkspaceAiFeatureDoctorChecks(workspace, inventory.aiFeatures),
|
|
1224
|
-
...getWorkspaceEditorPluginDoctorChecks(workspace, inventory.editorPlugins),
|
|
1225
|
-
...getWorkspaceAdminViewDoctorChecks(workspace, inventory)
|
|
1226
|
-
];
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-package.ts
|
|
1230
|
-
import path13 from "path";
|
|
1231
|
-
async function prepareWorkspacePackageDoctorSnapshot(workspace, packageJson) {
|
|
1232
|
-
const packageName = packageJson.name;
|
|
1233
|
-
const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
|
|
1234
|
-
const migrationConfigRelativePath = path13.join("src", "migrations", "config.ts");
|
|
1235
|
-
const [bootstrapExists, migrationConfigExists] = await Promise.all([
|
|
1236
|
-
pathExists(path13.join(workspace.projectDir, bootstrapRelativePath)),
|
|
1237
|
-
pathExists(path13.join(workspace.projectDir, migrationConfigRelativePath))
|
|
1238
|
-
]);
|
|
1239
|
-
return {
|
|
1240
|
-
bootstrapExists,
|
|
1241
|
-
bootstrapRelativePath,
|
|
1242
|
-
migrationConfigExists,
|
|
1243
|
-
migrationConfigRelativePath
|
|
1244
|
-
};
|
|
1245
|
-
}
|
|
1246
|
-
function getWorkspacePackageMetadataCheck(workspace, packageJson, snapshot) {
|
|
1247
|
-
const issues = [];
|
|
1248
|
-
const packageName = packageJson.name;
|
|
1249
|
-
const wpTypia = packageJson.wpTypia;
|
|
1250
|
-
if (typeof packageName !== "string" || packageName.length === 0) {
|
|
1251
|
-
issues.push("package.json must define a string name for workspace bootstrap resolution");
|
|
1252
|
-
}
|
|
1253
|
-
if (wpTypia?.projectType !== "workspace") {
|
|
1254
|
-
issues.push('wpTypia.projectType must be "workspace"');
|
|
1255
|
-
}
|
|
1256
|
-
if (wpTypia?.templatePackage !== WORKSPACE_TEMPLATE_PACKAGE) {
|
|
1257
|
-
issues.push(`wpTypia.templatePackage must be "${WORKSPACE_TEMPLATE_PACKAGE}"`);
|
|
1258
|
-
}
|
|
1259
|
-
if (wpTypia?.namespace !== workspace.workspace.namespace) {
|
|
1260
|
-
issues.push(`wpTypia.namespace must equal "${workspace.workspace.namespace}"`);
|
|
1261
|
-
}
|
|
1262
|
-
if (wpTypia?.textDomain !== workspace.workspace.textDomain) {
|
|
1263
|
-
issues.push(`wpTypia.textDomain must equal "${workspace.workspace.textDomain}"`);
|
|
1264
|
-
}
|
|
1265
|
-
if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
|
|
1266
|
-
issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
|
|
1267
|
-
}
|
|
1268
|
-
if (!snapshot.bootstrapExists) {
|
|
1269
|
-
issues.push(`Missing bootstrap file ${snapshot.bootstrapRelativePath}`);
|
|
1270
|
-
}
|
|
1271
|
-
return createDoctorCheck("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${snapshot.bootstrapRelativePath}` : issues.join("; "));
|
|
1272
|
-
}
|
|
1273
|
-
function getMigrationWorkspaceHintCheck(packageJson, snapshot) {
|
|
1274
|
-
const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
|
|
1275
|
-
if (!hasMigrationScript && !snapshot.migrationConfigExists) {
|
|
1276
|
-
return null;
|
|
1277
|
-
}
|
|
1278
|
-
return createDoctorCheck("Migration workspace", snapshot.migrationConfigExists ? "pass" : "fail", snapshot.migrationConfigExists ? "Run `wp-typia migrate doctor --all` for migration target, snapshot, fixture, and generated artifact checks" : `Missing ${snapshot.migrationConfigRelativePath} for the configured migration workspace`);
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
|
|
1282
|
-
function formatWorkspaceInventorySummary(inventory) {
|
|
1283
|
-
return [
|
|
1284
|
-
`${inventory.blocks.length} block(s)`,
|
|
1285
|
-
`${inventory.variations.length} variation(s)`,
|
|
1286
|
-
`${inventory.blockStyles.length} block style(s)`,
|
|
1287
|
-
`${inventory.blockTransforms.length} block transform(s)`,
|
|
1288
|
-
`${inventory.patterns.length} pattern(s)`,
|
|
1289
|
-
`${inventory.bindingSources.length} binding source(s)`,
|
|
1290
|
-
`${inventory.restResources.length} REST resource(s)`,
|
|
1291
|
-
`${inventory.postMeta.length} post meta contract(s)`,
|
|
1292
|
-
`${inventory.abilities.length} ability scaffold(s)`,
|
|
1293
|
-
`${inventory.aiFeatures.length} AI feature(s)`,
|
|
1294
|
-
`${inventory.editorPlugins.length} editor plugin(s)`,
|
|
1295
|
-
`${inventory.adminViews.length} admin view(s)`
|
|
1296
|
-
].join(", ");
|
|
1297
|
-
}
|
|
1298
|
-
async function getWorkspaceDoctorChecks(cwd) {
|
|
1299
|
-
const checks = [];
|
|
1300
|
-
let workspace = null;
|
|
1301
|
-
let invalidWorkspaceReason = null;
|
|
1302
|
-
try {
|
|
1303
|
-
invalidWorkspaceReason = getInvalidWorkspaceProjectReason(cwd);
|
|
1304
|
-
workspace = tryResolveWorkspaceProject(cwd);
|
|
1305
|
-
} catch (error) {
|
|
1306
|
-
checks.push(createDoctorScopeCheck("fail", "Scope: blocked before workspace checks. Environment checks ran, but workspace discovery could not continue. Fix the nearby workspace package metadata and rerun `wp-typia doctor`."));
|
|
1307
|
-
checks.push(createDoctorCheck("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
|
|
1308
|
-
return checks;
|
|
1309
|
-
}
|
|
1310
|
-
if (!workspace) {
|
|
1311
|
-
if (invalidWorkspaceReason) {
|
|
1312
|
-
checks.push(createDoctorScopeCheck("fail", "Scope: blocked before workspace checks. Environment checks ran, but workspace diagnostics could not continue because a nearby wp-typia workspace candidate is invalid. Fix the workspace package metadata and rerun `wp-typia doctor`."));
|
|
1313
|
-
checks.push(createDoctorCheck("Workspace package metadata", "fail", invalidWorkspaceReason));
|
|
1314
|
-
} else {
|
|
1315
|
-
checks.push(createDoctorScopeCheck("pass", "Scope: environment-only. No official wp-typia workspace root was detected, so this run only covered environment readiness. Re-run `wp-typia doctor` from a workspace root if you expected package metadata, inventory, or generated artifact checks."));
|
|
1316
|
-
}
|
|
1317
|
-
return checks;
|
|
1318
|
-
}
|
|
1319
|
-
checks.push(createDoctorScopeCheck("pass", `Scope: full workspace diagnostics for ${workspace.workspace.namespace}. Environment readiness checks ran and workspace-scoped diagnostics are enabled for the package metadata, inventory, source-tree drift, and any configured migration hint rows below.`));
|
|
1320
|
-
let workspacePackageJson;
|
|
1321
|
-
try {
|
|
1322
|
-
workspacePackageJson = parseWorkspacePackageJson(workspace.projectDir);
|
|
1323
|
-
} catch (error) {
|
|
1324
|
-
checks.push(createDoctorCheck("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
|
|
1325
|
-
return checks;
|
|
1326
|
-
}
|
|
1327
|
-
const packageDoctorSnapshot = await prepareWorkspacePackageDoctorSnapshot(workspace, workspacePackageJson);
|
|
1328
|
-
checks.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson, packageDoctorSnapshot));
|
|
1329
|
-
try {
|
|
1330
|
-
const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
|
|
1331
|
-
checks.push(createDoctorCheck("Workspace inventory", "pass", formatWorkspaceInventorySummary(inventory)));
|
|
1332
|
-
checks.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
|
|
1333
|
-
checks.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
|
|
1334
|
-
checks.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
|
|
1335
|
-
const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspacePackageJson, packageDoctorSnapshot);
|
|
1336
|
-
if (migrationWorkspaceCheck) {
|
|
1337
|
-
checks.push(migrationWorkspaceCheck);
|
|
1338
|
-
}
|
|
1339
|
-
} catch (error) {
|
|
1340
|
-
checks.push(createDoctorCheck("Workspace inventory", "fail", error instanceof Error ? error.message : String(error)));
|
|
1341
|
-
}
|
|
1342
|
-
return checks;
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
// ../wp-typia-project-tools/src/runtime/cli-doctor.ts
|
|
1346
|
-
var DEFAULT_DOCTOR_EXIT_POLICY = "strict";
|
|
1347
|
-
var defaultDoctorLinePrinter = (line) => {
|
|
1348
|
-
process.stdout.write(`${line}
|
|
1349
|
-
`);
|
|
1350
|
-
};
|
|
1351
|
-
function renderDefaultDoctorCheckLine(check) {
|
|
1352
|
-
defaultDoctorLinePrinter(formatDoctorCheckLine(check));
|
|
1353
|
-
}
|
|
1354
|
-
function renderDefaultDoctorSummaryLine(summaryLine) {
|
|
1355
|
-
defaultDoctorLinePrinter(summaryLine);
|
|
1356
|
-
}
|
|
1357
|
-
function annotateDoctorChecks(checks, scope) {
|
|
1358
|
-
return checks.map((check) => ({
|
|
1359
|
-
...check,
|
|
1360
|
-
scope: check.scope ?? scope
|
|
1361
|
-
}));
|
|
1362
|
-
}
|
|
1363
|
-
function resolveDoctorExitPolicy(options) {
|
|
1364
|
-
return options.exitPolicy ?? DEFAULT_DOCTOR_EXIT_POLICY;
|
|
1365
|
-
}
|
|
1366
|
-
function doesCheckContributeToExit(check, exitPolicy) {
|
|
1367
|
-
if (check.status !== "fail") {
|
|
1368
|
-
return false;
|
|
1369
|
-
}
|
|
1370
|
-
if (exitPolicy === "strict") {
|
|
1371
|
-
return true;
|
|
1372
|
-
}
|
|
1373
|
-
return check.scope === "workspace";
|
|
1374
|
-
}
|
|
1375
|
-
function toFailureSummary(check, severity) {
|
|
1376
|
-
return {
|
|
1377
|
-
...check.code ? { code: check.code } : {},
|
|
1378
|
-
label: check.label,
|
|
1379
|
-
scope: check.scope ?? "unknown",
|
|
1380
|
-
severity
|
|
1381
|
-
};
|
|
1382
|
-
}
|
|
1383
|
-
async function getDoctorChecks(cwd) {
|
|
1384
|
-
return [
|
|
1385
|
-
...annotateDoctorChecks(await getEnvironmentDoctorChecks(cwd), "environment"),
|
|
1386
|
-
...annotateDoctorChecks(await getWorkspaceDoctorChecks(cwd), "workspace")
|
|
1387
|
-
];
|
|
1388
|
-
}
|
|
1389
|
-
function getDoctorExitFailureChecks(checks, options = {}) {
|
|
1390
|
-
const exitPolicy = resolveDoctorExitPolicy(options);
|
|
1391
|
-
return checks.filter((check) => doesCheckContributeToExit(check, exitPolicy));
|
|
1392
|
-
}
|
|
1393
|
-
function getDoctorExitFailureDetailLines(checks, options = {}) {
|
|
1394
|
-
return getDoctorExitFailureChecks(checks, options).map((check) => `${check.label}: ${check.detail}`);
|
|
1395
|
-
}
|
|
1396
|
-
function createDoctorRunSummary(checks, options = {}) {
|
|
1397
|
-
const exitPolicy = resolveDoctorExitPolicy(options);
|
|
1398
|
-
const failedChecks = checks.filter((check) => check.status === "fail");
|
|
1399
|
-
const exitFailureChecks = failedChecks.filter((check) => doesCheckContributeToExit(check, exitPolicy));
|
|
1400
|
-
const advisoryFailureChecks = failedChecks.filter((check) => !doesCheckContributeToExit(check, exitPolicy));
|
|
1401
|
-
const warnings = checks.filter((check) => check.status === "warn").length;
|
|
1402
|
-
return {
|
|
1403
|
-
advisoryFailureCount: advisoryFailureChecks.length,
|
|
1404
|
-
advisoryFailures: advisoryFailureChecks.map((check) => toFailureSummary(check, "advisory")),
|
|
1405
|
-
exitCode: exitFailureChecks.length > 0 ? 1 : 0,
|
|
1406
|
-
exitFailureCount: exitFailureChecks.length,
|
|
1407
|
-
exitFailures: exitFailureChecks.map((check) => toFailureSummary(check, "error")),
|
|
1408
|
-
exitPolicy,
|
|
1409
|
-
failed: failedChecks.length,
|
|
1410
|
-
passed: checks.length - failedChecks.length - warnings,
|
|
1411
|
-
total: checks.length,
|
|
1412
|
-
warnings
|
|
1413
|
-
};
|
|
1414
|
-
}
|
|
1415
|
-
async function runDoctor(cwd, options = {}) {
|
|
1416
|
-
const exitPolicy = resolveDoctorExitPolicy(options);
|
|
1417
|
-
const renderLine = options.renderLine ?? renderDefaultDoctorCheckLine;
|
|
1418
|
-
const renderSummaryLine = options.renderSummaryLine ?? (options.renderLine ? () => {
|
|
1419
|
-
return;
|
|
1420
|
-
} : renderDefaultDoctorSummaryLine);
|
|
1421
|
-
const checks = await getDoctorChecks(cwd);
|
|
1422
|
-
for (const check of checks) {
|
|
1423
|
-
renderLine(check);
|
|
1424
|
-
}
|
|
1425
|
-
const exitFailureChecks = getDoctorExitFailureChecks(checks, { exitPolicy });
|
|
1426
|
-
renderSummaryLine(formatDoctorSummaryLine(checks, { exitFailureChecks }));
|
|
1427
|
-
const failureDetailLines = getDoctorExitFailureDetailLines(checks, { exitPolicy });
|
|
1428
|
-
if (failureDetailLines.length > 0) {
|
|
1429
|
-
throw createCliCommandError({
|
|
1430
|
-
code: CLI_DIAGNOSTIC_CODES.DOCTOR_CHECK_FAILED,
|
|
1431
|
-
command: "doctor",
|
|
1432
|
-
detailLines: failureDetailLines,
|
|
1433
|
-
summary: "One or more doctor checks failed."
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
return checks;
|
|
1437
|
-
}
|
|
1438
|
-
export {
|
|
1439
|
-
runDoctor,
|
|
1440
|
-
getDoctorExitFailureDetailLines,
|
|
1441
|
-
getDoctorExitFailureChecks,
|
|
1442
|
-
getDoctorChecks,
|
|
1443
|
-
createDoctorRunSummary
|
|
1444
|
-
};
|
|
1445
|
-
|
|
1446
|
-
//# debugId=7D607F817A3CF55764756E2164756E21
|