@wp-typia/block-types 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,298 @@
1
+ import { createWordPressBlockApiCompatibilityManifest, } from "./compatibility.js";
2
+ export const DEFINED_BLOCK_VARIATION_METADATA = Symbol.for("@wp-typia/block-types/defined-variation");
3
+ export const DEFINED_BLOCK_VARIATIONS_METADATA = Symbol.for("@wp-typia/block-types/defined-variations");
4
+ const DEFINE_VARIATION_INLINE_OPTION_KEYS = new Set([
5
+ "allowMissingIsActive",
6
+ "minVersion",
7
+ "minWordPress",
8
+ "onDiagnostic",
9
+ "requireIsActive",
10
+ "strict",
11
+ ]);
12
+ const STABLE_VARIATION_MARKER_ATTRIBUTES = [
13
+ "className",
14
+ "namespace",
15
+ "wpTypiaVariation",
16
+ ];
17
+ function isObjectRecord(value) {
18
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19
+ }
20
+ function splitDefineVariationInput(variation) {
21
+ const inlineOptions = {};
22
+ const normalizedVariation = {};
23
+ for (const [key, value] of Object.entries(variation)) {
24
+ if (DEFINE_VARIATION_INLINE_OPTION_KEYS.has(key)) {
25
+ Object.assign(inlineOptions, { [key]: value });
26
+ continue;
27
+ }
28
+ normalizedVariation[key] = value;
29
+ }
30
+ return {
31
+ inlineOptions,
32
+ variation: normalizedVariation,
33
+ };
34
+ }
35
+ function resolveDefineVariationSettings(inlineOptions, options) {
36
+ const compatibility = {};
37
+ const allowUnknownFutureKeys = options.allowUnknownFutureKeys;
38
+ const minVersion = options.minVersion ??
39
+ options.minWordPress ??
40
+ inlineOptions.minVersion ??
41
+ inlineOptions.minWordPress;
42
+ const strict = options.strict ?? inlineOptions.strict ?? true;
43
+ if (allowUnknownFutureKeys !== undefined) {
44
+ Object.assign(compatibility, { allowUnknownFutureKeys });
45
+ }
46
+ if (minVersion !== undefined) {
47
+ Object.assign(compatibility, { minVersion });
48
+ }
49
+ Object.assign(compatibility, { strict });
50
+ return {
51
+ compatibility,
52
+ diagnostics: {
53
+ allowMissingIsActive: options.allowMissingIsActive ?? inlineOptions.allowMissingIsActive ?? false,
54
+ requireIsActive: options.requireIsActive ?? inlineOptions.requireIsActive ?? true,
55
+ strict,
56
+ },
57
+ onDiagnostic: options.onDiagnostic ?? inlineOptions.onDiagnostic,
58
+ };
59
+ }
60
+ function getDiagnosticSeverity(strict) {
61
+ return strict ? "error" : "warning";
62
+ }
63
+ export function collectBlockVariationCompatibilityFeatures() {
64
+ return [
65
+ {
66
+ area: "blockVariations",
67
+ feature: "editorRegistration",
68
+ },
69
+ ];
70
+ }
71
+ export function createBlockVariationCompatibilityManifest(settings = {}) {
72
+ const resolved = resolveDefineVariationSettings({}, settings);
73
+ return createWordPressBlockApiCompatibilityManifest(collectBlockVariationCompatibilityFeatures(), resolved.compatibility);
74
+ }
75
+ function hasStableMarkerAttribute(attributes) {
76
+ if (!isObjectRecord(attributes)) {
77
+ return false;
78
+ }
79
+ return STABLE_VARIATION_MARKER_ATTRIBUTES.some((key) => key in attributes);
80
+ }
81
+ function createVariationDiagnostics(blockName, variation, options) {
82
+ const diagnostics = [];
83
+ const variationName = variation.name;
84
+ const attributes = variation.attributes;
85
+ const isActive = variation.isActive;
86
+ if (options.requireIsActive &&
87
+ !options.allowMissingIsActive &&
88
+ !variation.isDefault &&
89
+ isActive === undefined) {
90
+ diagnostics.push({
91
+ blockName,
92
+ code: "missing-is-active",
93
+ message: `Block variation "${variationName}" for "${blockName}" does not declare isActive; add an active discriminator or set allowMissingIsActive.`,
94
+ severity: "warning",
95
+ variationName,
96
+ });
97
+ }
98
+ if (options.requireIsActive &&
99
+ !options.allowMissingIsActive &&
100
+ !variation.isDefault &&
101
+ isActive === undefined &&
102
+ !hasStableMarkerAttribute(attributes)) {
103
+ diagnostics.push({
104
+ blockName,
105
+ code: "missing-stable-marker",
106
+ message: `Block variation "${variationName}" for "${blockName}" has no stable marker attribute such as className, namespace, or wpTypiaVariation.`,
107
+ severity: "warning",
108
+ variationName,
109
+ });
110
+ }
111
+ if (Array.isArray(isActive)) {
112
+ for (const attribute of isActive) {
113
+ if (!isObjectRecord(attributes) || !(attribute in attributes)) {
114
+ diagnostics.push({
115
+ attribute,
116
+ blockName,
117
+ code: "unknown-is-active-attribute",
118
+ message: `Block variation "${variationName}" for "${blockName}" uses isActive attribute "${attribute}" that is not present in its attributes.`,
119
+ severity: "warning",
120
+ variationName,
121
+ });
122
+ }
123
+ }
124
+ }
125
+ return diagnostics;
126
+ }
127
+ function handleVariationDiagnostics(diagnostics, onDiagnostic) {
128
+ const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
129
+ if (errors.length > 0) {
130
+ throw new Error([
131
+ "WordPress block variation check failed:",
132
+ ...errors.map((diagnostic) => `- ${diagnostic.message}`),
133
+ ].join("\n"));
134
+ }
135
+ for (const diagnostic of diagnostics) {
136
+ if (onDiagnostic) {
137
+ onDiagnostic(diagnostic);
138
+ continue;
139
+ }
140
+ console.warn(`[wp-typia] ${diagnostic.message}`);
141
+ }
142
+ }
143
+ export function getDefinedVariationMetadata(variation) {
144
+ return isObjectRecord(variation)
145
+ ? variation[DEFINED_BLOCK_VARIATION_METADATA]
146
+ : undefined;
147
+ }
148
+ export function getDefinedVariationBlockName(variation) {
149
+ return getDefinedVariationMetadata(variation)?.blockName;
150
+ }
151
+ export function getDefinedVariationCompatibilityManifest(variation) {
152
+ return getDefinedVariationMetadata(variation)?.manifest;
153
+ }
154
+ export function getDefinedVariationsMetadata(variations) {
155
+ return Array.isArray(variations)
156
+ ? variations[DEFINED_BLOCK_VARIATIONS_METADATA]
157
+ : undefined;
158
+ }
159
+ export function defineVariation(blockName, variation, options = {}) {
160
+ const { inlineOptions, variation: normalizedVariation } = splitDefineVariationInput(variation);
161
+ const resolved = resolveDefineVariationSettings(inlineOptions, options);
162
+ const manifest = createWordPressBlockApiCompatibilityManifest(collectBlockVariationCompatibilityFeatures(), resolved.compatibility);
163
+ const diagnostics = [
164
+ ...manifest.diagnostics,
165
+ ...createVariationDiagnostics(blockName, normalizedVariation, resolved.diagnostics),
166
+ ];
167
+ handleVariationDiagnostics(diagnostics, resolved.onDiagnostic);
168
+ Object.defineProperty(normalizedVariation, DEFINED_BLOCK_VARIATION_METADATA, {
169
+ configurable: false,
170
+ enumerable: false,
171
+ value: {
172
+ blockName,
173
+ diagnostics,
174
+ manifest,
175
+ },
176
+ writable: false,
177
+ });
178
+ return normalizedVariation;
179
+ }
180
+ function createCollectionDiagnostics(entries, strict) {
181
+ const diagnostics = [];
182
+ const seenNames = new Map();
183
+ const seenActiveMarkers = new Map();
184
+ for (const entry of entries) {
185
+ const nameKey = `${entry.blockName}:${entry.variation.name}`;
186
+ const activeMarker = Array.isArray(entry.variation.isActive)
187
+ ? entry.variation.isActive.join("|")
188
+ : undefined;
189
+ if (seenNames.has(nameKey)) {
190
+ diagnostics.push({
191
+ blockName: entry.blockName,
192
+ code: "duplicate-variation-name",
193
+ message: `Duplicate block variation name "${entry.variation.name}" for "${entry.blockName}".`,
194
+ severity: getDiagnosticSeverity(strict),
195
+ variationName: entry.variation.name,
196
+ });
197
+ }
198
+ seenNames.set(nameKey, entry);
199
+ if (activeMarker && activeMarker.length > 0) {
200
+ const markerKey = `${entry.blockName}:${activeMarker}`;
201
+ const existing = seenActiveMarkers.get(markerKey);
202
+ if (existing) {
203
+ diagnostics.push({
204
+ blockName: entry.blockName,
205
+ code: "duplicate-active-marker",
206
+ message: `Block variations "${existing.variation.name}" and "${entry.variation.name}" for "${entry.blockName}" share the same isActive discriminator "${activeMarker}".`,
207
+ severity: "warning",
208
+ variationName: entry.variation.name,
209
+ });
210
+ }
211
+ seenActiveMarkers.set(markerKey, entry);
212
+ }
213
+ }
214
+ return diagnostics;
215
+ }
216
+ export function createBlockVariationRegistrationPlan(variations) {
217
+ return variations.map((variation) => {
218
+ const metadata = getDefinedVariationMetadata(variation);
219
+ if (!metadata) {
220
+ throw new Error(`Block variation "${variation.name}" was not created by defineVariation().`);
221
+ }
222
+ return {
223
+ blockName: metadata.blockName,
224
+ variation,
225
+ };
226
+ });
227
+ }
228
+ export function defineVariations(variations, options = {}) {
229
+ const entries = createBlockVariationRegistrationPlan(variations);
230
+ const strict = options.strict ?? true;
231
+ const variationDiagnostics = entries.flatMap((entry) => getDefinedVariationMetadata(entry.variation)?.diagnostics ?? []);
232
+ const collectionDiagnostics = createCollectionDiagnostics(entries, strict);
233
+ const diagnostics = [
234
+ ...variationDiagnostics,
235
+ ...collectionDiagnostics,
236
+ ];
237
+ handleVariationDiagnostics(collectionDiagnostics, options.onDiagnostic);
238
+ const normalizedVariations = [...variations];
239
+ Object.defineProperty(normalizedVariations, DEFINED_BLOCK_VARIATIONS_METADATA, {
240
+ configurable: false,
241
+ enumerable: false,
242
+ value: {
243
+ diagnostics,
244
+ entries,
245
+ },
246
+ writable: false,
247
+ });
248
+ return normalizedVariations;
249
+ }
250
+ function normalizeStaticRegistrationValue(value, path) {
251
+ if (value === undefined) {
252
+ return undefined;
253
+ }
254
+ if (value === null ||
255
+ typeof value === "boolean" ||
256
+ typeof value === "number" ||
257
+ typeof value === "string") {
258
+ return value;
259
+ }
260
+ if (typeof value === "function") {
261
+ throw new Error(`Cannot generate static variation registration code for function value at ${path}.`);
262
+ }
263
+ if (typeof value === "bigint" || typeof value === "symbol") {
264
+ throw new Error(`Cannot generate static variation registration code for ${typeof value} value at ${path}.`);
265
+ }
266
+ if (Array.isArray(value)) {
267
+ return value.map((entry, index) => normalizeStaticRegistrationValue(entry, `${path}[${index}]`));
268
+ }
269
+ if (isObjectRecord(value)) {
270
+ const normalized = {};
271
+ for (const [key, nestedValue] of Object.entries(value)) {
272
+ const nextValue = normalizeStaticRegistrationValue(nestedValue, `${path}.${key}`);
273
+ if (nextValue !== undefined) {
274
+ normalized[key] = nextValue;
275
+ }
276
+ }
277
+ return normalized;
278
+ }
279
+ throw new Error(`Cannot generate static variation registration code for unsupported value at ${path}.`);
280
+ }
281
+ export function createStaticBlockVariationRegistrationSource(variations, options = {}) {
282
+ const importSource = options.importSource ?? "@wordpress/blocks";
283
+ const functionName = options.functionName ?? "registerWpTypiaBlockVariations";
284
+ const entries = createBlockVariationRegistrationPlan(variations).map((entry, index) => normalizeStaticRegistrationValue(entry, `variations[${index}]`));
285
+ const serializedEntries = JSON.stringify(entries, null, 2);
286
+ return [
287
+ `import { registerBlockVariation } from ${JSON.stringify(importSource)};`,
288
+ "",
289
+ `const variations = ${serializedEntries};`,
290
+ "",
291
+ `export function ${functionName}() {`,
292
+ " for (const { blockName, variation } of variations) {",
293
+ " registerBlockVariation(blockName, variation);",
294
+ " }",
295
+ "}",
296
+ "",
297
+ ].join("\n");
298
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-typia/block-types",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Shared WordPress block semantic types derived from Gutenberg and unofficial declarations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,6 +56,16 @@
56
56
  "import": "./dist/blocks/index.js",
57
57
  "default": "./dist/blocks/index.js"
58
58
  },
59
+ "./blocks/bindings": {
60
+ "types": "./dist/blocks/bindings.d.ts",
61
+ "import": "./dist/blocks/bindings.js",
62
+ "default": "./dist/blocks/bindings.js"
63
+ },
64
+ "./blocks/compatibility": {
65
+ "types": "./dist/blocks/compatibility.d.ts",
66
+ "import": "./dist/blocks/compatibility.js",
67
+ "default": "./dist/blocks/compatibility.js"
68
+ },
59
69
  "./blocks/registration": {
60
70
  "types": "./dist/blocks/registration.d.ts",
61
71
  "import": "./dist/blocks/registration.js",
@@ -66,6 +76,11 @@
66
76
  "import": "./dist/blocks/supports.js",
67
77
  "default": "./dist/blocks/supports.js"
68
78
  },
79
+ "./blocks/variations": {
80
+ "types": "./dist/blocks/variations.d.ts",
81
+ "import": "./dist/blocks/variations.js",
82
+ "default": "./dist/blocks/variations.js"
83
+ },
69
84
  "./package.json": "./package.json"
70
85
  },
71
86
  "files": [