@wp-typia/project-tools 0.24.6 → 0.24.8
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/cli/cli-core.d.ts +1 -1
- package/dist/runtime/cli/cli-help.js +10 -9
- package/dist/runtime/doctor/cli-doctor-wordpress-version.d.ts +15 -0
- package/dist/runtime/doctor/cli-doctor-wordpress-version.js +239 -0
- package/dist/runtime/doctor/cli-doctor-workspace.d.ts +10 -3
- package/dist/runtime/doctor/cli-doctor-workspace.js +9 -3
- package/dist/runtime/doctor/cli-doctor.d.ts +10 -1
- package/dist/runtime/doctor/cli-doctor.js +10 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/templates/block-generator-service-core.d.ts +1 -1
- package/dist/runtime/templates/block-generator-service-core.js +2 -1
- package/dist/runtime/templates/block-generator-service-spec.d.ts +4 -1
- package/dist/runtime/templates/block-generator-service-spec.js +6 -3
- package/dist/runtime/templates/cli-scaffold-emission.d.ts +4 -0
- package/dist/runtime/templates/cli-scaffold.d.ts +2 -1
- package/dist/runtime/templates/cli-scaffold.js +4 -1
- package/dist/runtime/templates/scaffold-compatibility.d.ts +29 -0
- package/dist/runtime/templates/scaffold-compatibility.js +43 -0
- package/dist/runtime/templates/scaffold-template-variables.d.ts +12 -1
- package/dist/runtime/templates/scaffold-template-variables.js +7 -3
- package/dist/runtime/templates/scaffold.d.ts +3 -1
- package/dist/runtime/templates/scaffold.js +4 -1
- package/dist/runtime/workspace/workspace-inventory-parser-entries.js +106 -3
- package/dist/runtime/workspace/workspace-inventory-parser-validation.d.ts +3 -2
- package/dist/runtime/workspace/workspace-inventory-section-descriptors.js +2 -0
- package/dist/runtime/workspace/workspace-inventory-types.d.ts +3 -0
- package/package.json +3 -3
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* `getTemplateSelectOptions`, `listTemplates`, and `isBuiltInTemplateId` for
|
|
31
31
|
* template inspection flows.
|
|
32
32
|
*/
|
|
33
|
-
export { createDoctorRunSummary, getDoctorChecks, getDoctorExitFailureChecks, getDoctorExitFailureDetailLines, runDoctor, type DoctorCheck, type DoctorCheckScope, type DoctorExitPolicy, type DoctorFailureSummary, type DoctorRunSummary, } from "../doctor/cli-doctor.js";
|
|
33
|
+
export { createDoctorRunSummary, getDoctorChecks, getDoctorExitFailureChecks, getDoctorExitFailureDetailLines, runDoctor, type DoctorCheck, type DoctorCheckScope, type DoctorExitPolicy, type DoctorFailureSummary, type DoctorRunSummary, type GetDoctorChecksOptions, } from "../doctor/cli-doctor.js";
|
|
34
34
|
export { createCliCommandError, createCliDiagnosticCodeError, CliDiagnosticError, CLI_DIAGNOSTIC_CODE_METADATA, CLI_DIAGNOSTIC_CODES, formatCliDiagnosticError, formatDoctorCheckLine, formatDoctorSummaryLine, getCliDiagnosticCodeMetadata, getDoctorFailureDetailLines, getFailingDoctorChecks, isCliDiagnosticError, } from "./cli-diagnostics.js";
|
|
35
35
|
export type { CliDiagnosticCode, CliDiagnosticCodeError, CliDiagnosticMessage, } from "./cli-diagnostics.js";
|
|
36
36
|
export { EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, getWorkspaceBlockSelectOptions, getWorkspaceBlockSelectOptionsAsync, PATTERN_CATALOG_SCOPE_IDS, runAddAdminViewCommand, runAddAbilityCommand, runAddBindingSourceCommand, runAddAiFeatureCommand, runAddBlockCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddContractCommand, runAddCoreVariationCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddPostMetaCommand, runAddRestResourceCommand, runAddVariationCommand, seedWorkspaceMigrationProject, } from "../add/cli-add.js";
|
|
@@ -10,13 +10,13 @@ import { TEMPLATE_IDS } from "../templates/template-registry.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export function formatHelpText() {
|
|
12
12
|
return `Usage:
|
|
13
|
-
wp-typia create <project-dir> [--template <basic|interactivity>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
14
|
-
wp-typia create <project-dir> [--template workspace] [--profile <plugin-qa>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
15
|
-
wp-typia create <project-dir> [--template query-loop] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--query-post-type <post-type>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
16
|
-
wp-typia create <project-dir> [--template <./path|github:owner/repo/path[#ref]>] [--variant <name>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
17
|
-
wp-typia create <project-dir> [--template <npm-package>] [--variant <name>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
18
|
-
wp-typia create <project-dir> [--template persistence] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
19
|
-
wp-typia create <project-dir> [--template compound] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
13
|
+
wp-typia create <project-dir> [--template <basic|interactivity>] [--wp-version <6.9|7.0>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
14
|
+
wp-typia create <project-dir> [--template workspace] [--wp-version <6.9|7.0>] [--profile <plugin-qa>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
15
|
+
wp-typia create <project-dir> [--template query-loop] [--wp-version <6.9|7.0>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--query-post-type <post-type>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
16
|
+
wp-typia create <project-dir> [--template <./path|github:owner/repo/path[#ref]>] [--wp-version <6.9|7.0>] [--variant <name>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
17
|
+
wp-typia create <project-dir> [--template <npm-package>] [--wp-version <6.9|7.0>] [--variant <name>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
18
|
+
wp-typia create <project-dir> [--template persistence] [--wp-version <6.9|7.0>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
19
|
+
wp-typia create <project-dir> [--template compound] [--wp-version <6.9|7.0>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--namespace <value>] [--text-domain <value>] [--php-prefix <value>] [--with-migration-ui] [--with-wp-env] [--with-test-preset] [--yes] [--dry-run] [--no-install] [--package-manager <id>]
|
|
20
20
|
wp-typia <project-dir> [create flags...]
|
|
21
21
|
wp-typia init [project-dir] [--apply] [--package-manager <id>]
|
|
22
22
|
wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>]
|
|
@@ -39,7 +39,7 @@ export function formatHelpText() {
|
|
|
39
39
|
wp-typia migrate <init|snapshot|diff|scaffold|verify|doctor|fixtures|fuzz> [...]
|
|
40
40
|
wp-typia templates list
|
|
41
41
|
wp-typia templates inspect <id>
|
|
42
|
-
wp-typia doctor
|
|
42
|
+
wp-typia doctor [--wp-version-check]
|
|
43
43
|
wp-typia mcp <list|sync>
|
|
44
44
|
wp-typia skills <list|sync>
|
|
45
45
|
wp-typia completions <bash|zsh|fish|powershell>
|
|
@@ -55,6 +55,7 @@ Notes:
|
|
|
55
55
|
\`wp-typia init\` previews the minimum retrofit sync surface by default; rerun with \`--apply\` to write package.json updates and generated helper scripts.
|
|
56
56
|
Use \`--template workspace\` as shorthand for \`@wp-typia/create-workspace-template\`, the official empty workspace scaffold behind \`wp-typia add ...\`.
|
|
57
57
|
Use \`--profile plugin-qa\` with \`--template workspace\` when a plugin needs local wp-env smoke checks, \`.env.example\`, and release zip scripts from day one; omit it for the minimal workspace shell.
|
|
58
|
+
Use \`--wp-version 6.9\` to keep legacy \`Tested up to: 6.9\` headers; new scaffolds default to WordPress 7.0 while keeping \`Requires at least\` at the selected feature floor.
|
|
58
59
|
Interactive add flows let you choose a template when \`--template\` is omitted; non-interactive runs default to \`basic\`.
|
|
59
60
|
Unknown \`core/*\` targets for \`add core-variation\` warn instead of failing so newer WordPress core blocks remain scaffoldable; third-party namespaces are allowed without local discovery.
|
|
60
61
|
\`add admin-view\` scaffolds an opt-in DataViews-powered WordPress admin screen under \`src/admin-views/\`.
|
|
@@ -77,7 +78,7 @@ Notes:
|
|
|
77
78
|
\`add ai-feature\` scaffolds server-owned AI feature endpoints under \`src/ai-features/\` and PHP route glue under \`inc/ai-features/\`.
|
|
78
79
|
\`add editor-plugin\` scaffolds a document-level editor extension under \`src/editor-plugins/\`; legacy aliases \`PluginSidebar\` and \`PluginDocumentSettingPanel\` resolve to \`sidebar\` and \`document-setting-panel\`.
|
|
79
80
|
\`add hooked-block\` patches an existing workspace block's \`block.json\` \`blockHooks\` metadata.
|
|
80
|
-
\`wp-typia doctor\` always checks environment readiness and reports when it only ran environment-level diagnostics; official workspace roots also get inventory, source-tree drift, shared convention checks, and iframe/API v3 compatibility checks.
|
|
81
|
+
\`wp-typia doctor\` always checks environment readiness and reports when it only ran environment-level diagnostics; official workspace roots also get inventory, source-tree drift, shared convention checks, and iframe/API v3 compatibility checks. Pass \`--wp-version-check\` to compare generated feature floors such as block supports, blockHooks, abilities, and AI feature metadata with plugin bootstrap compatibility headers.
|
|
81
82
|
\`wp-typia init\` previews or applies the minimum sync/doctor/migration adoption layer for supported existing layouts; pass \`--package-manager <id>\` to pin emitted scripts and next steps.
|
|
82
83
|
\`wp-typia migrate doctor --all\` checks migration target alignment, snapshots, fixtures, and generated migration artifacts.
|
|
83
84
|
\`migrate\` is the canonical migration command; \`migrations\` is no longer supported.`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DoctorCheck } from "./cli-doctor.js";
|
|
2
|
+
import type { WorkspaceInventory } from "../workspace/workspace-inventory.js";
|
|
3
|
+
import type { WorkspaceProject } from "../workspace/workspace-project.js";
|
|
4
|
+
/** Options for opt-in WordPress version compatibility doctor checks. */
|
|
5
|
+
export interface WorkspaceWordPressVersionDoctorCheckOptions {
|
|
6
|
+
/** WordPress target used for `Tested up to` warnings. Defaults to the scaffold target. */
|
|
7
|
+
targetVersion?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Collect opt-in WordPress feature floor checks for an official workspace.
|
|
11
|
+
*
|
|
12
|
+
* These checks compare generated feature metadata against plugin bootstrap
|
|
13
|
+
* headers without changing the default doctor output shape.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getWorkspaceWordPressVersionDoctorChecks(workspace: WorkspaceProject, inventory: WorkspaceInventory, options?: WorkspaceWordPressVersionDoctorCheckOptions): DoctorCheck[];
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
4
|
+
import { WORDPRESS_BLOCK_API_COMPATIBILITY } from "@wp-typia/block-types/blocks/compatibility";
|
|
5
|
+
import { createDoctorCheck, resolveWorkspaceBootstrapPath, } from "./cli-doctor-workspace-shared.js";
|
|
6
|
+
import { readJsonFileSync } from "../shared/json-utils.js";
|
|
7
|
+
import { compareVersionFloors, pickHigherVersionFloor, } from "../shared/version-floor.js";
|
|
8
|
+
import { DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION } from "../templates/scaffold-compatibility.js";
|
|
9
|
+
const WORDPRESS_VERSION_CHECK_CODES = {
|
|
10
|
+
featureMinimum: "wp-typia.workspace.wordpress.feature-minimum",
|
|
11
|
+
testedTarget: "wp-typia.workspace.wordpress.tested-target",
|
|
12
|
+
};
|
|
13
|
+
function isEnabledMetadataValue(value) {
|
|
14
|
+
return value !== undefined && value !== false && value !== null;
|
|
15
|
+
}
|
|
16
|
+
function getNestedMetadataValue(object, key) {
|
|
17
|
+
if (!object) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
21
|
+
return object[key];
|
|
22
|
+
}
|
|
23
|
+
return key
|
|
24
|
+
.split(".")
|
|
25
|
+
.reduce((current, segment) => {
|
|
26
|
+
if (current === null ||
|
|
27
|
+
typeof current !== "object" ||
|
|
28
|
+
Array.isArray(current)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const record = current;
|
|
32
|
+
return Object.prototype.hasOwnProperty.call(record, segment)
|
|
33
|
+
? record[segment]
|
|
34
|
+
: undefined;
|
|
35
|
+
}, object);
|
|
36
|
+
}
|
|
37
|
+
function getBootstrapHeaderValue(source, headerName) {
|
|
38
|
+
const escapedHeaderName = headerName.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
39
|
+
const pattern = new RegExp(`^\\s*\\*\\s*${escapedHeaderName}:\\s*([^\\r\\n]*)`, "mu");
|
|
40
|
+
const match = pattern.exec(source);
|
|
41
|
+
return match?.[1]?.trim();
|
|
42
|
+
}
|
|
43
|
+
function readBootstrapHeaderVersions(workspace) {
|
|
44
|
+
const bootstrapPath = resolveWorkspaceBootstrapPath(workspace.projectDir, workspace.packageName);
|
|
45
|
+
if (!fs.existsSync(bootstrapPath)) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
49
|
+
return {
|
|
50
|
+
requiresAtLeast: getBootstrapHeaderValue(source, "Requires at least"),
|
|
51
|
+
testedUpTo: getBootstrapHeaderValue(source, "Tested up to"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function pushRequirement(requirements, label, version) {
|
|
55
|
+
requirements.push({
|
|
56
|
+
label,
|
|
57
|
+
version,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function pushBlockApiRequirement(requirements, labelPrefix, entry) {
|
|
61
|
+
pushRequirement(requirements, `${labelPrefix} ${entry.label}`, entry.since);
|
|
62
|
+
}
|
|
63
|
+
function readExistingTextFile(filePath) {
|
|
64
|
+
if (!fs.existsSync(filePath)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return fs.readFileSync(filePath, "utf8");
|
|
68
|
+
}
|
|
69
|
+
function collectBlockMetadataRequirements(workspace, inventory) {
|
|
70
|
+
const issues = [];
|
|
71
|
+
const requirements = [];
|
|
72
|
+
for (const block of inventory.blocks) {
|
|
73
|
+
const blockJsonRelativePath = path.join("src", "blocks", block.slug, "block.json");
|
|
74
|
+
const blockJsonPath = path.join(workspace.projectDir, blockJsonRelativePath);
|
|
75
|
+
if (!fs.existsSync(blockJsonPath)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
let blockJson;
|
|
79
|
+
try {
|
|
80
|
+
blockJson = parseScaffoldBlockMetadata(readJsonFileSync(blockJsonPath, {
|
|
81
|
+
context: "workspace block metadata",
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
issues.push(`${blockJsonRelativePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
for (const [feature, entry] of Object.entries(WORDPRESS_BLOCK_API_COMPATIBILITY.blockSupports)) {
|
|
89
|
+
if (isEnabledMetadataValue(getNestedMetadataValue(blockJson.supports, feature))) {
|
|
90
|
+
pushBlockApiRequirement(requirements, `Block ${block.slug}`, entry);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const [feature, entry] of Object.entries(WORDPRESS_BLOCK_API_COMPATIBILITY.blockMetadata)) {
|
|
94
|
+
if (isEnabledMetadataValue(getNestedMetadataValue(blockJson, feature))) {
|
|
95
|
+
pushBlockApiRequirement(requirements, `Block ${block.slug}`, entry);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const [feature, entry] of Object.entries(WORDPRESS_BLOCK_API_COMPATIBILITY.blockBindings)) {
|
|
99
|
+
if (entry.runtime.includes("block-json") &&
|
|
100
|
+
isEnabledMetadataValue(getNestedMetadataValue(blockJson, feature))) {
|
|
101
|
+
pushBlockApiRequirement(requirements, `Block ${block.slug}`, entry);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
issues,
|
|
107
|
+
requirements,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function collectInventoryCompatibilityRequirements(inventory) {
|
|
111
|
+
const requirements = [];
|
|
112
|
+
for (const ability of inventory.abilities) {
|
|
113
|
+
const wordpressMinimum = ability.compatibility?.hardMinimums.wordpress;
|
|
114
|
+
if (wordpressMinimum) {
|
|
115
|
+
requirements.push({
|
|
116
|
+
label: `Ability ${ability.slug} compatibility metadata`,
|
|
117
|
+
version: wordpressMinimum,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const aiFeature of inventory.aiFeatures) {
|
|
122
|
+
const wordpressMinimum = aiFeature.compatibility?.hardMinimums.wordpress;
|
|
123
|
+
if (wordpressMinimum) {
|
|
124
|
+
requirements.push({
|
|
125
|
+
label: `AI feature ${aiFeature.slug} compatibility metadata`,
|
|
126
|
+
version: wordpressMinimum,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
issues: [],
|
|
132
|
+
requirements,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function collectBindingSourceRequirements(workspace, inventory) {
|
|
136
|
+
const requirements = [];
|
|
137
|
+
const bindingEntries = WORDPRESS_BLOCK_API_COMPATIBILITY.blockBindings;
|
|
138
|
+
for (const bindingSource of inventory.bindingSources) {
|
|
139
|
+
pushBlockApiRequirement(requirements, `Binding source ${bindingSource.slug}`, bindingEntries.serverRegistration);
|
|
140
|
+
pushBlockApiRequirement(requirements, `Binding source ${bindingSource.slug}`, bindingEntries.editorRegistration);
|
|
141
|
+
const editorFilePath = path.join(workspace.projectDir, bindingSource.editorFile);
|
|
142
|
+
if (readExistingTextFile(editorFilePath)?.includes("getFieldsList")) {
|
|
143
|
+
pushBlockApiRequirement(requirements, `Binding source ${bindingSource.slug}`, bindingEntries.editorFieldsList);
|
|
144
|
+
}
|
|
145
|
+
const serverFilePath = path.join(workspace.projectDir, bindingSource.serverFile);
|
|
146
|
+
if (readExistingTextFile(serverFilePath)?.includes("block_bindings_supported_attributes_")) {
|
|
147
|
+
pushBlockApiRequirement(requirements, `Binding source ${bindingSource.slug}`, bindingEntries.supportedAttributesFilter);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
issues: [],
|
|
152
|
+
requirements,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function collectWordPressVersionRequirements(workspace, inventory) {
|
|
156
|
+
const blockRequirements = collectBlockMetadataRequirements(workspace, inventory);
|
|
157
|
+
const bindingRequirements = collectBindingSourceRequirements(workspace, inventory);
|
|
158
|
+
const inventoryRequirements = collectInventoryCompatibilityRequirements(inventory);
|
|
159
|
+
return {
|
|
160
|
+
issues: [
|
|
161
|
+
...blockRequirements.issues,
|
|
162
|
+
...bindingRequirements.issues,
|
|
163
|
+
...inventoryRequirements.issues,
|
|
164
|
+
],
|
|
165
|
+
requirements: [
|
|
166
|
+
...blockRequirements.requirements,
|
|
167
|
+
...bindingRequirements.requirements,
|
|
168
|
+
...inventoryRequirements.requirements,
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function pickHighestRequirementFloor(requirements, issues) {
|
|
173
|
+
let highest;
|
|
174
|
+
for (const requirement of requirements) {
|
|
175
|
+
try {
|
|
176
|
+
highest = pickHigherVersionFloor(highest, requirement.version);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
issues.push(`${requirement.label} declares invalid WordPress version floor "${requirement.version}".`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return highest;
|
|
183
|
+
}
|
|
184
|
+
function formatRequirementSummary(requirements, floor) {
|
|
185
|
+
const labels = requirements
|
|
186
|
+
.filter((requirement) => requirement.version === floor)
|
|
187
|
+
.map((requirement) => requirement.label);
|
|
188
|
+
return labels.length > 0 ? labels.join(", ") : "generated workspace features";
|
|
189
|
+
}
|
|
190
|
+
function createFeatureMinimumCheck(workspace, inventory, headers) {
|
|
191
|
+
const { issues, requirements } = collectWordPressVersionRequirements(workspace, inventory);
|
|
192
|
+
const highestFloor = pickHighestRequirementFloor(requirements, issues);
|
|
193
|
+
if (issues.length > 0) {
|
|
194
|
+
return createDoctorCheck("WordPress feature minimum", "fail", issues.join("; "), WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
195
|
+
}
|
|
196
|
+
if (!highestFloor) {
|
|
197
|
+
return createDoctorCheck("WordPress feature minimum", "pass", "No generated workspace features declare an additional WordPress hard floor.", WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
198
|
+
}
|
|
199
|
+
if (!headers.requiresAtLeast) {
|
|
200
|
+
return createDoctorCheck("WordPress feature minimum", "fail", `Plugin bootstrap is missing a Requires at least header but generated features require WordPress ${highestFloor}.`, WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
if (compareVersionFloors(headers.requiresAtLeast, highestFloor) < 0) {
|
|
204
|
+
return createDoctorCheck("WordPress feature minimum", "fail", `Requires at least ${headers.requiresAtLeast} is below generated feature floor ${highestFloor} (${formatRequirementSummary(requirements, highestFloor)}).`, WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return createDoctorCheck("WordPress feature minimum", "fail", `Plugin bootstrap Requires at least header "${headers.requiresAtLeast}" is not a dotted numeric version.`, WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
209
|
+
}
|
|
210
|
+
return createDoctorCheck("WordPress feature minimum", "pass", `Requires at least ${headers.requiresAtLeast} covers generated feature floor ${highestFloor} (${formatRequirementSummary(requirements, highestFloor)}).`, WORDPRESS_VERSION_CHECK_CODES.featureMinimum);
|
|
211
|
+
}
|
|
212
|
+
function createTestedTargetCheck(headers, targetVersion) {
|
|
213
|
+
if (!headers.testedUpTo) {
|
|
214
|
+
return createDoctorCheck("WordPress tested target", "fail", `Plugin bootstrap is missing a Tested up to header; expected ${targetVersion} or newer.`, WORDPRESS_VERSION_CHECK_CODES.testedTarget);
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
if (compareVersionFloors(headers.testedUpTo, targetVersion) < 0) {
|
|
218
|
+
return createDoctorCheck("WordPress tested target", "warn", `Tested up to ${headers.testedUpTo} is below the selected WordPress target ${targetVersion}.`, WORDPRESS_VERSION_CHECK_CODES.testedTarget);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return createDoctorCheck("WordPress tested target", "fail", `Plugin bootstrap Tested up to header "${headers.testedUpTo}" is not a dotted numeric version.`, WORDPRESS_VERSION_CHECK_CODES.testedTarget);
|
|
223
|
+
}
|
|
224
|
+
return createDoctorCheck("WordPress tested target", "pass", `Tested up to ${headers.testedUpTo} covers the selected WordPress target ${targetVersion}.`, WORDPRESS_VERSION_CHECK_CODES.testedTarget);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Collect opt-in WordPress feature floor checks for an official workspace.
|
|
228
|
+
*
|
|
229
|
+
* These checks compare generated feature metadata against plugin bootstrap
|
|
230
|
+
* headers without changing the default doctor output shape.
|
|
231
|
+
*/
|
|
232
|
+
export function getWorkspaceWordPressVersionDoctorChecks(workspace, inventory, options = {}) {
|
|
233
|
+
const targetVersion = options.targetVersion ?? DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION;
|
|
234
|
+
const headers = readBootstrapHeaderVersions(workspace);
|
|
235
|
+
return [
|
|
236
|
+
createFeatureMinimumCheck(workspace, inventory, headers),
|
|
237
|
+
createTestedTargetCheck(headers, targetVersion),
|
|
238
|
+
];
|
|
239
|
+
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { DoctorCheck } from "./cli-doctor.js";
|
|
2
|
+
/** Options used when collecting workspace-scoped doctor rows. */
|
|
3
|
+
export interface WorkspaceDoctorChecksOptions {
|
|
4
|
+
/** Include opt-in WordPress feature floor and plugin header checks. */
|
|
5
|
+
wordpressVersionCheck?: boolean;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Collect workspace-scoped doctor checks for the given working directory.
|
|
4
9
|
*
|
|
@@ -9,10 +14,12 @@ import type { DoctorCheck } from "./cli-doctor.js";
|
|
|
9
14
|
* failing rows are returned early and the remaining checks are skipped.
|
|
10
15
|
* When an official workspace is detected, a passing "Doctor scope" row is
|
|
11
16
|
* emitted first so the remaining package metadata, inventory, source-tree
|
|
12
|
-
* drift, and optional migration hint rows
|
|
13
|
-
* diagnostics for that run.
|
|
17
|
+
* drift, optional WordPress version checks, and optional migration hint rows
|
|
18
|
+
* are clearly framed as workspace diagnostics for that run.
|
|
14
19
|
*
|
|
15
20
|
* @param cwd Working directory expected to host an official workspace.
|
|
21
|
+
* @param options Optional feature gates for additional workspace doctor rows.
|
|
22
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
16
23
|
* @returns Ordered workspace check rows ready for CLI rendering.
|
|
17
24
|
*/
|
|
18
|
-
export declare function getWorkspaceDoctorChecks(cwd: string): Promise<DoctorCheck[]>;
|
|
25
|
+
export declare function getWorkspaceDoctorChecks(cwd: string, options?: WorkspaceDoctorChecksOptions): Promise<DoctorCheck[]>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getWorkspaceBindingDoctorChecks, } from "./cli-doctor-workspace-bindings.js";
|
|
2
2
|
import { getWorkspaceBlockDoctorChecks, } from "./cli-doctor-workspace-blocks.js";
|
|
3
3
|
import { getWorkspaceFeatureDoctorChecks, } from "./cli-doctor-workspace-features.js";
|
|
4
|
+
import { getWorkspaceWordPressVersionDoctorChecks, } from "./cli-doctor-wordpress-version.js";
|
|
4
5
|
import { getMigrationWorkspaceHintCheck, getWorkspacePackageMetadataCheck, prepareWorkspacePackageDoctorSnapshot, } from "./cli-doctor-workspace-package.js";
|
|
5
6
|
import { createDoctorCheck, createDoctorScopeCheck, } from "./cli-doctor-workspace-shared.js";
|
|
6
7
|
import { readWorkspaceInventoryAsync, } from "../workspace/workspace-inventory.js";
|
|
@@ -31,13 +32,15 @@ function formatWorkspaceInventorySummary(inventory) {
|
|
|
31
32
|
* failing rows are returned early and the remaining checks are skipped.
|
|
32
33
|
* When an official workspace is detected, a passing "Doctor scope" row is
|
|
33
34
|
* emitted first so the remaining package metadata, inventory, source-tree
|
|
34
|
-
* drift, and optional migration hint rows
|
|
35
|
-
* diagnostics for that run.
|
|
35
|
+
* drift, optional WordPress version checks, and optional migration hint rows
|
|
36
|
+
* are clearly framed as workspace diagnostics for that run.
|
|
36
37
|
*
|
|
37
38
|
* @param cwd Working directory expected to host an official workspace.
|
|
39
|
+
* @param options Optional feature gates for additional workspace doctor rows.
|
|
40
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
38
41
|
* @returns Ordered workspace check rows ready for CLI rendering.
|
|
39
42
|
*/
|
|
40
|
-
export async function getWorkspaceDoctorChecks(cwd) {
|
|
43
|
+
export async function getWorkspaceDoctorChecks(cwd, options = {}) {
|
|
41
44
|
const checks = [];
|
|
42
45
|
let workspace = null;
|
|
43
46
|
let invalidWorkspaceReason = null;
|
|
@@ -85,6 +88,9 @@ export async function getWorkspaceDoctorChecks(cwd) {
|
|
|
85
88
|
checks.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
|
|
86
89
|
checks.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
|
|
87
90
|
checks.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
|
|
91
|
+
if (options.wordpressVersionCheck) {
|
|
92
|
+
checks.push(...getWorkspaceWordPressVersionDoctorChecks(workspace, inventory));
|
|
93
|
+
}
|
|
88
94
|
const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspacePackageJson, packageDoctorSnapshot);
|
|
89
95
|
if (migrationWorkspaceCheck) {
|
|
90
96
|
checks.push(migrationWorkspaceCheck);
|
|
@@ -41,10 +41,16 @@ interface RunDoctorOptions {
|
|
|
41
41
|
exitPolicy?: DoctorExitPolicy;
|
|
42
42
|
renderLine?: (check: DoctorCheck) => void;
|
|
43
43
|
renderSummaryLine?: (summaryLine: string) => void;
|
|
44
|
+
wordpressVersionCheck?: boolean;
|
|
44
45
|
}
|
|
45
46
|
interface DoctorSummaryOptions {
|
|
46
47
|
exitPolicy?: DoctorExitPolicy;
|
|
47
48
|
}
|
|
49
|
+
/** Options used when collecting doctor checks before rendering. */
|
|
50
|
+
export interface GetDoctorChecksOptions {
|
|
51
|
+
/** Include opt-in WordPress feature floor and plugin header checks. */
|
|
52
|
+
wordpressVersionCheck?: boolean;
|
|
53
|
+
}
|
|
48
54
|
/**
|
|
49
55
|
* Collect all runtime doctor checks for the current environment.
|
|
50
56
|
*
|
|
@@ -54,9 +60,11 @@ interface DoctorSummaryOptions {
|
|
|
54
60
|
* patterns, bindings, and optional migration hints) in display order.
|
|
55
61
|
*
|
|
56
62
|
* @param cwd Working directory to validate for writability.
|
|
63
|
+
* @param options Optional feature gates for additional doctor rows.
|
|
64
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
57
65
|
* @returns Ordered doctor check rows ready for CLI rendering.
|
|
58
66
|
*/
|
|
59
|
-
export declare function getDoctorChecks(cwd: string): Promise<DoctorCheck[]>;
|
|
67
|
+
export declare function getDoctorChecks(cwd: string, options?: GetDoctorChecksOptions): Promise<DoctorCheck[]>;
|
|
60
68
|
/**
|
|
61
69
|
* Return failed rows that contribute to the process exit code for one policy.
|
|
62
70
|
*/
|
|
@@ -83,6 +91,7 @@ export declare function createDoctorRunSummary(checks: readonly DoctorCheck[], o
|
|
|
83
91
|
* @param options.exitPolicy Policy deciding which failed checks contribute to the process exit code.
|
|
84
92
|
* @param options.renderLine Optional renderer for each check row. Defaults to the stdout line printer.
|
|
85
93
|
* @param options.renderSummaryLine Optional renderer for the summary row. Defaults to the stdout line printer unless a custom `renderLine` suppresses implicit summary output.
|
|
94
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
86
95
|
* @returns The completed list of doctor checks.
|
|
87
96
|
* @throws {Error} When one or more failed checks contribute to the exit code under the active policy.
|
|
88
97
|
*/
|
|
@@ -46,12 +46,16 @@ function toFailureSummary(check, severity) {
|
|
|
46
46
|
* patterns, bindings, and optional migration hints) in display order.
|
|
47
47
|
*
|
|
48
48
|
* @param cwd Working directory to validate for writability.
|
|
49
|
+
* @param options Optional feature gates for additional doctor rows.
|
|
50
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
49
51
|
* @returns Ordered doctor check rows ready for CLI rendering.
|
|
50
52
|
*/
|
|
51
|
-
export async function getDoctorChecks(cwd) {
|
|
53
|
+
export async function getDoctorChecks(cwd, options = {}) {
|
|
52
54
|
return [
|
|
53
55
|
...annotateDoctorChecks(await getEnvironmentDoctorChecks(cwd), "environment"),
|
|
54
|
-
...annotateDoctorChecks(await getWorkspaceDoctorChecks(cwd
|
|
56
|
+
...annotateDoctorChecks(await getWorkspaceDoctorChecks(cwd, {
|
|
57
|
+
wordpressVersionCheck: options.wordpressVersionCheck,
|
|
58
|
+
}), "workspace"),
|
|
55
59
|
];
|
|
56
60
|
}
|
|
57
61
|
/**
|
|
@@ -103,6 +107,7 @@ export function createDoctorRunSummary(checks, options = {}) {
|
|
|
103
107
|
* @param options.exitPolicy Policy deciding which failed checks contribute to the process exit code.
|
|
104
108
|
* @param options.renderLine Optional renderer for each check row. Defaults to the stdout line printer.
|
|
105
109
|
* @param options.renderSummaryLine Optional renderer for the summary row. Defaults to the stdout line printer unless a custom `renderLine` suppresses implicit summary output.
|
|
110
|
+
* @param options.wordpressVersionCheck Include WordPress feature floor and plugin header checks.
|
|
106
111
|
* @returns The completed list of doctor checks.
|
|
107
112
|
* @throws {Error} When one or more failed checks contribute to the exit code under the active policy.
|
|
108
113
|
*/
|
|
@@ -111,7 +116,9 @@ export async function runDoctor(cwd, options = {}) {
|
|
|
111
116
|
const renderLine = options.renderLine ?? renderDefaultDoctorCheckLine;
|
|
112
117
|
const renderSummaryLine = options.renderSummaryLine ??
|
|
113
118
|
(options.renderLine ? () => undefined : renderDefaultDoctorSummaryLine);
|
|
114
|
-
const checks = await getDoctorChecks(cwd
|
|
119
|
+
const checks = await getDoctorChecks(cwd, {
|
|
120
|
+
wordpressVersionCheck: options.wordpressVersionCheck,
|
|
121
|
+
});
|
|
115
122
|
for (const check of checks) {
|
|
116
123
|
renderLine(check);
|
|
117
124
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -41,5 +41,5 @@ export type { ExternalTemplateCachePruneOptions, ExternalTemplateCachePruneResul
|
|
|
41
41
|
export { STALE_TEMP_ROOT_MAX_AGE_MS, WP_TYPIA_TEMP_ROOT_PREFIX, cleanupManagedTempRoot, cleanupStaleTempRoots, createManagedTempRoot, getTrackedTempRoots, } from "./temp-roots.js";
|
|
42
42
|
export { createReadlinePrompt, createDoctorRunSummary, createCliCommandError, createCliDiagnosticCodeError, CliDiagnosticError, CLI_DIAGNOSTIC_CODES, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorExitFailureChecks, getDoctorExitFailureDetailLines, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, getWorkspaceBlockSelectOptionsAsync, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddCoreVariationCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddPostMetaCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
43
43
|
export { extractPatternSectionRoleMatches, extractPatternSectionRolesFromAttributes, formatPatternCatalogDiagnostics, PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, resolvePatternCatalogContentFile, validatePatternCatalog, } from "./pattern-catalog.js";
|
|
44
|
-
export type { CliDiagnosticCode, CliDiagnosticCodeError, CliDiagnosticMessage, DoctorCheck, DoctorCheckScope, DoctorExitPolicy, DoctorFailureSummary, DoctorRunSummary, EditorPluginSlotId, HookedBlockPositionId, ReadlinePrompt, WorkspaceBlockSelectOption, } from "./cli-core.js";
|
|
44
|
+
export type { CliDiagnosticCode, CliDiagnosticCodeError, CliDiagnosticMessage, DoctorCheck, DoctorCheckScope, DoctorExitPolicy, DoctorFailureSummary, DoctorRunSummary, GetDoctorChecksOptions, EditorPluginSlotId, HookedBlockPositionId, ReadlinePrompt, WorkspaceBlockSelectOption, } from "./cli-core.js";
|
|
45
45
|
export type { PatternCatalogDiagnostic, PatternCatalogDiagnosticCode, PatternCatalogDiagnosticSeverity, PatternCatalogEntry, PatternCatalogScope, PatternCatalogSectionRoleConvention, PatternCatalogSectionRoleMatch, PatternCatalogValidationOptions, PatternCatalogValidationResult, } from "./pattern-catalog.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ApplyBlockInput, type PlanBlockInput, type PlanBlockResult, type RenderBlockInput, type RenderBlockResult, type ValidateBlockInput, type ValidateBlockResult } from "./block-generator-service-spec.js";
|
|
2
2
|
import type { ScaffoldProjectResult } from "./scaffold.js";
|
|
3
3
|
export declare class BlockGeneratorService {
|
|
4
|
-
plan({ allowExistingDir, alternateRenderTargets, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, noInstall, packageManager, persistencePolicy, projectDir, repositoryReference, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, }: PlanBlockInput): Promise<PlanBlockResult>;
|
|
4
|
+
plan({ allowExistingDir, alternateRenderTargets, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, noInstall, packageManager, persistencePolicy, projectDir, repositoryReference, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, wpVersion, }: PlanBlockInput): Promise<PlanBlockResult>;
|
|
5
5
|
validate({ plan }: ValidateBlockInput): Promise<ValidateBlockResult>;
|
|
6
6
|
render({ validated }: RenderBlockInput): Promise<RenderBlockResult>;
|
|
7
7
|
apply({ rendered, installDependencies, onProgress, }: ApplyBlockInput): Promise<ScaffoldProjectResult>;
|
|
@@ -83,7 +83,7 @@ async function runCleanupGroup(label, cleanups) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
export class BlockGeneratorService {
|
|
86
|
-
async plan({ allowExistingDir = false, alternateRenderTargets, answers, cwd = process.cwd(), dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, noInstall = false, packageManager, persistencePolicy, projectDir, repositoryReference, templateId, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
86
|
+
async plan({ allowExistingDir = false, alternateRenderTargets, answers, cwd = process.cwd(), dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, noInstall = false, packageManager, persistencePolicy, projectDir, repositoryReference, templateId, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, wpVersion, }) {
|
|
87
87
|
return {
|
|
88
88
|
spec: createBuiltInBlockSpec({
|
|
89
89
|
alternateRenderTargets,
|
|
@@ -94,6 +94,7 @@ export class BlockGeneratorService {
|
|
|
94
94
|
withMigrationUi,
|
|
95
95
|
withTestPreset,
|
|
96
96
|
withWpEnv,
|
|
97
|
+
wpVersion,
|
|
97
98
|
}),
|
|
98
99
|
target: {
|
|
99
100
|
allowExistingDir,
|
|
@@ -3,6 +3,7 @@ import { type AlternateRenderTargetId } from "../add/alternate-render-targets.js
|
|
|
3
3
|
import { type CompoundInnerBlocksPresetId } from "../add/compound-inner-blocks.js";
|
|
4
4
|
import { type BuiltInTemplateId } from "./template-registry.js";
|
|
5
5
|
import type { InstallDependenciesOptions } from "./scaffold-apply-utils.js";
|
|
6
|
+
import { type ScaffoldWordPressTargetVersion } from "./scaffold-compatibility.js";
|
|
6
7
|
import type { DataStorageMode, PersistencePolicy, ScaffoldAnswers, ScaffoldProgressEvent, ScaffoldTemplateVariables } from "./scaffold.js";
|
|
7
8
|
export interface BlockSpec {
|
|
8
9
|
alternateRenderTargets: readonly AlternateRenderTargetId[];
|
|
@@ -42,6 +43,7 @@ export interface BlockSpec {
|
|
|
42
43
|
withMigrationUi: boolean;
|
|
43
44
|
withTestPreset: boolean;
|
|
44
45
|
withWpEnv: boolean;
|
|
46
|
+
wpVersion: ScaffoldWordPressTargetVersion;
|
|
45
47
|
};
|
|
46
48
|
template: {
|
|
47
49
|
description: string;
|
|
@@ -81,6 +83,7 @@ export interface PlanBlockInput {
|
|
|
81
83
|
queryPostType?: string;
|
|
82
84
|
withTestPreset?: boolean;
|
|
83
85
|
withWpEnv?: boolean;
|
|
86
|
+
wpVersion?: ScaffoldWordPressTargetVersion;
|
|
84
87
|
}
|
|
85
88
|
export interface PlanBlockResult {
|
|
86
89
|
spec: BlockSpec;
|
|
@@ -114,5 +117,5 @@ export interface ApplyBlockInput {
|
|
|
114
117
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
115
118
|
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
116
119
|
}
|
|
117
|
-
export declare function createBuiltInBlockSpec({ alternateRenderTargets, answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi, withTestPreset, withWpEnv, }: Omit<PlanBlockInput, "allowExistingDir" | "cwd" | "noInstall" | "packageManager" | "projectDir" | "variant">): BlockSpec;
|
|
120
|
+
export declare function createBuiltInBlockSpec({ alternateRenderTargets, answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi, withTestPreset, withWpEnv, wpVersion, }: Omit<PlanBlockInput, "allowExistingDir" | "cwd" | "noInstall" | "packageManager" | "projectDir" | "variant">): BlockSpec;
|
|
118
121
|
export declare function buildTemplateVariablesFromBlockSpec(spec: BlockSpec): ScaffoldTemplateVariables;
|
|
@@ -5,7 +5,7 @@ import { DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID, getCompoundInnerBlocksPresetDe
|
|
|
5
5
|
import { getTemplateById, } from "./template-registry.js";
|
|
6
6
|
import { toPascalCase, toSnakeCase, } from "../shared/string-case.js";
|
|
7
7
|
import { buildBlockCssClassName, buildFrontendCssClassName, resolveScaffoldIdentifiers, } from "./scaffold-identifiers.js";
|
|
8
|
-
import { resolveScaffoldCompatibilityPolicy } from "./scaffold-compatibility.js";
|
|
8
|
+
import { createScaffoldCompatibilityBaseline, DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION, resolveScaffoldCompatibilityPolicy, } from "./scaffold-compatibility.js";
|
|
9
9
|
import { attachScaffoldTemplateVariableGroups } from "./scaffold-template-variable-groups.js";
|
|
10
10
|
function getBuiltInPersistenceSpec({ templateId, dataStorageMode, persistencePolicy, }) {
|
|
11
11
|
if (templateId === "persistence") {
|
|
@@ -37,7 +37,7 @@ const DEFAULT_QUERY_LOOP_ALLOWED_CONTROLS = [
|
|
|
37
37
|
"author",
|
|
38
38
|
"search",
|
|
39
39
|
];
|
|
40
|
-
export function createBuiltInBlockSpec({ alternateRenderTargets, answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
40
|
+
export function createBuiltInBlockSpec({ alternateRenderTargets, answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi = false, withTestPreset = false, withWpEnv = false, wpVersion, }) {
|
|
41
41
|
const template = getTemplateById(templateId);
|
|
42
42
|
const metadataDefaults = getBuiltInTemplateMetadataDefaults(templateId);
|
|
43
43
|
const identifiers = resolveScaffoldIdentifiers({
|
|
@@ -89,6 +89,7 @@ export function createBuiltInBlockSpec({ alternateRenderTargets, answers, dataSt
|
|
|
89
89
|
withMigrationUi,
|
|
90
90
|
withTestPreset,
|
|
91
91
|
withWpEnv,
|
|
92
|
+
wpVersion: wpVersion ?? DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION,
|
|
92
93
|
},
|
|
93
94
|
template: {
|
|
94
95
|
description: template.description,
|
|
@@ -123,7 +124,9 @@ export function buildTemplateVariablesFromBlockSpec(spec) {
|
|
|
123
124
|
? spec.persistence.persistencePolicy
|
|
124
125
|
: "authenticated";
|
|
125
126
|
const queryVariationNamespace = `${namespace}/${slug}`;
|
|
126
|
-
const compatibility = resolveScaffoldCompatibilityPolicy([]
|
|
127
|
+
const compatibility = resolveScaffoldCompatibilityPolicy([], {
|
|
128
|
+
baseline: createScaffoldCompatibilityBaseline(spec.runtime.wpVersion),
|
|
129
|
+
});
|
|
127
130
|
const flatVariables = {
|
|
128
131
|
alternateRenderTargetsCsv: formatAlternateRenderTargets(alternateRenderTargets),
|
|
129
132
|
alternateRenderTargetsJson: JSON.stringify(alternateRenderTargets),
|
|
@@ -103,6 +103,10 @@ export interface ScaffoldEmissionOptions {
|
|
|
103
103
|
* Whether local wp-env support should be emitted.
|
|
104
104
|
*/
|
|
105
105
|
withWpEnv: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* WordPress version target used for generated plugin Tested up to headers.
|
|
108
|
+
*/
|
|
109
|
+
wpVersion?: ScaffoldProjectOptions["wpVersion"];
|
|
106
110
|
}
|
|
107
111
|
/**
|
|
108
112
|
* Emit scaffold files into the target project directory.
|
|
@@ -42,6 +42,7 @@ interface RunScaffoldFlowOptions {
|
|
|
42
42
|
withMigrationUi?: boolean;
|
|
43
43
|
withTestPreset?: boolean;
|
|
44
44
|
withWpEnv?: boolean;
|
|
45
|
+
wpVersion?: string;
|
|
45
46
|
yes?: boolean;
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
@@ -51,7 +52,7 @@ interface RunScaffoldFlowOptions {
|
|
|
51
52
|
* project.
|
|
52
53
|
* @returns The scaffold result together with next-step guidance.
|
|
53
54
|
*/
|
|
54
|
-
export declare function runScaffoldFlow({ projectInput, cwd, templateId, alternateRenderTargets, dataStorageMode, dryRun, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, profile, textDomain, phpPrefix, queryPostType, yes, noInstall, onProgress, isInteractive, allowExistingDir, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }: RunScaffoldFlowOptions): Promise<{
|
|
55
|
+
export declare function runScaffoldFlow({ projectInput, cwd, templateId, alternateRenderTargets, dataStorageMode, dryRun, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, profile, textDomain, phpPrefix, queryPostType, yes, noInstall, onProgress, isInteractive, allowExistingDir, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, wpVersion, }: RunScaffoldFlowOptions): Promise<{
|
|
55
56
|
dryRun: boolean;
|
|
56
57
|
optionalOnboarding: import("./cli-scaffold-output.js").OptionalOnboardingGuidance;
|
|
57
58
|
plan: import("./cli-scaffold-emission.js").ScaffoldDryRunPlan | undefined;
|
|
@@ -9,6 +9,7 @@ import { collectProjectDirectoryWarnings, collectTemplateCapabilityWarnings, res
|
|
|
9
9
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from "./template-registry.js";
|
|
10
10
|
import { resolveOptionalInteractiveExternalLayerId, } from "./external-layer-selection.js";
|
|
11
11
|
import { resolveLocalCliPathOption, normalizeOptionalCliString, } from "../cli/cli-validation.js";
|
|
12
|
+
import { resolveScaffoldWordPressTargetVersion, } from "./scaffold-compatibility.js";
|
|
12
13
|
export { getNextSteps, getOptionalOnboarding } from "./cli-scaffold-output.js";
|
|
13
14
|
/**
|
|
14
15
|
* Resolve scaffold options, prompts, and follow-up steps for one CLI run.
|
|
@@ -17,7 +18,7 @@ export { getNextSteps, getOptionalOnboarding } from "./cli-scaffold-output.js";
|
|
|
17
18
|
* project.
|
|
18
19
|
* @returns The scaffold result together with next-step guidance.
|
|
19
20
|
*/
|
|
20
|
-
export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, alternateRenderTargets, dataStorageMode, dryRun = false, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, profile, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, onProgress, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }) {
|
|
21
|
+
export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, alternateRenderTargets, dataStorageMode, dryRun = false, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, profile, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, onProgress, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, wpVersion, }) {
|
|
21
22
|
const normalizedExternalLayerId = normalizeOptionalCliString(externalLayerId);
|
|
22
23
|
const normalizedExternalLayerSource = resolveLocalCliPathOption({
|
|
23
24
|
cwd,
|
|
@@ -85,6 +86,7 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
|
|
|
85
86
|
isInteractive,
|
|
86
87
|
selectPackageManager,
|
|
87
88
|
});
|
|
89
|
+
const resolvedWpVersion = resolveScaffoldWordPressTargetVersion(wpVersion);
|
|
88
90
|
const resolvedWithWpEnv = resolvedProfile === "plugin-qa"
|
|
89
91
|
? true
|
|
90
92
|
: await resolveOptionalBooleanFlag({
|
|
@@ -145,6 +147,7 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
|
|
|
145
147
|
withMigrationUi: resolvedWithMigrationUi,
|
|
146
148
|
withTestPreset: resolvedWithTestPreset,
|
|
147
149
|
withWpEnv: resolvedWithWpEnv,
|
|
150
|
+
wpVersion: resolvedWpVersion,
|
|
148
151
|
};
|
|
149
152
|
const resolvedResult = dryRun
|
|
150
153
|
? await buildScaffoldDryRunPlan(emissionOptions)
|
|
@@ -20,6 +20,18 @@ export interface ScaffoldCompatibilityPolicy {
|
|
|
20
20
|
capabilityPlan: ResolvedAiFeatureCapabilityPlan;
|
|
21
21
|
pluginHeader: ScaffoldPluginHeaderCompatibility;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Supported WordPress target versions for generated scaffold plugin headers.
|
|
25
|
+
*/
|
|
26
|
+
export declare const SCAFFOLD_WORDPRESS_TARGET_VERSIONS: readonly ["6.9", "7.0"];
|
|
27
|
+
/**
|
|
28
|
+
* String literal union for scaffold WordPress targets, currently `6.9` or `7.0`.
|
|
29
|
+
*/
|
|
30
|
+
export type ScaffoldWordPressTargetVersion = (typeof SCAFFOLD_WORDPRESS_TARGET_VERSIONS)[number];
|
|
31
|
+
/**
|
|
32
|
+
* Default WordPress target version used when create callers omit `--wp-version`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION: ScaffoldWordPressTargetVersion;
|
|
23
35
|
/**
|
|
24
36
|
* Serializable compatibility metadata stored in generated workspace inventory.
|
|
25
37
|
*/
|
|
@@ -46,6 +58,23 @@ export interface UpdatePluginHeaderCompatibilityOptions {
|
|
|
46
58
|
* Baseline headers used by scaffold output before optional features are added.
|
|
47
59
|
*/
|
|
48
60
|
export declare const DEFAULT_SCAFFOLD_COMPATIBILITY: ScaffoldPluginHeaderCompatibility;
|
|
61
|
+
/**
|
|
62
|
+
* Return whether a string is one of the supported scaffold WordPress targets.
|
|
63
|
+
*/
|
|
64
|
+
export declare function isScaffoldWordPressTargetVersion(value: string): value is ScaffoldWordPressTargetVersion;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve CLI input into a supported scaffold WordPress target version.
|
|
67
|
+
*
|
|
68
|
+
* Empty input falls back to the default `7.0` target.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveScaffoldWordPressTargetVersion(value?: string): ScaffoldWordPressTargetVersion;
|
|
71
|
+
/**
|
|
72
|
+
* Build scaffold header compatibility for the selected WordPress target.
|
|
73
|
+
*
|
|
74
|
+
* The selected target controls `Tested up to`; hard minimums remain tied to the
|
|
75
|
+
* compatibility policy floor.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createScaffoldCompatibilityBaseline(wpVersion?: ScaffoldWordPressTargetVersion): ScaffoldPluginHeaderCompatibility;
|
|
49
78
|
/**
|
|
50
79
|
* Optional WordPress AI Client surface used by server-only AI feature scaffold.
|
|
51
80
|
*/
|
|
@@ -5,7 +5,16 @@
|
|
|
5
5
|
* metadata aligned when optional or required AI-capable features are added.
|
|
6
6
|
*/
|
|
7
7
|
import { AI_FEATURE_DEFINITIONS, resolveAiFeatureCapabilityPlan, } from '../add/ai-feature-capability.js';
|
|
8
|
+
import { CLI_DIAGNOSTIC_CODES, createCliDiagnosticCodeError, } from '../cli/cli-diagnostics.js';
|
|
8
9
|
import { parseVersionFloorParts, pickHigherVersionFloor, } from '../shared/version-floor.js';
|
|
10
|
+
/**
|
|
11
|
+
* Supported WordPress target versions for generated scaffold plugin headers.
|
|
12
|
+
*/
|
|
13
|
+
export const SCAFFOLD_WORDPRESS_TARGET_VERSIONS = ['6.9', '7.0'];
|
|
14
|
+
/**
|
|
15
|
+
* Default WordPress target version used when create callers omit `--wp-version`.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION = '7.0';
|
|
9
18
|
/**
|
|
10
19
|
* Baseline headers used by scaffold output before optional features are added.
|
|
11
20
|
*/
|
|
@@ -14,6 +23,40 @@ export const DEFAULT_SCAFFOLD_COMPATIBILITY = {
|
|
|
14
23
|
requiresPhp: '8.0',
|
|
15
24
|
testedUpTo: '6.9',
|
|
16
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Return whether a string is one of the supported scaffold WordPress targets.
|
|
28
|
+
*/
|
|
29
|
+
export function isScaffoldWordPressTargetVersion(value) {
|
|
30
|
+
return SCAFFOLD_WORDPRESS_TARGET_VERSIONS.includes(value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve CLI input into a supported scaffold WordPress target version.
|
|
34
|
+
*
|
|
35
|
+
* Empty input falls back to the default `7.0` target.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveScaffoldWordPressTargetVersion(value) {
|
|
38
|
+
if (value === undefined || value.trim().length === 0) {
|
|
39
|
+
return DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION;
|
|
40
|
+
}
|
|
41
|
+
const normalized = value.trim();
|
|
42
|
+
if (isScaffoldWordPressTargetVersion(normalized)) {
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unsupported --wp-version "${value}". Expected one of: ${SCAFFOLD_WORDPRESS_TARGET_VERSIONS.join(', ')}.`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build scaffold header compatibility for the selected WordPress target.
|
|
49
|
+
*
|
|
50
|
+
* The selected target controls `Tested up to`; hard minimums remain tied to the
|
|
51
|
+
* compatibility policy floor.
|
|
52
|
+
*/
|
|
53
|
+
export function createScaffoldCompatibilityBaseline(wpVersion) {
|
|
54
|
+
const testedUpTo = wpVersion ?? DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION;
|
|
55
|
+
return {
|
|
56
|
+
...DEFAULT_SCAFFOLD_COMPATIBILITY,
|
|
57
|
+
testedUpTo,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
17
60
|
/**
|
|
18
61
|
* Optional WordPress AI Client surface used by server-only AI feature scaffold.
|
|
19
62
|
*/
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import type { ScaffoldAnswers, ScaffoldTemplateVariables } from './scaffold.js';
|
|
2
|
+
import { type ScaffoldWordPressTargetVersion } from "./scaffold-compatibility.js";
|
|
3
|
+
/**
|
|
4
|
+
* Optional overrides for scaffold template variable generation.
|
|
5
|
+
*/
|
|
6
|
+
export interface GetTemplateVariablesOptions {
|
|
7
|
+
/**
|
|
8
|
+
* WordPress target version used for generated plugin `Tested up to` headers.
|
|
9
|
+
*/
|
|
10
|
+
wpVersion?: ScaffoldWordPressTargetVersion;
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
13
|
* Build the normalized template variables used by scaffold rendering.
|
|
4
14
|
*
|
|
5
15
|
* @param templateId Selected scaffold template identifier.
|
|
6
16
|
* @param answers Normalized scaffold answers collected from defaults, flags, and prompts.
|
|
17
|
+
* @param options Optional compatibility overrides used while building variables.
|
|
7
18
|
* @returns Template variables ready for file interpolation and generated artifacts.
|
|
8
19
|
*/
|
|
9
|
-
export declare function getTemplateVariables(templateId: string, answers: ScaffoldAnswers): ScaffoldTemplateVariables;
|
|
20
|
+
export declare function getTemplateVariables(templateId: string, answers: ScaffoldAnswers, options?: GetTemplateVariablesOptions): ScaffoldTemplateVariables;
|
|
@@ -6,21 +6,23 @@ import { DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID, getCompoundInnerBlocksPresetDe
|
|
|
6
6
|
import { getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
7
7
|
import { toPascalCase, toSnakeCase, } from '../shared/string-case.js';
|
|
8
8
|
import { attachScaffoldTemplateVariableGroups } from "./scaffold-template-variable-groups.js";
|
|
9
|
-
import { resolveScaffoldCompatibilityPolicy } from "./scaffold-compatibility.js";
|
|
9
|
+
import { createScaffoldCompatibilityBaseline, resolveScaffoldCompatibilityPolicy, } from "./scaffold-compatibility.js";
|
|
10
10
|
/**
|
|
11
11
|
* Build the normalized template variables used by scaffold rendering.
|
|
12
12
|
*
|
|
13
13
|
* @param templateId Selected scaffold template identifier.
|
|
14
14
|
* @param answers Normalized scaffold answers collected from defaults, flags, and prompts.
|
|
15
|
+
* @param options Optional compatibility overrides used while building variables.
|
|
15
16
|
* @returns Template variables ready for file interpolation and generated artifacts.
|
|
16
17
|
*/
|
|
17
|
-
export function getTemplateVariables(templateId, answers) {
|
|
18
|
+
export function getTemplateVariables(templateId, answers, options = {}) {
|
|
18
19
|
if (isBuiltInTemplateId(templateId)) {
|
|
19
20
|
return buildTemplateVariablesFromBlockSpec(createBuiltInBlockSpec({
|
|
20
21
|
answers,
|
|
21
22
|
dataStorageMode: answers.dataStorageMode,
|
|
22
23
|
persistencePolicy: answers.persistencePolicy,
|
|
23
24
|
templateId,
|
|
25
|
+
wpVersion: options.wpVersion,
|
|
24
26
|
}));
|
|
25
27
|
}
|
|
26
28
|
const { apiClientPackageVersion, blockRuntimePackageVersion, blockTypesPackageVersion, projectToolsPackageVersion, restPackageVersion, wpTypiaPackageVersion, } = getPackageVersions();
|
|
@@ -59,7 +61,9 @@ export function getTemplateVariables(templateId, answers) {
|
|
|
59
61
|
const persistencePolicy = templateId === 'persistence' || compoundPersistenceEnabled
|
|
60
62
|
? answers.persistencePolicy ?? 'authenticated'
|
|
61
63
|
: 'authenticated';
|
|
62
|
-
const compatibility = resolveScaffoldCompatibilityPolicy([]
|
|
64
|
+
const compatibility = resolveScaffoldCompatibilityPolicy([], {
|
|
65
|
+
baseline: createScaffoldCompatibilityBaseline(options.wpVersion),
|
|
66
|
+
});
|
|
63
67
|
const flatVariables = {
|
|
64
68
|
alternateRenderTargetsCsv: '',
|
|
65
69
|
alternateRenderTargetsJson: '[]',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PackageManagerId } from "../shared/package-managers.js";
|
|
2
|
+
import type { ScaffoldWordPressTargetVersion } from "./scaffold-compatibility.js";
|
|
2
3
|
import type { ScaffoldTemplateVariableGroupsCarrier } from "./scaffold-template-variable-groups.js";
|
|
3
4
|
/**
|
|
4
5
|
* User-facing scaffold answers before template rendering.
|
|
@@ -176,6 +177,7 @@ interface ScaffoldProjectOptions {
|
|
|
176
177
|
withMigrationUi?: boolean;
|
|
177
178
|
withTestPreset?: boolean;
|
|
178
179
|
withWpEnv?: boolean;
|
|
180
|
+
wpVersion?: ScaffoldWordPressTargetVersion;
|
|
179
181
|
}
|
|
180
182
|
export interface ScaffoldProjectResult {
|
|
181
183
|
packageManager: PackageManagerId;
|
|
@@ -202,4 +204,4 @@ export declare function isCreateProfileId(value: string): value is CreateProfile
|
|
|
202
204
|
* profile list for CLI diagnostics.
|
|
203
205
|
*/
|
|
204
206
|
export declare function resolveCreateProfileId(profile?: string): CreateProfileId | undefined;
|
|
205
|
-
export declare function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, profile, repositoryReference, cwd, allowExistingDir, noInstall, installDependencies, onProgress, variant, withMigrationUi, withTestPreset, withWpEnv, }: ScaffoldProjectOptions): Promise<ScaffoldProjectResult>;
|
|
207
|
+
export declare function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, profile, repositoryReference, cwd, allowExistingDir, noInstall, installDependencies, onProgress, variant, withMigrationUi, withTestPreset, withWpEnv, wpVersion, }: ScaffoldProjectOptions): Promise<ScaffoldProjectResult>;
|
|
@@ -77,7 +77,7 @@ async function applyCreateProfile({ profile, projectDir, }) {
|
|
|
77
77
|
async function reportScaffoldProgress(onProgress, event) {
|
|
78
78
|
await onProgress?.(event);
|
|
79
79
|
}
|
|
80
|
-
export async function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, profile, repositoryReference, cwd = process.cwd(), allowExistingDir = false, noInstall = false, installDependencies = undefined, onProgress = undefined, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
80
|
+
export async function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, profile, repositoryReference, cwd = process.cwd(), allowExistingDir = false, noInstall = false, installDependencies = undefined, onProgress = undefined, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, wpVersion, }) {
|
|
81
81
|
const resolvedTemplateId = normalizeTemplateSelection(templateId);
|
|
82
82
|
const resolvedPackageManager = getPackageManager(packageManager).id;
|
|
83
83
|
const isBuiltInTemplate = isBuiltInTemplateId(resolvedTemplateId);
|
|
@@ -115,6 +115,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, alterna
|
|
|
115
115
|
withMigrationUi,
|
|
116
116
|
withTestPreset,
|
|
117
117
|
withWpEnv,
|
|
118
|
+
wpVersion,
|
|
118
119
|
});
|
|
119
120
|
const validated = await blockGeneratorService.validate({ plan });
|
|
120
121
|
const rendered = await blockGeneratorService.render({ validated });
|
|
@@ -131,6 +132,8 @@ export async function scaffoldProject({ projectDir, templateId, answers, alterna
|
|
|
131
132
|
...answers,
|
|
132
133
|
dataStorageMode: dataStorageMode ?? answers.dataStorageMode,
|
|
133
134
|
persistencePolicy: persistencePolicy ?? answers.persistencePolicy,
|
|
135
|
+
}, {
|
|
136
|
+
wpVersion,
|
|
134
137
|
});
|
|
135
138
|
await reportScaffoldProgress(onProgress, {
|
|
136
139
|
detail: "Loading template files, variants, and external package metadata when needed.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { getPropertyNameText } from "../shared/ts-property-names.js";
|
|
3
|
+
import { parseVersionFloorParts } from "../shared/version-floor.js";
|
|
3
4
|
import { assertParsedInventoryEntry, } from "./workspace-inventory-parser-validation.js";
|
|
4
5
|
function findExportedArrayLiteral(sourceFile, exportName) {
|
|
5
6
|
for (const statement of sourceFile.statements) {
|
|
@@ -88,6 +89,106 @@ function getOptionalBooleanProperty(entryName, elementIndex, objectLiteral, key)
|
|
|
88
89
|
}
|
|
89
90
|
return undefined;
|
|
90
91
|
}
|
|
92
|
+
function findObjectPropertyExpression(objectLiteral, key) {
|
|
93
|
+
for (const property of objectLiteral.properties) {
|
|
94
|
+
if (!ts.isPropertyAssignment(property)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (getPropertyNameText(property.name) === key) {
|
|
98
|
+
return property.initializer;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function getRequiredObjectLiteralProperty(objectLiteral, key, context) {
|
|
104
|
+
const expression = findObjectPropertyExpression(objectLiteral, key);
|
|
105
|
+
if (!expression) {
|
|
106
|
+
throw new Error(`${context}.${key} is required in scripts/block-config.ts.`);
|
|
107
|
+
}
|
|
108
|
+
if (!ts.isObjectLiteralExpression(expression)) {
|
|
109
|
+
throw new Error(`${context}.${key} must be an object literal in scripts/block-config.ts.`);
|
|
110
|
+
}
|
|
111
|
+
return expression;
|
|
112
|
+
}
|
|
113
|
+
function getRequiredStringProperty(objectLiteral, key, context) {
|
|
114
|
+
const expression = findObjectPropertyExpression(objectLiteral, key);
|
|
115
|
+
if (!expression) {
|
|
116
|
+
throw new Error(`${context}.${key} is required in scripts/block-config.ts.`);
|
|
117
|
+
}
|
|
118
|
+
if (!ts.isStringLiteralLike(expression)) {
|
|
119
|
+
throw new Error(`${context}.${key} must be a string literal in scripts/block-config.ts.`);
|
|
120
|
+
}
|
|
121
|
+
return expression.text;
|
|
122
|
+
}
|
|
123
|
+
function getOptionalNestedStringProperty(objectLiteral, key, context) {
|
|
124
|
+
const expression = findObjectPropertyExpression(objectLiteral, key);
|
|
125
|
+
if (!expression) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
if (!ts.isStringLiteralLike(expression)) {
|
|
129
|
+
throw new Error(`${context}.${key} must be a string literal in scripts/block-config.ts.`);
|
|
130
|
+
}
|
|
131
|
+
return expression.text;
|
|
132
|
+
}
|
|
133
|
+
function getOptionalVersionFloorProperty(objectLiteral, key, context) {
|
|
134
|
+
const value = getOptionalNestedStringProperty(objectLiteral, key, context);
|
|
135
|
+
if (value === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
parseVersionFloorParts(value);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
throw new Error(`${context}.${key} must be a dotted numeric version such as "6.7" or "8.1.2" in scripts/block-config.ts.`);
|
|
143
|
+
}
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
function getRequiredStringArrayProperty(objectLiteral, key, context) {
|
|
147
|
+
const expression = findObjectPropertyExpression(objectLiteral, key);
|
|
148
|
+
if (!expression) {
|
|
149
|
+
throw new Error(`${context}.${key} is required in scripts/block-config.ts.`);
|
|
150
|
+
}
|
|
151
|
+
if (!ts.isArrayLiteralExpression(expression)) {
|
|
152
|
+
throw new Error(`${context}.${key} must be an array literal in scripts/block-config.ts.`);
|
|
153
|
+
}
|
|
154
|
+
return expression.elements.map((element, itemIndex) => {
|
|
155
|
+
if (!ts.isStringLiteralLike(element)) {
|
|
156
|
+
throw new Error(`${context}.${key}[${itemIndex}] must be a string literal in scripts/block-config.ts.`);
|
|
157
|
+
}
|
|
158
|
+
return element.text;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function parseCompatibilityConfigLiteral(objectLiteral, context) {
|
|
162
|
+
const hardMinimumsObject = getRequiredObjectLiteralProperty(objectLiteral, "hardMinimums", context);
|
|
163
|
+
const mode = getRequiredStringProperty(objectLiteral, "mode", context);
|
|
164
|
+
if (mode !== "baseline" && mode !== "optional" && mode !== "required") {
|
|
165
|
+
throw new Error(`${context}.mode must be baseline, optional, or required in scripts/block-config.ts.`);
|
|
166
|
+
}
|
|
167
|
+
const php = getOptionalVersionFloorProperty(hardMinimumsObject, "php", `${context}.hardMinimums`);
|
|
168
|
+
const wordpress = getOptionalVersionFloorProperty(hardMinimumsObject, "wordpress", `${context}.hardMinimums`);
|
|
169
|
+
return {
|
|
170
|
+
hardMinimums: {
|
|
171
|
+
...(php ? { php } : {}),
|
|
172
|
+
...(wordpress ? { wordpress } : {}),
|
|
173
|
+
},
|
|
174
|
+
mode,
|
|
175
|
+
optionalFeatureIds: getRequiredStringArrayProperty(objectLiteral, "optionalFeatureIds", context),
|
|
176
|
+
optionalFeatures: getRequiredStringArrayProperty(objectLiteral, "optionalFeatures", context),
|
|
177
|
+
requiredFeatureIds: getRequiredStringArrayProperty(objectLiteral, "requiredFeatureIds", context),
|
|
178
|
+
requiredFeatures: getRequiredStringArrayProperty(objectLiteral, "requiredFeatures", context),
|
|
179
|
+
runtimeGates: getRequiredStringArrayProperty(objectLiteral, "runtimeGates", context),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function getOptionalCompatibilityConfigProperty(entryName, elementIndex, objectLiteral, key) {
|
|
183
|
+
const expression = findObjectPropertyExpression(objectLiteral, key);
|
|
184
|
+
if (!expression) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
if (!ts.isObjectLiteralExpression(expression)) {
|
|
188
|
+
throw new Error(`${entryName}[${elementIndex}].${key} must be an object literal in scripts/block-config.ts.`);
|
|
189
|
+
}
|
|
190
|
+
return parseCompatibilityConfigLiteral(expression, `${entryName}[${elementIndex}].${key}`);
|
|
191
|
+
}
|
|
91
192
|
function parseInventoryEntries(arrayLiteral, descriptor) {
|
|
92
193
|
return arrayLiteral.elements.map((element, elementIndex) => {
|
|
93
194
|
if (!ts.isObjectLiteralExpression(element)) {
|
|
@@ -98,9 +199,11 @@ function parseInventoryEntries(arrayLiteral, descriptor) {
|
|
|
98
199
|
const kind = field.kind ?? "string";
|
|
99
200
|
const value = kind === "stringArray"
|
|
100
201
|
? getOptionalStringArrayProperty(descriptor.entryName, elementIndex, element, field.key)
|
|
101
|
-
: kind === "
|
|
102
|
-
?
|
|
103
|
-
:
|
|
202
|
+
: kind === "compatibilityConfig"
|
|
203
|
+
? getOptionalCompatibilityConfigProperty(descriptor.entryName, elementIndex, element, field.key)
|
|
204
|
+
: kind === "boolean"
|
|
205
|
+
? getOptionalBooleanProperty(descriptor.entryName, elementIndex, element, field.key)
|
|
206
|
+
: getOptionalStringProperty(descriptor.entryName, elementIndex, element, field.key);
|
|
104
207
|
field.validate?.(value, {
|
|
105
208
|
elementIndex,
|
|
106
209
|
entryName: descriptor.entryName,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { WorkspaceInventoryAppendOptionKey, WorkspaceInventoryEntriesKey, WorkspaceInventorySectionFlagKey } from "./workspace-inventory-types.js";
|
|
2
|
+
import type { ScaffoldCompatibilityConfig } from "../templates/scaffold-compatibility.js";
|
|
2
3
|
/**
|
|
3
4
|
* Literal value shape accepted by descriptor-driven inventory entry fields.
|
|
4
5
|
*/
|
|
5
|
-
export type InventoryEntryFieldValue = string | string[] | boolean | undefined;
|
|
6
|
+
export type InventoryEntryFieldValue = string | string[] | boolean | ScaffoldCompatibilityConfig | undefined;
|
|
6
7
|
/**
|
|
7
8
|
* Context passed to custom field validators while parsing one inventory entry.
|
|
8
9
|
*/
|
|
@@ -13,7 +14,7 @@ export type InventoryEntryFieldValidationContext = {
|
|
|
13
14
|
};
|
|
14
15
|
type InventoryEntryFieldDescriptor = {
|
|
15
16
|
key: string;
|
|
16
|
-
kind?: "boolean" | "string" | "stringArray";
|
|
17
|
+
kind?: "boolean" | "compatibilityConfig" | "string" | "stringArray";
|
|
17
18
|
required?: boolean;
|
|
18
19
|
validate?: (value: InventoryEntryFieldValue, context: InventoryEntryFieldValidationContext) => void;
|
|
19
20
|
};
|
|
@@ -336,6 +336,7 @@ export const INVENTORY_SECTIONS = [
|
|
|
336
336
|
entryName: "ABILITIES",
|
|
337
337
|
fields: [
|
|
338
338
|
{ key: "clientFile", required: true },
|
|
339
|
+
{ key: "compatibility", kind: "compatibilityConfig" },
|
|
339
340
|
{ key: "configFile", required: true },
|
|
340
341
|
{ key: "dataFile", required: true },
|
|
341
342
|
{ key: "inputSchemaFile", required: true },
|
|
@@ -371,6 +372,7 @@ export const INVENTORY_SECTIONS = [
|
|
|
371
372
|
{ key: "aiSchemaFile", required: true },
|
|
372
373
|
{ key: "apiFile", required: true },
|
|
373
374
|
{ key: "clientFile", required: true },
|
|
375
|
+
{ key: "compatibility", kind: "compatibilityConfig" },
|
|
374
376
|
{ key: "dataFile", required: true },
|
|
375
377
|
{ key: "namespace", required: true },
|
|
376
378
|
{ key: "openApiFile", required: true },
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScaffoldCompatibilityConfig } from "../templates/scaffold-compatibility.js";
|
|
1
2
|
export interface WorkspaceBlockInventoryEntry {
|
|
2
3
|
apiTypesFile?: string;
|
|
3
4
|
attributeTypeName?: string;
|
|
@@ -113,6 +114,7 @@ export interface WorkspacePostMetaInventoryEntry {
|
|
|
113
114
|
*/
|
|
114
115
|
export interface WorkspaceAbilityInventoryEntry {
|
|
115
116
|
clientFile: string;
|
|
117
|
+
compatibility?: ScaffoldCompatibilityConfig;
|
|
116
118
|
configFile: string;
|
|
117
119
|
dataFile: string;
|
|
118
120
|
inputSchemaFile: string;
|
|
@@ -134,6 +136,7 @@ export interface WorkspaceAiFeatureInventoryEntry {
|
|
|
134
136
|
aiSchemaFile: string;
|
|
135
137
|
apiFile: string;
|
|
136
138
|
clientFile: string;
|
|
139
|
+
compatibility?: ScaffoldCompatibilityConfig;
|
|
137
140
|
dataFile: string;
|
|
138
141
|
namespace: string;
|
|
139
142
|
openApiFile: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-typia/project-tools",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.8",
|
|
4
4
|
"description": "Project orchestration and programmatic tooling for wp-typia",
|
|
5
5
|
"packageManager": "bun@1.3.11",
|
|
6
6
|
"type": "module",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"package.json"
|
|
122
122
|
],
|
|
123
123
|
"scripts": {
|
|
124
|
-
"build": "bun run --filter @wp-typia/api-client build && bun run --filter @wp-typia/block-runtime build && rm -rf dist && tsc -p tsconfig.runtime.json",
|
|
124
|
+
"build": "bun run --filter @wp-typia/block-types build && bun run --filter @wp-typia/api-client build && bun run --filter @wp-typia/block-runtime build && rm -rf dist && tsc -p tsconfig.runtime.json",
|
|
125
125
|
"prepack": "bun run build && node ./scripts/publish-manifest.mjs prepare",
|
|
126
126
|
"postpack": "node ./scripts/publish-manifest.mjs restore",
|
|
127
127
|
"test": "bun run build && bun test tests/*.test.ts",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"@wp-typia/api-client": "^0.4.6",
|
|
169
169
|
"@wp-typia/block-runtime": "^0.7.1",
|
|
170
170
|
"@wp-typia/rest": "^0.3.14",
|
|
171
|
-
"@wp-typia/block-types": "^0.3.
|
|
171
|
+
"@wp-typia/block-types": "^0.3.4",
|
|
172
172
|
"mustache": "^4.2.0",
|
|
173
173
|
"npm-package-arg": "^13.0.0",
|
|
174
174
|
"semver": "^7.7.3",
|