arrmatura 6.2.1 → 6.3.2
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/README.md +41 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/docs/glossary.md +19 -0
- package/docs/hello.md +46 -0
- package/docs/manual.md +312 -0
- package/index.ts +9 -7
- package/package.json +13 -5
- package/src/core/Arrmatron.ts +417 -0
- package/src/core/Component.ts +90 -0
- package/src/core/ManifestNode.ts +150 -0
- package/src/core/resolveExpression.ts +25 -0
- package/src/{core → registry}/composition.ts +21 -25
- package/src/{core → registry}/conditionals.ts +19 -22
- package/src/registry/connector.ts +47 -0
- package/src/registry/elementary.ts +37 -0
- package/src/registry/fragment.ts +22 -0
- package/src/registry/index.ts +65 -0
- package/src/{core → registry}/iterations.ts +49 -36
- package/src/{core → registry}/root.ts +12 -10
- package/src/registry/routing.ts +32 -0
- package/src/registry/selection.ts +59 -0
- package/src/registry/slot.ts +37 -0
- package/src/utils/FingerprintMashine.ts +128 -0
- package/src/utils/applyStateChangedToImpl.ts +18 -0
- package/src/utils/compileExpression.ts +142 -53
- package/src/utils/objectFingerprint.spec.ts +70 -0
- package/src/utils/stringify.ts +3 -9
- package/types.ts +82 -0
- package/src/core/elementary.ts +0 -40
- package/src/core/fragment.ts +0 -21
- package/src/core/index.ts +0 -19
- package/src/core/routing.ts +0 -37
- package/src/core/selection.ts +0 -57
- package/src/core/slot.ts +0 -36
- package/src/ctx/Ctx.ts +0 -424
- package/src/ctx/CtxNode.ts +0 -159
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Ctx } from "../ctx/Ctx";
|
|
1
|
+
import type { EContent, IManifestNode, IPlatform } from "arrmatura/types";
|
|
3
2
|
import type { Hash, XmlNode } from "ultimus/types";
|
|
4
|
-
import type { EContent, ICtxNode, IPlatform } from "arrmatura-api/types";
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
5
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
6
|
+
|
|
7
|
+
export class Composite extends Arrmatron<CCompositeNode> {
|
|
7
8
|
get displayName(): string {
|
|
8
|
-
return `💠${this.
|
|
9
|
+
return `💠${this.manifest.tag}`;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
get recontentScope():
|
|
12
|
+
get recontentScope(): Arrmatron {
|
|
12
13
|
return this;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
slotContent(slotId?: string): EContent | undefined {
|
|
16
|
-
return this.
|
|
17
|
+
return this.manifest.getSlotContent(this.platform, slotId);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
createComponent(initials: Hash) {
|
|
20
|
-
return this.platform.createComponent(this.
|
|
21
|
+
return this.platform.createComponent(this.manifest.tag, initials, this);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
export class CCompositeNode extends
|
|
25
|
+
export class CCompositeNode extends ManifestNode {
|
|
25
26
|
slotContent: Hash<EContent> | null = null;
|
|
26
27
|
tag: string;
|
|
27
28
|
nodes?: XmlNode["nodes"];
|
|
28
|
-
#content
|
|
29
|
+
#content?: Map<string, IManifestNode>;
|
|
29
30
|
|
|
30
|
-
constructor({ tag, attrs, nodes }: XmlNode) {
|
|
31
|
-
super();
|
|
31
|
+
constructor({ id, tag, attrs, nodes }: XmlNode) {
|
|
32
|
+
super(id);
|
|
32
33
|
this.tag = tag;
|
|
33
34
|
this.nodes = nodes;
|
|
34
35
|
this.compileAttributes(attrs);
|
|
@@ -43,29 +44,24 @@ export class CCompositeNode extends CtxNode {
|
|
|
43
44
|
gId = e.tag.split(":")[1];
|
|
44
45
|
isContainer = true;
|
|
45
46
|
}
|
|
46
|
-
groups[gId] = (groups[gId] || []).concat(
|
|
47
|
-
isContainer ? e.nodes ?? [] : e
|
|
48
|
-
);
|
|
47
|
+
groups[gId] = (groups[gId] || []).concat(isContainer ? e.nodes ?? [] : e);
|
|
49
48
|
return groups;
|
|
50
49
|
}, {});
|
|
51
50
|
|
|
52
|
-
this.slotContent = Object.entries(slots ?? {}).reduce<Hash<EContent>>(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
},
|
|
57
|
-
{}
|
|
58
|
-
);
|
|
51
|
+
this.slotContent = Object.entries(slots ?? {}).reduce<Hash<EContent>>((groups, [gId, nodes]) => {
|
|
52
|
+
groups[gId] = platform.getCompiledNodes(nodes);
|
|
53
|
+
return groups;
|
|
54
|
+
}, {});
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
return this.slotContent[slotId
|
|
57
|
+
return this.slotContent[slotId || "default"] ?? undefined;
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
|
|
60
|
+
getSubNodes(platform: IPlatform) {
|
|
65
61
|
return this.#content ?? (this.#content = platform.getCompiledNodes(this.tag));
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
get
|
|
64
|
+
get EntitronConstructor() {
|
|
69
65
|
return Composite;
|
|
70
66
|
}
|
|
71
67
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Composite } from "./composition";
|
|
3
|
-
import { Ctx } from "../ctx/Ctx";
|
|
4
|
-
import type { EContent, ICtx, IPlatform } from "arrmatura-api/types";
|
|
1
|
+
import type { EContent, IArrmatron, IPlatform } from "arrmatura/types";
|
|
5
2
|
import type { XmlNode } from "ultimus/types";
|
|
3
|
+
|
|
4
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
5
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
6
6
|
import { compilePlaceholder } from "../utils/compileExpression";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import { Composite } from "./composition";
|
|
9
|
+
|
|
10
|
+
class Conditional extends Arrmatron<CIfNode> {
|
|
11
|
+
get contentManifests() {
|
|
12
|
+
const branches = this.manifest.getBranches(this.platform);
|
|
13
|
+
return this.$component.condition ? branches.then : branches.else;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
get displayName(): string {
|
|
@@ -16,16 +18,16 @@ class Conditional extends Ctx<CIfNode> {
|
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export class CIfNode extends
|
|
21
|
+
export class CIfNode extends ManifestNode {
|
|
20
22
|
#xml: XmlNode;
|
|
21
23
|
#branches?: { then?: EContent; else?: EContent };
|
|
22
24
|
constructor(xml: XmlNode, expr: string) {
|
|
23
|
-
super();
|
|
25
|
+
super(xml.id);
|
|
24
26
|
this.#xml = xml;
|
|
25
27
|
this.compileCondition(expr);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
get
|
|
30
|
+
get EntitronConstructor() {
|
|
29
31
|
return Conditional;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -43,16 +45,14 @@ export class CIfNode extends CtxNode {
|
|
|
43
45
|
const ifElse = nodes.find((e) => e.tag === "Else");
|
|
44
46
|
const ifThen = nodes.find((e) => e.tag === "Then");
|
|
45
47
|
if (ifElse) {
|
|
46
|
-
this.#branches.else = ifElse.nodes
|
|
47
|
-
? platform.getCompiledNodes(ifElse.nodes)
|
|
48
|
-
: undefined;
|
|
48
|
+
this.#branches.else = ifElse.nodes ? platform.getCompiledNodes(ifElse.nodes) : undefined;
|
|
49
49
|
$then = ifThen
|
|
50
50
|
? ifThen.nodes
|
|
51
51
|
: [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
Object.assign(this.#xml, {
|
|
53
|
+
nodes: nodes.filter((e) => e !== ifElse),
|
|
54
|
+
}),
|
|
55
|
+
];
|
|
56
56
|
} else if (ifThen) {
|
|
57
57
|
$then = ifThen.nodes;
|
|
58
58
|
}
|
|
@@ -68,10 +68,7 @@ export class CIfNode extends CtxNode {
|
|
|
68
68
|
} else if (expr.slice(0, 5) === "slot(") {
|
|
69
69
|
const slotId = expr.slice(5, -1);
|
|
70
70
|
// DO NOT place inside iterations.
|
|
71
|
-
this.addPropertyResolver(
|
|
72
|
-
(c: ICtx) => !!(c.scope as Composite).slotContent?.(slotId)?.size,
|
|
73
|
-
"condition"
|
|
74
|
-
);
|
|
71
|
+
this.addPropertyResolver((c: IArrmatron) => !!(c.scope as Composite).slotContent?.(slotId)?.size, "condition");
|
|
75
72
|
} else {
|
|
76
73
|
const resolver = compilePlaceholder(expr);
|
|
77
74
|
this.addPropertyResolver((c) => !!resolver(c), "condition");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Fn, XmlNode } from "ultimus";
|
|
2
|
+
|
|
3
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
4
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
5
|
+
import { objectFingerprint } from "../utils/FingerprintMashine";
|
|
6
|
+
|
|
7
|
+
class Connector extends Arrmatron<ConnectorNode> {
|
|
8
|
+
prevkey: any;
|
|
9
|
+
|
|
10
|
+
counter = 0;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Triggers an with changes after a specified timeout.
|
|
14
|
+
*
|
|
15
|
+
* @return {void} No return value.
|
|
16
|
+
*/
|
|
17
|
+
touch() {
|
|
18
|
+
super.touch();
|
|
19
|
+
// if (this.isDone) return;
|
|
20
|
+
const { trigger, data, change } = this.$component;
|
|
21
|
+
const key = 'trigger' in this.$component ? trigger : data;
|
|
22
|
+
const fprint = objectFingerprint(key);
|
|
23
|
+
const changed = !('prevkey' in this) || this.prevkey != fprint;
|
|
24
|
+
|
|
25
|
+
if (!changed) return;
|
|
26
|
+
|
|
27
|
+
this.prevkey = fprint;
|
|
28
|
+
|
|
29
|
+
(change as Fn)?.(data);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get displayName(): string {
|
|
33
|
+
return "🔹Connector";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class ConnectorNode extends ManifestNode {
|
|
38
|
+
constructor({ attrs, id }: XmlNode) {
|
|
39
|
+
super(id);
|
|
40
|
+
this.compileAttributes(attrs);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get EntitronConstructor() {
|
|
44
|
+
return Connector;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IPlatform } from "arrmatura/types";
|
|
2
|
+
import type { Hash, XmlNode } from "ultimus/types";
|
|
3
|
+
|
|
4
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
5
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
6
|
+
|
|
7
|
+
class NativeElementEntitron extends Arrmatron<CElementNode> {
|
|
8
|
+
get displayName(): string {
|
|
9
|
+
return this.manifest.tag;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
createComponent(initials: Hash) {
|
|
13
|
+
return this.platform.createComponent({ tag: this.manifest.tag, native: true }, initials, this);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class CElementNode extends ManifestNode {
|
|
18
|
+
#nodes: XmlNode[] | undefined;
|
|
19
|
+
|
|
20
|
+
constructor({ id, tag, attrs, nodes, text }: XmlNode) {
|
|
21
|
+
super(id);
|
|
22
|
+
this.tag = tag;
|
|
23
|
+
this.compileAttributes(attrs);
|
|
24
|
+
if (text) {
|
|
25
|
+
this.compileAttribute("#text", text);
|
|
26
|
+
}
|
|
27
|
+
this.#nodes = nodes;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getSubNodes(platform: IPlatform) {
|
|
31
|
+
return this.#nodes ? platform.getCompiledNodes(this.#nodes) : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get EntitronConstructor() {
|
|
35
|
+
return NativeElementEntitron;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IPlatform } from "arrmatura/types";
|
|
2
|
+
import type { XmlNode } from "ultimus/types";
|
|
3
|
+
|
|
4
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
5
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
6
|
+
|
|
7
|
+
export class CFragmentNode extends ManifestNode {
|
|
8
|
+
#nodes: XmlNode[] | undefined;
|
|
9
|
+
|
|
10
|
+
constructor({ id, nodes }: XmlNode) {
|
|
11
|
+
super(id);
|
|
12
|
+
this.#nodes = nodes;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getSubNodes(platform: IPlatform) {
|
|
16
|
+
return this.#nodes ? platform.getCompiledNodes(this.#nodes) : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get EntitronConstructor() {
|
|
20
|
+
return Arrmatron;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Uid, XmlNode } from "ultimus";
|
|
2
|
+
|
|
3
|
+
import { IManifestNode } from "../../types";
|
|
4
|
+
|
|
5
|
+
import { CCompositeNode } from "./composition";
|
|
6
|
+
import { CIfNode } from "./conditionals";
|
|
7
|
+
import { ConnectorNode } from "./connector";
|
|
8
|
+
import { CElementNode } from "./elementary";
|
|
9
|
+
import { CFragmentNode } from "./fragment";
|
|
10
|
+
import { CForNode } from "./iterations";
|
|
11
|
+
import { CDynamicTagNode } from "./routing";
|
|
12
|
+
import { CSelectorNode } from "./selection";
|
|
13
|
+
import { CSlotNode } from "./slot";
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const cloneNode = (x: XmlNode, eliminateAttr: string): XmlNode => {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
const { [eliminateAttr]: _, ...attrs } = x.attrs ?? {};
|
|
20
|
+
return {
|
|
21
|
+
text: x.text,
|
|
22
|
+
tag: x.tag,
|
|
23
|
+
id: x.id,
|
|
24
|
+
attrs,
|
|
25
|
+
nodes: x.nodes?.map((n) => n),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const __compileManifestNode = (x: XmlNode): IManifestNode => {
|
|
30
|
+
const { tag = 'div', attrs } = x;
|
|
31
|
+
if (attrs?.["Each"]) {
|
|
32
|
+
return new CForNode(cloneNode(x, "Each"), String(attrs["Each"]).trim().split(" "));
|
|
33
|
+
}
|
|
34
|
+
if (attrs?.["If"]) {
|
|
35
|
+
return new CIfNode(cloneNode(x, "If"), String(attrs["If"]));
|
|
36
|
+
}
|
|
37
|
+
if (tag === "div" || tag[0]?.match(/[A-Z0-9]/) == null) {
|
|
38
|
+
return new CElementNode(x);
|
|
39
|
+
}
|
|
40
|
+
if (tag === "Dynamic") {
|
|
41
|
+
return new CDynamicTagNode(cloneNode(x, "As"), String(attrs?.As ?? "Error.Dynamic"));
|
|
42
|
+
}
|
|
43
|
+
if (tag === "Slot") {
|
|
44
|
+
return new CSlotNode(x);
|
|
45
|
+
}
|
|
46
|
+
if (tag === "Selector") {
|
|
47
|
+
return new CSelectorNode(x);
|
|
48
|
+
}
|
|
49
|
+
if (tag === "Connector") {
|
|
50
|
+
return new ConnectorNode(x);
|
|
51
|
+
}
|
|
52
|
+
if (tag === "Fragment" || tag === "Then" || tag === "Else") {
|
|
53
|
+
return new CFragmentNode(x);
|
|
54
|
+
}
|
|
55
|
+
return new CCompositeNode(x);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const CTXNODES = new Map();
|
|
59
|
+
|
|
60
|
+
export const compileManifestNode = (x: XmlNode): IManifestNode => {
|
|
61
|
+
return CTXNODES.has(x) ? CTXNODES.get(x) : CTXNODES.set(x, __compileManifestNode(x)).get(x);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const compileManifestNodes = (x: XmlNode[]): Map<Uid, IManifestNode> =>
|
|
65
|
+
new Map<Uid, IManifestNode>(x?.map(compileManifestNode).map((c) => [c.uid, c]) ?? []);
|
|
@@ -1,41 +1,61 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { EContent, IManifestNode, IPlatform } from "arrmatura/types";
|
|
2
|
+
import { mapEntries } from "ultimus";
|
|
3
3
|
import type { Datum, Delta, Hash, Uid, XmlNode } from "ultimus/types";
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
6
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
5
7
|
import { compilePlaceholder } from "../utils/compileExpression";
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
const narrowData = (data: any) => {
|
|
11
|
+
if (!data) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(data)) return data;
|
|
15
|
+
if (typeof data[Symbol.iterator] === 'function') return [...data];
|
|
16
|
+
if (typeof data === "string") return data.split(',').map(id => ({ id, name: id }));
|
|
17
|
+
if (typeof data === "object") return mapEntries(data, (key, value) => ({ ...value, id: key }));
|
|
18
|
+
return [{ id: String(data), name: String(data) }];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class Iterative extends Arrmatron<CForNode> {
|
|
8
22
|
pkHash: Hash<Datum> = {};
|
|
9
23
|
|
|
10
24
|
get displayName(): string {
|
|
11
25
|
return "🔹each";
|
|
12
26
|
}
|
|
13
27
|
|
|
14
|
-
get
|
|
15
|
-
const each: any = this
|
|
16
|
-
const itemNode = this.
|
|
17
|
-
const nodes: Map<Uid,
|
|
28
|
+
get contentManifests() {
|
|
29
|
+
const each: any = narrowData(this.$component.each);
|
|
30
|
+
const itemNode = this.manifest.getItemCtxNode(this.platform);
|
|
31
|
+
const nodes: Map<Uid, IManifestNode> = new Map();
|
|
18
32
|
this.pkHash = {};
|
|
19
33
|
if (each?.length) {
|
|
20
34
|
if (!each.forEach) {
|
|
21
|
-
|
|
35
|
+
|
|
22
36
|
throw new Error(`[each] Items has no forEach() ${each.toString()}`);
|
|
23
37
|
}
|
|
24
|
-
each.forEach((
|
|
38
|
+
each.forEach((_datum: Datum, index: number) => {
|
|
39
|
+
const datum = typeof _datum === "string" ? { id: _datum } : _datum;
|
|
25
40
|
let id = datum.id;
|
|
41
|
+
|
|
26
42
|
if (id == null) {
|
|
27
43
|
this.logError("ERROR: empty item id: ", datum);
|
|
28
44
|
id = String(index);
|
|
29
45
|
}
|
|
46
|
+
|
|
30
47
|
const pk = String(id);
|
|
31
48
|
if (this.pkHash[pk]) {
|
|
32
49
|
this.logError(`ERROR: duplicate item id : ${pk} (skipped)`, datum);
|
|
33
50
|
return;
|
|
34
51
|
}
|
|
52
|
+
|
|
35
53
|
this.pkHash[pk] = datum;
|
|
54
|
+
|
|
36
55
|
const inode = itemNode
|
|
37
56
|
.cloneWithDatum(datum, this.platform)
|
|
38
57
|
.addPropertyResolver(() => this.pkHash[pk], itemNode.itemName);
|
|
58
|
+
|
|
39
59
|
nodes.set(inode.uid, inode);
|
|
40
60
|
});
|
|
41
61
|
}
|
|
@@ -43,14 +63,17 @@ class Iterative extends Ctx<CForNode> {
|
|
|
43
63
|
}
|
|
44
64
|
}
|
|
45
65
|
|
|
46
|
-
export class CForNode extends
|
|
66
|
+
export class CForNode extends ManifestNode {
|
|
47
67
|
#itemNode?: CItemNode;
|
|
48
68
|
#itemName: string;
|
|
49
69
|
#xmlNode: XmlNode;
|
|
50
70
|
constructor(xmlNode: XmlNode, [itemName, prep, expr = prep]: string[]) {
|
|
51
|
-
super();
|
|
71
|
+
super(xmlNode.id);
|
|
72
|
+
|
|
52
73
|
this.#xmlNode = xmlNode;
|
|
53
|
-
|
|
74
|
+
|
|
75
|
+
this.#itemName = itemName.startsWith("@") ? itemName.slice(1) : itemName;
|
|
76
|
+
|
|
54
77
|
if (expr[0] === "<" && expr[1] === "-") {
|
|
55
78
|
this.addConnector(expr.slice(2), "each");
|
|
56
79
|
} else {
|
|
@@ -60,21 +83,17 @@ export class CForNode extends CtxNode {
|
|
|
60
83
|
|
|
61
84
|
getItemCtxNode(platform: IPlatform) {
|
|
62
85
|
return (
|
|
63
|
-
this.#itemNode ??
|
|
64
|
-
(this.#itemNode = new CItemNode(
|
|
65
|
-
this.#itemName,
|
|
66
|
-
platform.getCompiledNodes([this.#xmlNode])
|
|
67
|
-
))
|
|
86
|
+
this.#itemNode ?? (this.#itemNode = new CItemNode(this.#xmlNode.id, this.#itemName, platform.getCompiledNodes([this.#xmlNode])))
|
|
68
87
|
);
|
|
69
88
|
}
|
|
70
89
|
|
|
71
|
-
get
|
|
90
|
+
get EntitronConstructor() {
|
|
72
91
|
return Iterative;
|
|
73
92
|
}
|
|
74
93
|
}
|
|
75
94
|
|
|
76
|
-
class IterativeItem extends
|
|
77
|
-
get recontentScope():
|
|
95
|
+
class IterativeItem extends Arrmatron<CItemNode> {
|
|
96
|
+
get recontentScope(): Arrmatron {
|
|
78
97
|
return this;
|
|
79
98
|
}
|
|
80
99
|
|
|
@@ -87,35 +106,29 @@ class IterativeItem extends Ctx<CItemNode> {
|
|
|
87
106
|
}
|
|
88
107
|
|
|
89
108
|
get(propId: string) {
|
|
90
|
-
const iName: string = this.
|
|
91
|
-
const value =
|
|
92
|
-
propId.startsWith(`${iName}.`) || propId === iName
|
|
93
|
-
? super.get(propId)
|
|
94
|
-
: this.scope.get(propId);
|
|
109
|
+
const iName: string = this.manifest.itemName;
|
|
110
|
+
const value = propId.startsWith(`${iName}.`) || propId === iName ? super.get(propId) : this.scope.get(propId);
|
|
95
111
|
// this.log(propId, value);
|
|
96
112
|
return value;
|
|
97
113
|
}
|
|
98
114
|
}
|
|
99
115
|
|
|
100
|
-
class CItemNode extends
|
|
116
|
+
class CItemNode extends ManifestNode {
|
|
101
117
|
itemName: string;
|
|
102
|
-
constructor(itemName: string, content?: EContent) {
|
|
103
|
-
super();
|
|
118
|
+
constructor(id: string, itemName: string, content?: EContent) {
|
|
119
|
+
super(id);
|
|
104
120
|
this.itemName = itemName;
|
|
105
121
|
this.$content = content;
|
|
106
122
|
}
|
|
107
123
|
|
|
108
124
|
cloneWithDatum(datum: Datum, platform: IPlatform) {
|
|
109
125
|
const uid = `${String(this.uid)}#${datum.id}`;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
uid,
|
|
114
|
-
}
|
|
115
|
-
);
|
|
126
|
+
const c = new CItemNode(uid, this.itemName, this.getSubNodes(platform));
|
|
127
|
+
c.uid = uid;
|
|
128
|
+
return c;
|
|
116
129
|
}
|
|
117
130
|
|
|
118
|
-
get
|
|
131
|
+
get EntitronConstructor() {
|
|
119
132
|
return IterativeItem;
|
|
120
133
|
}
|
|
121
134
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Ctx } from "../ctx/Ctx";
|
|
3
|
-
import type { Hash, XmlNode } from "ultimus/types";
|
|
4
|
-
import type { EContent, IPlatform } from "arrmatura-api/types";
|
|
1
|
+
import type { EContent, IPlatform } from "arrmatura/types";
|
|
5
2
|
import { xmlParse } from "ultimus";
|
|
3
|
+
import type { Hash, XmlNode } from "ultimus/types";
|
|
4
|
+
|
|
5
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
6
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
7
|
+
|
|
6
8
|
import { CCompositeNode } from "./composition";
|
|
7
9
|
|
|
8
|
-
class RootCtx extends
|
|
10
|
+
class RootCtx extends Arrmatron<CCompositeNode> {
|
|
9
11
|
get displayName(): string {
|
|
10
12
|
return `ROOT`;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
get recontentScope():
|
|
15
|
+
get recontentScope(): Arrmatron {
|
|
14
16
|
return this;
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -23,16 +25,16 @@ class RootCtx extends Ctx<CCompositeNode> {
|
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
export class CRootNode extends
|
|
28
|
+
export class CRootNode extends ManifestNode {
|
|
27
29
|
slotContent: Hash<EContent>;
|
|
28
30
|
nodes?: XmlNode["nodes"];
|
|
29
31
|
|
|
30
32
|
constructor(private template: string) {
|
|
31
|
-
super();
|
|
33
|
+
super('R0');
|
|
32
34
|
this.slotContent = {};
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
getSubNodes(platform: IPlatform) {
|
|
36
38
|
return platform.getCompiledNodes(xmlParse(this.template));
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -40,7 +42,7 @@ export class CRootNode extends CtxNode {
|
|
|
40
42
|
return undefined;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
get
|
|
45
|
+
get EntitronConstructor() {
|
|
44
46
|
return RootCtx;
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { XmlNode } from "ultimus/types";
|
|
2
|
+
|
|
3
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
4
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
5
|
+
|
|
6
|
+
class DynamicTag extends Arrmatron<CDynamicTagNode> {
|
|
7
|
+
get displayName(): string {
|
|
8
|
+
return "dynamics";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get contentManifests() {
|
|
12
|
+
const tag = this.$component.tag;
|
|
13
|
+
const uid = `${this.uid}:${String(tag ?? "")}`;
|
|
14
|
+
return new Map([
|
|
15
|
+
[uid, Object.assign(this.platform.getCompiledNodes({ ...this.manifest.xml, tag } as XmlNode), { uid })],
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class CDynamicTagNode extends ManifestNode {
|
|
21
|
+
xml: XmlNode & { tag: string };
|
|
22
|
+
|
|
23
|
+
constructor(xml: XmlNode, expr: string) {
|
|
24
|
+
super(xml.id);
|
|
25
|
+
this.compileAttribute("tag", expr);
|
|
26
|
+
this.xml = xml;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get EntitronConstructor() {
|
|
30
|
+
return DynamicTag;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { EContent, IPlatform } from "arrmatura/types";
|
|
2
|
+
import type { Hash, XmlNode } from "ultimus/types";
|
|
3
|
+
|
|
4
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
5
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
6
|
+
|
|
7
|
+
export class Selector extends Arrmatron<CSelectorNode> {
|
|
8
|
+
get displayName(): string {
|
|
9
|
+
return `💠Selector`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the content of the function.
|
|
14
|
+
*
|
|
15
|
+
* @return {any} The content of the function.
|
|
16
|
+
*/
|
|
17
|
+
get contentManifests() {
|
|
18
|
+
const cases = this.manifest.getCases(this.platform);
|
|
19
|
+
const onKey = this.$component.On as string;
|
|
20
|
+
const matchedCase = cases?.[onKey];
|
|
21
|
+
if (!matchedCase) {
|
|
22
|
+
this.log("unmatched case", onKey, cases);
|
|
23
|
+
}
|
|
24
|
+
return matchedCase ?? cases?.["default"] ?? Object.values(cases)[0];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class CSelectorNode extends ManifestNode {
|
|
29
|
+
cases: Hash<EContent> | null = null;
|
|
30
|
+
key = "";
|
|
31
|
+
nodes?: XmlNode["nodes"];
|
|
32
|
+
|
|
33
|
+
constructor({ id, tag, attrs, nodes }: XmlNode) {
|
|
34
|
+
super(id);
|
|
35
|
+
this.tag = tag;
|
|
36
|
+
this.nodes = nodes;
|
|
37
|
+
this.compileAttributes(attrs);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves the cases nodes for a component.
|
|
42
|
+
*
|
|
43
|
+
* @param {IPlatform} platform - The platform to get cases for.
|
|
44
|
+
* @return {Hash<EContent>} - The cases for the platform.
|
|
45
|
+
*/
|
|
46
|
+
getCases(platform: IPlatform): Hash<EContent> {
|
|
47
|
+
return (
|
|
48
|
+
this.cases ??
|
|
49
|
+
(this.cases = (this.nodes ?? []).reduce<Hash<EContent>>((groups, node) => {
|
|
50
|
+
groups[node.attrs?.When as string] = platform.getCompiledNodes(node.nodes ?? []);
|
|
51
|
+
return groups;
|
|
52
|
+
}, {}))
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get EntitronConstructor() {
|
|
57
|
+
return Selector;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { XmlNode } from "ultimus/types";
|
|
2
|
+
|
|
3
|
+
import { Arrmatron } from "../core/Arrmatron";
|
|
4
|
+
import { ManifestNode } from "../core/ManifestNode";
|
|
5
|
+
|
|
6
|
+
import { Composite } from "./composition";
|
|
7
|
+
|
|
8
|
+
class Slot extends Arrmatron {
|
|
9
|
+
get displayName(): string {
|
|
10
|
+
return "🔸";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get compositeScope(): Composite {
|
|
14
|
+
return this.scope as Composite;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get contentManifests() {
|
|
18
|
+
return this.compositeScope.slotContent((this.manifest as CSlotNode).key);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get recontentScope(): Arrmatron {
|
|
22
|
+
return this.compositeScope.scope;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class CSlotNode extends ManifestNode {
|
|
27
|
+
key?: string;
|
|
28
|
+
|
|
29
|
+
constructor(x: XmlNode) {
|
|
30
|
+
super(x.id);
|
|
31
|
+
this.key = x.attrs?.Key as string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get EntitronConstructor() {
|
|
35
|
+
return Slot;
|
|
36
|
+
}
|
|
37
|
+
}
|