@wp-typia/project-tools 0.23.1 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
- package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
- package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
- package/dist/runtime/cli-add-collision.js +8 -0
- package/dist/runtime/cli-add-help.js +11 -7
- package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
- package/dist/runtime/cli-add-kind-ids.js +1 -0
- package/dist/runtime/cli-add-types.d.ts +28 -1
- package/dist/runtime/cli-add-types.js +2 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
- package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -311
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +1 -1
- package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
- package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -232
- package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
- package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +3 -171
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
- package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
- package/dist/runtime/cli-add-workspace-assets.js +6 -950
- package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
- package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
- package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
- package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-block-style.js +148 -0
- package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
- package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
- package/dist/runtime/cli-add-workspace-contract.js +1 -1
- package/dist/runtime/cli-add-workspace-core-variation.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-core-variation.js +429 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
- package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
- package/dist/runtime/cli-add-workspace-integration-env.js +5 -345
- package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
- package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
- package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
- package/dist/runtime/cli-add-workspace-pattern.js +99 -0
- package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
- package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
- package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +6 -9
- package/dist/runtime/cli-add-workspace-rest-anchors.js +6 -466
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +5 -3
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +3 -16
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +1 -7
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +3 -322
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -99
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -663
- package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +3 -3
- package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-variation.js +162 -0
- package/dist/runtime/cli-add-workspace.d.ts +42 -107
- package/dist/runtime/cli-add-workspace.js +42 -674
- package/dist/runtime/cli-add.d.ts +3 -3
- package/dist/runtime/cli-add.js +2 -2
- package/dist/runtime/cli-core.d.ts +2 -1
- package/dist/runtime/cli-core.js +1 -1
- package/dist/runtime/cli-doctor-workspace-bindings.js +59 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +33 -5
- package/dist/runtime/cli-doctor.d.ts +2 -0
- package/dist/runtime/cli-doctor.js +13 -2
- package/dist/runtime/cli-help.js +7 -4
- package/dist/runtime/index.d.ts +5 -2
- package/dist/runtime/index.js +4 -2
- package/dist/runtime/json-utils.d.ts +2 -5
- package/dist/runtime/json-utils.js +2 -5
- package/dist/runtime/local-dev-presets.js +2 -1
- package/dist/runtime/package-versions.d.ts +1 -0
- package/dist/runtime/package-versions.js +15 -8
- package/dist/runtime/pattern-catalog-section-roles.d.ts +101 -0
- package/dist/runtime/pattern-catalog-section-roles.js +276 -0
- package/dist/runtime/pattern-catalog.d.ts +67 -0
- package/dist/runtime/pattern-catalog.js +225 -0
- package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
- package/dist/runtime/post-meta-binding-fields.js +135 -0
- package/dist/runtime/template-source-cache-markers.js +7 -2
- package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
- package/dist/runtime/typia-llm-json-schema.js +33 -0
- package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
- package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
- package/dist/runtime/typia-llm-projection.d.ts +25 -0
- package/dist/runtime/typia-llm-projection.js +58 -0
- package/dist/runtime/typia-llm-render.d.ts +21 -0
- package/dist/runtime/typia-llm-render.js +252 -0
- package/dist/runtime/typia-llm-sync.d.ts +10 -0
- package/dist/runtime/typia-llm-sync.js +63 -0
- package/dist/runtime/typia-llm-types.d.ts +197 -0
- package/dist/runtime/typia-llm-types.js +1 -0
- package/dist/runtime/typia-llm.d.ts +9 -255
- package/dist/runtime/typia-llm.js +5 -634
- package/dist/runtime/workspace-inventory-mutations.js +13 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +9 -1
- package/dist/runtime/workspace-inventory-templates.d.ts +2 -2
- package/dist/runtime/workspace-inventory-templates.js +9 -1
- package/dist/runtime/workspace-inventory-types.d.ts +9 -1
- package/package.json +8 -3
- package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
- package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
- package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
- package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { validateBlockPatternContentNesting, } from "@wp-typia/block-runtime/metadata-core";
|
|
2
|
+
/**
|
|
3
|
+
* Validates section role slugs used by pattern manifests and content markers.
|
|
4
|
+
*/
|
|
5
|
+
export const PATTERN_SECTION_ROLE_PATTERN = /^[a-z][a-z0-9-]*$/u;
|
|
6
|
+
const DEFAULT_SECTION_ROLE_CONVENTION = {
|
|
7
|
+
baseClassName: "section",
|
|
8
|
+
requireUniqueFullPatternRoles: false,
|
|
9
|
+
roleAttributePaths: ["metadata.sectionRole"],
|
|
10
|
+
roleClassNamePattern: "section--{role}",
|
|
11
|
+
wrapperBlockName: "core/group",
|
|
12
|
+
};
|
|
13
|
+
function createPatternCatalogDiagnostic(diagnostic) {
|
|
14
|
+
return diagnostic;
|
|
15
|
+
}
|
|
16
|
+
function normalizeSectionRoleConventionInput(convention = {}) {
|
|
17
|
+
return {
|
|
18
|
+
baseClassName: convention.baseClassName ??
|
|
19
|
+
DEFAULT_SECTION_ROLE_CONVENTION.baseClassName,
|
|
20
|
+
requireUniqueFullPatternRoles: convention.requireUniqueFullPatternRoles ??
|
|
21
|
+
DEFAULT_SECTION_ROLE_CONVENTION.requireUniqueFullPatternRoles,
|
|
22
|
+
roleAttributePaths: convention.roleAttributePaths ??
|
|
23
|
+
DEFAULT_SECTION_ROLE_CONVENTION.roleAttributePaths,
|
|
24
|
+
roleClassNamePattern: convention.roleClassNamePattern ??
|
|
25
|
+
DEFAULT_SECTION_ROLE_CONVENTION.roleClassNamePattern,
|
|
26
|
+
wrapperBlockName: convention.wrapperBlockName ??
|
|
27
|
+
DEFAULT_SECTION_ROLE_CONVENTION.wrapperBlockName,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function escapeRegExp(value) {
|
|
31
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
32
|
+
}
|
|
33
|
+
function createRoleClassNamePattern(pattern) {
|
|
34
|
+
const parts = pattern.split("{role}");
|
|
35
|
+
if (parts.length !== 2) {
|
|
36
|
+
throw new Error(`roleClassNamePattern must contain exactly one "{role}" placeholder.`);
|
|
37
|
+
}
|
|
38
|
+
return new RegExp(`^${escapeRegExp(parts[0] ?? "")}(?<role>\\S*)${escapeRegExp(parts[1] ?? "")}$`, "u");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a section-role convention and compile its class-token matcher.
|
|
42
|
+
*
|
|
43
|
+
* @param convention Optional marker convention override.
|
|
44
|
+
* @returns A fully populated convention ready for repeated block traversal.
|
|
45
|
+
* @throws When `roleClassNamePattern` does not contain exactly one `{role}` placeholder.
|
|
46
|
+
*/
|
|
47
|
+
export function normalizePatternCatalogSectionRoleConvention(convention = {}) {
|
|
48
|
+
const normalized = normalizeSectionRoleConventionInput(convention);
|
|
49
|
+
return {
|
|
50
|
+
...normalized,
|
|
51
|
+
roleClassNamePatternRegExp: createRoleClassNamePattern(normalized.roleClassNamePattern),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function getClassNameTokens(attributes) {
|
|
55
|
+
const className = attributes.className;
|
|
56
|
+
if (typeof className !== "string") {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return className.split(/\s+/u).filter((token) => token.length > 0);
|
|
60
|
+
}
|
|
61
|
+
function getAttributePathValue(attributes, pathName) {
|
|
62
|
+
return pathName.split(".").reduce((current, segment) => {
|
|
63
|
+
if (current !== null &&
|
|
64
|
+
typeof current === "object" &&
|
|
65
|
+
!Array.isArray(current) &&
|
|
66
|
+
Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
67
|
+
return current[segment];
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}, attributes);
|
|
71
|
+
}
|
|
72
|
+
function collectStringValues(value) {
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
return [value];
|
|
75
|
+
}
|
|
76
|
+
if (Array.isArray(value)) {
|
|
77
|
+
return value.filter((item) => typeof item === "string");
|
|
78
|
+
}
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
function uniqueValues(values) {
|
|
82
|
+
return [...new Set(values)];
|
|
83
|
+
}
|
|
84
|
+
function formatRoleList(roles) {
|
|
85
|
+
if (roles.length === 0) {
|
|
86
|
+
return "none";
|
|
87
|
+
}
|
|
88
|
+
return roles.map((role) => `"${role}"`).join(", ");
|
|
89
|
+
}
|
|
90
|
+
function formatBlockPaths(paths) {
|
|
91
|
+
return paths.map((blockPath) => `at ${blockPath}`).join(", ");
|
|
92
|
+
}
|
|
93
|
+
function describeRoleMarkerConvention(convention) {
|
|
94
|
+
return `${convention.wrapperBlockName} wrappers with class "${convention.roleClassNamePattern}" or attributes ${convention.roleAttributePaths.join(", ")}`;
|
|
95
|
+
}
|
|
96
|
+
function isSectionWrapperCandidate(block, roles, convention) {
|
|
97
|
+
if (block.blockName !== convention.wrapperBlockName) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (roles.length > 0) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return getClassNameTokens(block.attributes).includes(convention.baseClassName);
|
|
104
|
+
}
|
|
105
|
+
function collectSectionRoleMatches(blocks, convention, pathSegments = []) {
|
|
106
|
+
return blocks.flatMap((block, index) => {
|
|
107
|
+
const blockPathSegments = [
|
|
108
|
+
...pathSegments,
|
|
109
|
+
`${block.blockName}[${index}]`,
|
|
110
|
+
];
|
|
111
|
+
const blockPath = blockPathSegments.join(" > ");
|
|
112
|
+
const roles = extractPatternSectionRolesFromNormalizedAttributes(block.attributes, convention);
|
|
113
|
+
const matches = isSectionWrapperCandidate(block, roles, convention)
|
|
114
|
+
? [
|
|
115
|
+
{
|
|
116
|
+
blockName: block.blockName,
|
|
117
|
+
blockPath,
|
|
118
|
+
roles,
|
|
119
|
+
},
|
|
120
|
+
]
|
|
121
|
+
: [];
|
|
122
|
+
return [
|
|
123
|
+
...matches,
|
|
124
|
+
...collectSectionRoleMatches(block.innerBlocks, convention, blockPathSegments),
|
|
125
|
+
];
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function unescapeSerializedBlockCommentJsonQuotes(content) {
|
|
129
|
+
return content.replace(/<!--([\s\S]*?)-->/gu, (comment, body) => {
|
|
130
|
+
const source = body.trim();
|
|
131
|
+
if (!source.startsWith("wp:") && !source.startsWith("/wp:")) {
|
|
132
|
+
return comment;
|
|
133
|
+
}
|
|
134
|
+
return `<!--${body.replace(/\\"/gu, '"')}-->`;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Extract section role slugs from serialized block attributes using the
|
|
139
|
+
* configured class and metadata marker convention.
|
|
140
|
+
*
|
|
141
|
+
* @param attributes Parsed block attributes from serialized pattern content.
|
|
142
|
+
* @param convention Optional marker convention override.
|
|
143
|
+
* @returns Unique role marker values in discovery order.
|
|
144
|
+
*/
|
|
145
|
+
export function extractPatternSectionRolesFromAttributes(attributes, convention = {}) {
|
|
146
|
+
const normalized = normalizePatternCatalogSectionRoleConvention(convention);
|
|
147
|
+
return extractPatternSectionRolesFromNormalizedAttributes(attributes, normalized);
|
|
148
|
+
}
|
|
149
|
+
function extractPatternSectionRolesFromNormalizedAttributes(attributes, normalized) {
|
|
150
|
+
const classRoles = getClassNameTokens(attributes)
|
|
151
|
+
.map((token) => normalized.roleClassNamePatternRegExp.exec(token)?.groups?.role)
|
|
152
|
+
.filter((role) => typeof role === "string");
|
|
153
|
+
const attributeRoles = normalized.roleAttributePaths.flatMap((pathName) => collectStringValues(getAttributePathValue(attributes, pathName)));
|
|
154
|
+
return uniqueValues([...classRoles, ...attributeRoles]);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Find section wrapper blocks and their role markers in parsed pattern content.
|
|
158
|
+
*
|
|
159
|
+
* @param blocks Parsed block tree returned by `validateBlockPatternContentNesting`.
|
|
160
|
+
* @param convention Optional marker convention override.
|
|
161
|
+
* @returns Section wrapper matches with serialized block paths.
|
|
162
|
+
*/
|
|
163
|
+
export function extractPatternSectionRoleMatches(blocks, convention = {}) {
|
|
164
|
+
return collectSectionRoleMatches(blocks, normalizePatternCatalogSectionRoleConvention(convention));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build the known valid section-role set from pattern catalog entries.
|
|
168
|
+
*
|
|
169
|
+
* @param patterns Catalog entries that may declare a `sectionRole`.
|
|
170
|
+
* @returns Valid section role slugs declared by the catalog.
|
|
171
|
+
*/
|
|
172
|
+
export function collectKnownPatternSectionRoles(patterns) {
|
|
173
|
+
return new Set(patterns
|
|
174
|
+
.map((pattern) => pattern.sectionRole)
|
|
175
|
+
.filter((sectionRole) => typeof sectionRole === "string" &&
|
|
176
|
+
PATTERN_SECTION_ROLE_PATTERN.test(sectionRole)));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Validate serialized pattern content against the catalog section-role rules.
|
|
180
|
+
*
|
|
181
|
+
* @param options Pattern content, marker convention, known roles, and diagnostic context.
|
|
182
|
+
* @returns Diagnostics for invalid, missing, mismatched, unknown, or duplicate section-role markers.
|
|
183
|
+
*/
|
|
184
|
+
export function validatePatternContentSectionRoles({ content, contentFile, convention, knownSectionRoles, label, pattern, }) {
|
|
185
|
+
const diagnostics = [];
|
|
186
|
+
const parsed = validateBlockPatternContentNesting(content, {
|
|
187
|
+
allowExternalBlockNames: true,
|
|
188
|
+
nesting: {},
|
|
189
|
+
patternFile: contentFile,
|
|
190
|
+
});
|
|
191
|
+
let matches = collectSectionRoleMatches(parsed.blocks, convention);
|
|
192
|
+
const unescapedContent = unescapeSerializedBlockCommentJsonQuotes(content);
|
|
193
|
+
if (unescapedContent !== content) {
|
|
194
|
+
const unescapedParsed = validateBlockPatternContentNesting(unescapedContent, {
|
|
195
|
+
allowExternalBlockNames: true,
|
|
196
|
+
nesting: {},
|
|
197
|
+
patternFile: contentFile,
|
|
198
|
+
});
|
|
199
|
+
const unescapedMatches = collectSectionRoleMatches(unescapedParsed.blocks, convention);
|
|
200
|
+
if (unescapedMatches.some((match) => match.roles.length > 0) ||
|
|
201
|
+
matches.length === 0) {
|
|
202
|
+
matches = unescapedMatches;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const locatedRoles = matches.flatMap((match) => match.roles.map((role) => ({
|
|
206
|
+
blockPath: match.blockPath,
|
|
207
|
+
role,
|
|
208
|
+
})));
|
|
209
|
+
const invalidRoles = locatedRoles.filter(({ role }) => !PATTERN_SECTION_ROLE_PATTERN.test(role));
|
|
210
|
+
for (const invalidRole of uniqueValues(invalidRoles.map(({ role }) => role))) {
|
|
211
|
+
const paths = invalidRoles
|
|
212
|
+
.filter(({ role }) => role === invalidRole)
|
|
213
|
+
.map(({ blockPath }) => blockPath);
|
|
214
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
215
|
+
code: "invalid-pattern-section-role-marker",
|
|
216
|
+
message: `${label}: section role marker "${invalidRole}" in ${contentFile} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens (${formatBlockPaths(paths)}).`,
|
|
217
|
+
patternSlug: pattern.slug,
|
|
218
|
+
severity: "error",
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
const validLocatedRoles = locatedRoles.filter(({ role }) => PATTERN_SECTION_ROLE_PATTERN.test(role));
|
|
222
|
+
const validRoles = validLocatedRoles.map(({ role }) => role);
|
|
223
|
+
const uniqueValidRoles = uniqueValues(validRoles);
|
|
224
|
+
const unknownRoles = uniqueValidRoles.filter((role) => !knownSectionRoles.has(role));
|
|
225
|
+
for (const unknownRole of unknownRoles) {
|
|
226
|
+
const paths = validLocatedRoles
|
|
227
|
+
.filter(({ role }) => role === unknownRole)
|
|
228
|
+
.map(({ blockPath }) => blockPath);
|
|
229
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
230
|
+
code: "unknown-pattern-section-role-marker",
|
|
231
|
+
message: `${label}: section role marker "${unknownRole}" in ${contentFile} is not declared by any PATTERNS sectionRole (${formatBlockPaths(paths)}).`,
|
|
232
|
+
patternSlug: pattern.slug,
|
|
233
|
+
severity: "warning",
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
const scope = pattern.scope ?? "full";
|
|
237
|
+
const expectedSectionRole = typeof pattern.sectionRole === "string" &&
|
|
238
|
+
PATTERN_SECTION_ROLE_PATTERN.test(pattern.sectionRole)
|
|
239
|
+
? pattern.sectionRole
|
|
240
|
+
: undefined;
|
|
241
|
+
if (scope === "section" && expectedSectionRole) {
|
|
242
|
+
if (validRoles.length === 0) {
|
|
243
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
244
|
+
code: "missing-pattern-section-role-marker",
|
|
245
|
+
message: `${label}: section-scoped pattern content in ${contentFile} must include section role marker "${expectedSectionRole}" using ${describeRoleMarkerConvention(convention)}.`,
|
|
246
|
+
patternSlug: pattern.slug,
|
|
247
|
+
severity: "error",
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
else if (!validRoles.includes(expectedSectionRole)) {
|
|
251
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
252
|
+
code: "mismatched-pattern-section-role",
|
|
253
|
+
message: `${label}: manifest sectionRole "${expectedSectionRole}" was not found in ${contentFile}; found ${formatRoleList(uniqueValidRoles)}.`,
|
|
254
|
+
patternSlug: pattern.slug,
|
|
255
|
+
severity: "error",
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (scope === "full" && convention.requireUniqueFullPatternRoles) {
|
|
260
|
+
for (const role of uniqueValidRoles) {
|
|
261
|
+
const paths = validLocatedRoles
|
|
262
|
+
.filter((locatedRole) => locatedRole.role === role)
|
|
263
|
+
.map(({ blockPath }) => blockPath);
|
|
264
|
+
if (paths.length <= 1) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
268
|
+
code: "duplicate-pattern-section-role-marker",
|
|
269
|
+
message: `${label}: full pattern content in ${contentFile} repeats section role marker "${role}" (${formatBlockPaths(paths)}).`,
|
|
270
|
+
patternSlug: pattern.slug,
|
|
271
|
+
severity: "warning",
|
|
272
|
+
}));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return diagnostics;
|
|
276
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { PatternCatalogSectionRoleConvention } from "./pattern-catalog-section-roles.js";
|
|
2
|
+
export { extractPatternSectionRoleMatches, extractPatternSectionRolesFromAttributes, } from "./pattern-catalog-section-roles.js";
|
|
3
|
+
export type { PatternCatalogSectionRoleConvention, PatternCatalogSectionRoleMatch, } from "./pattern-catalog-section-roles.js";
|
|
4
|
+
export declare const PATTERN_CATALOG_SCOPE_IDS: readonly ["full", "section"];
|
|
5
|
+
export type PatternCatalogScope = (typeof PATTERN_CATALOG_SCOPE_IDS)[number];
|
|
6
|
+
export type PatternCatalogEntry = {
|
|
7
|
+
contentFile?: string;
|
|
8
|
+
file?: string;
|
|
9
|
+
scope?: string;
|
|
10
|
+
sectionRole?: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
tags?: readonly string[];
|
|
13
|
+
thumbnailUrl?: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
};
|
|
16
|
+
export type PatternCatalogDiagnosticSeverity = "error" | "warning";
|
|
17
|
+
export type PatternCatalogDiagnosticCode = "duplicate-pattern-slug" | "invalid-pattern-content-file" | "invalid-pattern-scope" | "invalid-pattern-section-role" | "invalid-pattern-section-role-convention" | "invalid-pattern-section-role-marker" | "invalid-pattern-slug" | "invalid-pattern-tag" | "invalid-pattern-thumbnail-url" | "mismatched-pattern-section-role" | "missing-pattern-content-file" | "missing-pattern-section-role" | "missing-pattern-section-role-marker" | "duplicate-pattern-section-role-marker" | "unknown-pattern-section-role-marker";
|
|
18
|
+
export type PatternCatalogDiagnostic = {
|
|
19
|
+
code: PatternCatalogDiagnosticCode;
|
|
20
|
+
message: string;
|
|
21
|
+
patternSlug?: string;
|
|
22
|
+
severity: PatternCatalogDiagnosticSeverity;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Options for validating typed pattern catalog entries and, when `projectDir`
|
|
26
|
+
* is provided, their serialized pattern content. Set `sectionRoleConvention` to
|
|
27
|
+
* `false` to keep file existence checks but opt out of section-role marker
|
|
28
|
+
* validation.
|
|
29
|
+
*/
|
|
30
|
+
export type PatternCatalogValidationOptions = {
|
|
31
|
+
projectDir?: string;
|
|
32
|
+
sectionRoleConvention?: PatternCatalogSectionRoleConvention | false;
|
|
33
|
+
};
|
|
34
|
+
export type PatternCatalogValidationResult = {
|
|
35
|
+
diagnostics: PatternCatalogDiagnostic[];
|
|
36
|
+
errors: PatternCatalogDiagnostic[];
|
|
37
|
+
warnings: PatternCatalogDiagnostic[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Validate pattern thumbnail references with the same URL/path rules used by
|
|
41
|
+
* catalog diagnostics and `wp-typia add pattern`.
|
|
42
|
+
*
|
|
43
|
+
* @param value Candidate thumbnail URL or relative project path.
|
|
44
|
+
* @returns Whether the value is an http(s) URL or safe relative project path.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isValidPatternThumbnailUrl(value: string): boolean;
|
|
47
|
+
export declare function resolvePatternCatalogContentFile(pattern: Pick<PatternCatalogEntry, "contentFile" | "file">): string | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Validate typed pattern catalog metadata declared in `scripts/block-config.ts`.
|
|
50
|
+
*
|
|
51
|
+
* The validator checks catalog shape, duplicate slugs, optional section-role
|
|
52
|
+
* rules, safe content file paths, and missing files when a workspace root is
|
|
53
|
+
* provided. With a workspace root, it also parses serialized block markup and
|
|
54
|
+
* compares section role markers against the catalog manifest.
|
|
55
|
+
*
|
|
56
|
+
* @param patterns Pattern catalog entries to validate.
|
|
57
|
+
* @param options Optional project root and section role marker convention.
|
|
58
|
+
* @returns Structured diagnostics split into errors and warnings.
|
|
59
|
+
*/
|
|
60
|
+
export declare function validatePatternCatalog(patterns: readonly PatternCatalogEntry[], options?: PatternCatalogValidationOptions): PatternCatalogValidationResult;
|
|
61
|
+
/**
|
|
62
|
+
* Render pattern catalog diagnostics for CLI, sync, and doctor output.
|
|
63
|
+
*
|
|
64
|
+
* @param diagnostics Diagnostics returned from {@link validatePatternCatalog}.
|
|
65
|
+
* @returns Human-readable lines with stable diagnostic codes.
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatPatternCatalogDiagnostics(diagnostics: readonly PatternCatalogDiagnostic[]): string;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { PATTERN_SECTION_ROLE_PATTERN, collectKnownPatternSectionRoles, normalizePatternCatalogSectionRoleConvention, validatePatternContentSectionRoles, } from "./pattern-catalog-section-roles.js";
|
|
4
|
+
export { extractPatternSectionRoleMatches, extractPatternSectionRolesFromAttributes, } from "./pattern-catalog-section-roles.js";
|
|
5
|
+
export const PATTERN_CATALOG_SCOPE_IDS = ["full", "section"];
|
|
6
|
+
const PATTERN_SLUG_PATTERN = /^[a-z][a-z0-9-]*$/u;
|
|
7
|
+
const PATTERN_TAG_PATTERN = /^[a-z0-9][a-z0-9-]*$/u;
|
|
8
|
+
const PATTERN_CONTENT_FILE_ROOT = "src/patterns/";
|
|
9
|
+
function createPatternCatalogDiagnostic(diagnostic) {
|
|
10
|
+
return diagnostic;
|
|
11
|
+
}
|
|
12
|
+
function isPatternCatalogScope(value) {
|
|
13
|
+
return PATTERN_CATALOG_SCOPE_IDS.includes(value);
|
|
14
|
+
}
|
|
15
|
+
function isSafeRelativePath(value) {
|
|
16
|
+
return (value.length > 0 &&
|
|
17
|
+
!path.isAbsolute(value) &&
|
|
18
|
+
!value.includes("\\") &&
|
|
19
|
+
!value.split(/[\\/]+/u).includes("..") &&
|
|
20
|
+
!/[<>:"|?*\u0000-\u001F]/u.test(value));
|
|
21
|
+
}
|
|
22
|
+
function isPatternContentFilePath(value) {
|
|
23
|
+
if (!isSafeRelativePath(value) ||
|
|
24
|
+
!value.startsWith(PATTERN_CONTENT_FILE_ROOT) ||
|
|
25
|
+
!value.endsWith(".php")) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const patternRelativePath = value.slice(PATTERN_CONTENT_FILE_ROOT.length);
|
|
29
|
+
const segments = patternRelativePath.split("/");
|
|
30
|
+
return ((segments.length === 1 || segments.length === 2) &&
|
|
31
|
+
segments.every((segment) => segment.length > 0));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate pattern thumbnail references with the same URL/path rules used by
|
|
35
|
+
* catalog diagnostics and `wp-typia add pattern`.
|
|
36
|
+
*
|
|
37
|
+
* @param value Candidate thumbnail URL or relative project path.
|
|
38
|
+
* @returns Whether the value is an http(s) URL or safe relative project path.
|
|
39
|
+
*/
|
|
40
|
+
export function isValidPatternThumbnailUrl(value) {
|
|
41
|
+
if (value.length === 0) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const url = new URL(value);
|
|
46
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return isSafeRelativePath(value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function resolvePatternCatalogContentFile(pattern) {
|
|
53
|
+
return pattern.contentFile ?? pattern.file;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validate typed pattern catalog metadata declared in `scripts/block-config.ts`.
|
|
57
|
+
*
|
|
58
|
+
* The validator checks catalog shape, duplicate slugs, optional section-role
|
|
59
|
+
* rules, safe content file paths, and missing files when a workspace root is
|
|
60
|
+
* provided. With a workspace root, it also parses serialized block markup and
|
|
61
|
+
* compares section role markers against the catalog manifest.
|
|
62
|
+
*
|
|
63
|
+
* @param patterns Pattern catalog entries to validate.
|
|
64
|
+
* @param options Optional project root and section role marker convention.
|
|
65
|
+
* @returns Structured diagnostics split into errors and warnings.
|
|
66
|
+
*/
|
|
67
|
+
export function validatePatternCatalog(patterns, options = {}) {
|
|
68
|
+
const diagnostics = [];
|
|
69
|
+
const seenSlugs = new Map();
|
|
70
|
+
let sectionRoleConvention = null;
|
|
71
|
+
if (options.sectionRoleConvention !== false) {
|
|
72
|
+
try {
|
|
73
|
+
sectionRoleConvention = normalizePatternCatalogSectionRoleConvention(options.sectionRoleConvention);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
77
|
+
code: "invalid-pattern-section-role-convention",
|
|
78
|
+
message: `sectionRoleConvention.roleClassNamePattern is invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
79
|
+
severity: "error",
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const knownSectionRoles = collectKnownPatternSectionRoles(patterns);
|
|
84
|
+
for (const [index, pattern] of patterns.entries()) {
|
|
85
|
+
const label = pattern.slug || `PATTERNS[${index}]`;
|
|
86
|
+
if (!PATTERN_SLUG_PATTERN.test(pattern.slug)) {
|
|
87
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
88
|
+
code: "invalid-pattern-slug",
|
|
89
|
+
message: `${label}: slug must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
|
|
90
|
+
patternSlug: pattern.slug,
|
|
91
|
+
severity: "error",
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
const previousIndex = seenSlugs.get(pattern.slug);
|
|
95
|
+
if (previousIndex !== undefined) {
|
|
96
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
97
|
+
code: "duplicate-pattern-slug",
|
|
98
|
+
message: `${label}: duplicate slug already declared at PATTERNS[${previousIndex}].`,
|
|
99
|
+
patternSlug: pattern.slug,
|
|
100
|
+
severity: "error",
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
seenSlugs.set(pattern.slug, index);
|
|
105
|
+
}
|
|
106
|
+
const scope = pattern.scope ?? "full";
|
|
107
|
+
if (!isPatternCatalogScope(scope)) {
|
|
108
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
109
|
+
code: "invalid-pattern-scope",
|
|
110
|
+
message: `${label}: scope must be one of ${PATTERN_CATALOG_SCOPE_IDS.join(", ")}.`,
|
|
111
|
+
patternSlug: pattern.slug,
|
|
112
|
+
severity: "error",
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
if (scope === "section" && !pattern.sectionRole) {
|
|
116
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
117
|
+
code: "missing-pattern-section-role",
|
|
118
|
+
message: `${label}: section-scoped patterns must declare sectionRole.`,
|
|
119
|
+
patternSlug: pattern.slug,
|
|
120
|
+
severity: "error",
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
if (pattern.sectionRole !== undefined &&
|
|
124
|
+
!PATTERN_SECTION_ROLE_PATTERN.test(pattern.sectionRole)) {
|
|
125
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
126
|
+
code: "invalid-pattern-section-role",
|
|
127
|
+
message: `${label}: sectionRole must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
|
|
128
|
+
patternSlug: pattern.slug,
|
|
129
|
+
severity: "error",
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
for (const [tagIndex, tag] of (pattern.tags ?? []).entries()) {
|
|
133
|
+
if (!PATTERN_TAG_PATTERN.test(tag)) {
|
|
134
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
135
|
+
code: "invalid-pattern-tag",
|
|
136
|
+
message: `${label}: tags[${tagIndex}] must contain only lowercase letters, numbers, and hyphens.`,
|
|
137
|
+
patternSlug: pattern.slug,
|
|
138
|
+
severity: "error",
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (pattern.thumbnailUrl !== undefined &&
|
|
143
|
+
!isValidPatternThumbnailUrl(pattern.thumbnailUrl)) {
|
|
144
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
145
|
+
code: "invalid-pattern-thumbnail-url",
|
|
146
|
+
message: `${label}: thumbnailUrl must be an http(s) URL or safe relative project path.`,
|
|
147
|
+
patternSlug: pattern.slug,
|
|
148
|
+
severity: "error",
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
const contentFile = resolvePatternCatalogContentFile(pattern);
|
|
152
|
+
if (!contentFile) {
|
|
153
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
154
|
+
code: "missing-pattern-content-file",
|
|
155
|
+
message: `${label}: contentFile or legacy file must point at the pattern PHP file.`,
|
|
156
|
+
patternSlug: pattern.slug,
|
|
157
|
+
severity: "error",
|
|
158
|
+
}));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (!isPatternContentFilePath(contentFile)) {
|
|
162
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
163
|
+
code: "invalid-pattern-content-file",
|
|
164
|
+
message: `${label}: contentFile must be a safe relative project path directly under src/patterns/ or one nested directory under src/patterns/ and end in .php.`,
|
|
165
|
+
patternSlug: pattern.slug,
|
|
166
|
+
severity: "error",
|
|
167
|
+
}));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!options.projectDir) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const absoluteContentFile = path.join(options.projectDir, contentFile);
|
|
174
|
+
if (!fs.existsSync(absoluteContentFile)) {
|
|
175
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
176
|
+
code: "missing-pattern-content-file",
|
|
177
|
+
message: `${label}: missing pattern content file ${contentFile}.`,
|
|
178
|
+
patternSlug: pattern.slug,
|
|
179
|
+
severity: "error",
|
|
180
|
+
}));
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (sectionRoleConvention) {
|
|
184
|
+
let content;
|
|
185
|
+
try {
|
|
186
|
+
content = fs.readFileSync(absoluteContentFile, "utf8");
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
diagnostics.push(createPatternCatalogDiagnostic({
|
|
190
|
+
code: "invalid-pattern-content-file",
|
|
191
|
+
message: `${label}: failed to read pattern content file ${contentFile}: ${error instanceof Error ? error.message : String(error)}.`,
|
|
192
|
+
patternSlug: pattern.slug,
|
|
193
|
+
severity: "error",
|
|
194
|
+
}));
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
diagnostics.push(...validatePatternContentSectionRoles({
|
|
198
|
+
content,
|
|
199
|
+
contentFile,
|
|
200
|
+
convention: sectionRoleConvention,
|
|
201
|
+
knownSectionRoles,
|
|
202
|
+
label,
|
|
203
|
+
pattern,
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const warnings = diagnostics.filter((diagnostic) => diagnostic.severity === "warning");
|
|
208
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
209
|
+
return {
|
|
210
|
+
diagnostics,
|
|
211
|
+
errors,
|
|
212
|
+
warnings,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Render pattern catalog diagnostics for CLI, sync, and doctor output.
|
|
217
|
+
*
|
|
218
|
+
* @param diagnostics Diagnostics returned from {@link validatePatternCatalog}.
|
|
219
|
+
* @returns Human-readable lines with stable diagnostic codes.
|
|
220
|
+
*/
|
|
221
|
+
export function formatPatternCatalogDiagnostics(diagnostics) {
|
|
222
|
+
return diagnostics
|
|
223
|
+
.map((diagnostic) => `- [${diagnostic.code}] ${diagnostic.message}`)
|
|
224
|
+
.join("\n");
|
|
225
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { WorkspacePostMetaInventoryEntry } from "./workspace-inventory-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Field metadata extracted from a typed post-meta schema for a generated block
|
|
4
|
+
* bindings source.
|
|
5
|
+
*
|
|
6
|
+
* @property fallbackValue Editor preview value used when live post meta is unavailable.
|
|
7
|
+
* @property label Human-readable label derived from the schema property name.
|
|
8
|
+
* @property name Top-level schema property name used as the binding `field` arg.
|
|
9
|
+
* @property required Whether the field is listed in the schema's required array.
|
|
10
|
+
* @property schemaType Resolved JSON Schema type used to choose a preview value.
|
|
11
|
+
*/
|
|
12
|
+
export interface PostMetaBindingField {
|
|
13
|
+
fallbackValue: string;
|
|
14
|
+
label: string;
|
|
15
|
+
name: string;
|
|
16
|
+
required: boolean;
|
|
17
|
+
schemaType: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load and extract binding fields from a post-meta JSON Schema artifact.
|
|
21
|
+
*
|
|
22
|
+
* @param projectDir Workspace root directory.
|
|
23
|
+
* @param postMeta Post-meta inventory entry that points to the schema file.
|
|
24
|
+
* @returns Promise resolving to the extracted top-level binding fields.
|
|
25
|
+
* @throws If the schema cannot be read or does not expose object properties.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadPostMetaBindingFields(projectDir: string, postMeta: WorkspacePostMetaInventoryEntry): Promise<PostMetaBindingField[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Synchronously load and extract binding fields from a post-meta JSON Schema artifact.
|
|
30
|
+
*
|
|
31
|
+
* @param projectDir Workspace root directory.
|
|
32
|
+
* @param postMeta Post-meta inventory entry that points to the schema file.
|
|
33
|
+
* @returns Extracted top-level binding fields.
|
|
34
|
+
* @throws If the schema cannot be read or does not expose object properties.
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadPostMetaBindingFieldsSync(projectDir: string, postMeta: WorkspacePostMetaInventoryEntry): PostMetaBindingField[];
|
|
37
|
+
/**
|
|
38
|
+
* Validate and resolve a top-level post-meta binding path.
|
|
39
|
+
*
|
|
40
|
+
* @param fields Binding fields extracted from the post-meta schema.
|
|
41
|
+
* @param postMetaSlug Post-meta contract slug used in diagnostics.
|
|
42
|
+
* @param metaPath User-provided field path to validate.
|
|
43
|
+
* @returns The matching binding field.
|
|
44
|
+
* @throws If the path is empty, nested, or missing from the schema fields.
|
|
45
|
+
*/
|
|
46
|
+
export declare function assertPostMetaBindingPath(fields: readonly PostMetaBindingField[], postMetaSlug: string, metaPath: string): PostMetaBindingField;
|