@mark1russell7/render-biblo 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +41 -2
- package/build/index.d.ts +205 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +531 -0
- package/build/index.js.map +1 -0
- package/package.json +65 -3
- package/src/class.ts +63 -0
- package/src/index.ts +9 -0
- package/src/instance.ts +23 -0
- package/src/nodeops.ts +31 -0
- package/src/registry.ts +510 -0
- package/src/traits.ts +99 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mark Russell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @mark1russell7/render-biblo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@mark1russell7/render-biblo) [](https://github.com/mark1russell7/render/actions/workflows/ci.yml) [](https://github.com/mark1russell7/render/blob/main/LICENSE)
|
|
4
|
+
|
|
5
|
+
The classes of render. A class is a template of nodes: cells with expressions, and methods. An instance is an ID and a scope. A change of a class reaches each instance that still follows it.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm i @mark1russell7/render-biblo @mark1russell7/render-node @mark1russell7/render-dsl
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { app, lit, ref } from "@mark1russell7/render-dsl";
|
|
13
|
+
import { biblo, classNodeOps, componentClass, instantiate, registerClass, updateClass } from "@mark1russell7/render-biblo";
|
|
14
|
+
import { nodeStore, readValue } from "@mark1russell7/render-node";
|
|
15
|
+
|
|
16
|
+
const ops = { concat: (...parts: unknown[]) => parts.join("") };
|
|
17
|
+
const badge = (label: string) =>
|
|
18
|
+
componentClass("Badge", {
|
|
19
|
+
label: { expr: lit(label) },
|
|
20
|
+
text: { expr: app("concat", lit("[ "), ref("self", "label"), lit(" ]")) },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const b = biblo();
|
|
24
|
+
const store = nodeStore({ nodeOps: classNodeOps(b), ops });
|
|
25
|
+
registerClass(b, badge("star"));
|
|
26
|
+
const inst = instantiate(b, store, "Badge");
|
|
27
|
+
const text = store.nodes.get(inst.id)!.slots.get("text")!;
|
|
28
|
+
readValue(store, text); // { tag: "some", value: "[ star ]" }
|
|
29
|
+
|
|
30
|
+
updateClass(b, store, badge("planet"));
|
|
31
|
+
readValue(store, text); // { tag: "some", value: "[ planet ]" }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Traits give methods to each class with a set of cells. The fingerprint of a class is a product of primes, thus the match of a trait is one division.
|
|
35
|
+
|
|
36
|
+
## More
|
|
37
|
+
|
|
38
|
+
- [The site](https://mark1russell7.github.io/render/): the guide, live demos and the viewer.
|
|
39
|
+
- [The API reference](https://mark1russell7.github.io/render/reference/api/): the exports of each package.
|
|
40
|
+
- [The repository](https://github.com/mark1russell7/render): the source, the tests and the review of each known defect.
|
|
41
|
+
|
|
42
|
+
Each package of render is ESM, has TypeScript declarations, and works in Node.js 22.12 or later and in browsers. The license is MIT.
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { Expr } from "@mark1russell7/render-dsl";
|
|
2
|
+
import { NodeId, NodeOps, NodeStore } from "@mark1russell7/render-node";
|
|
3
|
+
//#region src/class.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A cell template of a class. It has an expression, and optionally a type: the name of another class.
|
|
6
|
+
* A typed cell holds an instance of that class, thus the class level knows the paths through its children.
|
|
7
|
+
*/
|
|
8
|
+
type CellDef = {
|
|
9
|
+
readonly expr: Expr;
|
|
10
|
+
/** The class of the child instance that this cell holds. */
|
|
11
|
+
readonly type?: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The bindings of a typed cell: expressions that replace cells of the child.
|
|
14
|
+
* They are in the scope of the child. For example, `{ value: ref("parent", "key") }` binds the cell `value`
|
|
15
|
+
* of the child to the cell `key` of this instance.
|
|
16
|
+
*/
|
|
17
|
+
readonly bindings?: Readonly<Record<string, Expr>> | undefined;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A class is a template. Instances share it, and nothing copies it.
|
|
21
|
+
*
|
|
22
|
+
* - `cells`: the reactive structure, which is the data that each instance holds.
|
|
23
|
+
* - `methods`: the behavior. The extends chain resolves them, and the most specific method wins.
|
|
24
|
+
* - `extends`: the parent class. Cells and methods both resolve through it.
|
|
25
|
+
*
|
|
26
|
+
* The values of `methods` are opaque. Each layer reads the method names that it knows, for example
|
|
27
|
+
* `render` for splay and `splash` for the node engine. The class `Top` gives the defaults.
|
|
28
|
+
*/
|
|
29
|
+
type ComponentClass = {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly cells: Readonly<Record<string, CellDef>>;
|
|
32
|
+
readonly extends?: string | undefined;
|
|
33
|
+
readonly methods?: Readonly<Record<string, unknown>> | undefined;
|
|
34
|
+
};
|
|
35
|
+
/** This function makes a class. */
|
|
36
|
+
export declare const componentClass: (name: string, cells: Readonly<Record<string, CellDef>>, ext?: string, methods?: Readonly<Record<string, unknown>>) => ComponentClass;
|
|
37
|
+
/**
|
|
38
|
+
* This function gives a copy of a class with more cells and methods. The copy keeps the name.
|
|
39
|
+
* An override with the name of an existing cell or method replaces it.
|
|
40
|
+
*/
|
|
41
|
+
export declare const extendClass: (base: ComponentClass, overrides: {
|
|
42
|
+
readonly cells?: Readonly<Record<string, CellDef>>;
|
|
43
|
+
readonly methods?: Readonly<Record<string, unknown>>;
|
|
44
|
+
}) => ComponentClass;
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/instance.d.ts
|
|
47
|
+
/** The identity of an instance. It is also the ID of the root node of the instance. */
|
|
48
|
+
type InstanceId = string;
|
|
49
|
+
/**
|
|
50
|
+
* The scope of an instance: the names that its expressions can use.
|
|
51
|
+
* `ref("self", ...)` reads this instance, and `ref("parent", ...)` reads the parent instance.
|
|
52
|
+
*/
|
|
53
|
+
type Scope = {
|
|
54
|
+
readonly self: InstanceId;
|
|
55
|
+
readonly parent: InstanceId | undefined;
|
|
56
|
+
/** The child instances, in order. Splay renders them, and dehydrate reads them. */
|
|
57
|
+
readonly children: readonly InstanceId[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* An instance is small: an ID, a class name and a scope. It copies no data of its class.
|
|
61
|
+
* The values of its cells are in the node store, in the slots of its root node.
|
|
62
|
+
*/
|
|
63
|
+
type Instance = {
|
|
64
|
+
readonly id: InstanceId;
|
|
65
|
+
readonly classRef: string;
|
|
66
|
+
readonly scope: Scope;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/traits.d.ts
|
|
70
|
+
/**
|
|
71
|
+
* Structural traits with prime fingerprints: a granular polymorphism.
|
|
72
|
+
*
|
|
73
|
+
* Each atomic feature of a class gets a unique prime: a cell (`value`), or a typed cell (`kid:Point`).
|
|
74
|
+
* The fingerprint of a class is the product of the primes of its features. The product does not depend on
|
|
75
|
+
* the order of the features, thus two classes with the same features have the same fingerprint.
|
|
76
|
+
*
|
|
77
|
+
* A trait gives methods to each class that has the features of its list. Then the fingerprint of the trait
|
|
78
|
+
* divides the fingerprint of the class. Among the traits that apply, only the most specific ones count
|
|
79
|
+
* (a trait whose fingerprint divides the fingerprint of another applicable trait is dominated). When two of
|
|
80
|
+
* them give the same method, the method is ambiguous: no trait gives it, and the ambiguity is visible.
|
|
81
|
+
*/
|
|
82
|
+
/** A trait: methods for each class that has the cells of its list. */
|
|
83
|
+
type Trait = {
|
|
84
|
+
readonly name: string;
|
|
85
|
+
/** The features that a class must have: a cell name (`label`), or a typed cell (`kid:Point`). */
|
|
86
|
+
readonly requires: readonly string[];
|
|
87
|
+
readonly methods: Readonly<Record<string, unknown>>;
|
|
88
|
+
};
|
|
89
|
+
/** The traits that apply to a class, and the names of the methods that two of them give. */
|
|
90
|
+
type TraitResolution = {
|
|
91
|
+
readonly applied: readonly Trait[];
|
|
92
|
+
readonly ambiguous: readonly string[];
|
|
93
|
+
};
|
|
94
|
+
/** This function gives the features of an item of the list of a trait: `kid:Point` is the cell `kid` with the type `Point`. */
|
|
95
|
+
export declare const requirementAtoms: (requirement: string) => string[];
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/registry.d.ts
|
|
98
|
+
/**
|
|
99
|
+
* The biblo is the class registry and the instance store.
|
|
100
|
+
*
|
|
101
|
+
* Classes are shared templates. Instances are small (an ID and a scope), and the values of their cells
|
|
102
|
+
* are in the node store. A trait gives methods to each class that has the cells of its list.
|
|
103
|
+
* Change a biblo only through its functions, for example `registerClass`, `registerTrait` and `instantiate`.
|
|
104
|
+
*/
|
|
105
|
+
type Biblo = {
|
|
106
|
+
readonly classes: ReadonlyMap<string, ComponentClass>;
|
|
107
|
+
readonly instances: ReadonlyMap<InstanceId, Instance>;
|
|
108
|
+
readonly traits: ReadonlyMap<string, Trait>;
|
|
109
|
+
};
|
|
110
|
+
/** This function makes an empty biblo. */
|
|
111
|
+
export declare const biblo: () => Biblo;
|
|
112
|
+
/**
|
|
113
|
+
* This function gives an independent copy of a biblo: the same classes, traits, instances and counters. The
|
|
114
|
+
* classes and the traits are immutable, thus the copy shares them. Pair the copy with a copy of its store
|
|
115
|
+
* (`forkStore`), with the class semantics of the copy (`classNodeOps`).
|
|
116
|
+
*/
|
|
117
|
+
export declare const forkBiblo: (b: Biblo) => Biblo;
|
|
118
|
+
/** This function registers a class, or replaces the class with the same name. The live instances do not change. */
|
|
119
|
+
export declare const registerClass: (b: Biblo, cls: ComponentClass) => void;
|
|
120
|
+
/** This function registers a trait, or replaces the trait with the same name. The live instances use it at once. */
|
|
121
|
+
export declare const registerTrait: (b: Biblo, trait: Trait) => void;
|
|
122
|
+
/** This function removes a trait. */
|
|
123
|
+
export declare const unregisterTrait: (b: Biblo, name: string) => void;
|
|
124
|
+
/**
|
|
125
|
+
* This function renames a class. Its subclasses, the typed cells that use it and its live instances use the
|
|
126
|
+
* new name. A trait whose list has a typed cell of the class (`kid:Point`) also uses the new name. The function
|
|
127
|
+
* does nothing and gives `false` when the class is missing or the new name is in use.
|
|
128
|
+
*/
|
|
129
|
+
export declare const renameClass: (b: Biblo, from: string, to: string) => boolean;
|
|
130
|
+
/** This function registers each class of a list, in order. */
|
|
131
|
+
export declare const registerClasses: (b: Biblo, classes: readonly ComponentClass[]) => void;
|
|
132
|
+
/** This function gives all cell templates of a class through its extends chain. A subclass cell replaces a parent cell. */
|
|
133
|
+
export declare const resolveCells: (b: Biblo, className: string) => Readonly<Record<string, CellDef>>;
|
|
134
|
+
/** This function gives the fingerprint of a class: the product of the primes of its cells and typed cells. */
|
|
135
|
+
export declare const classFingerprint: (b: Biblo, className: string) => bigint;
|
|
136
|
+
/** This function gives the prime of an atomic feature, for example `cell:value`. */
|
|
137
|
+
export declare const primeOf: (b: Biblo, atom: string) => bigint;
|
|
138
|
+
/** This function gives the traits that apply to a class (the most specific ones), and the ambiguous method names. */
|
|
139
|
+
export declare const resolveTraits: (b: Biblo, className: string) => TraitResolution;
|
|
140
|
+
/**
|
|
141
|
+
* This function gives all methods of a class. There are three layers, from the lowest to the highest.
|
|
142
|
+
* The first layer is the root of the extends chain, for example `Top`. The second layer is the traits that apply.
|
|
143
|
+
* The third layer is the other classes of the chain, to the class itself.
|
|
144
|
+
*
|
|
145
|
+
* Thus a trait changes the defaults of the root, and a class changes a trait.
|
|
146
|
+
* A method that two traits give is ambiguous: no trait gives it.
|
|
147
|
+
*/
|
|
148
|
+
export declare const resolveMethods: (b: Biblo, className: string) => Readonly<Record<string, unknown>>;
|
|
149
|
+
/**
|
|
150
|
+
* This function makes an instance of a class. The class is not copied: the instance gets an ID, a scope,
|
|
151
|
+
* and a root node with one slot for each cell. All nodes are evaluated before the end of the function.
|
|
152
|
+
*
|
|
153
|
+
* - A typed cell becomes a child instance of its class, with the bindings of the cell. The slot of the cell
|
|
154
|
+
* holds the root node of the child, thus `ref("self", "kid", "value")` reads a cell of the child.
|
|
155
|
+
* A typed cell whose class is already above it on the chain of typed cells is a plain cell.
|
|
156
|
+
* - `bindings` replace cells of this instance. They are in the scope of this instance. A binding for a typed
|
|
157
|
+
* cell makes it a plain cell with the bound expression.
|
|
158
|
+
* - An unknown class gives an instance with no cells.
|
|
159
|
+
*/
|
|
160
|
+
export declare const instantiate: (b: Biblo, store: NodeStore, className: string, parentId?: InstanceId, bindings?: Readonly<Record<string, Expr>>) => Instance;
|
|
161
|
+
/**
|
|
162
|
+
* This function moves a child instance to a position in the children of its parent. A position past the end
|
|
163
|
+
* moves it to the end. It does nothing for an instance without a parent.
|
|
164
|
+
*/
|
|
165
|
+
export declare const moveChild: (b: Biblo, childId: InstanceId, index: number) => void;
|
|
166
|
+
/**
|
|
167
|
+
* This function destroys an instance, the inverse of `instantiate`. It destroys the children first, then
|
|
168
|
+
* removes the nodes of the instance and detaches it from its parent. The readers of the removed nodes
|
|
169
|
+
* become `none` in one epoch.
|
|
170
|
+
*/
|
|
171
|
+
export declare const destroyInstance: (b: Biblo, store: NodeStore, instanceId: InstanceId) => void;
|
|
172
|
+
/**
|
|
173
|
+
* This function registers a new version of a class and updates the live instances: the class is a template,
|
|
174
|
+
* and the instances follow it. The update applies to each instance of the class and of its subclasses.
|
|
175
|
+
* When a cell of the resolved class changes, the instance cell changes too, if it still has the old expression.
|
|
176
|
+
*
|
|
177
|
+
* - A cell with an edit of its own keeps it. A cell that a binding gave keeps the binding.
|
|
178
|
+
* - A new cell is added, and a removed cell is removed. A shared cell node only loses its slot.
|
|
179
|
+
* - A typed cell that changes its type gets a new child instance. A change of its bindings reaches the cells of
|
|
180
|
+
* the child that still follow the old bindings. A change between a typed cell and a plain cell replaces the cell.
|
|
181
|
+
*
|
|
182
|
+
* All changes evaluate in one epoch.
|
|
183
|
+
*/
|
|
184
|
+
export declare const updateClass: (b: Biblo, store: NodeStore, cls: ComponentClass) => void;
|
|
185
|
+
/**
|
|
186
|
+
* This function gives the instance that owns a node. For an instance root, it is the node itself.
|
|
187
|
+
* For another node, it is the nearest owner up the slot tree. A node outside all instances gives `undefined`.
|
|
188
|
+
*/
|
|
189
|
+
export declare const ownerOf: (b: Biblo, store: NodeStore, nodeId: NodeId) => InstanceId | undefined;
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/nodeops.d.ts
|
|
192
|
+
/**
|
|
193
|
+
* This function makes the class-level reactive semantics (the defaults of `Top`).
|
|
194
|
+
*
|
|
195
|
+
* The ops of the result use the `splash`, `flow`, `deref` and `targets` methods of the class that owns each node.
|
|
196
|
+
* The extends chain resolves them, thus the defaults of `Top` apply to all classes, and a class can
|
|
197
|
+
* change them. A node without an owner, or a class without the method, uses `fallback`.
|
|
198
|
+
*
|
|
199
|
+
* The node layer knows nothing of biblo. This factory is how the class layer gives semantics to the
|
|
200
|
+
* node layer without a dependency in the wrong direction. Give the result to `nodeStore`.
|
|
201
|
+
*/
|
|
202
|
+
export declare const classNodeOps: (b: Biblo, fallback?: NodeOps) => NodeOps;
|
|
203
|
+
//#endregion
|
|
204
|
+
export type { Biblo, CellDef, ComponentClass, Instance, InstanceId, Scope, Trait, TraitResolution };
|
|
205
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/class.ts","../src/instance.ts","../src/traits.ts","../src/registry.ts","../src/nodeops.ts"],"mappings":";;;;;;;KAMY;WACD,MAAM;;WAEN;;;;;;WAMA,WAAW,SAAS,eAAe;;;;;;;;;;;;KAalC;WACD;WACA,OAAO,SAAS,eAAe;WAC/B;WACA,UAAU,SAAS;;;qBAIjB,iBACX,cACA,OAAO,SAAS,eAAe,WAC/B,cACA,UAAU,SAAS,6BAClB;;;;;qBAWU,cACX,MAAM,gBACN;WACW,QAAQ,SAAS,eAAe;WAChC,UAAU,SAAS;MAE7B;;;;KCzDS;;;;;KAMA;WACD,MAAM;WACN,QAAQ;;WAER,mBAAmB;;;;;;KAOlB;WACD,IAAI;WACJ;WACA,OAAO;;;;;;;;;;;;;;;;;KCPN;WACD;;WAEA;WACA,SAAS,SAAS;;;KAIjB;WACD,kBAAkB;WAClB;;;qBAkDE,mBAAoB;;;;;;;;;;KC1DrB;WACD,SAAS,oBAAoB;WAC7B,WAAW,YAAY,YAAY;WACnC,QAAQ,oBAAoB;;;qBA+B1B,aAAY;;;;;;qBAoBZ,YAAa,GAAG,UAAQ;;qBA4BxB,gBAAiB,GAAG,OAAO,KAAK;;qBAOhC,gBAAiB,GAAG,OAAO,OAAO;;qBAOlC,kBAAmB,GAAG,OAAO;;;;;;qBAW7B,cAAe,GAAG,OAAO,cAAc;;qBAiCvC,kBAAmB,GAAG,OAAO,kBAAkB;;qBAiC/C,eAAgB,GAAG,OAAO,sBAAoB,SAAS,eAAe;;qBAWtE,mBAAoB,GAAG,OAAO;;qBAU9B,UAAW,GAAG,OAAO;;qBAGrB,gBAAiB,GAAG,OAAO,sBAAoB;;;;;;;;;qBAkB/C,iBAAkB,GAAG,OAAO,sBAAoB,SAAS;;;;;;;;;;;;qBAsGzD,cACX,GAAG,OACH,OAAO,WACP,mBACA,WAAW,YACX,WAAW,SAAS,eAAe,WAClC;;;;;qBAqBU,YAAa,GAAG,OAAO,SAAS,YAAY;;;;;;qBAiB5C,kBAAmB,GAAG,OAAO,OAAO,WAAW,YAAY;;;;;;;;;;;;;qBAuE3D,cAAe,GAAG,OAAO,OAAO,WAAW,KAAK;;;;;qBAsDhD,UAAW,GAAG,OAAO,OAAO,WAAW,QAAQ,WAAS;;;;;;;;;;;;;qBCvexD,eAAgB,GAAG,OAAO,WAAU,YAAuB"}
|