@wp-typia/project-tools 0.23.0 → 0.23.1
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/dist/runtime/ai-feature-artifacts.js +4 -1
- package/dist/runtime/block-generator-service-spec.js +2 -1
- package/dist/runtime/cli-add-block-json.js +5 -1
- package/dist/runtime/cli-add-help.js +4 -3
- package/dist/runtime/cli-add-types.d.ts +18 -6
- package/dist/runtime/cli-add-validation.d.ts +7 -0
- package/dist/runtime/cli-add-validation.js +9 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +4 -1
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +5 -1
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +18 -27
- package/dist/runtime/cli-add-workspace-admin-view-templates.js +30 -1326
- package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -1
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +17 -1
- package/dist/runtime/cli-add-workspace-integration-env.d.ts +3 -1
- package/dist/runtime/cli-add-workspace-integration-env.js +42 -5
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.js +41 -0
- package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +158 -0
- package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +279 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +678 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +25 -4
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
- package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
- package/dist/runtime/cli-add-workspace-rest.d.ts +3 -20
- package/dist/runtime/cli-add-workspace-rest.js +33 -788
- package/dist/runtime/cli-core.d.ts +1 -1
- package/dist/runtime/cli-core.js +1 -1
- package/dist/runtime/cli-diagnostics.d.ts +3 -1
- package/dist/runtime/cli-diagnostics.js +17 -5
- package/dist/runtime/cli-doctor-workspace-bindings.js +4 -1
- package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +134 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
- package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
- package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
- package/dist/runtime/cli-doctor-workspace-features.js +14 -487
- package/dist/runtime/cli-doctor.d.ts +52 -3
- package/dist/runtime/cli-doctor.js +79 -8
- package/dist/runtime/cli-help.js +6 -3
- package/dist/runtime/cli-init-package-json.js +4 -2
- package/dist/runtime/cli-prompt.d.ts +16 -2
- package/dist/runtime/cli-prompt.js +29 -12
- package/dist/runtime/cli-scaffold.d.ts +2 -1
- package/dist/runtime/cli-scaffold.js +19 -10
- package/dist/runtime/external-template-guards.js +4 -6
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/json-utils.d.ts +62 -4
- package/dist/runtime/json-utils.js +78 -4
- package/dist/runtime/local-dev-presets.js +4 -1
- package/dist/runtime/migration-ui-capability.js +4 -1
- package/dist/runtime/migration-utils.js +4 -1
- package/dist/runtime/package-managers.js +6 -1
- package/dist/runtime/package-versions.js +6 -1
- package/dist/runtime/scaffold-bootstrap.js +7 -2
- package/dist/runtime/scaffold-package-manager-files.js +5 -1
- package/dist/runtime/scaffold-repository-reference.js +4 -2
- package/dist/runtime/scaffold-template-variables.js +2 -1
- package/dist/runtime/scaffold.d.ts +18 -1
- package/dist/runtime/scaffold.js +55 -2
- package/dist/runtime/temp-roots.js +4 -1
- package/dist/runtime/template-layers.js +4 -1
- package/dist/runtime/template-registry.js +9 -3
- package/dist/runtime/template-source-contracts.d.ts +2 -0
- package/dist/runtime/template-source-normalization.js +2 -1
- package/dist/runtime/template-source-remote.js +18 -5
- package/dist/runtime/template-source-seeds.js +10 -3
- package/dist/runtime/workspace-inventory-mutations.js +2 -1
- package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
- package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
- package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
- package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
- package/dist/runtime/workspace-inventory-parser.d.ts +3 -45
- package/dist/runtime/workspace-inventory-parser.js +3 -581
- package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +435 -0
- package/dist/runtime/workspace-inventory-templates.d.ts +1 -1
- package/dist/runtime/workspace-inventory-templates.js +1 -0
- package/dist/runtime/workspace-inventory-types.d.ts +1 -0
- package/dist/runtime/workspace-project.js +4 -6
- package/package.json +2 -2
|
@@ -1,441 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
function isManualRestResource(restResource) {
|
|
8
|
-
return restResource.mode === "manual";
|
|
9
|
-
}
|
|
10
|
-
function getWorkspaceRestResourceRequiredFiles(restResource) {
|
|
11
|
-
const schemaNames = new Set();
|
|
12
|
-
if (isManualRestResource(restResource)) {
|
|
13
|
-
schemaNames.add("query");
|
|
14
|
-
if (restResource.bodyTypeName) {
|
|
15
|
-
schemaNames.add("request");
|
|
16
|
-
}
|
|
17
|
-
schemaNames.add("response");
|
|
18
|
-
return Array.from(new Set([
|
|
19
|
-
restResource.apiFile,
|
|
20
|
-
...Array.from(schemaNames, (schemaName) => path.join(path.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
21
|
-
restResource.clientFile,
|
|
22
|
-
restResource.openApiFile,
|
|
23
|
-
restResource.typesFile,
|
|
24
|
-
restResource.validatorsFile,
|
|
25
|
-
]));
|
|
26
|
-
}
|
|
27
|
-
if (restResource.methods.includes("list")) {
|
|
28
|
-
schemaNames.add("list-query");
|
|
29
|
-
schemaNames.add("list-response");
|
|
30
|
-
}
|
|
31
|
-
if (restResource.methods.includes("read")) {
|
|
32
|
-
schemaNames.add("read-query");
|
|
33
|
-
schemaNames.add("read-response");
|
|
34
|
-
}
|
|
35
|
-
if (restResource.methods.includes("create")) {
|
|
36
|
-
schemaNames.add("create-request");
|
|
37
|
-
schemaNames.add("create-response");
|
|
38
|
-
}
|
|
39
|
-
if (restResource.methods.includes("update")) {
|
|
40
|
-
schemaNames.add("update-query");
|
|
41
|
-
schemaNames.add("update-request");
|
|
42
|
-
schemaNames.add("update-response");
|
|
43
|
-
}
|
|
44
|
-
if (restResource.methods.includes("delete")) {
|
|
45
|
-
schemaNames.add("delete-query");
|
|
46
|
-
schemaNames.add("delete-response");
|
|
47
|
-
}
|
|
48
|
-
return Array.from(new Set([
|
|
49
|
-
restResource.apiFile,
|
|
50
|
-
...Array.from(schemaNames, (schemaName) => path.join(path.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
|
|
51
|
-
restResource.clientFile,
|
|
52
|
-
...(restResource.dataFile ? [restResource.dataFile] : []),
|
|
53
|
-
restResource.openApiFile,
|
|
54
|
-
...(restResource.phpFile ? [restResource.phpFile] : []),
|
|
55
|
-
restResource.typesFile,
|
|
56
|
-
restResource.validatorsFile,
|
|
57
|
-
]));
|
|
58
|
-
}
|
|
59
|
-
function checkWorkspaceRestResourceConfig(restResource) {
|
|
60
|
-
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(restResource.namespace);
|
|
61
|
-
if (isManualRestResource(restResource)) {
|
|
62
|
-
const hasAuth = restResource.auth == null ||
|
|
63
|
-
MANUAL_REST_CONTRACT_AUTH_IDS.includes(restResource.auth);
|
|
64
|
-
const hasMethod = typeof restResource.method === "string" &&
|
|
65
|
-
MANUAL_REST_CONTRACT_HTTP_METHOD_IDS.includes(restResource.method);
|
|
66
|
-
const hasPathPattern = typeof restResource.pathPattern === "string" &&
|
|
67
|
-
restResource.pathPattern.startsWith("/") &&
|
|
68
|
-
restResource.pathPattern.length > 1;
|
|
69
|
-
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasAuth && hasMethod && hasPathPattern ? "pass" : "fail", hasNamespace && hasAuth && hasMethod && hasPathPattern
|
|
70
|
-
? `Manual REST contract ${restResource.method} /${restResource.namespace}${restResource.pathPattern}`
|
|
71
|
-
: "Manual REST contract namespace, auth, method, or path pattern is invalid");
|
|
72
|
-
}
|
|
73
|
-
const hasMethods = restResource.methods.length > 0 &&
|
|
74
|
-
restResource.methods.every((method) => REST_RESOURCE_METHOD_IDS.includes(method));
|
|
75
|
-
const hasGeneratedFiles = typeof restResource.dataFile === "string" &&
|
|
76
|
-
restResource.dataFile.length > 0 &&
|
|
77
|
-
typeof restResource.phpFile === "string" &&
|
|
78
|
-
restResource.phpFile.length > 0;
|
|
79
|
-
const hasRoutePattern = restResource.routePattern == null ||
|
|
80
|
-
(typeof restResource.routePattern === "string" &&
|
|
81
|
-
restResource.routePattern.startsWith("/") &&
|
|
82
|
-
restResource.routePattern.length > 1 &&
|
|
83
|
-
!/\s/u.test(restResource.routePattern) &&
|
|
84
|
-
isGeneratedRestResourceRoutePatternCompatible(restResource.routePattern));
|
|
85
|
-
return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern
|
|
86
|
-
? "pass"
|
|
87
|
-
: "fail", hasNamespace && hasMethods && hasGeneratedFiles && hasRoutePattern
|
|
88
|
-
? `REST resource namespace ${restResource.namespace} with methods ${restResource.methods.join(", ")}`
|
|
89
|
-
: "REST resource namespace, methods, dataFile, phpFile, or routePattern are invalid");
|
|
90
|
-
}
|
|
91
|
-
function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
|
|
92
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
93
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
94
|
-
return createDoctorCheck("REST resource bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
95
|
-
}
|
|
96
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
97
|
-
const registerFunctionName = `${phpPrefix}_register_rest_resources`;
|
|
98
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
99
|
-
const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
|
|
100
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
101
|
-
return createDoctorCheck("REST resource bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook
|
|
102
|
-
? "REST resource PHP loader hook is present"
|
|
103
|
-
: "Missing REST resource PHP require glob or init hook");
|
|
104
|
-
}
|
|
105
|
-
function getWorkspacePostMetaRequiredFiles(postMeta) {
|
|
106
|
-
return Array.from(new Set([
|
|
107
|
-
postMeta.phpFile,
|
|
108
|
-
postMeta.schemaFile,
|
|
109
|
-
postMeta.typesFile,
|
|
110
|
-
]));
|
|
111
|
-
}
|
|
112
|
-
function checkWorkspacePostMetaConfig(postMeta) {
|
|
113
|
-
let hasPostType = false;
|
|
114
|
-
try {
|
|
115
|
-
hasPostType = assertValidPostMetaPostType(postMeta.postType) === postMeta.postType;
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
hasPostType = false;
|
|
119
|
-
}
|
|
120
|
-
const hasMetaKey = typeof postMeta.metaKey === "string" &&
|
|
121
|
-
postMeta.metaKey.trim().length > 0 &&
|
|
122
|
-
!/\s/u.test(postMeta.metaKey);
|
|
123
|
-
const hasRestExposure = typeof postMeta.showInRest === "boolean";
|
|
124
|
-
return createDoctorCheck(`Post meta config ${postMeta.slug}`, hasPostType && hasMetaKey && hasRestExposure ? "pass" : "fail", hasPostType && hasMetaKey && hasRestExposure
|
|
125
|
-
? `Post meta ${postMeta.metaKey} targets ${postMeta.postType}`
|
|
126
|
-
: "Post meta postType, metaKey, or showInRest configuration is invalid");
|
|
127
|
-
}
|
|
128
|
-
function checkWorkspacePostMetaBootstrap(projectDir, packageName, phpPrefix) {
|
|
129
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
130
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
131
|
-
return createDoctorCheck("Post meta bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
132
|
-
}
|
|
133
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
134
|
-
const registerFunctionName = `${phpPrefix}_register_post_meta_contracts`;
|
|
135
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
136
|
-
const hasServerGlob = source.includes(WORKSPACE_POST_META_GLOB);
|
|
137
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
138
|
-
return createDoctorCheck("Post meta bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook
|
|
139
|
-
? "Post meta PHP loader hook is present"
|
|
140
|
-
: "Missing post meta PHP require glob or init hook");
|
|
141
|
-
}
|
|
142
|
-
function checkWorkspacePostMetaPhp(projectDir, postMeta) {
|
|
143
|
-
const phpPath = path.join(projectDir, postMeta.phpFile);
|
|
144
|
-
if (!fs.existsSync(phpPath)) {
|
|
145
|
-
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, "fail", `Missing ${postMeta.phpFile}`);
|
|
146
|
-
}
|
|
147
|
-
const source = fs.readFileSync(phpPath, "utf8");
|
|
148
|
-
const hasRegisterPostMeta = source.includes("register_post_meta");
|
|
149
|
-
const hasPostType = source.includes(postMeta.postType);
|
|
150
|
-
const hasMetaKey = source.includes(postMeta.metaKey);
|
|
151
|
-
const hasSchemaFile = source.includes(postMeta.schemaFile);
|
|
152
|
-
const hasRestExposure = source.includes("'show_in_rest'");
|
|
153
|
-
return createDoctorCheck(`Post meta PHP ${postMeta.slug}`, hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure
|
|
154
|
-
? "pass"
|
|
155
|
-
: "fail", hasRegisterPostMeta && hasPostType && hasMetaKey && hasSchemaFile && hasRestExposure
|
|
156
|
-
? "Post meta registration, schema path, and REST exposure flag are wired"
|
|
157
|
-
: "Missing register_post_meta, post type, meta key, schema path, or show_in_rest wiring");
|
|
158
|
-
}
|
|
159
|
-
function getWorkspaceAbilityRequiredFiles(ability) {
|
|
160
|
-
return Array.from(new Set([
|
|
161
|
-
ability.clientFile,
|
|
162
|
-
ability.configFile,
|
|
163
|
-
ability.dataFile,
|
|
164
|
-
ability.inputSchemaFile,
|
|
165
|
-
ability.outputSchemaFile,
|
|
166
|
-
ability.phpFile,
|
|
167
|
-
ability.typesFile,
|
|
168
|
-
]));
|
|
169
|
-
}
|
|
170
|
-
function checkWorkspaceAbilityConfig(projectDir, ability) {
|
|
171
|
-
const configPath = path.join(projectDir, ability.configFile);
|
|
172
|
-
if (!fs.existsSync(configPath)) {
|
|
173
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
177
|
-
const abilityId = typeof config.abilityId === "string" ? config.abilityId.trim() : "";
|
|
178
|
-
const categorySlug = typeof config.category?.slug === "string"
|
|
179
|
-
? config.category.slug.trim()
|
|
180
|
-
: "";
|
|
181
|
-
const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
|
|
182
|
-
const hasValidCategorySlug = /^[a-z0-9-]+$/u.test(categorySlug);
|
|
183
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, hasValidAbilityId && hasValidCategorySlug ? "pass" : "fail", hasValidAbilityId && hasValidCategorySlug
|
|
184
|
-
? `Ability id ${abilityId} in category ${categorySlug} is valid`
|
|
185
|
-
: "Ability config must define a valid abilityId (`namespace/ability-name`) and category.slug.");
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
return createDoctorCheck(`Ability config ${ability.slug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
192
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
193
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
194
|
-
return createDoctorCheck("Ability bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
195
|
-
}
|
|
196
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
197
|
-
const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
|
|
198
|
-
const enqueueFunctionName = `${phpPrefix}_enqueue_workflow_abilities`;
|
|
199
|
-
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
200
|
-
const adminEnqueueHook = `add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );`;
|
|
201
|
-
const editorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
202
|
-
const hasLoaderHook = source.includes(loadHook);
|
|
203
|
-
const hasAdminEnqueueHook = source.includes(adminEnqueueHook);
|
|
204
|
-
const hasEditorEnqueueHook = source.includes(editorEnqueueHook);
|
|
205
|
-
const hasServerGlob = source.includes(WORKSPACE_ABILITY_GLOB);
|
|
206
|
-
const hasEditorScript = source.includes(WORKSPACE_ABILITY_EDITOR_SCRIPT);
|
|
207
|
-
const hasEditorAsset = source.includes(WORKSPACE_ABILITY_EDITOR_ASSET);
|
|
208
|
-
const hasScriptModuleEnqueue = source.includes("wp_enqueue_script_module");
|
|
209
|
-
return createDoctorCheck("Ability bootstrap", hasLoaderHook &&
|
|
210
|
-
hasAdminEnqueueHook &&
|
|
211
|
-
hasEditorEnqueueHook &&
|
|
212
|
-
hasServerGlob &&
|
|
213
|
-
hasEditorScript &&
|
|
214
|
-
hasEditorAsset &&
|
|
215
|
-
hasScriptModuleEnqueue
|
|
216
|
-
? "pass"
|
|
217
|
-
: "fail", hasLoaderHook &&
|
|
218
|
-
hasAdminEnqueueHook &&
|
|
219
|
-
hasEditorEnqueueHook &&
|
|
220
|
-
hasServerGlob &&
|
|
221
|
-
hasEditorScript &&
|
|
222
|
-
hasEditorAsset &&
|
|
223
|
-
hasScriptModuleEnqueue
|
|
224
|
-
? "Ability loader and admin/editor script-module bootstrap hooks are present"
|
|
225
|
-
: "Missing ability loader hook, script-module enqueue, or build/abilities asset references");
|
|
226
|
-
}
|
|
227
|
-
function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
228
|
-
const indexRelativePath = [
|
|
229
|
-
path.join("src", "abilities", "index.ts"),
|
|
230
|
-
path.join("src", "abilities", "index.js"),
|
|
231
|
-
].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
|
|
232
|
-
if (!indexRelativePath) {
|
|
233
|
-
return createDoctorCheck("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
|
|
234
|
-
}
|
|
235
|
-
const indexPath = path.join(projectDir, indexRelativePath);
|
|
236
|
-
const source = fs.readFileSync(indexPath, "utf8");
|
|
237
|
-
const missingExports = abilities.filter((ability) => {
|
|
238
|
-
const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex(ability.slug)}\\/client['"\`]`, "mu");
|
|
239
|
-
return !exportPattern.test(source);
|
|
240
|
-
});
|
|
241
|
-
return createDoctorCheck("Abilities index", missingExports.length === 0 ? "pass" : "fail", missingExports.length === 0
|
|
242
|
-
? "Ability client helpers are aggregated"
|
|
243
|
-
: `Missing ability exports for: ${missingExports.map((entry) => entry.slug).join(", ")}`);
|
|
244
|
-
}
|
|
245
|
-
function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
|
|
246
|
-
return Array.from(new Set([
|
|
247
|
-
aiFeature.aiSchemaFile,
|
|
248
|
-
aiFeature.apiFile,
|
|
249
|
-
path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
|
|
250
|
-
path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
|
|
251
|
-
path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
|
|
252
|
-
aiFeature.clientFile,
|
|
253
|
-
aiFeature.dataFile,
|
|
254
|
-
aiFeature.openApiFile,
|
|
255
|
-
aiFeature.phpFile,
|
|
256
|
-
aiFeature.typesFile,
|
|
257
|
-
aiFeature.validatorsFile,
|
|
258
|
-
]));
|
|
259
|
-
}
|
|
260
|
-
function checkWorkspaceAiFeatureConfig(aiFeature) {
|
|
261
|
-
const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(aiFeature.namespace);
|
|
262
|
-
return createDoctorCheck(`AI feature config ${aiFeature.slug}`, hasNamespace ? "pass" : "fail", hasNamespace
|
|
263
|
-
? `AI feature namespace ${aiFeature.namespace} is valid`
|
|
264
|
-
: "AI feature namespace is invalid");
|
|
265
|
-
}
|
|
266
|
-
function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
|
|
267
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
268
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
269
|
-
return createDoctorCheck("AI feature bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
270
|
-
}
|
|
271
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
272
|
-
const registerFunctionName = `${phpPrefix}_register_ai_features`;
|
|
273
|
-
const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
|
|
274
|
-
const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
|
|
275
|
-
const hasRegisterHook = source.includes(registerHook);
|
|
276
|
-
return createDoctorCheck("AI feature bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook
|
|
277
|
-
? "AI feature PHP loader hook is present"
|
|
278
|
-
: "Missing AI feature PHP require glob or init hook");
|
|
279
|
-
}
|
|
280
|
-
function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
|
|
281
|
-
const editorPluginDir = path.join("src", "editor-plugins", editorPlugin.slug);
|
|
282
|
-
const surfaceFile = editorPlugin.slot === "PluginSidebar"
|
|
283
|
-
? path.join(editorPluginDir, "Sidebar.tsx")
|
|
284
|
-
: path.join(editorPluginDir, "Surface.tsx");
|
|
285
|
-
return Array.from(new Set([
|
|
286
|
-
editorPlugin.file,
|
|
287
|
-
surfaceFile,
|
|
288
|
-
path.join(editorPluginDir, "data.ts"),
|
|
289
|
-
path.join(editorPluginDir, "types.ts"),
|
|
290
|
-
path.join(editorPluginDir, "style.scss"),
|
|
291
|
-
]));
|
|
292
|
-
}
|
|
293
|
-
function checkWorkspaceEditorPluginConfig(editorPlugin) {
|
|
294
|
-
const normalizedSlot = resolveEditorPluginSlotAlias(editorPlugin.slot);
|
|
295
|
-
const isValidSlot = Boolean(normalizedSlot);
|
|
296
|
-
return createDoctorCheck(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot
|
|
297
|
-
? `Editor plugin slot ${editorPlugin.slot} is supported as ${normalizedSlot}`
|
|
298
|
-
: `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")} or legacy aliases PluginSidebar, PluginDocumentSettingPanel.`);
|
|
299
|
-
}
|
|
300
|
-
function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
|
|
301
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
302
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
303
|
-
return createDoctorCheck("Editor plugin bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
304
|
-
}
|
|
305
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
306
|
-
const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
|
|
307
|
-
const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
308
|
-
const hasEditorEnqueueHook = source.includes(enqueueHook);
|
|
309
|
-
const hasEditorScript = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT);
|
|
310
|
-
const hasEditorAsset = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET);
|
|
311
|
-
const hasEditorStyle = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE);
|
|
312
|
-
return createDoctorCheck("Editor plugin bootstrap", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "pass" : "fail", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle
|
|
313
|
-
? "Editor plugin enqueue hook is present"
|
|
314
|
-
: "Missing editor plugin enqueue hook or build/editor-plugins script/style asset references");
|
|
315
|
-
}
|
|
316
|
-
function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
|
|
317
|
-
const indexRelativePath = [
|
|
318
|
-
path.join("src", "editor-plugins", "index.ts"),
|
|
319
|
-
path.join("src", "editor-plugins", "index.js"),
|
|
320
|
-
].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
|
|
321
|
-
if (!indexRelativePath) {
|
|
322
|
-
return createDoctorCheck("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
|
|
323
|
-
}
|
|
324
|
-
const indexPath = path.join(projectDir, indexRelativePath);
|
|
325
|
-
const source = fs.readFileSync(indexPath, "utf8");
|
|
326
|
-
const missingImports = editorPlugins.filter((editorPlugin) => {
|
|
327
|
-
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
328
|
-
return !importPattern.test(source);
|
|
329
|
-
});
|
|
330
|
-
return createDoctorCheck("Editor plugins index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0
|
|
331
|
-
? "Editor plugin registrations are aggregated"
|
|
332
|
-
: `Missing editor plugin imports for: ${missingImports
|
|
333
|
-
.map((entry) => entry.slug)
|
|
334
|
-
.join(", ")}`);
|
|
335
|
-
}
|
|
336
|
-
function getWorkspaceAdminViewRequiredFiles(adminView) {
|
|
337
|
-
const adminViewDir = path.join("src", "admin-views", adminView.slug);
|
|
338
|
-
return Array.from(new Set([
|
|
339
|
-
adminView.file,
|
|
340
|
-
adminView.phpFile,
|
|
341
|
-
path.join(adminViewDir, "Screen.tsx"),
|
|
342
|
-
path.join(adminViewDir, "config.ts"),
|
|
343
|
-
path.join(adminViewDir, "data.ts"),
|
|
344
|
-
path.join(adminViewDir, "style.scss"),
|
|
345
|
-
path.join(adminViewDir, "types.ts"),
|
|
346
|
-
]));
|
|
347
|
-
}
|
|
348
|
-
function checkWorkspaceAdminViewConfig(adminView, inventory) {
|
|
349
|
-
if (adminView.source === undefined) {
|
|
350
|
-
return createDoctorCheck(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
|
|
351
|
-
}
|
|
352
|
-
const source = adminView.source.trim();
|
|
353
|
-
const restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
|
|
354
|
-
const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
|
|
355
|
-
const restResourceSlug = restSourceMatch?.[1];
|
|
356
|
-
const restResource = restResourceSlug
|
|
357
|
-
? inventory.restResources.find((entry) => entry.slug === restResourceSlug)
|
|
358
|
-
: undefined;
|
|
359
|
-
const isListCapableRestResource = Boolean(restResource?.methods.includes("list"));
|
|
360
|
-
const isManualSettingsRestResource = isAdminViewManualSettingsRestResource(restResource);
|
|
361
|
-
const hasManualSettingsRouteParameters = isManualSettingsRestResource &&
|
|
362
|
-
hasAdminViewManualSettingsRouteParameters(restResource);
|
|
363
|
-
const isValid = isListCapableRestResource ||
|
|
364
|
-
(isManualSettingsRestResource && !hasManualSettingsRouteParameters) ||
|
|
365
|
-
Boolean(coreDataSourceMatch);
|
|
366
|
-
const failDetail = hasManualSettingsRouteParameters
|
|
367
|
-
? `Admin view source ${source} uses route parameters or regex groups and cannot scaffold a singleton settings form`
|
|
368
|
-
: "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>";
|
|
369
|
-
return createDoctorCheck(`Admin view config ${adminView.slug}`, isValid ? "pass" : "fail", isValid
|
|
370
|
-
? `Admin view source ${source} is ${isManualSettingsRestResource
|
|
371
|
-
? "settings-form capable"
|
|
372
|
-
: coreDataSourceMatch
|
|
373
|
-
? "core-data capable"
|
|
374
|
-
: "list-capable"}`
|
|
375
|
-
: failDetail);
|
|
376
|
-
}
|
|
377
|
-
function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
|
|
378
|
-
const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
|
|
379
|
-
if (!fs.existsSync(bootstrapPath)) {
|
|
380
|
-
return createDoctorCheck("Admin view bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
381
|
-
}
|
|
382
|
-
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
383
|
-
const loadFunctionName = `${phpPrefix}_load_admin_views`;
|
|
384
|
-
const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
|
|
385
|
-
const hasLoaderHook = source.includes(loadHook);
|
|
386
|
-
const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
|
|
387
|
-
return createDoctorCheck("Admin view bootstrap", hasLoaderHook && hasServerGlob ? "pass" : "fail", hasLoaderHook && hasServerGlob
|
|
388
|
-
? "Admin view PHP loader hook is present"
|
|
389
|
-
: "Missing admin view PHP require glob or plugins_loaded hook");
|
|
390
|
-
}
|
|
391
|
-
function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
|
|
392
|
-
const indexRelativePath = [
|
|
393
|
-
path.join("src", "admin-views", "index.ts"),
|
|
394
|
-
path.join("src", "admin-views", "index.js"),
|
|
395
|
-
].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
|
|
396
|
-
if (!indexRelativePath) {
|
|
397
|
-
return createDoctorCheck("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
|
|
398
|
-
}
|
|
399
|
-
const indexPath = path.join(projectDir, indexRelativePath);
|
|
400
|
-
const source = fs.readFileSync(indexPath, "utf8");
|
|
401
|
-
const missingImports = adminViews.filter((adminView) => {
|
|
402
|
-
const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
|
|
403
|
-
return !importPattern.test(source);
|
|
404
|
-
});
|
|
405
|
-
return createDoctorCheck("Admin views index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0
|
|
406
|
-
? "Admin view registrations are aggregated"
|
|
407
|
-
: `Missing admin view imports for: ${missingImports
|
|
408
|
-
.map((entry) => entry.slug)
|
|
409
|
-
.join(", ")}`);
|
|
410
|
-
}
|
|
411
|
-
function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
412
|
-
const phpPath = path.join(projectDir, adminView.phpFile);
|
|
413
|
-
if (!fs.existsSync(phpPath)) {
|
|
414
|
-
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
|
|
415
|
-
}
|
|
416
|
-
const source = fs.readFileSync(phpPath, "utf8");
|
|
417
|
-
const hasAdminMenu = source.includes("add_submenu_page");
|
|
418
|
-
const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
|
|
419
|
-
const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
|
|
420
|
-
const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
|
|
421
|
-
const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
|
|
422
|
-
const hasComponentsStyleDependency = source.includes("'wp-components'");
|
|
423
|
-
return createDoctorCheck(`Admin view PHP ${adminView.slug}`, hasAdminMenu &&
|
|
424
|
-
hasAdminEnqueue &&
|
|
425
|
-
hasScript &&
|
|
426
|
-
hasAsset &&
|
|
427
|
-
hasStyle &&
|
|
428
|
-
hasComponentsStyleDependency
|
|
429
|
-
? "pass"
|
|
430
|
-
: "fail", hasAdminMenu &&
|
|
431
|
-
hasAdminEnqueue &&
|
|
432
|
-
hasScript &&
|
|
433
|
-
hasAsset &&
|
|
434
|
-
hasStyle &&
|
|
435
|
-
hasComponentsStyleDependency
|
|
436
|
-
? "Admin menu, script, style, and wp-components style dependency are wired"
|
|
437
|
-
: "Missing admin menu, enqueue hook, build/admin-views asset reference, or wp-components style dependency");
|
|
438
|
-
}
|
|
1
|
+
import { getWorkspaceAbilityDoctorChecks, } from "./cli-doctor-workspace-features-abilities.js";
|
|
2
|
+
import { getWorkspaceAdminViewDoctorChecks, } from "./cli-doctor-workspace-features-admin-views.js";
|
|
3
|
+
import { getWorkspaceAiFeatureDoctorChecks, } from "./cli-doctor-workspace-features-ai.js";
|
|
4
|
+
import { getWorkspaceEditorPluginDoctorChecks, } from "./cli-doctor-workspace-features-editor-plugins.js";
|
|
5
|
+
import { getWorkspacePostMetaDoctorChecks, } from "./cli-doctor-workspace-features-post-meta.js";
|
|
6
|
+
import { getWorkspaceRestResourceDoctorChecks, } from "./cli-doctor-workspace-features-rest.js";
|
|
439
7
|
/**
|
|
440
8
|
* Collect workspace doctor checks for REST resources, abilities, AI features, editor plugins, and admin views.
|
|
441
9
|
*
|
|
@@ -444,53 +12,12 @@ function checkWorkspaceAdminViewPhp(projectDir, adminView) {
|
|
|
444
12
|
* @returns Ordered `DoctorCheck[]` rows for extracted workspace feature diagnostics.
|
|
445
13
|
*/
|
|
446
14
|
export function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
if (inventory.postMeta.length > 0) {
|
|
456
|
-
checks.push(checkWorkspacePostMetaBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
457
|
-
}
|
|
458
|
-
for (const postMeta of inventory.postMeta) {
|
|
459
|
-
checks.push(checkWorkspacePostMetaConfig(postMeta));
|
|
460
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Post meta ${postMeta.slug}`, getWorkspacePostMetaRequiredFiles(postMeta)));
|
|
461
|
-
checks.push(checkWorkspacePostMetaPhp(workspace.projectDir, postMeta));
|
|
462
|
-
}
|
|
463
|
-
if (inventory.abilities.length > 0) {
|
|
464
|
-
checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
465
|
-
checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
|
|
466
|
-
}
|
|
467
|
-
for (const ability of inventory.abilities) {
|
|
468
|
-
checks.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
|
|
469
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
|
|
470
|
-
}
|
|
471
|
-
if (inventory.aiFeatures.length > 0) {
|
|
472
|
-
checks.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
473
|
-
}
|
|
474
|
-
for (const aiFeature of inventory.aiFeatures) {
|
|
475
|
-
checks.push(checkWorkspaceAiFeatureConfig(aiFeature));
|
|
476
|
-
checks.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
|
|
477
|
-
}
|
|
478
|
-
if (inventory.editorPlugins.length > 0) {
|
|
479
|
-
checks.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
480
|
-
checks.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
|
|
481
|
-
}
|
|
482
|
-
for (const editorPlugin of inventory.editorPlugins) {
|
|
483
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
|
|
484
|
-
checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
|
|
485
|
-
}
|
|
486
|
-
if (inventory.adminViews.length > 0) {
|
|
487
|
-
checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
|
|
488
|
-
checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
|
|
489
|
-
}
|
|
490
|
-
for (const adminView of inventory.adminViews) {
|
|
491
|
-
checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
|
|
492
|
-
checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
|
|
493
|
-
checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
|
|
494
|
-
}
|
|
495
|
-
return checks;
|
|
15
|
+
return [
|
|
16
|
+
...getWorkspaceRestResourceDoctorChecks(workspace, inventory.restResources),
|
|
17
|
+
...getWorkspacePostMetaDoctorChecks(workspace, inventory.postMeta),
|
|
18
|
+
...getWorkspaceAbilityDoctorChecks(workspace, inventory.abilities),
|
|
19
|
+
...getWorkspaceAiFeatureDoctorChecks(workspace, inventory.aiFeatures),
|
|
20
|
+
...getWorkspaceEditorPluginDoctorChecks(workspace, inventory.editorPlugins),
|
|
21
|
+
...getWorkspaceAdminViewDoctorChecks(workspace, inventory),
|
|
22
|
+
];
|
|
496
23
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Scope bucket used by doctor exit policies and JSON summaries. */
|
|
2
|
+
export type DoctorCheckScope = "environment" | "workspace";
|
|
3
|
+
/** Policy used to decide which failed checks should fail the process. */
|
|
4
|
+
export type DoctorExitPolicy = "strict" | "workspace-only";
|
|
1
5
|
/**
|
|
2
6
|
* One doctor check rendered by the CLI diagnostics flow.
|
|
3
7
|
*/
|
|
@@ -8,13 +12,39 @@ export interface DoctorCheck {
|
|
|
8
12
|
detail: string;
|
|
9
13
|
/** Short label for the dependency, directory, or template check. */
|
|
10
14
|
label: string;
|
|
15
|
+
/** Scope bucket used by machine-readable summaries and exit-code policies. */
|
|
16
|
+
scope?: DoctorCheckScope;
|
|
11
17
|
/** Final pass/fail/warn status for this diagnostic row. */
|
|
12
18
|
status: "pass" | "fail" | "warn";
|
|
13
19
|
}
|
|
20
|
+
/** One failed row classified against the active doctor exit policy. */
|
|
21
|
+
export interface DoctorFailureSummary {
|
|
22
|
+
code?: string;
|
|
23
|
+
label: string;
|
|
24
|
+
scope: DoctorCheckScope | "unknown";
|
|
25
|
+
severity: "advisory" | "error";
|
|
26
|
+
}
|
|
27
|
+
/** Stable JSON summary for `wp-typia doctor --format json`. */
|
|
28
|
+
export interface DoctorRunSummary {
|
|
29
|
+
advisoryFailureCount: number;
|
|
30
|
+
advisoryFailures: DoctorFailureSummary[];
|
|
31
|
+
exitCode: 0 | 1;
|
|
32
|
+
exitFailureCount: number;
|
|
33
|
+
exitFailures: DoctorFailureSummary[];
|
|
34
|
+
exitPolicy: DoctorExitPolicy;
|
|
35
|
+
failed: number;
|
|
36
|
+
passed: number;
|
|
37
|
+
total: number;
|
|
38
|
+
warnings: number;
|
|
39
|
+
}
|
|
14
40
|
interface RunDoctorOptions {
|
|
41
|
+
exitPolicy?: DoctorExitPolicy;
|
|
15
42
|
renderLine?: (check: DoctorCheck) => void;
|
|
16
43
|
renderSummaryLine?: (summaryLine: string) => void;
|
|
17
44
|
}
|
|
45
|
+
interface DoctorSummaryOptions {
|
|
46
|
+
exitPolicy?: DoctorExitPolicy;
|
|
47
|
+
}
|
|
18
48
|
/**
|
|
19
49
|
* Collect all runtime doctor checks for the current environment.
|
|
20
50
|
*
|
|
@@ -28,12 +58,31 @@ interface RunDoctorOptions {
|
|
|
28
58
|
*/
|
|
29
59
|
export declare function getDoctorChecks(cwd: string): Promise<DoctorCheck[]>;
|
|
30
60
|
/**
|
|
31
|
-
*
|
|
61
|
+
* Return failed rows that contribute to the process exit code for one policy.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getDoctorExitFailureChecks(checks: readonly DoctorCheck[], options?: DoctorSummaryOptions): DoctorCheck[];
|
|
64
|
+
/**
|
|
65
|
+
* Format only exit-contributing doctor failures for structured diagnostics.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getDoctorExitFailureDetailLines(checks: readonly DoctorCheck[], options?: DoctorSummaryOptions): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Build the stable JSON summary for one doctor run.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createDoctorRunSummary(checks: readonly DoctorCheck[], options?: DoctorSummaryOptions): DoctorRunSummary;
|
|
72
|
+
/**
|
|
73
|
+
* Run doctor checks, render each line, and fail when one or more failed checks
|
|
74
|
+
* contribute to the exit code under the active exit policy.
|
|
75
|
+
*
|
|
76
|
+
* The default `strict` policy treats every failed row as exit-contributing.
|
|
77
|
+
* The `workspace-only` policy only fails on workspace-scoped rows so
|
|
78
|
+
* environment/runtime failures remain advisory for CI gates that only care
|
|
79
|
+
* about generated workspace artifacts.
|
|
32
80
|
*
|
|
33
81
|
* @param cwd Working directory to validate.
|
|
34
|
-
* @param options Optional renderer
|
|
82
|
+
* @param options Optional renderer overrides and exit-policy selection.
|
|
83
|
+
* @param options.exitPolicy Policy deciding which failed checks contribute to the process exit code.
|
|
35
84
|
* @returns The completed list of doctor checks.
|
|
36
|
-
* @throws {Error} When one or more checks
|
|
85
|
+
* @throws {Error} When one or more failed checks contribute to the exit code under the active policy.
|
|
37
86
|
*/
|
|
38
87
|
export declare function runDoctor(cwd: string, options?: RunDoctorOptions): Promise<DoctorCheck[]>;
|
|
39
88
|
export {};
|