@wp-typia/project-tools 0.24.7 → 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.
@@ -1,24 +1,39 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
4
- import ts from "typescript";
4
+ import { WORDPRESS_BLOCK_API_COMPATIBILITY } from "@wp-typia/block-types/blocks/compatibility";
5
5
  import { createDoctorCheck, resolveWorkspaceBootstrapPath, } from "./cli-doctor-workspace-shared.js";
6
6
  import { readJsonFileSync } from "../shared/json-utils.js";
7
- import { getPropertyNameText } from "../shared/ts-property-names.js";
8
7
  import { compareVersionFloors, pickHigherVersionFloor, } from "../shared/version-floor.js";
9
8
  import { DEFAULT_SCAFFOLD_WORDPRESS_TARGET_VERSION } from "../templates/scaffold-compatibility.js";
10
9
  const WORDPRESS_VERSION_CHECK_CODES = {
11
10
  featureMinimum: "wp-typia.workspace.wordpress.feature-minimum",
12
11
  testedTarget: "wp-typia.workspace.wordpress.tested-target",
13
12
  };
14
- const BLOCK_METADATA_WORDPRESS_FLOORS = {
15
- blockHooks: "6.4",
16
- supportsInteractivity: "6.5",
17
- supportsSplitting: "6.5",
18
- };
19
13
  function isEnabledMetadataValue(value) {
20
14
  return value !== undefined && value !== false && value !== null;
21
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
+ }
22
37
  function getBootstrapHeaderValue(source, headerName) {
23
38
  const escapedHeaderName = headerName.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
24
39
  const pattern = new RegExp(`^\\s*\\*\\s*${escapedHeaderName}:\\s*([^\\r\\n]*)`, "mu");
@@ -42,6 +57,15 @@ function pushRequirement(requirements, label, version) {
42
57
  version,
43
58
  });
44
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
+ }
45
69
  function collectBlockMetadataRequirements(workspace, inventory) {
46
70
  const issues = [];
47
71
  const requirements = [];
@@ -61,14 +85,21 @@ function collectBlockMetadataRequirements(workspace, inventory) {
61
85
  issues.push(`${blockJsonRelativePath}: ${error instanceof Error ? error.message : String(error)}`);
62
86
  continue;
63
87
  }
64
- if (isEnabledMetadataValue(blockJson.supports?.interactivity)) {
65
- pushRequirement(requirements, `Block ${block.slug} supports.interactivity`, BLOCK_METADATA_WORDPRESS_FLOORS.supportsInteractivity);
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
+ }
66
92
  }
67
- if (isEnabledMetadataValue(blockJson.supports?.splitting)) {
68
- pushRequirement(requirements, `Block ${block.slug} supports.splitting`, BLOCK_METADATA_WORDPRESS_FLOORS.supportsSplitting);
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
+ }
69
97
  }
70
- if (blockJson.blockHooks !== undefined) {
71
- pushRequirement(requirements, `Block ${block.slug} blockHooks`, BLOCK_METADATA_WORDPRESS_FLOORS.blockHooks);
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
+ }
72
103
  }
73
104
  }
74
105
  return {
@@ -76,89 +107,64 @@ function collectBlockMetadataRequirements(workspace, inventory) {
76
107
  requirements,
77
108
  };
78
109
  }
79
- function findExportedArrayLiteral(sourceFile, exportName) {
80
- for (const statement of sourceFile.statements) {
81
- if (!ts.isVariableStatement(statement) ||
82
- !statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
83
- continue;
84
- }
85
- for (const declaration of statement.declarationList.declarations) {
86
- if (ts.isIdentifier(declaration.name) &&
87
- declaration.name.text === exportName &&
88
- declaration.initializer &&
89
- ts.isArrayLiteralExpression(declaration.initializer)) {
90
- return declaration.initializer;
91
- }
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
+ });
92
119
  }
93
120
  }
94
- return null;
95
- }
96
- function getObjectProperty(objectLiteral, key) {
97
- for (const property of objectLiteral.properties) {
98
- if (!ts.isPropertyAssignment(property)) {
99
- continue;
100
- }
101
- if (getPropertyNameText(property.name) === key) {
102
- return property.initializer;
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
+ });
103
128
  }
104
129
  }
105
- return undefined;
106
- }
107
- function getObjectLiteralProperty(objectLiteral, key) {
108
- const property = objectLiteral ? getObjectProperty(objectLiteral, key) : undefined;
109
- return property && ts.isObjectLiteralExpression(property) ? property : undefined;
110
- }
111
- function getStringLiteralProperty(objectLiteral, key) {
112
- const property = getObjectProperty(objectLiteral, key);
113
- return property && ts.isStringLiteralLike(property) ? property.text : undefined;
130
+ return {
131
+ issues: [],
132
+ requirements,
133
+ };
114
134
  }
115
- function collectInventoryCompatibilityRequirements(inventory) {
116
- const issues = [];
135
+ function collectBindingSourceRequirements(workspace, inventory) {
117
136
  const requirements = [];
118
- const sourceFile = ts.createSourceFile("scripts/block-config.ts", inventory.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
119
- for (const section of [
120
- { exportName: "ABILITIES", label: "Ability" },
121
- { exportName: "AI_FEATURES", label: "AI feature" },
122
- ]) {
123
- const arrayLiteral = findExportedArrayLiteral(sourceFile, section.exportName);
124
- if (!arrayLiteral) {
125
- continue;
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);
126
148
  }
127
- arrayLiteral.elements.forEach((element, elementIndex) => {
128
- if (!ts.isObjectLiteralExpression(element)) {
129
- return;
130
- }
131
- const slug = getStringLiteralProperty(element, "slug") ?? `entry ${elementIndex + 1}`;
132
- const compatibility = getObjectLiteralProperty(element, "compatibility");
133
- const hardMinimums = getObjectLiteralProperty(compatibility, "hardMinimums");
134
- const wordpressMinimum = hardMinimums
135
- ? getObjectProperty(hardMinimums, "wordpress")
136
- : undefined;
137
- if (wordpressMinimum === undefined) {
138
- return;
139
- }
140
- if (!ts.isStringLiteralLike(wordpressMinimum)) {
141
- issues.push(`${section.exportName}[${elementIndex}].compatibility.hardMinimums.wordpress must be a string literal.`);
142
- return;
143
- }
144
- requirements.push({
145
- label: `${section.label} ${slug} compatibility metadata`,
146
- version: wordpressMinimum.text,
147
- });
148
- });
149
149
  }
150
150
  return {
151
- issues,
151
+ issues: [],
152
152
  requirements,
153
153
  };
154
154
  }
155
155
  function collectWordPressVersionRequirements(workspace, inventory) {
156
156
  const blockRequirements = collectBlockMetadataRequirements(workspace, inventory);
157
+ const bindingRequirements = collectBindingSourceRequirements(workspace, inventory);
157
158
  const inventoryRequirements = collectInventoryCompatibilityRequirements(inventory);
158
159
  return {
159
- issues: [...blockRequirements.issues, ...inventoryRequirements.issues],
160
+ issues: [
161
+ ...blockRequirements.issues,
162
+ ...bindingRequirements.issues,
163
+ ...inventoryRequirements.issues,
164
+ ],
160
165
  requirements: [
161
166
  ...blockRequirements.requirements,
167
+ ...bindingRequirements.requirements,
162
168
  ...inventoryRequirements.requirements,
163
169
  ],
164
170
  };
@@ -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) {
@@ -129,6 +130,19 @@ function getOptionalNestedStringProperty(objectLiteral, key, context) {
129
130
  }
130
131
  return expression.text;
131
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
+ }
132
146
  function getRequiredStringArrayProperty(objectLiteral, key, context) {
133
147
  const expression = findObjectPropertyExpression(objectLiteral, key);
134
148
  if (!expression) {
@@ -150,8 +164,8 @@ function parseCompatibilityConfigLiteral(objectLiteral, context) {
150
164
  if (mode !== "baseline" && mode !== "optional" && mode !== "required") {
151
165
  throw new Error(`${context}.mode must be baseline, optional, or required in scripts/block-config.ts.`);
152
166
  }
153
- const php = getOptionalNestedStringProperty(hardMinimumsObject, "php", `${context}.hardMinimums`);
154
- const wordpress = getOptionalNestedStringProperty(hardMinimumsObject, "wordpress", `${context}.hardMinimums`);
167
+ const php = getOptionalVersionFloorProperty(hardMinimumsObject, "php", `${context}.hardMinimums`);
168
+ const wordpress = getOptionalVersionFloorProperty(hardMinimumsObject, "wordpress", `${context}.hardMinimums`);
155
169
  return {
156
170
  hardMinimums: {
157
171
  ...(php ? { php } : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-typia/project-tools",
3
- "version": "0.24.7",
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",