@oscarpalmer/abydon 0.3.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 CHANGED
Binary file
package/dist/index.js CHANGED
@@ -34,22 +34,167 @@ 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
+
127
+ // src/fragment.ts
128
+ function createFragment(strings, expressions) {
129
+ const data = {
130
+ expressions,
131
+ strings,
132
+ nodes: [],
133
+ values: []
134
+ };
135
+ const instance = Object.create({
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);
150
+ }
151
+ data.nodes.splice(0, data.nodes.length);
152
+ }
153
+ });
154
+ Object.defineProperty(instance, "$fragment", {
155
+ value: true
156
+ });
157
+ return instance;
158
+ }
159
+ function isFragment(value10) {
160
+ return typeof value10 === "object" && value10 != null && "$fragment" in value10;
161
+ }
162
+
37
163
  // src/html.ts
38
- function html(strings, ...values) {
39
- const parsed = parse(strings, values);
40
- const templated = createTemplate(parsed);
41
- return getNodes(templated);
164
+ function getFragment(nodes) {
165
+ const fragment3 = document.createDocumentFragment();
166
+ fragment3.append(...nodes);
167
+ return fragment3;
42
168
  }
43
- var parse = function(parts, values) {
44
- const { length } = parts;
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
+ };
187
+ function html2(strings, ...values) {
188
+ return createFragment(strings, values);
189
+ }
190
+ function parse(data) {
191
+ const { length } = data.strings;
45
192
  let template = "";
46
193
  for (let index = 0;index < length; index += 1) {
47
- const part = parts[index];
48
- const value = values[index];
49
- template += isNullableOrWhitespace(value) ? part : `${part}${value}`;
194
+ template += handleExpression(data, data.strings[index], data.expressions[index]);
50
195
  }
51
196
  return template;
52
- };
197
+ }
53
198
  export {
54
- html
199
+ html2 as html
55
200
  };
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.3.0"
39
+ "version": "0.5.0"
39
40
  }
@@ -0,0 +1,63 @@
1
+ import {createTemplate, getNodes} from './helpers/dom';
2
+ import {getFragment, parse} from './html';
3
+ import {mapNodes} from './node';
4
+
5
+ export type Fragment = {
6
+ get(): DocumentFragment;
7
+ remove(): void;
8
+ };
9
+
10
+ export type FragmentData = {
11
+ expressions: unknown[];
12
+ nodes: Node[];
13
+ strings: TemplateStringsArray;
14
+ values: unknown[];
15
+ };
16
+
17
+ export function createFragment(
18
+ strings: TemplateStringsArray,
19
+ expressions: unknown[],
20
+ ): Fragment {
21
+ const data: FragmentData = {
22
+ expressions,
23
+ strings,
24
+ nodes: [],
25
+ values: [],
26
+ };
27
+
28
+ const instance = Object.create({
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);
37
+ }
38
+
39
+ return getFragment(data.nodes);
40
+ },
41
+ remove(): void {
42
+ const {length} = data.nodes;
43
+
44
+ for (let index = 0; index < length; index += 1) {
45
+ const node = data.nodes[index];
46
+
47
+ node.parentNode?.removeChild(node);
48
+ }
49
+
50
+ data.nodes.splice(0, data.nodes.length);
51
+ },
52
+ });
53
+
54
+ Object.defineProperty(instance, '$fragment', {
55
+ value: true,
56
+ });
57
+
58
+ return instance;
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,26 +1,62 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
- import {createTemplate, getNodes} from './helpers/dom';
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,
6
44
  ...values: unknown[]
7
- ): Node[] {
8
- const parsed = parse(strings, values);
9
- const templated = createTemplate(parsed);
10
-
11
- return getNodes(templated);
45
+ ): Fragment {
46
+ return createFragment(strings, values);
12
47
  }
13
48
 
14
- function parse(parts: TemplateStringsArray, values: unknown[]): string {
15
- const {length} = parts;
49
+ export function parse(data: FragmentData): string {
50
+ const {length} = data.strings;
16
51
 
17
52
  let template = '';
18
53
 
19
54
  for (let index = 0; index < length; index += 1) {
20
- const part = parts[index];
21
- const value = values[index];
22
-
23
- template += isNullableOrWhitespace(value) ? part : `${part}${value}`;
55
+ template += handleExpression(
56
+ data,
57
+ data.strings[index],
58
+ data.expressions[index],
59
+ );
24
60
  }
25
61
 
26
62
  return template;
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
- export * from './html';
1
+ export type {Fragment} from './fragment';
2
+ export {html} from './html';
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ export type Fragment = {
2
+ get(): DocumentFragment;
3
+ remove(): void;
4
+ };
5
+ export type FragmentData = {
6
+ expressions: unknown[];
7
+ nodes: Node[];
8
+ strings: TemplateStringsArray;
9
+ values: unknown[];
10
+ };
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 +1,4 @@
1
- export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Node[];
1
+ import { type Fragment, type FragmentData } from './fragment';
2
+ export declare function getFragment(nodes: Node[]): DocumentFragment;
3
+ export declare function html(strings: TemplateStringsArray, ...values: unknown[]): Fragment;
4
+ export declare function parse(data: FragmentData): string;
package/types/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export * from './html';
1
+ export type { Fragment } from './fragment';
2
+ export { html } from './html';
@@ -0,0 +1,2 @@
1
+ import { type FragmentData } from '../fragment';
2
+ export declare function mapNodes(data: FragmentData, nodes: Node[]): void;