@bettercms-ai/kit 2.0.0-next.6 → 2.0.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/lossy.d.ts +3 -3
- package/dist/adapters/lossy.js +3 -3
- package/dist/adapters/lossy.js.map +1 -1
- package/dist/adapters/prod-types.d.ts +49 -4
- package/dist/adapters/prod-types.js +4 -3
- package/dist/adapters/prod-types.js.map +1 -1
- package/dist/adapters/schema.d.ts +39 -0
- package/dist/adapters/schema.js +215 -61
- package/dist/adapters/schema.js.map +1 -1
- package/dist/controls/icon.d.ts +1 -1
- package/dist/controls/icon.js +1 -1
- package/dist/controls/icon.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/ledgers/exclusions.v1.js +132 -0
- package/dist/ledgers/exclusions.v1.js.map +1 -0
- package/dist/library/coverage.d.ts +13 -1
- package/dist/library/coverage.js +12 -1
- package/dist/library/coverage.js.map +1 -1
- package/dist/library/kit-catalog.json +149 -149
- package/dist/testing/coverage-extras.d.ts +8 -0
- package/dist/testing/coverage-extras.js +44 -0
- package/dist/testing/coverage-extras.js.map +1 -0
- package/dist/testing/exclusions.d.ts +30 -0
- package/dist/testing/exclusions.js +13 -0
- package/dist/testing/exclusions.js.map +1 -0
- package/package.json +2 -2
package/dist/adapters/schema.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dockIconOf, tablerIconOf } from "./icons.js";
|
|
|
4
4
|
import { slotChildrenFromStored, slotChildrenToStored } from "../controls/slot-services.js";
|
|
5
5
|
import { isDataTableProp, tableConfigFromOptions, tableOptionsFromConfig } from "../controls/table/prod.js";
|
|
6
6
|
import { buttonFromProd, buttonToProd, datetimeFromProd, datetimeToProd, imageFromProd, imageToProd, isCropRect, linkFromProd, linkToProd, listFromProd, listToProd, ratingFromProd, ratingToProd, referenceFromProd, referenceToProd, scaleFromProd, scaleToProd, typedRowsFromProd, typedRowsToProd, videoFromProd, videoToProd, zoneListFromProd, zoneListToProd } from "./values.js";
|
|
7
|
-
import { BLOCK_FIELD_TYPES_RENDERABLE_NOW, KEY_FORMAT, PRIMITIVE_ARRAY_RULE, RICHTEXT_FEATURES, isReservedKey, normaliseRichTextFeatures } from "@bettercms-ai/types";
|
|
7
|
+
import { BLOCK_FIELD_TYPES_RENDERABLE_NOW, KEY_FORMAT, KIT_CATEGORIES, PRIMITIVE_ARRAY_RULE, RICHTEXT_FEATURES, SEGMENTED_MAX, SEGMENTED_MIN, isReservedKey, normaliseRichTextFeatures } from "@bettercms-ai/types";
|
|
8
8
|
//#region src/adapters/schema.ts
|
|
9
9
|
var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
10
10
|
function deepEqual(a, b) {
|
|
@@ -185,6 +185,44 @@ var CATEGORY_TO_PROD = {
|
|
|
185
185
|
};
|
|
186
186
|
/** The field types a kind:'block' model holds today: the ones a block primitive renders (types, staged to G7). */
|
|
187
187
|
var BLOCK_FIELD_TYPES = new Set(BLOCK_FIELD_TYPES_RENDERABLE_NOW);
|
|
188
|
+
/** What a block row's cell may hold, and a primitive list's items (backend block-model-mapping.ts CELL_FIELD_TYPES, LIST_ITEM_TYPES). */
|
|
189
|
+
/** The block-variant select's key on a model (c2ee279dd: a top-level select, only beside v2.variants). */
|
|
190
|
+
var BLOCK_VARIANT_KEY = "_variant";
|
|
191
|
+
var BLOCK_CELL_TYPES = /* @__PURE__ */ new Set([
|
|
192
|
+
"text",
|
|
193
|
+
"longtext",
|
|
194
|
+
"richtext",
|
|
195
|
+
"image",
|
|
196
|
+
"link",
|
|
197
|
+
"slug",
|
|
198
|
+
"email",
|
|
199
|
+
"phone",
|
|
200
|
+
"color",
|
|
201
|
+
"select",
|
|
202
|
+
"number",
|
|
203
|
+
"rating",
|
|
204
|
+
"date",
|
|
205
|
+
"datetime",
|
|
206
|
+
"boolean"
|
|
207
|
+
]);
|
|
208
|
+
var BLOCK_LIST_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
209
|
+
"text",
|
|
210
|
+
"number",
|
|
211
|
+
"date"
|
|
212
|
+
]);
|
|
213
|
+
/**
|
|
214
|
+
* Whether a block model may hold this stored field (backend findUnmappableFields / containerProblem): its type has a
|
|
215
|
+
* primitive, and an object or array has rows of cells (an array no non-repeating fields), or lists text, numbers or dates.
|
|
216
|
+
*/
|
|
217
|
+
function blockRenders(f) {
|
|
218
|
+
if (!BLOCK_FIELD_TYPES.has(f.type)) return false;
|
|
219
|
+
if (f.type !== "object" && f.type !== "array") return true;
|
|
220
|
+
const zones = f.config?.zones;
|
|
221
|
+
if (f.type === "array" && zones?.nonRepeatable?.length) return false;
|
|
222
|
+
const row = f.type === "object" ? f.fields ?? [] : zones ? zones.repeatable?.fields ?? [] : null;
|
|
223
|
+
if (row === null) return BLOCK_LIST_ITEM_TYPES.has(String(f.config?.itemType));
|
|
224
|
+
return row.length > 0 && row.every((c) => BLOCK_CELL_TYPES.has(c.type));
|
|
225
|
+
}
|
|
188
226
|
/** A slot prop's config.minItems / maxItems cap (SLOT_ITEMS_CAP, componentPropDefSchema). */
|
|
189
227
|
var SLOT_ITEMS_CAP = 50;
|
|
190
228
|
/** A table prop's rows and an array prop's items: their config.minItems / maxItems cap (LIST_ITEMS_CAP). */
|
|
@@ -348,8 +386,10 @@ function shapeOf(f, lv, ctx, top, nest) {
|
|
|
348
386
|
* `layout`, `page`, a forbidden key or a leading `_`; or one off KEY_FORMAT), renamed. V2 authoring follows the API
|
|
349
387
|
* lane, so `id` is a field key like any other (only the derive lane, which mints keys, reserves it).
|
|
350
388
|
*/
|
|
351
|
-
|
|
352
|
-
|
|
389
|
+
/** The address-prefix keys a model may hold below its top level (019141ffc): they are no address there. */
|
|
390
|
+
var NESTED_OK_KEYS = /* @__PURE__ */ new Set(["layout", "page"]);
|
|
391
|
+
function modelKeyOf(name, nested = false) {
|
|
392
|
+
if (KEY_FORMAT.test(name) && (!isReservedKey(name) || nested && NESTED_OK_KEYS.has(name))) return name;
|
|
353
393
|
let k = name.replace(/^_+/, "").replace(/[^A-Za-z0-9_-]/g, "");
|
|
354
394
|
if (!/^[A-Za-z]/.test(k)) k = `f${k}`;
|
|
355
395
|
return isReservedKey(k) ? `${k}Field` : k;
|
|
@@ -528,8 +568,8 @@ function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = f
|
|
|
528
568
|
if (twins) {
|
|
529
569
|
node.key = `${f.name}_${twins + 1}`;
|
|
530
570
|
lose(ctx, `${at}/name`, "duplicate name");
|
|
531
|
-
} else if (!props && modelKeyOf(f.name) !== f.name) {
|
|
532
|
-
node.key = modelKeyOf(f.name);
|
|
571
|
+
} else if (!props && modelKeyOf(f.name, lv > 1) !== f.name) {
|
|
572
|
+
node.key = modelKeyOf(f.name, lv > 1);
|
|
533
573
|
lose(ctx, `${at}/name`, "reserved name");
|
|
534
574
|
}
|
|
535
575
|
const nesting = shape.kind === "object" || shape.kind === "zones" || shape.kind === "types";
|
|
@@ -613,7 +653,7 @@ function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = f
|
|
|
613
653
|
case "hidden":
|
|
614
654
|
if (typeof f.hidden === "boolean") node.ui.hidden = f.hidden;
|
|
615
655
|
else {
|
|
616
|
-
const showIf = conditionToShowIf(f.hidden, p, siblings, ctx,
|
|
656
|
+
const showIf = conditionToShowIf(f.hidden, p, siblings, ctx, top && (props || !!ctx.variants));
|
|
617
657
|
if (showIf) node.showIf = showIf;
|
|
618
658
|
}
|
|
619
659
|
break;
|
|
@@ -646,7 +686,7 @@ function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = f
|
|
|
646
686
|
node.advanced = f.advanced;
|
|
647
687
|
break;
|
|
648
688
|
case "ai":
|
|
649
|
-
|
|
689
|
+
node.ai = f.ai;
|
|
650
690
|
break;
|
|
651
691
|
case "reference":
|
|
652
692
|
if (shape.kind === "leaf" && shape.type === "reference") referenceToConfig(f.reference, node, p, ctx);
|
|
@@ -793,10 +833,24 @@ function placeInSet(f, node, at, ctx, top, siblings) {
|
|
|
793
833
|
}
|
|
794
834
|
return;
|
|
795
835
|
}
|
|
836
|
+
if (f.fieldset !== void 0 && !ctx.sets.has(f.fieldset) && !ctx.tabs.has(f.fieldset) && !ctx.droppedTabs.has(f.fieldset) && f.fieldset.length <= 60) {
|
|
837
|
+
const derived = ctx.derivedSets ??= [];
|
|
838
|
+
if (derived.length + ctx.sets.size + ctx.tabs.size < 30) {
|
|
839
|
+
derived.push({
|
|
840
|
+
id: f.fieldset,
|
|
841
|
+
name: f.fieldset,
|
|
842
|
+
kind: "group"
|
|
843
|
+
});
|
|
844
|
+
ctx.sets.set(f.fieldset, void 0);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
796
847
|
const set = f.fieldset !== void 0 && ctx.sets.has(f.fieldset) ? f.fieldset : void 0;
|
|
797
848
|
if (f.fieldset !== void 0 && !set) lose(ctx, `${at}/fieldset`, "fieldset collision");
|
|
798
849
|
if (!top) {
|
|
799
|
-
if (f.group !== void 0)
|
|
850
|
+
if (f.group !== void 0) {
|
|
851
|
+
if (ctx.tabs.has(f.group)) node.ui.tab = { id: f.group };
|
|
852
|
+
else lose(ctx, `${at}/group`, "group (nested)");
|
|
853
|
+
}
|
|
800
854
|
if (set) node.fieldsetId = set;
|
|
801
855
|
return;
|
|
802
856
|
}
|
|
@@ -1277,8 +1331,8 @@ function layoutToProd(f, shape, node, at, ctx) {
|
|
|
1277
1331
|
const t = shape.type;
|
|
1278
1332
|
const n = f.options?.length ?? 0;
|
|
1279
1333
|
if (l === "segmented" && t === "select") {
|
|
1280
|
-
if (n >=
|
|
1281
|
-
else if (n
|
|
1334
|
+
if (n >= SEGMENTED_MIN && n <= SEGMENTED_MAX) node.ui.control = "segmented";
|
|
1335
|
+
else if (n > SEGMENTED_MAX) cat(ctx, at, "segmented fallback");
|
|
1282
1336
|
else lose(ctx, at, "layout");
|
|
1283
1337
|
} else if (l === "slider" && t === "number" && f.type === "number") node.ui.control = "slider";
|
|
1284
1338
|
else if (UI_CONTROLS.includes(l) && l !== "segmented" && l !== "slider" && CONTROL_TYPES[l]?.includes(t)) node.ui.control = l;
|
|
@@ -1581,28 +1635,8 @@ function blockModelFor(item, at, ctx, list) {
|
|
|
1581
1635
|
if (item[k] === void 0 || k === "type" || k === "title") continue;
|
|
1582
1636
|
if (k === "name") {
|
|
1583
1637
|
if (camel(slug) !== item.name) lose(ctx, p, "item identity");
|
|
1584
|
-
} else if (k === "fields") {
|
|
1585
|
-
|
|
1586
|
-
let shifted = false;
|
|
1587
|
-
fields.forEach((c, j) => {
|
|
1588
|
-
const fp = `${p}/${j}`;
|
|
1589
|
-
const mark = ctx.lossy.length;
|
|
1590
|
-
const markCat = ctx.catalog.length;
|
|
1591
|
-
const node = convertField(c, fp, 1, sub, fields, false);
|
|
1592
|
-
if (BLOCK_FIELD_TYPES.has(node.type)) {
|
|
1593
|
-
kept.push(emitField(node));
|
|
1594
|
-
if (dropped && !shifted) {
|
|
1595
|
-
shifted = true;
|
|
1596
|
-
lose(ctx, p, "block model field");
|
|
1597
|
-
}
|
|
1598
|
-
return;
|
|
1599
|
-
}
|
|
1600
|
-
ctx.lossy.length = mark;
|
|
1601
|
-
ctx.catalog.length = markCat;
|
|
1602
|
-
dropped = true;
|
|
1603
|
-
lose(ctx, fp, "block model field");
|
|
1604
|
-
});
|
|
1605
|
-
} else if (k === "openMode") cat(ctx, p, "item openMode");
|
|
1638
|
+
} else if (k === "fields") fields.forEach((c, j) => kept.push(emitField(convertField(c, `${p}/${j}`, 1, sub, fields, false))));
|
|
1639
|
+
else if (k === "openMode") chrome.openMode = item.openMode;
|
|
1606
1640
|
else if (k === "icon") {
|
|
1607
1641
|
const dock = dockIconOf(item.icon);
|
|
1608
1642
|
if (dock) chrome.icon = dock;
|
|
@@ -1610,11 +1644,17 @@ function blockModelFor(item, at, ctx, list) {
|
|
|
1610
1644
|
} else if (k === "preview") chrome.preview = previewToProd(item.preview, fields, p, ctx);
|
|
1611
1645
|
else lose(ctx, p, "item identity");
|
|
1612
1646
|
}
|
|
1613
|
-
const model = {
|
|
1647
|
+
const model = kept.every(blockRenders) ? {
|
|
1614
1648
|
name: item.title,
|
|
1615
1649
|
slug,
|
|
1616
1650
|
kind: "block",
|
|
1617
1651
|
fields: kept
|
|
1652
|
+
} : {
|
|
1653
|
+
name: item.title,
|
|
1654
|
+
slug,
|
|
1655
|
+
kind: "model",
|
|
1656
|
+
fields: kept,
|
|
1657
|
+
v2: { shape: "block" }
|
|
1618
1658
|
};
|
|
1619
1659
|
const prev = ctx.blockModels.get(slug);
|
|
1620
1660
|
const keep = () => {
|
|
@@ -1784,13 +1824,14 @@ function conditionToShowIf(h, at, siblings, ctx, variantOk) {
|
|
|
1784
1824
|
/** One V2 rule as a prod rule, or null when prod cannot hold it (a scope, a non-sibling, a value showIf cannot test). */
|
|
1785
1825
|
function conditionRule(r, head, siblings, variantOk) {
|
|
1786
1826
|
const variant = variantOk && r.field === "_variant";
|
|
1787
|
-
if (!r.field || r.scope
|
|
1827
|
+
if (!r.field || r.scope === void 0 && !variant && !siblings.some((s) => s.name === r.field)) return null;
|
|
1788
1828
|
const allowed = head ? [
|
|
1789
1829
|
"field",
|
|
1790
1830
|
"equals",
|
|
1791
1831
|
"notEmpty",
|
|
1792
1832
|
"op",
|
|
1793
1833
|
"value",
|
|
1834
|
+
"scope",
|
|
1794
1835
|
"also",
|
|
1795
1836
|
"match"
|
|
1796
1837
|
] : [
|
|
@@ -1798,7 +1839,8 @@ function conditionRule(r, head, siblings, variantOk) {
|
|
|
1798
1839
|
"equals",
|
|
1799
1840
|
"notEmpty",
|
|
1800
1841
|
"op",
|
|
1801
|
-
"value"
|
|
1842
|
+
"value",
|
|
1843
|
+
"scope"
|
|
1802
1844
|
];
|
|
1803
1845
|
if (Object.keys(r).some((k) => !allowed.includes(k) && r[k] !== void 0)) return null;
|
|
1804
1846
|
if ([
|
|
@@ -1806,22 +1848,26 @@ function conditionRule(r, head, siblings, variantOk) {
|
|
|
1806
1848
|
r.equals !== void 0,
|
|
1807
1849
|
r.notEmpty !== void 0
|
|
1808
1850
|
].filter(Boolean).length !== 1) return null;
|
|
1851
|
+
const scope = r.scope ? { scope: r.scope } : {};
|
|
1809
1852
|
if (r.notEmpty !== void 0) return r.notEmpty === true ? {
|
|
1810
1853
|
field: r.field,
|
|
1811
|
-
op: "notEmpty"
|
|
1854
|
+
op: "notEmpty",
|
|
1855
|
+
...scope
|
|
1812
1856
|
} : null;
|
|
1813
1857
|
const target = r.op !== void 0 ? r.value : r.equals;
|
|
1814
1858
|
const op = r.op !== void 0 ? SHOW_IF_OP[r.op] : Array.isArray(target) ? "in" : "eq";
|
|
1815
1859
|
if (!op) return null;
|
|
1816
1860
|
if (VALUELESS.has(op)) return r.value === void 0 ? {
|
|
1817
1861
|
field: r.field,
|
|
1818
|
-
op
|
|
1862
|
+
op,
|
|
1863
|
+
...scope
|
|
1819
1864
|
} : null;
|
|
1820
|
-
const sibType = variant ? void 0 : siblings.find((s) => s.name === r.field)?.type;
|
|
1865
|
+
const sibType = variant || r.scope ? void 0 : siblings.find((s) => s.name === r.field)?.type;
|
|
1821
1866
|
if (op === "gt" || op === "lt") return typeof target === "number" && Number.isFinite(target) ? {
|
|
1822
1867
|
field: r.field,
|
|
1823
1868
|
op,
|
|
1824
|
-
value: String(target)
|
|
1869
|
+
value: String(target),
|
|
1870
|
+
...scope
|
|
1825
1871
|
} : null;
|
|
1826
1872
|
const list = Array.isArray(target) ? target : [target];
|
|
1827
1873
|
const strs = [];
|
|
@@ -1838,16 +1884,19 @@ function conditionRule(r, head, siblings, variantOk) {
|
|
|
1838
1884
|
if (op === "in" || op === "notIn") return {
|
|
1839
1885
|
field: r.field,
|
|
1840
1886
|
op,
|
|
1841
|
-
value: strs
|
|
1887
|
+
value: strs,
|
|
1888
|
+
...scope
|
|
1842
1889
|
};
|
|
1843
1890
|
return Array.isArray(target) ? strs.length ? {
|
|
1844
1891
|
field: r.field,
|
|
1845
1892
|
op: op === "eq" ? "in" : "notIn",
|
|
1846
|
-
value: strs
|
|
1893
|
+
value: strs,
|
|
1894
|
+
...scope
|
|
1847
1895
|
} : null : {
|
|
1848
1896
|
field: r.field,
|
|
1849
1897
|
op,
|
|
1850
|
-
value: strs[0]
|
|
1898
|
+
value: strs[0],
|
|
1899
|
+
...scope
|
|
1851
1900
|
};
|
|
1852
1901
|
}
|
|
1853
1902
|
var nonEmpty = (o) => Object.keys(o).length ? o : void 0;
|
|
@@ -1864,6 +1913,7 @@ function common(n) {
|
|
|
1864
1913
|
"showIf",
|
|
1865
1914
|
"helpMore",
|
|
1866
1915
|
"advanced",
|
|
1916
|
+
"ai",
|
|
1867
1917
|
"recommendedMax",
|
|
1868
1918
|
"openMode",
|
|
1869
1919
|
"localized",
|
|
@@ -1957,9 +2007,12 @@ function fromTypeSchema(v2, target) {
|
|
|
1957
2007
|
blockModels: /* @__PURE__ */ new Map()
|
|
1958
2008
|
};
|
|
1959
2009
|
const props = target === "props";
|
|
2010
|
+
if (!props && v2.variants?.length) ctx.variants = true;
|
|
1960
2011
|
const slug = kebab(v2.name);
|
|
1961
|
-
const
|
|
2012
|
+
const kitCategory = KIT_CATEGORIES.includes(v2.category ?? "") ? v2.category : void 0;
|
|
2013
|
+
const category = kitCategory ?? (v2.category !== void 0 ? CATEGORY_TO_PROD[v2.category] : void 0);
|
|
1962
2014
|
const fieldsets = [];
|
|
2015
|
+
const block = {};
|
|
1963
2016
|
for (const k of Object.keys(v2)) {
|
|
1964
2017
|
if (v2[k] === void 0) continue;
|
|
1965
2018
|
const p = `/${k}`;
|
|
@@ -1973,23 +2026,22 @@ function fromTypeSchema(v2, target) {
|
|
|
1973
2026
|
case "fieldsets":
|
|
1974
2027
|
case "groups": break;
|
|
1975
2028
|
case "kind":
|
|
1976
|
-
if (props
|
|
1977
|
-
else if (!props && v2.kind !== "entry") cat(ctx, p, v2.kind === "global" ? "kind:global" : v2.kind === "page" ? "kind:page" : v2.kind === "block" ? "kind:block (fields)" : "kind:object");
|
|
2029
|
+
if (props ? v2.kind !== "block" : v2.kind !== "entry") block.shape = v2.kind;
|
|
1978
2030
|
break;
|
|
1979
2031
|
case "icon":
|
|
1980
|
-
if (!
|
|
1981
|
-
break;
|
|
1982
|
-
case "preview":
|
|
1983
|
-
if (!props) cat(ctx, p, "document preview");
|
|
2032
|
+
if (!dockIconOf(v2.icon)) cat(ctx, p, "block icon");
|
|
1984
2033
|
break;
|
|
2034
|
+
case "preview": break;
|
|
1985
2035
|
case "variants":
|
|
1986
|
-
cat(ctx, p, "variants");
|
|
2036
|
+
if (!ctx.variants) cat(ctx, p, "variants");
|
|
1987
2037
|
break;
|
|
1988
2038
|
case "category":
|
|
1989
|
-
if (
|
|
2039
|
+
if (kitCategory) {
|
|
2040
|
+
if (!props) block.category = kitCategory;
|
|
2041
|
+
} else if (!props || !category || capitalize(category) !== v2.category) cat(ctx, p, "category");
|
|
1990
2042
|
break;
|
|
1991
2043
|
case "placement":
|
|
1992
|
-
|
|
2044
|
+
block.placement = v2.placement;
|
|
1993
2045
|
break;
|
|
1994
2046
|
case "initialValue":
|
|
1995
2047
|
cat(ctx, p, "seeded instance");
|
|
@@ -2010,6 +2062,7 @@ function fromTypeSchema(v2, target) {
|
|
|
2010
2062
|
};
|
|
2011
2063
|
if (v2.description !== void 0) component.description = v2.description;
|
|
2012
2064
|
if (category) component.category = category;
|
|
2065
|
+
if (nonEmpty(block)) component.v2 = { ...block };
|
|
2013
2066
|
const icon = v2.icon === void 0 ? void 0 : dockIconOf(v2.icon);
|
|
2014
2067
|
if (icon) component.icon = icon;
|
|
2015
2068
|
if (v2.preview !== void 0) {
|
|
@@ -2030,7 +2083,35 @@ function fromTypeSchema(v2, target) {
|
|
|
2030
2083
|
fields: nodes.map(emitField)
|
|
2031
2084
|
};
|
|
2032
2085
|
if (v2.description !== void 0) model.description = v2.description;
|
|
2033
|
-
|
|
2086
|
+
const modelIcon = v2.icon === void 0 ? void 0 : dockIconOf(v2.icon);
|
|
2087
|
+
if (modelIcon) model.icon = modelIcon;
|
|
2088
|
+
model.kind = block.shape === "block" && model.fields.every(blockRenders) ? "block" : "model";
|
|
2089
|
+
if (ctx.variants) {
|
|
2090
|
+
const variants = v2.variants;
|
|
2091
|
+
model.fields.unshift({
|
|
2092
|
+
key: BLOCK_VARIANT_KEY,
|
|
2093
|
+
label: "Variant",
|
|
2094
|
+
type: "select",
|
|
2095
|
+
required: false,
|
|
2096
|
+
options: variants.map((v) => ({
|
|
2097
|
+
label: v.name,
|
|
2098
|
+
value: v.id
|
|
2099
|
+
}))
|
|
2100
|
+
});
|
|
2101
|
+
model.v2 = {
|
|
2102
|
+
...block,
|
|
2103
|
+
variants: Object.fromEntries(variants.map((v) => [v.id, v.description !== void 0 ? { description: v.description } : {}]))
|
|
2104
|
+
};
|
|
2105
|
+
} else if (nonEmpty(block)) model.v2 = { ...block };
|
|
2106
|
+
if (v2.preview !== void 0) {
|
|
2107
|
+
const preview = componentPreviewToProd(v2.preview, new Set(model.fields.map((x) => x.key)), v2.fields, "/preview", ctx);
|
|
2108
|
+
if (Object.keys(preview).length) model.listPreview = preview;
|
|
2109
|
+
}
|
|
2110
|
+
if (ctx.derivedSets) {
|
|
2111
|
+
const declared = fieldsets.filter((x) => x.kind !== "tab").length;
|
|
2112
|
+
ctx.derivedSets.forEach((_, i) => cat(ctx, `/fieldsets/${declared + i}`, "fieldset (derived)"));
|
|
2113
|
+
fieldsets.push(...ctx.derivedSets);
|
|
2114
|
+
}
|
|
2034
2115
|
if (fieldsets.length) model.fieldsets = fieldsets;
|
|
2035
2116
|
return {
|
|
2036
2117
|
schema: model,
|
|
@@ -2414,9 +2495,12 @@ function previewFromProd(pv, children) {
|
|
|
2414
2495
|
function showIfToCondition(s, siblings, at, ctx) {
|
|
2415
2496
|
const conds = [];
|
|
2416
2497
|
for (const r of s.rules) {
|
|
2417
|
-
const c = showIfRuleToCondition(r, siblings);
|
|
2498
|
+
const c = showIfRuleToCondition(r, r.scope ? [] : siblings);
|
|
2418
2499
|
if (!c) return void ctx.onLoss(at, "condition", `V2 conditions have no "${r.op}" with this value; the field always shows.`);
|
|
2419
|
-
conds.push(
|
|
2500
|
+
conds.push(r.scope ? {
|
|
2501
|
+
...c,
|
|
2502
|
+
scope: r.scope
|
|
2503
|
+
} : c);
|
|
2420
2504
|
}
|
|
2421
2505
|
if (!conds.length) return void 0;
|
|
2422
2506
|
const [head, ...also] = conds;
|
|
@@ -2530,6 +2614,7 @@ function readToV2(n, at, siblings, ctx, top, lane) {
|
|
|
2530
2614
|
if (n.unique !== void 0) val.unique = n.unique;
|
|
2531
2615
|
if (n.recommendedMax !== void 0) val.recommendedMax = n.recommendedMax;
|
|
2532
2616
|
if (n.advanced !== void 0) f.advanced = n.advanced;
|
|
2617
|
+
if (n.ai !== void 0) f.ai = n.ai;
|
|
2533
2618
|
if (n.openMode !== void 0) f.openMode = n.openMode;
|
|
2534
2619
|
if (n.readOnly === true) f.readOnly = true;
|
|
2535
2620
|
if (n.archived === true) f.archived = true;
|
|
@@ -2569,7 +2654,7 @@ function readToV2(n, at, siblings, ctx, top, lane) {
|
|
|
2569
2654
|
} else loss("fieldsetId", "fieldset", `No fieldset "${n.fieldsetId}" exists on this model; the membership is dropped.`);
|
|
2570
2655
|
}
|
|
2571
2656
|
if (lane === "props" && n.ui.group) f.fieldset = n.ui.group.id;
|
|
2572
|
-
if (lane === "props" && n.ui.tab) f.group = n.ui.tab.id;
|
|
2657
|
+
if ((lane === "props" || !top) && n.ui.tab) f.group = n.ui.tab.id;
|
|
2573
2658
|
for (const k of [
|
|
2574
2659
|
"target",
|
|
2575
2660
|
"stale",
|
|
@@ -2593,6 +2678,7 @@ function readToV2(n, at, siblings, ctx, top, lane) {
|
|
|
2593
2678
|
]);
|
|
2594
2679
|
const use = (...k) => k.forEach((x) => used.add(x));
|
|
2595
2680
|
const useUi = (...k) => k.forEach((x) => usedUi.add(x));
|
|
2681
|
+
if (!top && lane === "fields") useUi("tab");
|
|
2596
2682
|
if (lane === "props") useUi("group");
|
|
2597
2683
|
if (lane === "props") useUi("tab");
|
|
2598
2684
|
if (RICH_TYPES.has(n.type) && cfg.references !== void 0) {
|
|
@@ -2815,6 +2901,7 @@ function readToV2(n, at, siblings, ctx, top, lane) {
|
|
|
2815
2901
|
};
|
|
2816
2902
|
if (chrome?.icon) item.icon = tablerIconOf(chrome.icon);
|
|
2817
2903
|
if (chrome?.preview) item.preview = previewFromProd(chrome.preview, kids);
|
|
2904
|
+
if (chrome?.openMode) item.openMode = chrome.openMode;
|
|
2818
2905
|
return item;
|
|
2819
2906
|
});
|
|
2820
2907
|
const missing = slugs.filter((s) => !ctx.blockModels.has(s));
|
|
@@ -2972,14 +3059,27 @@ function toTypeSchema(model, opts = {}) {
|
|
|
2972
3059
|
if (s.icon !== void 0) ctx.onLoss(`/fieldsets/${i}/icon`, "fieldset icon", "V2 sections have no icon.");
|
|
2973
3060
|
fieldsets.push(fs);
|
|
2974
3061
|
});
|
|
2975
|
-
const
|
|
3062
|
+
const variantField = model.v2?.variants ? model.fields.find((f) => f.key === BLOCK_VARIANT_KEY && f.type === "select") : void 0;
|
|
3063
|
+
const nodes = model.fields.filter((f) => f !== variantField).map(readField);
|
|
2976
3064
|
const out = {
|
|
2977
3065
|
name: camel(model.slug),
|
|
2978
3066
|
title: model.name,
|
|
2979
|
-
kind: model.kind === "block" ? "block" : "entry",
|
|
3067
|
+
kind: model.kind === "block" ? "block" : model.v2?.shape ?? "entry",
|
|
2980
3068
|
fields: nodes.map((n, i) => readToV2(n, `/fields/${i}`, nodes, ctx, true, "fields"))
|
|
2981
3069
|
};
|
|
3070
|
+
if (model.v2?.placement) out.placement = model.v2.placement;
|
|
3071
|
+
if (variantField) {
|
|
3072
|
+
const meta = model.v2.variants;
|
|
3073
|
+
out.variants = (variantField.options ?? []).map((o) => ({
|
|
3074
|
+
id: o.value,
|
|
3075
|
+
name: o.label,
|
|
3076
|
+
...meta[o.value]?.description !== void 0 ? { description: meta[o.value].description } : {}
|
|
3077
|
+
}));
|
|
3078
|
+
}
|
|
3079
|
+
if (model.listPreview) out.preview = previewFromProd(model.listPreview, nodes);
|
|
3080
|
+
if (model.v2?.category) out.category = model.v2.category;
|
|
2982
3081
|
if (model.description !== void 0) out.description = model.description;
|
|
3082
|
+
if (model.icon) out.icon = tablerIconOf(model.icon);
|
|
2983
3083
|
if (fieldsets.length) out.fieldsets = fieldsets;
|
|
2984
3084
|
if (groups.length) out.groups = groups;
|
|
2985
3085
|
return out;
|
|
@@ -3048,18 +3148,72 @@ function propsToTypeSchema(component, opts = {}) {
|
|
|
3048
3148
|
const out = {
|
|
3049
3149
|
name: camel(component.slug),
|
|
3050
3150
|
title: component.name,
|
|
3051
|
-
kind: "block",
|
|
3151
|
+
kind: component.v2?.shape ?? "block",
|
|
3052
3152
|
fields: nodes.map((n, i) => readToV2(n, `/fields/${i}`, nodes, ctx, true, "props"))
|
|
3053
3153
|
};
|
|
3154
|
+
if (component.v2?.placement) out.placement = component.v2.placement;
|
|
3054
3155
|
if (component.description !== void 0 && component.description !== null) out.description = component.description;
|
|
3055
|
-
if (component.category !== void 0 && component.category !== "custom") out.category = capitalize(component.category);
|
|
3156
|
+
if (component.category !== void 0 && component.category !== "custom") out.category = KIT_CATEGORIES.includes(component.category) ? component.category : capitalize(component.category);
|
|
3056
3157
|
if (component.icon) out.icon = tablerIconOf(component.icon);
|
|
3057
3158
|
if (component.preview) out.preview = previewFromProd(component.preview, nodes);
|
|
3058
3159
|
if (fieldsets.length) out.fieldsets = fieldsets;
|
|
3059
3160
|
if (groups.length) out.groups = groups;
|
|
3060
3161
|
return out;
|
|
3061
3162
|
}
|
|
3163
|
+
/** A V2 variant id a member slug can carry, so the read takes it back verbatim (the component slug rule). */
|
|
3164
|
+
var VARIANT_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3165
|
+
function variantFamilyFromTypeSchema(v2) {
|
|
3166
|
+
const base = fromTypeSchema(v2, "props");
|
|
3167
|
+
const variants = v2.variants ?? [];
|
|
3168
|
+
if (!variants.length || !variants.every((v) => VARIANT_ID_RE.test(v.id))) return {
|
|
3169
|
+
members: [base.schema],
|
|
3170
|
+
group: null,
|
|
3171
|
+
lossy: base.lossy,
|
|
3172
|
+
catalog: base.catalog
|
|
3173
|
+
};
|
|
3174
|
+
const slug = base.schema.slug;
|
|
3175
|
+
return {
|
|
3176
|
+
members: variants.map((v) => ({
|
|
3177
|
+
...base.schema,
|
|
3178
|
+
name: v.name,
|
|
3179
|
+
slug: `${slug}-${v.id}`,
|
|
3180
|
+
sectionType: v2.title
|
|
3181
|
+
})),
|
|
3182
|
+
group: {
|
|
3183
|
+
name: v2.title,
|
|
3184
|
+
slug,
|
|
3185
|
+
variants: variants.map((v) => ({
|
|
3186
|
+
member: `${slug}-${v.id}`,
|
|
3187
|
+
...v.description !== void 0 ? { description: v.description } : {}
|
|
3188
|
+
}))
|
|
3189
|
+
},
|
|
3190
|
+
lossy: base.lossy,
|
|
3191
|
+
catalog: base.catalog.filter((c) => c.feature !== "variants")
|
|
3192
|
+
};
|
|
3193
|
+
}
|
|
3194
|
+
/** The group's `v2` (component_variant_groups.v2, variantGroupV2Schema) once the members exist: `idOf` maps a member slug to its id. */
|
|
3195
|
+
function variantGroupV2(group, idOf) {
|
|
3196
|
+
return { variants: group.variants.map((v) => ({
|
|
3197
|
+
componentId: idOf(v.member),
|
|
3198
|
+
...v.description !== void 0 ? { description: v.description } : {}
|
|
3199
|
+
})) };
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* A family read back as one V2 block: the first member's props, the family's name and title, and its variants from the
|
|
3203
|
+
* group's members in `v2.variants` order (the id after the group slug, the member's name, the meta's description).
|
|
3204
|
+
*/
|
|
3205
|
+
function variantFamilyToTypeSchema(members, group, opts = {}) {
|
|
3206
|
+
const out = propsToTypeSchema(members[0], opts);
|
|
3207
|
+
out.name = camel(group.slug);
|
|
3208
|
+
if (members[0].sectionType) out.title = members[0].sectionType;
|
|
3209
|
+
out.variants = members.map((m, i) => ({
|
|
3210
|
+
id: m.slug.slice(group.slug.length + 1),
|
|
3211
|
+
name: m.name,
|
|
3212
|
+
...group.variants[i]?.description !== void 0 ? { description: group.variants[i].description } : {}
|
|
3213
|
+
}));
|
|
3214
|
+
return out;
|
|
3215
|
+
}
|
|
3062
3216
|
//#endregion
|
|
3063
|
-
export { CATEGORY_TO_PROD, SHOPIFY_REF_LOCK, fromTypeSchema, leafValuePlan, planFromProd, planToProd, propsToTypeSchema, schemaSlugOf, toTypeSchema };
|
|
3217
|
+
export { CATEGORY_TO_PROD, SHOPIFY_REF_LOCK, fromTypeSchema, leafValuePlan, planFromProd, planToProd, propsToTypeSchema, schemaSlugOf, toTypeSchema, variantFamilyFromTypeSchema, variantFamilyToTypeSchema, variantGroupV2 };
|
|
3064
3218
|
|
|
3065
3219
|
//# sourceMappingURL=schema.js.map
|