@parity-app/cli 0.7.5 → 0.7.7
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/bin.mjs +8 -8
- package/dist/{client-D6bpjpy-.mjs → client-CkT-5H3_.mjs} +8 -2
- package/dist/index.mjs +1 -1
- package/dist/{published-BtL8RM6W.mjs → published-B0sNR0jd.mjs} +1 -1
- package/dist/{published-CdXoUgfD.mjs → published-DYY8_8m9.mjs} +54 -16
- package/dist/{schema-CemdtCeF.mjs → schema-Dp5Jhloe.mjs} +2 -2
- package/dist/src-C4S96XEj.mjs +5 -0
- package/dist/{src-DjSCuWcT.mjs → src-Ck9A-Gxr.mjs} +550 -370
- package/dist/{src-Bf12xdm5.mjs → src-XUZS4M-k.mjs} +180 -137
- package/dist/{src-Q382DbAK.mjs → src-ZsXhzNYa.mjs} +1 -1
- package/dist/{src-B9VW36v9.mjs → src-gCnKQqH5.mjs} +9 -3
- package/package.json +1 -1
- package/skills/execute.md +9 -0
- package/dist/src-Btr2eWdT.mjs +0 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as fileObject, o as parseData, r as finiteNumber, s as plainObject } from "./schema-
|
|
1
|
+
import { i as jsonText, n as fileObject, o as parseData, r as finiteNumber, s as plainObject } from "./schema-Dp5Jhloe.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
// ../core/src/adapters.ts
|
|
4
4
|
const packageVersions = z.record(z.string(), z.string());
|
|
@@ -18,6 +18,7 @@ const packageManifest = z.looseObject({
|
|
|
18
18
|
version: z.string().optional(),
|
|
19
19
|
dependencies: packageVersions.optional(),
|
|
20
20
|
devDependencies: packageVersions.optional(),
|
|
21
|
+
optionalDependencies: packageVersions.optional(),
|
|
21
22
|
scripts: z.record(z.string(), z.string()).optional(),
|
|
22
23
|
/** Entry points by subpath (`.`, `./tailwind.css`), or where the package's one entry point leads. */
|
|
23
24
|
exports: exportsTarget.optional(),
|
|
@@ -28,8 +29,28 @@ const packageManifest = z.looseObject({
|
|
|
28
29
|
/** The stylesheet a project imports to use the package, as some packages name it. */
|
|
29
30
|
style: z.string().optional(),
|
|
30
31
|
/** A workspace root's package folders, as npm, Yarn and Bun write them. */
|
|
31
|
-
workspaces: z.union([z.array(z.string()), z.looseObject({ packages: z.array(z.string()).optional() })]).optional()
|
|
32
|
+
workspaces: z.union([z.array(z.string()), z.looseObject({ packages: z.array(z.string()).optional() })]).optional(),
|
|
33
|
+
/** The command line it installs: one file named after the package, or files by command name. */
|
|
34
|
+
bin: z.union([z.string(), z.record(z.string(), z.string())]).optional(),
|
|
35
|
+
/** Where its source is, which libgen reads examples from. */
|
|
36
|
+
repository: z.union([z.string(), z.looseObject({
|
|
37
|
+
url: z.string().optional(),
|
|
38
|
+
directory: z.string().optional()
|
|
39
|
+
})]).optional(),
|
|
40
|
+
/** The package manager and version a project asks for, as Corepack writes it (`pnpm@10.4.0`). */
|
|
41
|
+
packageManager: z.string().optional()
|
|
32
42
|
});
|
|
43
|
+
/**
|
|
44
|
+
* A package.json's text, read through {@link packageManifest}. Throws `TypeError` naming the file and the field at
|
|
45
|
+
* fault, as in `/app/package.json: /scripts/dev: expected a string`, or `/: expected JSON`.
|
|
46
|
+
*/
|
|
47
|
+
function parseManifest(text, file) {
|
|
48
|
+
try {
|
|
49
|
+
return parseData(jsonText(packageManifest), text);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new TypeError(`${file}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
33
54
|
// ../core/src/devices.ts
|
|
34
55
|
const deviceKinds = [
|
|
35
56
|
"phone",
|
|
@@ -341,6 +362,7 @@ const detectionCorrections = fileObject({
|
|
|
341
362
|
include: z.array(componentRef).optional(),
|
|
342
363
|
exclude: z.unknown().optional()
|
|
343
364
|
}).transform(({ exclude: _dropped, ...corrections }) => corrections);
|
|
365
|
+
/** Text on the canvas outside any design, as a project file or the clipboard holds it. */
|
|
344
366
|
const noteSpec = fileObject({
|
|
345
367
|
id: z.string(),
|
|
346
368
|
text: z.string(),
|
|
@@ -504,18 +526,20 @@ const componentNode$1 = nodeBase.extend({
|
|
|
504
526
|
return z.record(z.string(), z.array(designNode)).optional();
|
|
505
527
|
}
|
|
506
528
|
});
|
|
529
|
+
/** The elements a text node can be. */
|
|
530
|
+
const textTags = [
|
|
531
|
+
"p",
|
|
532
|
+
"span",
|
|
533
|
+
"h1",
|
|
534
|
+
"h2",
|
|
535
|
+
"h3",
|
|
536
|
+
"h4",
|
|
537
|
+
"strong"
|
|
538
|
+
];
|
|
507
539
|
const textNode = nodeBase.extend({
|
|
508
540
|
type: z.literal("text"),
|
|
509
541
|
text: z.string(),
|
|
510
|
-
tag: z.enum(
|
|
511
|
-
"p",
|
|
512
|
-
"span",
|
|
513
|
-
"h1",
|
|
514
|
-
"h2",
|
|
515
|
-
"h3",
|
|
516
|
-
"h4",
|
|
517
|
-
"strong"
|
|
518
|
-
]).optional()
|
|
542
|
+
tag: z.enum(textTags).optional()
|
|
519
543
|
});
|
|
520
544
|
const instanceNode = nodeBase.extend({
|
|
521
545
|
type: z.literal("instance"),
|
|
@@ -535,6 +559,7 @@ const imageFits = [
|
|
|
535
559
|
"contain",
|
|
536
560
|
"fill"
|
|
537
561
|
];
|
|
562
|
+
/** Who made a stock image and where it came from, as an image node or a dragged image holds it. */
|
|
538
563
|
const imageCredit = fileObject({
|
|
539
564
|
name: z.string(),
|
|
540
565
|
url: z.string(),
|
|
@@ -652,6 +677,7 @@ const stateSpec = fileObject({
|
|
|
652
677
|
*/
|
|
653
678
|
overrides: nodePatches.optional()
|
|
654
679
|
});
|
|
680
|
+
/** One design, as a project file or the clipboard holds it (see `ContainerSpec`). */
|
|
655
681
|
const containerSpec = fileObject({
|
|
656
682
|
id: z.string(),
|
|
657
683
|
name: z.string(),
|
|
@@ -750,42 +776,285 @@ const canvasDocument = fileObject({
|
|
|
750
776
|
/** The source each lens reads, where the person switched from the one Parity picked. */
|
|
751
777
|
sources: lensSources.optional()
|
|
752
778
|
});
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
779
|
+
// ../core/src/values/evaluate.ts
|
|
780
|
+
/** The keys that mark an object as one of the value forms rather than plain JSON. */
|
|
781
|
+
const valueForms = [
|
|
782
|
+
"$import",
|
|
783
|
+
"$call",
|
|
784
|
+
"$global",
|
|
785
|
+
"$frame",
|
|
786
|
+
"$function"
|
|
787
|
+
];
|
|
788
|
+
/** The parts of a frame a `$frame` value can name. */
|
|
789
|
+
const frameParts = [
|
|
790
|
+
"root",
|
|
791
|
+
"host",
|
|
792
|
+
"body",
|
|
793
|
+
"document",
|
|
794
|
+
"dir",
|
|
795
|
+
"lang",
|
|
796
|
+
"selector"
|
|
797
|
+
];
|
|
798
|
+
/** Whether a sample's prop value is elements. */
|
|
799
|
+
function isSampleElement(value) {
|
|
800
|
+
return typeof value === "object" && value !== null && Array.isArray(value.$element);
|
|
801
|
+
}
|
|
802
|
+
/** Whether a value is one the package makes. */
|
|
803
|
+
function isMadeValue(value) {
|
|
804
|
+
const call = typeof value === "object" && value !== null ? value.$call : void 0;
|
|
805
|
+
return typeof call === "object" && call !== null && typeof call.import === "string";
|
|
806
|
+
}
|
|
807
|
+
/** Whether a sample's child or prop value is a render function. */
|
|
808
|
+
function isSampleRender(value) {
|
|
809
|
+
return typeof value === "object" && value !== null && Array.isArray(value.$render);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* A value worked out against a host: plain JSON as written, and its kind's forms made. A `$import` without an `export`
|
|
813
|
+
* is the module's default export. A `$call` calls its function with its `args`, then the `methods` in order on what it
|
|
814
|
+
* returned, wherever the call is; a method that's missing or throws is passed over, as the made value is still usable.
|
|
815
|
+
* Arrays and objects with no form inside them come back as they were, so a prop keeps its identity between draws.
|
|
816
|
+
*/
|
|
817
|
+
function evaluateValue(value, host, kind = "decorator") {
|
|
818
|
+
const evaluate = (item) => evaluateValue(item, host, kind);
|
|
819
|
+
if (Array.isArray(value)) {
|
|
820
|
+
const items = value.map(evaluate);
|
|
821
|
+
return items.every((item, index) => item === value[index]) ? value : items;
|
|
822
|
+
}
|
|
823
|
+
if (typeof value !== "object" || value === null) return value;
|
|
824
|
+
const record = value;
|
|
825
|
+
if (isMadeValue(record)) return made$1(record, host, kind);
|
|
826
|
+
if (kind === "sample") return evaluateEntries(record, evaluate);
|
|
827
|
+
if (typeof record.$import === "string") {
|
|
828
|
+
const imported = record;
|
|
829
|
+
return host.exported(imported.$import, imported.export ?? "default");
|
|
830
|
+
}
|
|
831
|
+
if (typeof record.$global === "string") {
|
|
832
|
+
const global = record;
|
|
833
|
+
const chosen = host.global(global.$global);
|
|
834
|
+
const values = global.values ?? {};
|
|
835
|
+
return evaluate(chosen !== void 0 && Object.hasOwn(values, chosen) ? values[chosen] : global.default);
|
|
836
|
+
}
|
|
837
|
+
if (typeof record.$frame === "string") return host.frame(record.$frame);
|
|
838
|
+
if ("$function" in record) return () => evaluate(record.$function);
|
|
839
|
+
return evaluateEntries(record, evaluate);
|
|
840
|
+
}
|
|
841
|
+
/** Plain JSON's entries worked out, or the object as it was when none of them changed. */
|
|
842
|
+
function evaluateEntries(record, evaluate) {
|
|
843
|
+
let changed = false;
|
|
844
|
+
const entries = Object.entries(record).map(([key, item]) => {
|
|
845
|
+
const evaluated = evaluate(item);
|
|
846
|
+
if (evaluated !== item) changed = true;
|
|
847
|
+
return [key, evaluated];
|
|
848
|
+
});
|
|
849
|
+
return changed ? Object.fromEntries(entries) : record;
|
|
756
850
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
if (
|
|
760
|
-
|
|
851
|
+
function made$1(value, host, kind) {
|
|
852
|
+
const key = JSON.stringify(value);
|
|
853
|
+
if (host.made.has(key)) return host.made.get(key);
|
|
854
|
+
const { import: specifier, export: name } = value.$call;
|
|
855
|
+
const fn = host.exported(specifier, name);
|
|
856
|
+
if (typeof fn !== "function") throw new Error(`${specifier} has no function ${name}`);
|
|
857
|
+
const result = fn(...(value.args ?? []).map((arg) => evaluateValue(arg, host, kind)));
|
|
858
|
+
for (const step of value.methods ?? []) {
|
|
859
|
+
const method = result?.[step.method];
|
|
860
|
+
if (typeof method !== "function") continue;
|
|
861
|
+
try {
|
|
862
|
+
method.apply(result, (step.args ?? []).map((arg) => evaluateValue(arg, host, kind)));
|
|
863
|
+
} catch {}
|
|
864
|
+
}
|
|
865
|
+
host.made.set(key, result);
|
|
866
|
+
return result;
|
|
761
867
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
868
|
+
/** The modules a value imports from, each once, in the order they first appear. Plain JSON imports none. */
|
|
869
|
+
function valueImports(value, kind = "decorator") {
|
|
870
|
+
const found = /* @__PURE__ */ new Set();
|
|
871
|
+
const visit = (item) => {
|
|
872
|
+
if (Array.isArray(item)) return item.forEach(visit);
|
|
873
|
+
if (typeof item !== "object" || item === null) return;
|
|
874
|
+
const record = item;
|
|
875
|
+
if (kind === "decorator" && typeof record.$import === "string") {
|
|
876
|
+
found.add(record.$import);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
if (isMadeValue(record)) {
|
|
880
|
+
found.add(record.$call.import);
|
|
881
|
+
record.args?.forEach(visit);
|
|
882
|
+
for (const step of record.methods ?? []) step.args?.forEach(visit);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (kind === "decorator" && typeof record.$frame === "string") return;
|
|
886
|
+
Object.values(record).forEach(visit);
|
|
887
|
+
};
|
|
888
|
+
visit(value);
|
|
889
|
+
return [...found];
|
|
890
|
+
}
|
|
891
|
+
/** An export of a module, following dots into namespaces (`Tooltip.Provider`). */
|
|
892
|
+
function exportOf(module, path) {
|
|
893
|
+
let found = module;
|
|
894
|
+
for (const part of path.split(".")) found = found?.[part];
|
|
895
|
+
return found;
|
|
765
896
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
897
|
+
/**
|
|
898
|
+
* Where a part's sample calls what's inside it: its function children, else a render prop (Chakra's `TreeView.Node`
|
|
899
|
+
* `render`), with the render function.
|
|
900
|
+
*/
|
|
901
|
+
function renderSlotOf(sample) {
|
|
902
|
+
const children = sample?.children?.find(isSampleRender);
|
|
903
|
+
if (children) return {
|
|
904
|
+
prop: "children",
|
|
905
|
+
render: children
|
|
906
|
+
};
|
|
907
|
+
const entry = Object.entries(sample?.props ?? {}).find(([, value]) => isSampleRender(value));
|
|
908
|
+
return entry ? {
|
|
909
|
+
prop: entry[0],
|
|
910
|
+
render: entry[1]
|
|
911
|
+
} : void 0;
|
|
769
912
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
913
|
+
/**
|
|
914
|
+
* The key a component node keeps a render function's nodes under (`renderInput`, function children): `$render:` and the
|
|
915
|
+
* prop, `$renderWith:` when what it's called with is spread onto them, and `?pass=a,b` for the props that take it.
|
|
916
|
+
*/
|
|
917
|
+
function renderSlotKey(prop, render) {
|
|
918
|
+
const pass = render.pass ? `?pass=${render.pass.join(",")}` : "";
|
|
919
|
+
return `${render.spread ? "$renderWith" : "$render"}:${prop}${pass}`;
|
|
773
920
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
921
|
+
/** A slot key `renderSlotKey` wrote, read back; `undefined` for a slot of plain nodes. */
|
|
922
|
+
function readRenderSlotKey(key) {
|
|
923
|
+
const match = /^\$render(With)?:([^?]+)(?:\?pass=(.+))?$/.exec(key);
|
|
924
|
+
if (!match) return void 0;
|
|
925
|
+
const [, spread, prop, pass] = match;
|
|
926
|
+
return {
|
|
927
|
+
prop,
|
|
928
|
+
spread: spread !== void 0,
|
|
929
|
+
...pass ? { pass: pass.split(",") } : {}
|
|
930
|
+
};
|
|
777
931
|
}
|
|
778
|
-
|
|
779
|
-
|
|
932
|
+
// ../core/src/values/grammar.ts
|
|
933
|
+
const primitives = [
|
|
934
|
+
z.string(),
|
|
935
|
+
finiteNumber,
|
|
936
|
+
z.boolean(),
|
|
937
|
+
z.null()
|
|
938
|
+
];
|
|
939
|
+
/**
|
|
940
|
+
* A decorator's or sample's value: JSON, or one of five forms that `evaluateValue` works out against a host, the frame
|
|
941
|
+
* in the guest and a trial outside one in libgen. An object with one of the forms' keys must be that form; any other
|
|
942
|
+
* object is plain JSON, its values values too.
|
|
943
|
+
*
|
|
944
|
+
* - `{ "$import": "pkg", "export": "name" }`: something the package exports, such as a theme object. `export` defaults
|
|
945
|
+
* to `default`, the default export.
|
|
946
|
+
* - `{ "$call": { "import": "pkg", "export": "name" }, "args": [...], "methods": [...] }`: what calling it returns,
|
|
947
|
+
* after calling `methods` on it in order.
|
|
948
|
+
* - `{ "$global": "theme", "values": { "dark": ... }, "default": ... }`: picked by the frame's global, which is the
|
|
949
|
+
* mode's option for that variable.
|
|
950
|
+
* - `{ "$frame": "root" | "host" | "body" }`: the frame's shadow root, the element it hangs from (which `:root[...]`
|
|
951
|
+
* rules match, as `:host(...)`), or the element standing in for its `<body>`. Also `document`, `dir`, `lang`, and
|
|
952
|
+
* `selector`, a CSS selector for the body alone.
|
|
953
|
+
* - `{ "$function": ... }`: a function returning the value it holds.
|
|
954
|
+
*
|
|
955
|
+
* Values are checked once, when their library file loads. The guest evaluates them on every frame without zod. A
|
|
956
|
+
* sample's values are `sampleValue`s.
|
|
957
|
+
*/
|
|
958
|
+
const decoratorValue = z.lazy(() => z.union([
|
|
959
|
+
...primitives,
|
|
960
|
+
z.array(decoratorValue),
|
|
961
|
+
form("$import", importedValue),
|
|
962
|
+
form("$call", madeValue),
|
|
963
|
+
form("$global", globalValue),
|
|
964
|
+
form("$frame", frameValue),
|
|
965
|
+
form("$function", functionValue),
|
|
966
|
+
plain(valueForms, decoratorValue)
|
|
967
|
+
]));
|
|
968
|
+
/**
|
|
969
|
+
* A sample's value, which a design node's props copy: JSON, and values the package makes (`$call`), as an example
|
|
970
|
+
* passes them. The other forms are a decorator's alone, so in a sample an object with their keys is data as written.
|
|
971
|
+
*/
|
|
972
|
+
const sampleValue = z.lazy(() => z.union([
|
|
973
|
+
...primitives,
|
|
974
|
+
z.array(sampleValue),
|
|
975
|
+
form("$call", made(sampleValue)),
|
|
976
|
+
plain(["$call"], sampleValue)
|
|
977
|
+
]));
|
|
978
|
+
/** Something the package exports, such as a theme object. */
|
|
979
|
+
const importedValue = fileObject({
|
|
980
|
+
$import: z.string(),
|
|
981
|
+
export: z.string().optional()
|
|
982
|
+
});
|
|
983
|
+
/**
|
|
984
|
+
* A value the package makes by calling one of its own functions, as an example does (Chakra's
|
|
985
|
+
* `collection={createTreeCollection({ rootNode })}`): the canvas calls it with `args`, once per frame.
|
|
986
|
+
*/
|
|
987
|
+
function made(value) {
|
|
988
|
+
return fileObject({
|
|
989
|
+
$call: fileObject({
|
|
990
|
+
import: z.string(),
|
|
991
|
+
export: z.string()
|
|
992
|
+
}),
|
|
993
|
+
args: z.array(value).optional(),
|
|
994
|
+
/**
|
|
995
|
+
* Methods called on what it makes, in order, as the examples call them (Chakra's `toaster.create({ title })`), so
|
|
996
|
+
* a toaster is drawn with a toast in it.
|
|
997
|
+
*/
|
|
998
|
+
methods: z.array(fileObject({
|
|
999
|
+
method: z.string(),
|
|
1000
|
+
args: z.array(value).optional()
|
|
1001
|
+
})).optional()
|
|
1002
|
+
});
|
|
780
1003
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
1004
|
+
const madeValue = made(decoratorValue);
|
|
1005
|
+
/** Picked by the frame's global, which is the mode's option for that variable, else `default`. */
|
|
1006
|
+
const globalValue = fileObject({
|
|
1007
|
+
$global: z.string(),
|
|
1008
|
+
values: z.record(z.string(), decoratorValue),
|
|
1009
|
+
default: decoratorValue.optional()
|
|
1010
|
+
});
|
|
1011
|
+
/** Part of the frame itself. */
|
|
1012
|
+
const frameValue = fileObject({ $frame: z.enum(frameParts) });
|
|
1013
|
+
/** A function returning the value it holds. */
|
|
1014
|
+
const functionValue = fileObject({ $function: decoratorValue });
|
|
1015
|
+
/**
|
|
1016
|
+
* An object with a form's key is that form. Any other object is refused as another type of value would be, which
|
|
1017
|
+
* `parseData` passes over, so a broken form reports its own mistake and not the closest of the other forms.
|
|
1018
|
+
*/
|
|
1019
|
+
function form(key, schema) {
|
|
1020
|
+
return z.unknown().superRefine((value, context) => {
|
|
1021
|
+
if (!(typeof value === "object" && value !== null && key in value)) context.addIssue({
|
|
1022
|
+
code: "invalid_type",
|
|
1023
|
+
expected: "object",
|
|
1024
|
+
input: value
|
|
1025
|
+
});
|
|
1026
|
+
}).pipe(schema);
|
|
784
1027
|
}
|
|
785
|
-
|
|
786
|
-
|
|
1028
|
+
/** Plain JSON, its values values too. An object with a form's key is refused, for the form to report. */
|
|
1029
|
+
function plain(forms, value) {
|
|
1030
|
+
return plainObject.superRefine((record, context) => {
|
|
1031
|
+
if (forms.some((key) => key in record)) context.addIssue({
|
|
1032
|
+
code: "invalid_type",
|
|
1033
|
+
expected: "object",
|
|
1034
|
+
input: record
|
|
1035
|
+
});
|
|
1036
|
+
}).pipe(z.record(z.string(), value));
|
|
787
1037
|
}
|
|
1038
|
+
/** A decorator's attributes, styles and element props. */
|
|
1039
|
+
const decoratorProps = z.record(z.string(), decoratorValue);
|
|
1040
|
+
/** A sample's props, and those of the components in its children. */
|
|
1041
|
+
const sampleProps = z.record(z.string(), sampleValue);
|
|
788
1042
|
// ../core/src/library.ts
|
|
1043
|
+
const libraryBreakpoint = fileObject({
|
|
1044
|
+
id: z.string(),
|
|
1045
|
+
name: z.string(),
|
|
1046
|
+
/** The width where it starts, in CSS pixels. */
|
|
1047
|
+
width: finiteNumber
|
|
1048
|
+
});
|
|
1049
|
+
/** The package a manifest describes. */
|
|
1050
|
+
const libraryPackage = fileObject({
|
|
1051
|
+
/** Its name on npm, as in `@mui/material`. */
|
|
1052
|
+
name: z.string(),
|
|
1053
|
+
/** The version it was generated from. */
|
|
1054
|
+
version: z.string().optional(),
|
|
1055
|
+
/** The versions it describes, as a semver range such as `^9.0.0`. Unset means any. */
|
|
1056
|
+
range: z.string().optional()
|
|
1057
|
+
});
|
|
789
1058
|
/** How a component was recognised, which is also why it's believed to be one. */
|
|
790
1059
|
const componentEvidence = [
|
|
791
1060
|
"function",
|
|
@@ -809,233 +1078,252 @@ const parentSignals = [
|
|
|
809
1078
|
"edit",
|
|
810
1079
|
"app"
|
|
811
1080
|
];
|
|
812
|
-
/** Whether a sample's prop value is elements. */
|
|
813
|
-
function isSampleElement(value) {
|
|
814
|
-
return typeof value === "object" && value !== null && Array.isArray(value.$element);
|
|
815
|
-
}
|
|
816
|
-
/** Whether a sample's prop value is one the package makes. */
|
|
817
|
-
function isMadeValue(value) {
|
|
818
|
-
const call = typeof value === "object" && value !== null ? value.$call : void 0;
|
|
819
|
-
return typeof call === "object" && call !== null && typeof call.import === "string";
|
|
820
|
-
}
|
|
821
|
-
/** Whether a sample's child or prop value is a render function. */
|
|
822
|
-
function isSampleRender(value) {
|
|
823
|
-
return typeof value === "object" && value !== null && Array.isArray(value.$render);
|
|
824
|
-
}
|
|
825
1081
|
/**
|
|
826
|
-
*
|
|
827
|
-
* `
|
|
1082
|
+
* A function returning these children. With `spread`, the object it's called with is spread onto the one element it
|
|
1083
|
+
* returns, as MUI's `renderInput={(params) => <TextField {...params} />}`; `pass` names props of that element that take
|
|
1084
|
+
* it whole, as React Aria's `{(segment) => <DateSegment segment={segment} />}`.
|
|
828
1085
|
*/
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1086
|
+
const sampleRender = fileObject({
|
|
1087
|
+
get $render() {
|
|
1088
|
+
return z.array(sampleChild);
|
|
1089
|
+
},
|
|
1090
|
+
spread: z.literal(true).optional(),
|
|
1091
|
+
pass: z.array(z.string()).optional()
|
|
1092
|
+
});
|
|
1093
|
+
/** A component of the same library, by its name in `components.list`, with its props and children. */
|
|
1094
|
+
const sampleComponent = fileObject({
|
|
1095
|
+
component: z.string(),
|
|
1096
|
+
props: sampleProps.optional(),
|
|
1097
|
+
get children() {
|
|
1098
|
+
return z.array(sampleChild).optional();
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
/**
|
|
1102
|
+
* Text, a component of the same library by its name in `components.list`, or a render function: what a part calls to
|
|
1103
|
+
* draw, as children (`Field.Validity`) or as a prop's value (`renderInput`).
|
|
1104
|
+
*/
|
|
1105
|
+
const sampleChild = z.union([
|
|
1106
|
+
z.string(),
|
|
1107
|
+
sampleRender,
|
|
1108
|
+
sampleComponent
|
|
1109
|
+
]);
|
|
1110
|
+
z.object({ $element: z.array(sampleChild) });
|
|
1111
|
+
/** What a component needs to draw something: props with sample values, and children, as for a collection's items. */
|
|
1112
|
+
const componentSample = fileObject({
|
|
1113
|
+
props: sampleProps.optional(),
|
|
1114
|
+
children: z.array(sampleChild).optional()
|
|
1115
|
+
});
|
|
1116
|
+
/** A regular expression's source, checked by compiling it. */
|
|
1117
|
+
const pattern = z.string().refine((source) => {
|
|
1118
|
+
try {
|
|
1119
|
+
new RegExp(source);
|
|
1120
|
+
return true;
|
|
1121
|
+
} catch {
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
}, "expected a regular expression");
|
|
1125
|
+
const flag = z.boolean("expected a boolean");
|
|
1126
|
+
/** What a component says about itself that a hand edit can change too. */
|
|
1127
|
+
const componentFields = {
|
|
1128
|
+
/** The type declarations that define it, relative to the package, for reading its props. */
|
|
1129
|
+
declaration: z.string().optional(),
|
|
1130
|
+
/** The family it belongs to in the Components panel, as Card, CardHeader and CardTitle share `Card`. */
|
|
1131
|
+
group: z.string().optional(),
|
|
1132
|
+
/**
|
|
1133
|
+
* The components a part is placed inside, outermost first, as `["Accordion", "AccordionItem"]` for
|
|
1134
|
+
* `AccordionTrigger`, and what said so.
|
|
1135
|
+
*/
|
|
1136
|
+
parents: z.array(z.string()).optional(),
|
|
1137
|
+
parentsFrom: z.enum(parentSignals).optional(),
|
|
1138
|
+
/**
|
|
1139
|
+
* Parents most examples show but it renders without (`DropdownMenuGroup`), a subset of `parents`: inserting it
|
|
1140
|
+
* where the parents outside them are already leaves them out.
|
|
1141
|
+
*/
|
|
1142
|
+
optionalParents: z.array(z.string()).optional(),
|
|
1143
|
+
/**
|
|
1144
|
+
* `true` when its parents need the other parts their samples hold around it to draw (a table's header beside the
|
|
1145
|
+
* body a row is in): inserting it alone puts it in its outermost parent's whole sample, in place of the first like it.
|
|
1146
|
+
*/
|
|
1147
|
+
parentParts: flag.optional(),
|
|
1148
|
+
/** `false` for exports that draw nothing of their own, such as a context's consumer or a `RootProvider`. */
|
|
1149
|
+
visual: flag.optional(),
|
|
1150
|
+
/**
|
|
1151
|
+
* `true` for a part the package renders inside its own components and that no example or docs page places
|
|
1152
|
+
* (`ChartStyle` in `ChartContainer`, a Select's scroll buttons). It can still be placed; the Components panel lists
|
|
1153
|
+
* it apart.
|
|
1154
|
+
*/
|
|
1155
|
+
internal: flag.optional(),
|
|
1156
|
+
/** What it needs to draw something: props with sample values, and children, as for a collection's items. */
|
|
1157
|
+
sample: componentSample.optional()
|
|
1158
|
+
};
|
|
1159
|
+
const libraryComponent = fileObject({
|
|
1160
|
+
as: z.enum(componentEvidence),
|
|
1161
|
+
...componentFields,
|
|
1162
|
+
/** A hash of what it was found as and its own props, to tell what changed when the file is regenerated. */
|
|
1163
|
+
fingerprint: z.string().optional(),
|
|
1164
|
+
/** Its own props (not the HTML attributes it passes on), each with a hash of its type; `?` marks an optional one. */
|
|
1165
|
+
props: z.record(z.string(), z.string()).optional()
|
|
1166
|
+
});
|
|
1167
|
+
const libraryComponentEdit = fileObject({
|
|
1168
|
+
as: z.enum(componentEvidence).optional(),
|
|
1169
|
+
...componentFields
|
|
1170
|
+
});
|
|
1171
|
+
const libraryComponents = fileObject({
|
|
1172
|
+
/** The module components are imported from. Defaults to the package name. */
|
|
1173
|
+
import: z.string().optional(),
|
|
1174
|
+
/**
|
|
1175
|
+
* Components by the name they're imported by: an export, or `Namespace.Member` for libraries that group a
|
|
1176
|
+
* component's parts, as Base UI's `Dialog.Root` does.
|
|
1177
|
+
*/
|
|
1178
|
+
list: z.record(z.string(), libraryComponent)
|
|
1179
|
+
});
|
|
1180
|
+
/** One React component that draws an icon given as data, as Hugeicons' `HugeiconsIcon` does with its `icon` prop. */
|
|
1181
|
+
const iconRenderer = fileObject({
|
|
1182
|
+
import: z.string(),
|
|
1183
|
+
component: z.string(),
|
|
1184
|
+
prop: z.string()
|
|
1185
|
+
});
|
|
1186
|
+
const iconVariants = fileObject({
|
|
1187
|
+
/**
|
|
1188
|
+
* Splits an export name into named groups: `name`, and optionally `size` and `style`, for sets that write them into
|
|
1189
|
+
* names (Fluent's `Add24Regular`). A name without a style has the default style.
|
|
1190
|
+
*/
|
|
1191
|
+
pattern: pattern.optional(),
|
|
1192
|
+
/** The prop that picks a style, for sets that take it as a prop (Phosphor's `weight`). */
|
|
1193
|
+
prop: z.string().optional(),
|
|
1194
|
+
/**
|
|
1195
|
+
* The module each style's icons are imported from, for sets that keep each style in a module of its own, as
|
|
1196
|
+
* Heroicons does in `@heroicons/react/16/solid`. The default style's is the set's `import`.
|
|
1197
|
+
*/
|
|
1198
|
+
modules: z.record(z.string(), z.string()).optional(),
|
|
1199
|
+
styles: z.array(z.string()).optional(),
|
|
1200
|
+
sizes: z.array(finiteNumber).optional(),
|
|
1201
|
+
/** What the picker shows first. An icon without a size in its name scales with the text. */
|
|
1202
|
+
default: fileObject({
|
|
1203
|
+
style: z.string().optional(),
|
|
1204
|
+
size: finiteNumber.optional()
|
|
1205
|
+
}).optional()
|
|
1206
|
+
});
|
|
1207
|
+
const libraryIcons = fileObject({
|
|
1208
|
+
/** The module icons are imported from. Defaults to the package name. */
|
|
1209
|
+
import: z.string().optional(),
|
|
1210
|
+
/**
|
|
1211
|
+
* `export` when every icon is a component of its own; otherwise the component that draws icons from data. A string
|
|
1212
|
+
* is checked as one, so a renderer with a mistake in it reports the mistake rather than `expected "export"`.
|
|
1213
|
+
*/
|
|
1214
|
+
render: z.union([z.string().pipe(z.literal("export")), iconRenderer]),
|
|
1215
|
+
/** A regular expression for the export names that are icons. Defaults to every export that can be one. */
|
|
1216
|
+
match: pattern.optional(),
|
|
1217
|
+
/** Exports that look like icons but aren't, such as Lucide's generic `Icon` and its provider. */
|
|
1218
|
+
exclude: z.array(z.string()).optional(),
|
|
1219
|
+
/**
|
|
1220
|
+
* For icons exported under several names, the one to insert where it isn't the shortest: the name the set's types
|
|
1221
|
+
* don't mark deprecated (Phosphor's `GearIcon`, not `Gear`), or the one an icon is declared under rather than an
|
|
1222
|
+
* alias. Read from the types when the file is generated.
|
|
1223
|
+
*/
|
|
1224
|
+
prefer: z.array(z.string()).optional(),
|
|
1225
|
+
/** Styles and sizes written into icon names, as in Fluent's `Add24Regular`. */
|
|
1226
|
+
variants: iconVariants.optional(),
|
|
1227
|
+
/** How many icons it had when it was generated. */
|
|
1228
|
+
count: finiteNumber.optional(),
|
|
1229
|
+
/**
|
|
1230
|
+
* Words to find each icon by, from the set's own published metadata: its tags and categories, by the icon's name
|
|
1231
|
+
* without a style or size (`Add` for Fluent's `Add24Regular`). Read when the file is generated, never typed by hand.
|
|
1232
|
+
*/
|
|
1233
|
+
tags: z.record(z.string(), z.array(z.string())).optional(),
|
|
1234
|
+
/** Where `tags` were read from, as `package@version/path`. */
|
|
1235
|
+
tagSource: z.string().optional()
|
|
1236
|
+
});
|
|
1237
|
+
const decoratorElement = fileObject({
|
|
1238
|
+
import: z.string(),
|
|
1239
|
+
/** The export to render; `default` for a default export. */
|
|
1240
|
+
component: z.string(),
|
|
1241
|
+
props: decoratorProps.optional()
|
|
1242
|
+
});
|
|
1243
|
+
const decoratorEffects = [
|
|
843
1244
|
"wrap",
|
|
844
1245
|
"add",
|
|
845
1246
|
"class",
|
|
846
1247
|
"attributes",
|
|
847
1248
|
"style"
|
|
848
1249
|
];
|
|
1250
|
+
/**
|
|
1251
|
+
* A decorator written as data, so it runs no code of its own: a component wrapped around the design, one rendered
|
|
1252
|
+
* beside it (a toast host), or a class, attributes or styles on the frame's body. A manifest lists them outermost
|
|
1253
|
+
* first, as the JSX they make reads. That is Parity's order, the reverse of Storybook's, where the first decorator in a
|
|
1254
|
+
* list is innermost, so a list compiled into Storybook's decorators is reversed first.
|
|
1255
|
+
*/
|
|
1256
|
+
const libraryDecorator = fileObject({
|
|
1257
|
+
/** Applies only when the frame's globals have these values, as in `{ "theme": "dark" }`. */
|
|
1258
|
+
when: z.record(z.string(), z.string()).optional(),
|
|
1259
|
+
wrap: decoratorElement.optional(),
|
|
1260
|
+
add: decoratorElement.optional(),
|
|
1261
|
+
class: decoratorValue.optional(),
|
|
1262
|
+
attributes: decoratorProps.optional(),
|
|
1263
|
+
style: decoratorProps.optional()
|
|
1264
|
+
}).superRefine((decorator, context) => {
|
|
1265
|
+
if (decoratorEffects.filter((key) => decorator[key] !== void 0).length !== 1) context.addIssue({
|
|
1266
|
+
code: "custom",
|
|
1267
|
+
message: "expected one of wrap, add, class, attributes or style"
|
|
1268
|
+
});
|
|
1269
|
+
});
|
|
1270
|
+
/**
|
|
1271
|
+
* Hand edits to a library file, kept apart from what `parity lib` generates so regenerating keeps them. Components are
|
|
1272
|
+
* keyed by export name and merged over the generated entry; `false` leaves a component out. Decorators, when given,
|
|
1273
|
+
* replace the generated ones. A manifest can name a shared file of edits instead, relative to itself.
|
|
1274
|
+
*/
|
|
1275
|
+
const libraryEdits = fileObject({
|
|
1276
|
+
$schema: z.string().optional(),
|
|
1277
|
+
components: z.record(z.string(), z.union([z.boolean().pipe(z.literal(false)), libraryComponentEdit])).optional(),
|
|
1278
|
+
decorators: z.array(libraryDecorator).optional()
|
|
1279
|
+
});
|
|
1280
|
+
/**
|
|
1281
|
+
* What a library says about itself, in a `.lib.par` file at its package root: its name, the stylesheet a project
|
|
1282
|
+
* imports to use it, the breakpoints it's designed for, its design tokens, its components, icons and decorators, and its
|
|
1283
|
+
* own canvas of designs. Any package with one is a library Parity can load. Packages that don't ship one are described
|
|
1284
|
+
* by Parity's registry, in the same format.
|
|
1285
|
+
*/
|
|
1286
|
+
const libraryManifest = fileObject({
|
|
1287
|
+
$schema: z.string().optional(),
|
|
1288
|
+
/** The current manifest format; obsolete formats are rejected rather than migrated. */
|
|
1289
|
+
version: z.literal(3),
|
|
1290
|
+
/** Short name its components are namespaced by, as in `nova/Button`. Defaults to the package name. */
|
|
1291
|
+
id: z.string().optional(),
|
|
1292
|
+
name: z.string(),
|
|
1293
|
+
description: z.string().optional(),
|
|
1294
|
+
/** The npm package it describes, and the versions it was made for. */
|
|
1295
|
+
package: libraryPackage.optional(),
|
|
1296
|
+
/** The stylesheet to import, relative to the package: its Tailwind entry, or plain CSS. */
|
|
1297
|
+
styles: z.string().optional(),
|
|
1298
|
+
/** The viewport widths it's designed around, smallest first, however the file lists them. */
|
|
1299
|
+
breakpoints: z.array(libraryBreakpoint).transform((breakpoints) => breakpoints.toSorted((a, b) => a.width - b.width)).optional(),
|
|
1300
|
+
/**
|
|
1301
|
+
* Its design tokens, in the DTCG format (2025.10): a path relative to the package, to a token file or to a resolver
|
|
1302
|
+
* that names its themes, or a resolver or token groups written inline.
|
|
1303
|
+
*/
|
|
1304
|
+
tokens: z.union([z.string(), plainObject]).optional(),
|
|
1305
|
+
/** The components it exports, as the type checker found them. */
|
|
1306
|
+
components: libraryComponents.optional(),
|
|
1307
|
+
/** Its icons, when it's an icon set: how they're imported and drawn. */
|
|
1308
|
+
icons: libraryIcons.optional(),
|
|
1309
|
+
/** What its components need around them in every frame: providers, toast hosts, theme classes. */
|
|
1310
|
+
decorators: z.array(libraryDecorator).optional(),
|
|
1311
|
+
/** Hand edits merged over the generated parts, or the path of a shared file of them, relative to this file. */
|
|
1312
|
+
edits: z.union([z.string(), libraryEdits]).optional(),
|
|
1313
|
+
/** The library's own canvas: its designs where its author placed them, its notes and its modes, as in a `.par`. */
|
|
1314
|
+
canvas: canvasDocument.optional()
|
|
1315
|
+
});
|
|
849
1316
|
/** A library manifest's extension. It describes a library, and its `canvas` holds the library's own designs. */
|
|
850
1317
|
const libraryManifestExtension = ".lib.par";
|
|
1318
|
+
/** Reads a library file, or throws `TypeError` with the first problem as `/json/pointer: message`. */
|
|
851
1319
|
function parseLibraryManifest(value) {
|
|
852
|
-
const manifest =
|
|
853
|
-
|
|
854
|
-
"$schema",
|
|
855
|
-
"version",
|
|
856
|
-
"id",
|
|
857
|
-
"name",
|
|
858
|
-
"description",
|
|
859
|
-
"styles",
|
|
860
|
-
"breakpoints",
|
|
861
|
-
"tokens",
|
|
862
|
-
"canvas",
|
|
863
|
-
"package",
|
|
864
|
-
"components",
|
|
865
|
-
"icons",
|
|
866
|
-
"decorators",
|
|
867
|
-
"edits"
|
|
868
|
-
], "");
|
|
869
|
-
if (manifest.version !== 3) throw new TypeError("/version: expected 3");
|
|
870
|
-
return compact({
|
|
871
|
-
version: 3,
|
|
872
|
-
id: optional(manifest.id, (v) => expectString(v, "/id")),
|
|
873
|
-
name: expectString(manifest.name, "/name"),
|
|
874
|
-
description: optional(manifest.description, (v) => expectString(v, "/description")),
|
|
875
|
-
package: optional(manifest.package, parsePackage),
|
|
876
|
-
styles: optional(manifest.styles, (v) => expectString(v, "/styles")),
|
|
877
|
-
breakpoints: optional(manifest.breakpoints, (v) => expectArray(v, "/breakpoints").map((item, index) => {
|
|
878
|
-
const at = `/breakpoints/${index}`;
|
|
879
|
-
const breakpoint = expectObject(item, at);
|
|
880
|
-
expectKnownKeys(breakpoint, [
|
|
881
|
-
"id",
|
|
882
|
-
"name",
|
|
883
|
-
"width"
|
|
884
|
-
], at);
|
|
885
|
-
return {
|
|
886
|
-
id: expectString(breakpoint.id, `${at}/id`),
|
|
887
|
-
name: expectString(breakpoint.name, `${at}/name`),
|
|
888
|
-
width: expectNumber(breakpoint.width, `${at}/width`)
|
|
889
|
-
};
|
|
890
|
-
}).sort((a, b) => a.width - b.width)),
|
|
891
|
-
tokens: optional(manifest.tokens, (v) => typeof v === "string" ? v : expectObject(v, "/tokens")),
|
|
892
|
-
components: optional(manifest.components, parseComponents),
|
|
893
|
-
icons: optional(manifest.icons, parseIcons),
|
|
894
|
-
decorators: optional(manifest.decorators, (v) => expectArray(v, "/decorators").map(parseDecorator)),
|
|
895
|
-
edits: optional(manifest.edits, (v) => typeof v === "string" ? v : parseLibraryEdits(v, "/edits")),
|
|
896
|
-
canvas: optional(manifest.canvas, (v) => {
|
|
897
|
-
try {
|
|
898
|
-
return parseCanvasDocument(v);
|
|
899
|
-
} catch (error) {
|
|
900
|
-
throw new TypeError(`/canvas${error instanceof Error ? error.message : String(error)}`);
|
|
901
|
-
}
|
|
902
|
-
})
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
function parsePackage(value) {
|
|
906
|
-
const pkg = expectObject(value, "/package");
|
|
907
|
-
expectKnownKeys(pkg, [
|
|
908
|
-
"name",
|
|
909
|
-
"version",
|
|
910
|
-
"range"
|
|
911
|
-
], "/package");
|
|
912
|
-
return compact({
|
|
913
|
-
name: expectString(pkg.name, "/package/name"),
|
|
914
|
-
version: optional(pkg.version, (v) => expectString(v, "/package/version")),
|
|
915
|
-
range: optional(pkg.range, (v) => expectString(v, "/package/range"))
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
function parseComponents(value) {
|
|
919
|
-
const components = expectObject(value, "/components");
|
|
920
|
-
expectKnownKeys(components, ["import", "list"], "/components");
|
|
921
|
-
const list = {};
|
|
922
|
-
for (const [name, entry] of Object.entries(expectObject(components.list, "/components/list"))) {
|
|
923
|
-
const at = `/components/list/${name}`;
|
|
924
|
-
const component = expectObject(entry, at);
|
|
925
|
-
expectKnownKeys(component, [
|
|
926
|
-
...componentKeys,
|
|
927
|
-
"fingerprint",
|
|
928
|
-
"props"
|
|
929
|
-
], at);
|
|
930
|
-
list[name] = compact({
|
|
931
|
-
...parseComponentFields(component, at),
|
|
932
|
-
as: expectOneOf(component.as, componentEvidence, `${at}/as`),
|
|
933
|
-
fingerprint: optional(component.fingerprint, (v) => expectString(v, `${at}/fingerprint`)),
|
|
934
|
-
props: optional(component.props, (v) => expectStringRecord(v, `${at}/props`))
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
return compact({
|
|
938
|
-
import: optional(components.import, (v) => expectString(v, "/components/import")),
|
|
939
|
-
list
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
const componentKeys = [
|
|
943
|
-
"as",
|
|
944
|
-
"declaration",
|
|
945
|
-
"group",
|
|
946
|
-
"parents",
|
|
947
|
-
"parentsFrom",
|
|
948
|
-
"optionalParents",
|
|
949
|
-
"parentParts",
|
|
950
|
-
"visual",
|
|
951
|
-
"internal",
|
|
952
|
-
"sample"
|
|
953
|
-
];
|
|
954
|
-
function parseComponentFields(component, at) {
|
|
955
|
-
return compact({
|
|
956
|
-
as: optional(component.as, (v) => expectOneOf(v, componentEvidence, `${at}/as`)),
|
|
957
|
-
declaration: optional(component.declaration, (v) => expectString(v, `${at}/declaration`)),
|
|
958
|
-
group: optional(component.group, (v) => expectString(v, `${at}/group`)),
|
|
959
|
-
parents: optional(component.parents, (v) => expectArray(v, `${at}/parents`).map((name, index) => expectString(name, `${at}/parents/${index}`))),
|
|
960
|
-
parentsFrom: optional(component.parentsFrom, (v) => expectOneOf(v, parentSignals, `${at}/parentsFrom`)),
|
|
961
|
-
optionalParents: optional(component.optionalParents, (v) => expectArray(v, `${at}/optionalParents`).map((name, index) => expectString(name, `${at}/optionalParents/${index}`))),
|
|
962
|
-
parentParts: optional(component.parentParts, (v) => {
|
|
963
|
-
if (typeof v !== "boolean") throw new TypeError(`${at}/parentParts: expected a boolean`);
|
|
964
|
-
return v;
|
|
965
|
-
}),
|
|
966
|
-
visual: optional(component.visual, (v) => {
|
|
967
|
-
if (typeof v !== "boolean") throw new TypeError(`${at}/visual: expected a boolean`);
|
|
968
|
-
return v;
|
|
969
|
-
}),
|
|
970
|
-
internal: optional(component.internal, (v) => {
|
|
971
|
-
if (typeof v !== "boolean") throw new TypeError(`${at}/internal: expected a boolean`);
|
|
972
|
-
return v;
|
|
973
|
-
}),
|
|
974
|
-
sample: optional(component.sample, (v) => parseSample(v, `${at}/sample`))
|
|
975
|
-
});
|
|
976
|
-
}
|
|
977
|
-
function parseSample(value, at) {
|
|
978
|
-
const sample = expectObject(value, at);
|
|
979
|
-
expectKnownKeys(sample, ["props", "children"], at);
|
|
980
|
-
return compact({
|
|
981
|
-
props: optional(sample.props, (v) => expectObject(v, `${at}/props`)),
|
|
982
|
-
children: optional(sample.children, (v) => parseSampleChildren(v, `${at}/children`))
|
|
983
|
-
});
|
|
984
|
-
}
|
|
985
|
-
function parseSampleChildren(value, at) {
|
|
986
|
-
return expectArray(value, at).map((item, index) => {
|
|
987
|
-
const here = `${at}/${index}`;
|
|
988
|
-
if (typeof item === "string") return item;
|
|
989
|
-
const child = expectObject(item, here);
|
|
990
|
-
if ("$render" in child) {
|
|
991
|
-
expectKnownKeys(child, [
|
|
992
|
-
"$render",
|
|
993
|
-
"spread",
|
|
994
|
-
"pass"
|
|
995
|
-
], here);
|
|
996
|
-
if (child.spread !== void 0 && child.spread !== true) throw new TypeError(`${here}/spread: expected true`);
|
|
997
|
-
const render = { $render: parseSampleChildren(child.$render, `${here}/$render`) };
|
|
998
|
-
if (child.spread) render.spread = true;
|
|
999
|
-
if (child.pass !== void 0) render.pass = expectArray(child.pass, `${here}/pass`).map((prop, index) => expectString(prop, `${here}/pass/${index}`));
|
|
1000
|
-
return render;
|
|
1001
|
-
}
|
|
1002
|
-
expectKnownKeys(child, [
|
|
1003
|
-
"component",
|
|
1004
|
-
"props",
|
|
1005
|
-
"children"
|
|
1006
|
-
], here);
|
|
1007
|
-
return compact({
|
|
1008
|
-
component: expectString(child.component, `${here}/component`),
|
|
1009
|
-
props: optional(child.props, (v) => expectObject(v, `${here}/props`)),
|
|
1010
|
-
children: optional(child.children, (v) => parseSampleChildren(v, `${here}/children`))
|
|
1011
|
-
});
|
|
1012
|
-
});
|
|
1320
|
+
const { $schema: _schema, ...manifest } = parseData(libraryManifest, value);
|
|
1321
|
+
return manifest;
|
|
1013
1322
|
}
|
|
1014
1323
|
/** Reads hand edits to a library file, from its `edits` or a shared file of them. */
|
|
1015
1324
|
function parseLibraryEdits(value, at = "") {
|
|
1016
|
-
const edits =
|
|
1017
|
-
|
|
1018
|
-
"$schema",
|
|
1019
|
-
"components",
|
|
1020
|
-
"decorators"
|
|
1021
|
-
], at);
|
|
1022
|
-
return compact({
|
|
1023
|
-
components: optional(edits.components, (v) => {
|
|
1024
|
-
const result = {};
|
|
1025
|
-
for (const [name, entry] of Object.entries(expectObject(v, `${at}/components`))) {
|
|
1026
|
-
const here = `${at}/components/${name}`;
|
|
1027
|
-
if (entry === false) {
|
|
1028
|
-
result[name] = false;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
const component = expectObject(entry, here);
|
|
1032
|
-
expectKnownKeys(component, componentKeys, here);
|
|
1033
|
-
result[name] = parseComponentFields(component, here);
|
|
1034
|
-
}
|
|
1035
|
-
return result;
|
|
1036
|
-
}),
|
|
1037
|
-
decorators: optional(edits.decorators, (v) => expectArray(v, `${at}/decorators`).map(parseDecorator))
|
|
1038
|
-
});
|
|
1325
|
+
const { $schema: _schema, ...edits } = parseData(libraryEdits, value, at);
|
|
1326
|
+
return edits;
|
|
1039
1327
|
}
|
|
1040
1328
|
/**
|
|
1041
1329
|
* The manifest with hand edits merged over what was generated, and the edited exports it no longer has, which are
|
|
@@ -1074,125 +1362,18 @@ function applyLibraryEdits(manifest, edits) {
|
|
|
1074
1362
|
list
|
|
1075
1363
|
};
|
|
1076
1364
|
}
|
|
1365
|
+
const merged = {
|
|
1366
|
+
...manifest,
|
|
1367
|
+
components,
|
|
1368
|
+
decorators: edits.decorators ?? manifest.decorators
|
|
1369
|
+
};
|
|
1370
|
+
if (!merged.components) delete merged.components;
|
|
1371
|
+
if (!merged.decorators) delete merged.decorators;
|
|
1077
1372
|
return {
|
|
1078
|
-
manifest:
|
|
1079
|
-
...manifest,
|
|
1080
|
-
components,
|
|
1081
|
-
decorators: edits.decorators ?? manifest.decorators
|
|
1082
|
-
}),
|
|
1373
|
+
manifest: merged,
|
|
1083
1374
|
orphans
|
|
1084
1375
|
};
|
|
1085
1376
|
}
|
|
1086
|
-
function parseIcons(value) {
|
|
1087
|
-
const icons = expectObject(value, "/icons");
|
|
1088
|
-
expectKnownKeys(icons, [
|
|
1089
|
-
"import",
|
|
1090
|
-
"render",
|
|
1091
|
-
"match",
|
|
1092
|
-
"exclude",
|
|
1093
|
-
"prefer",
|
|
1094
|
-
"variants",
|
|
1095
|
-
"count",
|
|
1096
|
-
"tags",
|
|
1097
|
-
"tagSource"
|
|
1098
|
-
], "/icons");
|
|
1099
|
-
let render;
|
|
1100
|
-
if (icons.render === "export") render = "export";
|
|
1101
|
-
else {
|
|
1102
|
-
const renderer = expectObject(icons.render, "/icons/render");
|
|
1103
|
-
expectKnownKeys(renderer, [
|
|
1104
|
-
"import",
|
|
1105
|
-
"component",
|
|
1106
|
-
"prop"
|
|
1107
|
-
], "/icons/render");
|
|
1108
|
-
render = {
|
|
1109
|
-
import: expectString(renderer.import, "/icons/render/import"),
|
|
1110
|
-
component: expectString(renderer.component, "/icons/render/component"),
|
|
1111
|
-
prop: expectString(renderer.prop, "/icons/render/prop")
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
return compact({
|
|
1115
|
-
import: optional(icons.import, (v) => expectString(v, "/icons/import")),
|
|
1116
|
-
render,
|
|
1117
|
-
match: optional(icons.match, (v) => expectPattern(v, "/icons/match")),
|
|
1118
|
-
exclude: optional(icons.exclude, (v) => expectArray(v, "/icons/exclude").map((name, index) => expectString(name, `/icons/exclude/${index}`))),
|
|
1119
|
-
prefer: optional(icons.prefer, (v) => expectArray(v, "/icons/prefer").map((name, index) => expectString(name, `/icons/prefer/${index}`))),
|
|
1120
|
-
variants: optional(icons.variants, (v) => {
|
|
1121
|
-
const variants = expectObject(v, "/icons/variants");
|
|
1122
|
-
expectKnownKeys(variants, [
|
|
1123
|
-
"pattern",
|
|
1124
|
-
"prop",
|
|
1125
|
-
"modules",
|
|
1126
|
-
"styles",
|
|
1127
|
-
"sizes",
|
|
1128
|
-
"default"
|
|
1129
|
-
], "/icons/variants");
|
|
1130
|
-
return compact({
|
|
1131
|
-
pattern: optional(variants.pattern, (pattern) => expectPattern(pattern, "/icons/variants/pattern")),
|
|
1132
|
-
prop: optional(variants.prop, (prop) => expectString(prop, "/icons/variants/prop")),
|
|
1133
|
-
modules: optional(variants.modules, (modules) => expectStringRecord(modules, "/icons/variants/modules")),
|
|
1134
|
-
styles: optional(variants.styles, (list) => expectArray(list, "/icons/variants/styles").map((style, index) => expectString(style, `/icons/variants/styles/${index}`))),
|
|
1135
|
-
sizes: optional(variants.sizes, (list) => expectArray(list, "/icons/variants/sizes").map((size, index) => expectNumber(size, `/icons/variants/sizes/${index}`))),
|
|
1136
|
-
default: optional(variants.default, (d) => {
|
|
1137
|
-
const fallback = expectObject(d, "/icons/variants/default");
|
|
1138
|
-
expectKnownKeys(fallback, ["style", "size"], "/icons/variants/default");
|
|
1139
|
-
return compact({
|
|
1140
|
-
style: optional(fallback.style, (s) => expectString(s, "/icons/variants/default/style")),
|
|
1141
|
-
size: optional(fallback.size, (s) => expectNumber(s, "/icons/variants/default/size"))
|
|
1142
|
-
});
|
|
1143
|
-
})
|
|
1144
|
-
});
|
|
1145
|
-
}),
|
|
1146
|
-
count: optional(icons.count, (v) => expectNumber(v, "/icons/count")),
|
|
1147
|
-
tags: optional(icons.tags, (v) => Object.fromEntries(Object.entries(expectObject(v, "/icons/tags")).map(([name, list]) => [name, expectArray(list, `/icons/tags/${name}`).map((tag, index) => expectString(tag, `/icons/tags/${name}/${index}`))]))),
|
|
1148
|
-
tagSource: optional(icons.tagSource, (v) => expectString(v, "/icons/tagSource"))
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
function parseDecorator(value, index) {
|
|
1152
|
-
const at = `/decorators/${index}`;
|
|
1153
|
-
const decorator = expectObject(value, at);
|
|
1154
|
-
expectKnownKeys(decorator, decoratorKeys, at);
|
|
1155
|
-
if (decoratorKeys.filter((key) => key !== "when" && decorator[key] !== void 0).length !== 1) throw new TypeError(`${at}: expected one of wrap, add, class, attributes or style`);
|
|
1156
|
-
const element = (v, path) => {
|
|
1157
|
-
const spec = expectObject(v, path);
|
|
1158
|
-
expectKnownKeys(spec, [
|
|
1159
|
-
"import",
|
|
1160
|
-
"component",
|
|
1161
|
-
"props"
|
|
1162
|
-
], path);
|
|
1163
|
-
return compact({
|
|
1164
|
-
import: expectString(spec.import, `${path}/import`),
|
|
1165
|
-
component: expectString(spec.component, `${path}/component`),
|
|
1166
|
-
props: optional(spec.props, (props) => expectObject(props, `${path}/props`))
|
|
1167
|
-
});
|
|
1168
|
-
};
|
|
1169
|
-
return compact({
|
|
1170
|
-
when: optional(decorator.when, (v) => {
|
|
1171
|
-
const when = expectObject(v, `${at}/when`);
|
|
1172
|
-
for (const [name, option] of Object.entries(when)) expectString(option, `${at}/when/${name}`);
|
|
1173
|
-
return when;
|
|
1174
|
-
}),
|
|
1175
|
-
wrap: optional(decorator.wrap, (v) => element(v, `${at}/wrap`)),
|
|
1176
|
-
add: optional(decorator.add, (v) => element(v, `${at}/add`)),
|
|
1177
|
-
class: decorator.class,
|
|
1178
|
-
attributes: optional(decorator.attributes, (v) => expectObject(v, `${at}/attributes`)),
|
|
1179
|
-
style: optional(decorator.style, (v) => expectObject(v, `${at}/style`))
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
|
-
function expectPattern(value, path) {
|
|
1183
|
-
const pattern = expectString(value, path);
|
|
1184
|
-
try {
|
|
1185
|
-
new RegExp(pattern);
|
|
1186
|
-
} catch {
|
|
1187
|
-
throw new TypeError(`${path}: expected a regular expression`);
|
|
1188
|
-
}
|
|
1189
|
-
return pattern;
|
|
1190
|
-
}
|
|
1191
|
-
function expectStringRecord(value, path) {
|
|
1192
|
-
const record = expectObject(value, path);
|
|
1193
|
-
for (const [key, item] of Object.entries(record)) expectString(item, `${path}/${key}`);
|
|
1194
|
-
return record;
|
|
1195
|
-
}
|
|
1196
1377
|
// ../core/src/project.ts
|
|
1197
1378
|
/**
|
|
1198
1379
|
* Props that say what's open or chosen: `defaultOpen` on what opens (a dialog, a popover, a menu), `defaultValue` on
|
|
@@ -1273,8 +1454,7 @@ function withLibraryContext(node, sources, around, taken) {
|
|
|
1273
1454
|
const plain = {};
|
|
1274
1455
|
const slots = {};
|
|
1275
1456
|
const renderSlot = (prop, render) => {
|
|
1276
|
-
|
|
1277
|
-
slots[`${render.spread ? "$renderWith" : "$render"}:${prop}${pass}`] = nodes(render.$render);
|
|
1457
|
+
slots[renderSlotKey(prop, render)] = nodes(render.$render);
|
|
1278
1458
|
};
|
|
1279
1459
|
for (const [key, value] of Object.entries(props)) if (isSampleRender(value)) renderSlot(key, value);
|
|
1280
1460
|
else if (isSampleElement(value)) slots[key] = nodes(value.$element);
|
|
@@ -1331,8 +1511,8 @@ function withLibraryContext(node, sources, around, taken) {
|
|
|
1331
1511
|
for (const parent of added.reverse()) {
|
|
1332
1512
|
const wrapper = component(parent);
|
|
1333
1513
|
const calls = renderSlotOf(sources[parent]?.sample);
|
|
1334
|
-
const slot = calls ?
|
|
1335
|
-
const kept = Object.fromEntries(Object.entries(wrapper.type === "component" ? wrapper.slots ?? {} : {}).filter(([name]) => !calls ||
|
|
1514
|
+
const slot = calls ? renderSlotKey(calls.prop, calls.render) : "children";
|
|
1515
|
+
const kept = Object.fromEntries(Object.entries(wrapper.type === "component" ? wrapper.slots ?? {} : {}).filter(([name]) => !calls || readRenderSlotKey(name)?.prop !== calls.prop));
|
|
1336
1516
|
placed = wrapper.type === "component" ? {
|
|
1337
1517
|
...wrapper,
|
|
1338
1518
|
slots: {
|
|
@@ -1468,4 +1648,4 @@ function sampleIds(sample, library) {
|
|
|
1468
1648
|
...sample.children ? { children: sample.children.map(child) } : {}
|
|
1469
1649
|
};
|
|
1470
1650
|
}
|
|
1471
|
-
export {
|
|
1651
|
+
export { lengthToPixels as $, canvasObjectKinds as A, nodeTree as B, isSampleRender as C, valueForms as D, renderSlotOf as E, imageFits as F, walkNodes as G, paramTypes as H, linkAllowed as I, collectCustomProperties as J, generateId as K, linkEndKinds as L, containerSpec as M, detectionCorrections as N, valueImports as O, imageCredit as P, deviceKinds as Q, linkTypes as R, isSampleElement as S, renderSlotKey as T, patchUnset as U, noteSpec as V, textTags as W, viewportHeightProperty as X, remProperty as Y, viewportWidthProperty as Z, sampleValue as _, openProps as a, frameParts as b, libraryManifest as c, parentSignals as d, packageManifest as et, parseLibraryEdits as f, sampleProps as g, decoratorValue as h, withLibraryContext as i, containerKinds as j, canvasDocument as k, libraryManifestExtension as l, decoratorProps as m, librarySource as n, applyLibraryEdits as o, parseLibraryManifest as p, modeSettings as q, sampleIds as r, componentEvidence as s, componentNode as t, parseManifest as tt, libraryPackage as u, evaluateValue as v, readRenderSlotKey as w, isMadeValue as x, exportOf as y, nodeStyle as z };
|