@wocart/theme 0.0.0-stage → 1.1.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.
- package/CHANGELOG.md +71 -0
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +479 -2
- package/dist/astro/InstanceView.astro +167 -0
- package/dist/astro/index.d.ts +34 -0
- package/dist/astro/index.js +21 -0
- package/dist/definitions.d.ts +7 -0
- package/dist/definitions.js +422 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +18 -0
- package/dist/instances.d.ts +43 -0
- package/dist/instances.js +307 -0
- package/dist/locales.d.ts +12 -0
- package/dist/locales.js +14 -0
- package/dist/manifest.d.ts +178 -0
- package/dist/manifest.js +325 -0
- package/dist/messages.d.ts +60 -0
- package/dist/messages.js +100 -0
- package/dist/page-data.d.ts +9 -0
- package/dist/page-data.js +154 -0
- package/dist/schemas.d.ts +57 -0
- package/dist/schemas.js +108 -0
- package/dist/settings.d.ts +15 -0
- package/dist/settings.js +80 -0
- package/dist/types.d.ts +479 -0
- package/dist/types.js +1 -0
- package/package.json +80 -4
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instance-level behavior: the defaults chain, composition gating, and
|
|
3
|
+
* insertion-time materialization. Pure functions — no I/O, no mutation of
|
|
4
|
+
* inputs. The renderer consumes `resolveInstance`; a future editor consumes
|
|
5
|
+
* `createInstance`.
|
|
6
|
+
*
|
|
7
|
+
* Chain: instance value (in the requested language, then the fallback chain)
|
|
8
|
+
* → `content[contentKey]` → `field.default` → omit (the component's own
|
|
9
|
+
* default applies last).
|
|
10
|
+
*/
|
|
11
|
+
import { localize } from "./locales.js";
|
|
12
|
+
import { COLOR_PATTERN, MENU_HANDLE_PATTERN, isLocaleMap, isSafeLinkTarget } from "./schemas.js";
|
|
13
|
+
/** Field kinds whose values may differ per language. Numbers, toggles and choices are shared. */
|
|
14
|
+
const TRANSLATABLE_KINDS = new Set(["text", "textarea", "url"]);
|
|
15
|
+
const isTranslatable = (field) => TRANSLATABLE_KINDS.has(field.kind);
|
|
16
|
+
/**
|
|
17
|
+
* Gate one instance for rendering: field values through the chain, children
|
|
18
|
+
* and named slots gated against the declared slots, every degradation
|
|
19
|
+
* reported. The instance (and page data) is never modified.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveInstance(definition, instance, scope = {}) {
|
|
22
|
+
const content = scope.content ?? {};
|
|
23
|
+
const locales = scope.locales ?? [];
|
|
24
|
+
const issues = [];
|
|
25
|
+
const fields = definition.fields ?? [];
|
|
26
|
+
const declaredFields = new Map(fields.map((field) => [field.key, field]));
|
|
27
|
+
const rawProps = instance.props ?? {};
|
|
28
|
+
for (const key of Object.keys(rawProps)) {
|
|
29
|
+
if (!declaredFields.has(key)) {
|
|
30
|
+
issues.push({
|
|
31
|
+
path: `props.${key}`,
|
|
32
|
+
code: "unknown-prop",
|
|
33
|
+
message: `"${key}" is not a declared field of "${definition.type}"`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const props = {};
|
|
38
|
+
for (const field of fields) {
|
|
39
|
+
const resolved = resolveField(field, ownValue(rawProps, field.key), content, locales, issues, "props");
|
|
40
|
+
if (resolved !== undefined) {
|
|
41
|
+
props[field.key] = resolved;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const slotDefinitions = new Map((definition.slots ?? []).map((slot) => [slot.name, slot]));
|
|
45
|
+
const fromChildren = instance.children ?? [];
|
|
46
|
+
const fromDefaultSlot = instance.slots?.default ?? [];
|
|
47
|
+
let children = [];
|
|
48
|
+
if (fromChildren.length + fromDefaultSlot.length > 0) {
|
|
49
|
+
const defaultSlot = slotDefinitions.get("default");
|
|
50
|
+
if (defaultSlot === undefined) {
|
|
51
|
+
issues.push({
|
|
52
|
+
path: "children",
|
|
53
|
+
code: "undeclared-children",
|
|
54
|
+
message: `"${definition.type}" declares no "default" slot; ${fromChildren.length + fromDefaultSlot.length} child instance(s) dropped`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const accepted = [
|
|
59
|
+
...filterAllowed(defaultSlot, fromChildren, "children", issues),
|
|
60
|
+
...filterAllowed(defaultSlot, fromDefaultSlot, "slots.default", issues),
|
|
61
|
+
];
|
|
62
|
+
children = applyMultiple(defaultSlot, accepted, "children", issues);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const slots = {};
|
|
66
|
+
for (const [name, list] of Object.entries(instance.slots ?? {})) {
|
|
67
|
+
if (name === "default") {
|
|
68
|
+
continue; // handled with children above
|
|
69
|
+
}
|
|
70
|
+
const slotDefinition = slotDefinitions.get(name);
|
|
71
|
+
if (slotDefinition === undefined) {
|
|
72
|
+
issues.push({
|
|
73
|
+
path: `slots.${name}`,
|
|
74
|
+
code: "unknown-slot",
|
|
75
|
+
message: `"${name}" is not a declared slot of "${definition.type}"; content dropped`,
|
|
76
|
+
});
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const accepted = filterAllowed(slotDefinition, list, `slots.${name}`, issues);
|
|
80
|
+
slots[name] = applyMultiple(slotDefinition, accepted, `slots.${name}`, issues);
|
|
81
|
+
}
|
|
82
|
+
return { props, children, slots, issues };
|
|
83
|
+
}
|
|
84
|
+
/** An own property only: `constructor` or `toString` must never read the prototype. */
|
|
85
|
+
export function ownValue(record, key) {
|
|
86
|
+
return Object.hasOwn(record, key) ? record[key] : undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The value an instance stores for this field, in the preferred language. A
|
|
90
|
+
* per-language map without an entry for any preferred language is not an
|
|
91
|
+
* error — the chain moves on to the pack and the default.
|
|
92
|
+
*/
|
|
93
|
+
function storedValueFor(field, raw, locales) {
|
|
94
|
+
if (!isTranslatable(field) || typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
95
|
+
return { kind: "value", value: raw };
|
|
96
|
+
}
|
|
97
|
+
if (!isLocaleMap(raw)) {
|
|
98
|
+
return {
|
|
99
|
+
kind: "invalid",
|
|
100
|
+
message: "must be a string or a map from language tags to strings",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const picked = localize(raw, locales);
|
|
104
|
+
return picked === undefined ? { kind: "untranslated" } : { kind: "value", value: picked };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* One field through the chain. `undefined` = omit the value. Issues are
|
|
108
|
+
* reported under `${prefix}.${field.key}` — a component's `props`, or a theme's
|
|
109
|
+
* `settings`.
|
|
110
|
+
*/
|
|
111
|
+
export function resolveField(field, raw, content, locales, issues, prefix) {
|
|
112
|
+
if (raw !== undefined) {
|
|
113
|
+
const stored = storedValueFor(field, raw, locales);
|
|
114
|
+
const checked = stored.kind === "value"
|
|
115
|
+
? checkFieldValue(field, stored.value)
|
|
116
|
+
: stored.kind === "invalid"
|
|
117
|
+
? { ok: false, message: stored.message }
|
|
118
|
+
: undefined;
|
|
119
|
+
if (checked?.ok) {
|
|
120
|
+
return checked.value;
|
|
121
|
+
}
|
|
122
|
+
if (checked !== undefined) {
|
|
123
|
+
issues.push({
|
|
124
|
+
path: `${prefix}.${field.key}`,
|
|
125
|
+
code: "invalid-prop",
|
|
126
|
+
message: `"${field.key}" ${checked.message}; treated as absent`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (field.kind === "text" || field.kind === "textarea") {
|
|
131
|
+
const contentKey = field.contentKey;
|
|
132
|
+
if (contentKey !== undefined) {
|
|
133
|
+
const fromContent = ownValue(content, contentKey);
|
|
134
|
+
if (fromContent !== undefined) {
|
|
135
|
+
return fromContent;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (field.default !== undefined) {
|
|
140
|
+
const fallback = field.kind === "text" || field.kind === "textarea"
|
|
141
|
+
? localize(field.default, locales)
|
|
142
|
+
: field.default;
|
|
143
|
+
if (fallback !== undefined) {
|
|
144
|
+
return fallback;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (field.required === true) {
|
|
148
|
+
issues.push({
|
|
149
|
+
path: `${prefix}.${field.key}`,
|
|
150
|
+
code: "missing-required-prop",
|
|
151
|
+
message: `required field "${field.key}" has no value`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* What a writer may store: a value that passes the field's rules, or — for a
|
|
158
|
+
* translatable field — a per-language map whose every entry passes them, so no
|
|
159
|
+
* language can hold an unsafe link or a wrong type.
|
|
160
|
+
*/
|
|
161
|
+
export function checkStoredValue(field, value) {
|
|
162
|
+
if (!isTranslatable(field) || typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
163
|
+
return checkFieldValue(field, value);
|
|
164
|
+
}
|
|
165
|
+
if (!isLocaleMap(value)) {
|
|
166
|
+
return { ok: false, message: "must be a string or a map from language tags to strings" };
|
|
167
|
+
}
|
|
168
|
+
for (const [locale, text] of Object.entries(value)) {
|
|
169
|
+
const checked = checkFieldValue(field, text);
|
|
170
|
+
if (!checked.ok)
|
|
171
|
+
return { ok: false, message: `(${locale}) ${checked.message}` };
|
|
172
|
+
}
|
|
173
|
+
return { ok: true, value };
|
|
174
|
+
}
|
|
175
|
+
/** Kind check shared by resolution and creation. */
|
|
176
|
+
function checkFieldValue(field, value) {
|
|
177
|
+
switch (field.kind) {
|
|
178
|
+
case "text":
|
|
179
|
+
case "textarea":
|
|
180
|
+
return typeof value === "string"
|
|
181
|
+
? { ok: true, value }
|
|
182
|
+
: { ok: false, message: "must be a string" };
|
|
183
|
+
case "number": {
|
|
184
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
185
|
+
return { ok: false, message: "must be a finite number" };
|
|
186
|
+
}
|
|
187
|
+
if (field.min !== undefined && value < field.min) {
|
|
188
|
+
return { ok: false, message: `must be >= ${field.min}` };
|
|
189
|
+
}
|
|
190
|
+
if (field.max !== undefined && value > field.max) {
|
|
191
|
+
return { ok: false, message: `must be <= ${field.max}` };
|
|
192
|
+
}
|
|
193
|
+
return { ok: true, value };
|
|
194
|
+
}
|
|
195
|
+
case "boolean":
|
|
196
|
+
return typeof value === "boolean"
|
|
197
|
+
? { ok: true, value }
|
|
198
|
+
: { ok: false, message: "must be a boolean" };
|
|
199
|
+
case "url":
|
|
200
|
+
return typeof value === "string" && isSafeLinkTarget(value)
|
|
201
|
+
? { ok: true, value }
|
|
202
|
+
: {
|
|
203
|
+
ok: false,
|
|
204
|
+
message: "must be a site path, #fragment, ?query, or an http(s), mailto or tel URL",
|
|
205
|
+
};
|
|
206
|
+
case "color":
|
|
207
|
+
return typeof value === "string" && COLOR_PATTERN.test(value)
|
|
208
|
+
? { ok: true, value }
|
|
209
|
+
: { ok: false, message: "must be a hex color, #rgb or #rrggbb" };
|
|
210
|
+
case "menu":
|
|
211
|
+
return typeof value === "string" && MENU_HANDLE_PATTERN.test(value)
|
|
212
|
+
? { ok: true, value }
|
|
213
|
+
: { ok: false, message: "must be a menu handle" };
|
|
214
|
+
case "select":
|
|
215
|
+
return typeof value === "string" && field.options.includes(value)
|
|
216
|
+
? { ok: true, value }
|
|
217
|
+
: {
|
|
218
|
+
ok: false,
|
|
219
|
+
message: `must be one of ${field.options.map((option) => JSON.stringify(option)).join(", ")}`,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/** A slot's `allow` list keeps the permitted types and reports every other child. */
|
|
224
|
+
function filterAllowed(slot, list, path, issues) {
|
|
225
|
+
if (slot.allow === undefined) {
|
|
226
|
+
return list;
|
|
227
|
+
}
|
|
228
|
+
const allowed = new Set(slot.allow);
|
|
229
|
+
return list.filter((child, index) => {
|
|
230
|
+
if (allowed.has(child.type)) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
issues.push({
|
|
234
|
+
path: `${path}[${index}]`,
|
|
235
|
+
code: "disallowed-child",
|
|
236
|
+
message: `"${child.type}" is not allowed in slot "${slot.name}"; dropped`,
|
|
237
|
+
});
|
|
238
|
+
return false;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/** `multiple: false` keeps the first child and reports the rest. */
|
|
242
|
+
function applyMultiple(slot, list, path, issues) {
|
|
243
|
+
if (slot.multiple === false && list.length > 1) {
|
|
244
|
+
issues.push({
|
|
245
|
+
path,
|
|
246
|
+
code: "slot-not-multiple",
|
|
247
|
+
message: `slot "${slot.name}" allows at most one child; ${list.length - 1} dropped`,
|
|
248
|
+
});
|
|
249
|
+
return [list[0]];
|
|
250
|
+
}
|
|
251
|
+
return list;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Create a new instance with insertion-time defaults:
|
|
255
|
+
* materialises `field.default` values only — content-keyed fields stay unset
|
|
256
|
+
* until a merchant overrides them. Throws on programmer errors (empty id,
|
|
257
|
+
* unknown keys, wrong-typed values, a required field with nothing to fill
|
|
258
|
+
* it); the storefront never calls this. A required field with a `contentKey`
|
|
259
|
+
* is filled from the content pack at render, so it may be left unset here.
|
|
260
|
+
*
|
|
261
|
+
* Authored defaults are validated exactly like provided values: a default that
|
|
262
|
+
* fails its field's rules (out-of-range number, off-list select option) is an
|
|
263
|
+
* authoring bug, and `validateThemeDefinition` reports it at assembly time —
|
|
264
|
+
* baking it into an instance silently here would let the writer and the reader
|
|
265
|
+
* disagree.
|
|
266
|
+
*/
|
|
267
|
+
export function createInstance(definition, id, props = {}) {
|
|
268
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
269
|
+
throw new TypeError("createInstance: `id` must be a non-empty string");
|
|
270
|
+
}
|
|
271
|
+
const fields = definition.fields ?? [];
|
|
272
|
+
const declaredFields = new Map(fields.map((field) => [field.key, field]));
|
|
273
|
+
for (const key of Object.keys(props)) {
|
|
274
|
+
if (!declaredFields.has(key)) {
|
|
275
|
+
throw new TypeError(`createInstance: "${key}" is not a declared field of "${definition.type}"`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const materialized = {};
|
|
279
|
+
for (const field of fields) {
|
|
280
|
+
const provided = ownValue(props, field.key);
|
|
281
|
+
if (provided !== undefined) {
|
|
282
|
+
const checked = checkStoredValue(field, provided);
|
|
283
|
+
if (!checked.ok) {
|
|
284
|
+
throw new TypeError(`createInstance: "${field.key}" ${checked.message}`);
|
|
285
|
+
}
|
|
286
|
+
materialized[field.key] = provided;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (field.default !== undefined) {
|
|
290
|
+
const checked = checkStoredValue(field, field.default);
|
|
291
|
+
if (!checked.ok) {
|
|
292
|
+
throw new TypeError(`createInstance: default for "${field.key}" ${checked.message}`);
|
|
293
|
+
}
|
|
294
|
+
materialized[field.key] = field.default;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const contentFilled = (field.kind === "text" || field.kind === "textarea") && field.contentKey !== undefined;
|
|
298
|
+
if (field.required === true && !contentFilled) {
|
|
299
|
+
throw new TypeError(`createInstance: required field "${field.key}" needs a value (it has no default or contentKey)`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const instance = { id, type: definition.type };
|
|
303
|
+
if (Object.keys(materialized).length > 0) {
|
|
304
|
+
instance.props = materialized;
|
|
305
|
+
}
|
|
306
|
+
return instance;
|
|
307
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Choosing the right language for a value. A plain string is the same in every
|
|
3
|
+
* language; a per-language map yields the entry for the first language in the
|
|
4
|
+
* preference list that it has.
|
|
5
|
+
*/
|
|
6
|
+
import type { LocaleCode, LocalizedText } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* The text for the first language in `locales` that `value` has, or
|
|
9
|
+
* `undefined` when it has none of them. A plain string applies to every
|
|
10
|
+
* language. Pass the requested language first, then the fallback chain.
|
|
11
|
+
*/
|
|
12
|
+
export declare function localize(value: LocalizedText, locales: readonly LocaleCode[]): string | undefined;
|
package/dist/locales.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text for the first language in `locales` that `value` has, or
|
|
3
|
+
* `undefined` when it has none of them. A plain string applies to every
|
|
4
|
+
* language. Pass the requested language first, then the fallback chain.
|
|
5
|
+
*/
|
|
6
|
+
export function localize(value, locales) {
|
|
7
|
+
if (typeof value === "string")
|
|
8
|
+
return value;
|
|
9
|
+
for (const locale of locales) {
|
|
10
|
+
if (Object.hasOwn(value, locale))
|
|
11
|
+
return value[locale];
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The serializable half of the theme contract: a `ThemeDefinition` as data, for
|
|
3
|
+
* tooling that must read a theme without executing its modules.
|
|
4
|
+
*
|
|
5
|
+
* `themeManifest` derives the manifest from the code (one source of truth).
|
|
6
|
+
* `validateThemeManifest` is the boundary for a manifest that arrives as JSON:
|
|
7
|
+
* serializability is checked on the raw input, structure by `ThemeManifestSchema`
|
|
8
|
+
* (which also normalizes), and relational rules by `validateThemeDefinition` —
|
|
9
|
+
* so the manifest and assembly validators cannot disagree.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import type { ThemeDefinition, ThemeManifest, ThemeManifestResult } from "./types.js";
|
|
13
|
+
/** Version of the manifest schema and its interpretation (not the theme's). */
|
|
14
|
+
export declare const THEME_MANIFEST_CONTRACT_VERSION: 1;
|
|
15
|
+
/** Derive the data-only manifest from a theme. `component` and `load` are dropped. */
|
|
16
|
+
export declare function themeManifest(theme: ThemeDefinition): ThemeManifest;
|
|
17
|
+
/**
|
|
18
|
+
* The manifest's structural shape. Unknown keys are stripped (the forward-compat
|
|
19
|
+
* tradeoff documented in the README); absent `fields`/`slots` normalize to `[]`.
|
|
20
|
+
* Rules that span fields are not here — `validateThemeManifest` applies them.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ThemeManifestSchema: z.ZodObject<{
|
|
23
|
+
contractVersion: z.ZodLiteral<1>;
|
|
24
|
+
key: z.ZodString;
|
|
25
|
+
version: z.ZodString;
|
|
26
|
+
surfaces: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
27
|
+
key: z.ZodString;
|
|
28
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
29
|
+
}, z.core.$strip>>>;
|
|
30
|
+
locales: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
31
|
+
settings: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
32
|
+
key: z.ZodString;
|
|
33
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
34
|
+
fields: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
35
|
+
key: z.ZodString;
|
|
36
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
37
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
38
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
39
|
+
contentKey: z.ZodExactOptional<z.ZodString>;
|
|
40
|
+
default: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
41
|
+
kind: z.ZodLiteral<"text">;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
key: z.ZodString;
|
|
44
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
45
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
46
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
47
|
+
contentKey: z.ZodExactOptional<z.ZodString>;
|
|
48
|
+
default: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
49
|
+
kind: z.ZodLiteral<"textarea">;
|
|
50
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
51
|
+
key: z.ZodString;
|
|
52
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
53
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
54
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
55
|
+
kind: z.ZodLiteral<"number">;
|
|
56
|
+
default: z.ZodExactOptional<z.ZodNumber>;
|
|
57
|
+
min: z.ZodExactOptional<z.ZodNumber>;
|
|
58
|
+
max: z.ZodExactOptional<z.ZodNumber>;
|
|
59
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
60
|
+
key: z.ZodString;
|
|
61
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
62
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
63
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
64
|
+
kind: z.ZodLiteral<"boolean">;
|
|
65
|
+
default: z.ZodExactOptional<z.ZodBoolean>;
|
|
66
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
67
|
+
key: z.ZodString;
|
|
68
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
69
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
70
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
71
|
+
kind: z.ZodLiteral<"select">;
|
|
72
|
+
options: z.ZodArray<z.ZodString>;
|
|
73
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
74
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
75
|
+
key: z.ZodString;
|
|
76
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
77
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
78
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
79
|
+
kind: z.ZodLiteral<"url">;
|
|
80
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
82
|
+
key: z.ZodString;
|
|
83
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
84
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
85
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
86
|
+
kind: z.ZodLiteral<"color">;
|
|
87
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
88
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
89
|
+
key: z.ZodString;
|
|
90
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
91
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
92
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
93
|
+
kind: z.ZodLiteral<"menu">;
|
|
94
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
95
|
+
}, z.core.$strip>], "kind">>;
|
|
96
|
+
}, z.core.$strip>>>;
|
|
97
|
+
components: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
98
|
+
type: z.ZodString;
|
|
99
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
100
|
+
group: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
101
|
+
fields: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
102
|
+
key: z.ZodString;
|
|
103
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
104
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
105
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
106
|
+
contentKey: z.ZodExactOptional<z.ZodString>;
|
|
107
|
+
default: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
108
|
+
kind: z.ZodLiteral<"text">;
|
|
109
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
110
|
+
key: z.ZodString;
|
|
111
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
112
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
113
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
114
|
+
contentKey: z.ZodExactOptional<z.ZodString>;
|
|
115
|
+
default: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
116
|
+
kind: z.ZodLiteral<"textarea">;
|
|
117
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
118
|
+
key: z.ZodString;
|
|
119
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
120
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
121
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
122
|
+
kind: z.ZodLiteral<"number">;
|
|
123
|
+
default: z.ZodExactOptional<z.ZodNumber>;
|
|
124
|
+
min: z.ZodExactOptional<z.ZodNumber>;
|
|
125
|
+
max: z.ZodExactOptional<z.ZodNumber>;
|
|
126
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
127
|
+
key: z.ZodString;
|
|
128
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
129
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
130
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
131
|
+
kind: z.ZodLiteral<"boolean">;
|
|
132
|
+
default: z.ZodExactOptional<z.ZodBoolean>;
|
|
133
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
134
|
+
key: z.ZodString;
|
|
135
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
136
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
137
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
138
|
+
kind: z.ZodLiteral<"select">;
|
|
139
|
+
options: z.ZodArray<z.ZodString>;
|
|
140
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
141
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
142
|
+
key: z.ZodString;
|
|
143
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
144
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
145
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
146
|
+
kind: z.ZodLiteral<"url">;
|
|
147
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
148
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
149
|
+
key: z.ZodString;
|
|
150
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
151
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
152
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
153
|
+
kind: z.ZodLiteral<"color">;
|
|
154
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
155
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
156
|
+
key: z.ZodString;
|
|
157
|
+
label: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>;
|
|
158
|
+
description: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
|
|
159
|
+
required: z.ZodExactOptional<z.ZodBoolean>;
|
|
160
|
+
kind: z.ZodLiteral<"menu">;
|
|
161
|
+
default: z.ZodExactOptional<z.ZodString>;
|
|
162
|
+
}, z.core.$strip>], "kind">>>;
|
|
163
|
+
slots: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
164
|
+
name: z.ZodString;
|
|
165
|
+
multiple: z.ZodExactOptional<z.ZodBoolean>;
|
|
166
|
+
allow: z.ZodExactOptional<z.ZodArray<z.ZodString>>;
|
|
167
|
+
}, z.core.$strip>>>;
|
|
168
|
+
capabilities: z.ZodExactOptional<z.ZodObject<{
|
|
169
|
+
insertable: z.ZodExactOptional<z.ZodBoolean>;
|
|
170
|
+
}, z.core.$strip>>;
|
|
171
|
+
}, z.core.$strip>>;
|
|
172
|
+
}, z.core.$strip>;
|
|
173
|
+
/**
|
|
174
|
+
* Validate a manifest that arrived from outside the code. A structural failure
|
|
175
|
+
* returns `{ manifest: null, issues }`; a non-semver `version` is advisory and
|
|
176
|
+
* returns the manifest with an `invalid-version` issue.
|
|
177
|
+
*/
|
|
178
|
+
export declare function validateThemeManifest(input: unknown): ThemeManifestResult;
|