@oscarpalmer/abydon 0.4.0 → 0.5.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/bun.lockb +0 -0
- package/dist/index.js +137 -11
- package/package.json +3 -2
- package/src/fragment.ts +32 -9
- package/src/html.ts +44 -7
- package/src/node/index.ts +64 -0
- package/types/fragment.d.ts +4 -1
- package/types/html.d.ts +2 -1
- package/types/node/index.d.ts +2 -0
package/bun.lockb
CHANGED
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -34,28 +34,156 @@ function getNodes(node) {
|
|
|
34
34
|
return /^documentfragment$/i.test(node.constructor.name) ? [...node.childNodes] : [node];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// node_modules/@oscarpalmer/sentinel/node_modules/@oscarpalmer/atoms/dist/js/queue.mjs
|
|
38
|
+
if (globalThis._atomic_queued == null) {
|
|
39
|
+
const queued = new Set;
|
|
40
|
+
Object.defineProperty(globalThis, "_atomic_queued", {
|
|
41
|
+
get() {
|
|
42
|
+
return queued;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// node_modules/@oscarpalmer/sentinel/dist/global.mjs
|
|
48
|
+
if (globalThis._sentinels == null) {
|
|
49
|
+
const effects = [];
|
|
50
|
+
Object.defineProperty(globalThis, "_sentinels", {
|
|
51
|
+
get() {
|
|
52
|
+
return effects;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// node_modules/@oscarpalmer/sentinel/dist/helpers/is.mjs
|
|
58
|
+
var isReactive = function(value) {
|
|
59
|
+
return isSentinel(value, /^array|computed|signal|store$/i);
|
|
60
|
+
};
|
|
61
|
+
var isSentinel = function(value, expression) {
|
|
62
|
+
return expression.test(value?.$sentinel ?? "");
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// node_modules/@oscarpalmer/sentinel/dist/helpers/value.mjs
|
|
66
|
+
var arrayOperations = new Set([
|
|
67
|
+
"copyWithin",
|
|
68
|
+
"fill",
|
|
69
|
+
"pop",
|
|
70
|
+
"push",
|
|
71
|
+
"reverse",
|
|
72
|
+
"shift",
|
|
73
|
+
"sort",
|
|
74
|
+
"splice",
|
|
75
|
+
"unshift"
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
// node_modules/@oscarpalmer/sentinel/dist/reactive/index.mjs
|
|
79
|
+
var primitives = new Set(["boolean", "number", "string"]);
|
|
80
|
+
|
|
81
|
+
// src/node/index.ts
|
|
82
|
+
var mapNode = function(data, comment) {
|
|
83
|
+
const matches = commentExpression.exec(comment.textContent ?? "");
|
|
84
|
+
const value10 = matches == null ? null : data.values[+matches[1]];
|
|
85
|
+
if (value10 != null) {
|
|
86
|
+
mapValue(comment, value10);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function mapNodes(data, nodes) {
|
|
90
|
+
const { length } = nodes;
|
|
91
|
+
for (let index = 0;index < length; index += 1) {
|
|
92
|
+
const node = nodes[index];
|
|
93
|
+
if (node instanceof Comment) {
|
|
94
|
+
mapNode(data, node);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (node instanceof Element) {
|
|
98
|
+
}
|
|
99
|
+
if (node.hasChildNodes()) {
|
|
100
|
+
mapNodes(data, [...node.childNodes]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
var mapReactive = function(comment, value10) {
|
|
105
|
+
};
|
|
106
|
+
var mapValue = function(comment, value10) {
|
|
107
|
+
switch (true) {
|
|
108
|
+
case value10 instanceof Node:
|
|
109
|
+
comment.replaceWith(value10);
|
|
110
|
+
return;
|
|
111
|
+
case isFragment(value10):
|
|
112
|
+
comment.replaceWith(value10.get());
|
|
113
|
+
break;
|
|
114
|
+
case isReactive(value10):
|
|
115
|
+
mapReactive(comment, value10);
|
|
116
|
+
break;
|
|
117
|
+
case typeof value10 === "function":
|
|
118
|
+
mapValue(comment, value10());
|
|
119
|
+
return;
|
|
120
|
+
case typeof value10 === "object":
|
|
121
|
+
comment.replaceWith(new Text(getString(value10)));
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var commentExpression = /^abydon\.(\d+)$/;
|
|
126
|
+
|
|
37
127
|
// src/fragment.ts
|
|
38
128
|
function createFragment(strings, expressions) {
|
|
39
129
|
const data = {
|
|
40
130
|
expressions,
|
|
41
131
|
strings,
|
|
42
|
-
nodes: []
|
|
132
|
+
nodes: [],
|
|
133
|
+
values: []
|
|
43
134
|
};
|
|
44
135
|
const instance = Object.create({
|
|
45
|
-
|
|
46
|
-
if (data.nodes.length
|
|
47
|
-
|
|
136
|
+
get() {
|
|
137
|
+
if (data.nodes.length === 0) {
|
|
138
|
+
const parsed = parse(data);
|
|
139
|
+
const templated = createTemplate(parsed);
|
|
140
|
+
data.nodes.splice(0, data.nodes.length, ...getNodes(templated));
|
|
141
|
+
mapNodes(data, data.nodes);
|
|
142
|
+
}
|
|
143
|
+
return getFragment(data.nodes);
|
|
144
|
+
},
|
|
145
|
+
remove() {
|
|
146
|
+
const { length } = data.nodes;
|
|
147
|
+
for (let index = 0;index < length; index += 1) {
|
|
148
|
+
const node2 = data.nodes[index];
|
|
149
|
+
node2.parentNode?.removeChild(node2);
|
|
48
150
|
}
|
|
49
|
-
|
|
50
|
-
const templated = createTemplate(parsed);
|
|
51
|
-
data.nodes.splice(0, data.nodes.length, ...getNodes(templated));
|
|
52
|
-
parent.append(...data.nodes);
|
|
151
|
+
data.nodes.splice(0, data.nodes.length);
|
|
53
152
|
}
|
|
54
153
|
});
|
|
154
|
+
Object.defineProperty(instance, "$fragment", {
|
|
155
|
+
value: true
|
|
156
|
+
});
|
|
55
157
|
return instance;
|
|
56
158
|
}
|
|
159
|
+
function isFragment(value10) {
|
|
160
|
+
return typeof value10 === "object" && value10 != null && "$fragment" in value10;
|
|
161
|
+
}
|
|
57
162
|
|
|
58
163
|
// src/html.ts
|
|
164
|
+
function getFragment(nodes) {
|
|
165
|
+
const fragment3 = document.createDocumentFragment();
|
|
166
|
+
fragment3.append(...nodes);
|
|
167
|
+
return fragment3;
|
|
168
|
+
}
|
|
169
|
+
var handleExpression = function(data, prefix, expression) {
|
|
170
|
+
if (isNullableOrWhitespace(expression)) {
|
|
171
|
+
return prefix;
|
|
172
|
+
}
|
|
173
|
+
if (Array.isArray(expression)) {
|
|
174
|
+
const { length } = expression;
|
|
175
|
+
let expressions = "";
|
|
176
|
+
for (let index = 0;index < length; index += 1) {
|
|
177
|
+
expressions += handleExpression(data, "", expression[index]);
|
|
178
|
+
}
|
|
179
|
+
return `${prefix}${expressions}`;
|
|
180
|
+
}
|
|
181
|
+
if (typeof expression === "object") {
|
|
182
|
+
const index = data.values.push(expression) - 1;
|
|
183
|
+
return `${prefix}<!--abydon.${index}-->`;
|
|
184
|
+
}
|
|
185
|
+
return `${prefix}${expression}`;
|
|
186
|
+
};
|
|
59
187
|
function html2(strings, ...values) {
|
|
60
188
|
return createFragment(strings, values);
|
|
61
189
|
}
|
|
@@ -63,9 +191,7 @@ function parse(data) {
|
|
|
63
191
|
const { length } = data.strings;
|
|
64
192
|
let template = "";
|
|
65
193
|
for (let index = 0;index < length; index += 1) {
|
|
66
|
-
|
|
67
|
-
const expression = data.expressions[index];
|
|
68
|
-
template += isNullableOrWhitespace(expression) ? part : `${part}${expression}`;
|
|
194
|
+
template += handleExpression(data, data.strings[index], data.expressions[index]);
|
|
69
195
|
}
|
|
70
196
|
return template;
|
|
71
197
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@oscarpalmer/atoms": "^0.61.0"
|
|
7
|
+
"@oscarpalmer/atoms": "^0.61.0",
|
|
8
|
+
"@oscarpalmer/sentinel": "^0.22.0"
|
|
8
9
|
},
|
|
9
10
|
"devDependencies": {
|
|
10
11
|
"@biomejs/biome": "^1.8.3",
|
|
@@ -35,5 +36,5 @@
|
|
|
35
36
|
"watch": "bun build ./src/index.ts --outfile ./dist/index.js --watch"
|
|
36
37
|
},
|
|
37
38
|
"types": "src/types.d.ts",
|
|
38
|
-
"version": "0.
|
|
39
|
+
"version": "0.5.0"
|
|
39
40
|
}
|
package/src/fragment.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import {createTemplate, getNodes} from './helpers/dom';
|
|
2
|
-
import {parse} from './html';
|
|
2
|
+
import {getFragment, parse} from './html';
|
|
3
|
+
import {mapNodes} from './node';
|
|
3
4
|
|
|
4
5
|
export type Fragment = {
|
|
5
|
-
|
|
6
|
+
get(): DocumentFragment;
|
|
7
|
+
remove(): void;
|
|
6
8
|
};
|
|
7
9
|
|
|
8
10
|
export type FragmentData = {
|
|
9
11
|
expressions: unknown[];
|
|
10
12
|
nodes: Node[];
|
|
11
13
|
strings: TemplateStringsArray;
|
|
14
|
+
values: unknown[];
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export function createFragment(
|
|
@@ -19,22 +22,42 @@ export function createFragment(
|
|
|
19
22
|
expressions,
|
|
20
23
|
strings,
|
|
21
24
|
nodes: [],
|
|
25
|
+
values: [],
|
|
22
26
|
};
|
|
23
27
|
|
|
24
28
|
const instance = Object.create({
|
|
25
|
-
|
|
26
|
-
if (data.nodes.length
|
|
27
|
-
|
|
29
|
+
get(): Node {
|
|
30
|
+
if (data.nodes.length === 0) {
|
|
31
|
+
const parsed = parse(data);
|
|
32
|
+
const templated = createTemplate(parsed);
|
|
33
|
+
|
|
34
|
+
data.nodes.splice(0, data.nodes.length, ...getNodes(templated));
|
|
35
|
+
|
|
36
|
+
mapNodes(data, data.nodes);
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
return getFragment(data.nodes);
|
|
40
|
+
},
|
|
41
|
+
remove(): void {
|
|
42
|
+
const {length} = data.nodes;
|
|
32
43
|
|
|
33
|
-
|
|
44
|
+
for (let index = 0; index < length; index += 1) {
|
|
45
|
+
const node = data.nodes[index];
|
|
46
|
+
|
|
47
|
+
node.parentNode?.removeChild(node);
|
|
48
|
+
}
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
data.nodes.splice(0, data.nodes.length);
|
|
36
51
|
},
|
|
37
52
|
});
|
|
38
53
|
|
|
54
|
+
Object.defineProperty(instance, '$fragment', {
|
|
55
|
+
value: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
39
58
|
return instance;
|
|
40
59
|
}
|
|
60
|
+
|
|
61
|
+
export function isFragment(value: unknown): value is Fragment {
|
|
62
|
+
return typeof value === 'object' && value != null && '$fragment' in value;
|
|
63
|
+
}
|
package/src/html.ts
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import {
|
|
2
|
+
import {type Fragment, type FragmentData, createFragment} from './fragment';
|
|
3
|
+
|
|
4
|
+
export function getFragment(nodes: Node[]): DocumentFragment {
|
|
5
|
+
const fragment = document.createDocumentFragment();
|
|
6
|
+
|
|
7
|
+
fragment.append(...nodes);
|
|
8
|
+
|
|
9
|
+
return fragment;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function handleExpression(
|
|
13
|
+
data: FragmentData,
|
|
14
|
+
prefix: string,
|
|
15
|
+
expression: unknown,
|
|
16
|
+
): string {
|
|
17
|
+
if (isNullableOrWhitespace(expression)) {
|
|
18
|
+
return prefix;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Array.isArray(expression)) {
|
|
22
|
+
const {length} = expression;
|
|
23
|
+
|
|
24
|
+
let expressions = '';
|
|
25
|
+
|
|
26
|
+
for (let index = 0; index < length; index += 1) {
|
|
27
|
+
expressions += handleExpression(data, '', expression[index]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return `${prefix}${expressions}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof expression === 'object') {
|
|
34
|
+
const index = data.values.push(expression) - 1;
|
|
35
|
+
|
|
36
|
+
return `${prefix}<!--abydon.${index}-->`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return `${prefix}${expression}`;
|
|
40
|
+
}
|
|
3
41
|
|
|
4
42
|
export function html(
|
|
5
43
|
strings: TemplateStringsArray,
|
|
@@ -14,12 +52,11 @@ export function parse(data: FragmentData): string {
|
|
|
14
52
|
let template = '';
|
|
15
53
|
|
|
16
54
|
for (let index = 0; index < length; index += 1) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
: `${part}${expression}`;
|
|
55
|
+
template += handleExpression(
|
|
56
|
+
data,
|
|
57
|
+
data.strings[index],
|
|
58
|
+
data.expressions[index],
|
|
59
|
+
);
|
|
23
60
|
}
|
|
24
61
|
|
|
25
62
|
return template;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
2
|
+
import {isReactive, type Reactive} from '@oscarpalmer/sentinel';
|
|
3
|
+
import {type FragmentData, isFragment} from '../fragment';
|
|
4
|
+
|
|
5
|
+
const commentExpression = /^abydon\.(\d+)$/;
|
|
6
|
+
|
|
7
|
+
function mapNode(data: FragmentData, comment: Comment): void {
|
|
8
|
+
const matches = commentExpression.exec(comment.textContent ?? '');
|
|
9
|
+
const value = matches == null ? null : data.values[+matches[1]];
|
|
10
|
+
|
|
11
|
+
if (value != null) {
|
|
12
|
+
mapValue(comment, value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function mapNodes(data: FragmentData, nodes: Node[]): void {
|
|
17
|
+
const {length} = nodes;
|
|
18
|
+
|
|
19
|
+
for (let index = 0; index < length; index += 1) {
|
|
20
|
+
const node = nodes[index];
|
|
21
|
+
|
|
22
|
+
if (node instanceof Comment) {
|
|
23
|
+
mapNode(data, node);
|
|
24
|
+
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (node instanceof Element) {
|
|
29
|
+
// Attributes
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (node.hasChildNodes()) {
|
|
33
|
+
mapNodes(data, [...node.childNodes]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function mapReactive(comment: Comment, value: Reactive): void {
|
|
39
|
+
// ?
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function mapValue(comment: Comment, value: unknown): void {
|
|
43
|
+
switch (true) {
|
|
44
|
+
case value instanceof Node:
|
|
45
|
+
comment.replaceWith(value);
|
|
46
|
+
return;
|
|
47
|
+
|
|
48
|
+
case isFragment(value):
|
|
49
|
+
comment.replaceWith(value.get());
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case isReactive(value):
|
|
53
|
+
mapReactive(comment, value);
|
|
54
|
+
break;
|
|
55
|
+
|
|
56
|
+
case typeof value === 'function':
|
|
57
|
+
mapValue(comment, value());
|
|
58
|
+
return;
|
|
59
|
+
|
|
60
|
+
case typeof value === 'object':
|
|
61
|
+
comment.replaceWith(new Text(getString(value)));
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/types/fragment.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type Fragment = {
|
|
2
|
-
|
|
2
|
+
get(): DocumentFragment;
|
|
3
|
+
remove(): void;
|
|
3
4
|
};
|
|
4
5
|
export type FragmentData = {
|
|
5
6
|
expressions: unknown[];
|
|
6
7
|
nodes: Node[];
|
|
7
8
|
strings: TemplateStringsArray;
|
|
9
|
+
values: unknown[];
|
|
8
10
|
};
|
|
9
11
|
export declare function createFragment(strings: TemplateStringsArray, expressions: unknown[]): Fragment;
|
|
12
|
+
export declare function isFragment(value: unknown): value is Fragment;
|
package/types/html.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Fragment, type FragmentData } from './fragment';
|
|
2
|
+
export declare function getFragment(nodes: Node[]): DocumentFragment;
|
|
2
3
|
export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Fragment;
|
|
3
4
|
export declare function parse(data: FragmentData): string;
|