@oscarpalmer/abydon 0.13.0 → 0.14.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/src/node/value.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
- import type {Key} from '@oscarpalmer/atoms/models';
3
2
  import {getString} from '@oscarpalmer/atoms/string';
4
3
  import type {Reactive} from '@oscarpalmer/mora';
5
4
  import {isChildNode} from '@oscarpalmer/toretto/is';
@@ -8,6 +7,94 @@ import {compareArrays, isFragment} from '../helpers';
8
7
  import {createNodes, replaceNodes} from '../helpers/dom';
9
8
  import type {FragmentData, FragmentItem} from '../models';
10
9
 
10
+ //
11
+
12
+ type Identifiers = {
13
+ next: unknown[];
14
+ previous: (unknown | undefined)[];
15
+ };
16
+
17
+ type BaseItems = {
18
+ fragments: Fragment[];
19
+ templates: Fragment[];
20
+ };
21
+
22
+ type ExtendedItems = {
23
+ next: Fragment[];
24
+ } & BaseItems;
25
+
26
+ //
27
+
28
+ function addToArray(
29
+ identifiers: Identifiers,
30
+ items: ExtendedItems,
31
+ nodes: ChildNode[],
32
+ added: boolean,
33
+ ): void {
34
+ let position = nodes[0];
35
+
36
+ const before =
37
+ added && !identifiers.previous.includes(items.templates[0].identifier);
38
+
39
+ const next = items.next.flatMap(fragment =>
40
+ fragment.get().flatMap(node => ({
41
+ identifier: fragment.identifier,
42
+ value: node,
43
+ })),
44
+ );
45
+
46
+ const {length} = next;
47
+
48
+ for (let index = 0; index < length; index += 1) {
49
+ const node = next[index];
50
+
51
+ if (!(added && identifiers.previous.includes(node.identifier))) {
52
+ if (index === 0 && before) {
53
+ position.before(node.value);
54
+ } else {
55
+ position.after(node.value);
56
+ }
57
+ }
58
+
59
+ position = node.value;
60
+ }
61
+ }
62
+
63
+ function handleArray(
64
+ identifiers: Identifiers,
65
+ items: BaseItems,
66
+ nodes: ChildNode[],
67
+ ): Partial<FragmentItem> {
68
+ const next = items.templates.map(
69
+ template =>
70
+ items.fragments?.find(
71
+ fragment => fragment.identifier === template.identifier,
72
+ ) ?? template,
73
+ );
74
+
75
+ const comparison = compareArrays(items.fragments ?? [], items.templates);
76
+
77
+ if (comparison !== 'removed') {
78
+ addToArray(identifiers, {...items, next}, nodes, comparison === 'added');
79
+ }
80
+
81
+ const toRemove =
82
+ items.fragments?.filter(
83
+ fragment => !identifiers.next.includes(fragment.identifier),
84
+ ) ?? [];
85
+
86
+ const {length} = toRemove;
87
+
88
+ for (let index = 0; index < length; index += 1) {
89
+ toRemove[index].remove();
90
+ }
91
+
92
+ return {
93
+ fragments: next,
94
+ nodes: next.flatMap(fragment => fragment.get()),
95
+ };
96
+ }
97
+
11
98
  function removeFragments(fragments: Fragment[] | undefined): void {
12
99
  if (fragments != null) {
13
100
  const {length} = fragments;
@@ -19,15 +106,13 @@ function removeFragments(fragments: Fragment[] | undefined): void {
19
106
  }
20
107
 
21
108
  function setArray(
22
- fragments: Fragment[] | undefined,
23
- nodes: ChildNode[] | undefined,
109
+ item: FragmentItem,
24
110
  comment: Comment,
25
- text: Text,
26
111
  value: unknown[],
27
112
  ): Partial<FragmentItem> | boolean {
28
113
  if (value.length === 0) {
29
114
  return {
30
- nodes: setText(fragments, nodes, comment, text, value),
115
+ nodes: setText(item, comment, value),
31
116
  };
32
117
  }
33
118
 
@@ -35,10 +120,10 @@ function setArray(
35
120
  item => isFragment(item) && item.identifier != null,
36
121
  ) as Fragment[];
37
122
 
38
- const identifiers = templates.map(fragment => fragment.identifier) as Key[];
39
- const oldIdentifiers = fragments?.map(fragment => fragment.identifier) ?? [];
123
+ const next = templates.map(fragment => fragment.identifier) as unknown[];
124
+ const previous = item.fragments?.map(fragment => fragment.identifier) ?? [];
40
125
 
41
- if (new Set(identifiers).size !== templates.length) {
126
+ if (new Set(next).size !== templates.length) {
42
127
  templates = [];
43
128
  }
44
129
 
@@ -46,16 +131,14 @@ function setArray(
46
131
 
47
132
  if (
48
133
  noTemplates ||
49
- nodes == null ||
50
- oldIdentifiers.some(identifier => identifier == null)
134
+ item.nodes == null ||
135
+ previous.some(identifier => identifier == null)
51
136
  ) {
52
137
  return {
53
138
  fragments: noTemplates ? undefined : templates,
54
139
  nodes: setNodes(
55
- fragments,
56
- nodes,
140
+ item,
57
141
  comment,
58
- text,
59
142
  noTemplates
60
143
  ? value.flatMap(item => createNodes(item))
61
144
  : templates.flatMap(template => template.get()),
@@ -63,84 +146,35 @@ function setArray(
63
146
  };
64
147
  }
65
148
 
66
- const next = templates.map(
67
- template =>
68
- fragments?.find(
69
- fragment => fragment.identifier === template.identifier,
70
- ) ?? template,
149
+ return handleArray(
150
+ {
151
+ next,
152
+ previous,
153
+ },
154
+ {
155
+ templates,
156
+ fragments: item.fragments ?? [],
157
+ },
158
+ item.nodes,
71
159
  );
72
-
73
- const comparison = compareArrays(fragments ?? [], templates);
74
-
75
- if (comparison !== 'removed') {
76
- let position = nodes[0];
77
-
78
- const before =
79
- comparison === 'added' &&
80
- !oldIdentifiers.includes(templates[0].identifier);
81
-
82
- const items = next.flatMap(fragment =>
83
- fragment.get().flatMap(node => ({
84
- identifier: fragment.identifier,
85
- value: node,
86
- })),
87
- );
88
-
89
- const {length} = items;
90
-
91
- for (let index = 0; index < length; index += 1) {
92
- const item = items[index];
93
-
94
- if (
95
- comparison === 'dissimilar' ||
96
- !oldIdentifiers.includes(item.identifier)
97
- ) {
98
- if (index === 0 && before) {
99
- position.before(item.value);
100
- } else {
101
- position.after(item.value);
102
- }
103
- }
104
-
105
- position = item.value;
106
- }
107
- }
108
-
109
- const toRemove =
110
- fragments?.filter(
111
- fragment => !identifiers.includes(fragment.identifier as Key),
112
- ) ?? [];
113
-
114
- const {length} = toRemove;
115
-
116
- for (let index = 0; index < length; index += 1) {
117
- toRemove[index].remove();
118
- }
119
-
120
- return {
121
- fragments: next,
122
- nodes: next.flatMap(fragment => fragment.get()),
123
- };
124
160
  }
125
161
 
126
162
  function setNodes(
127
- fragments: Fragment[] | undefined,
128
- nodes: ChildNode[] | undefined,
163
+ item: FragmentItem,
129
164
  comment: Comment,
130
- text: Text,
131
165
  next: ChildNode[],
132
166
  ): ChildNode[] {
133
- if (nodes == null) {
167
+ if (item.nodes == null) {
134
168
  if (comment.parentNode != null) {
135
169
  replaceNodes([comment], next);
136
- } else if (text.parentNode != null) {
137
- replaceNodes([text], next);
170
+ } else if (item.text?.parentNode != null) {
171
+ replaceNodes([item.text], next);
138
172
  }
139
173
  } else {
140
- replaceNodes(nodes, next);
174
+ replaceNodes(item.nodes, next);
141
175
  }
142
176
 
143
- removeFragments(fragments);
177
+ removeFragments(item.fragments);
144
178
 
145
179
  return next;
146
180
  }
@@ -150,71 +184,85 @@ export function setReactiveValue(
150
184
  comment: Comment,
151
185
  reactive: Reactive<unknown>,
152
186
  ): void {
153
- const item = data.items.find(item => item.nodes.includes(comment));
154
- const text = new Text();
187
+ let item = data.items.find(item => item.nodes?.includes(comment));
188
+
189
+ item ??= {};
155
190
 
156
- let fragments: Fragment[] | undefined;
157
- let nodes: ChildNode[] | undefined;
191
+ item.text = new Text();
158
192
 
159
193
  data.mora.subscribers.add(
160
194
  reactive.subscribe(value => {
161
195
  if (Array.isArray(value)) {
162
- const result = setArray(fragments, nodes, comment, text, value);
163
-
164
- fragments = typeof result === 'boolean' ? undefined : result?.fragments;
165
-
166
- nodes =
167
- typeof result === 'boolean'
168
- ? result
169
- ? [text]
170
- : undefined
171
- : result?.nodes;
196
+ setReactiveValueForArray(item, comment, value);
172
197
  } else {
173
- const valueIsFragment = isFragment(value);
174
-
175
- fragments = valueIsFragment ? [value] : undefined;
176
-
177
- if (valueIsFragment || isChildNode(value)) {
178
- nodes = setNodes(fragments, nodes, comment, text, createNodes(value));
179
- } else {
180
- nodes = setText(fragments, nodes, comment, text, value);
181
- }
198
+ setReactiveValueForSingle(item, comment, value);
182
199
  }
183
200
 
184
- if (item != null) {
185
- item.fragments = fragments;
186
- item.nodes = [...(nodes ?? [comment])];
187
- }
201
+ item.nodes = [...(item.nodes ?? [comment])];
188
202
  }),
189
203
  );
190
204
  }
191
205
 
206
+ function setReactiveValueForArray(
207
+ item: FragmentItem,
208
+ comment: Comment,
209
+ value: unknown[],
210
+ ): void {
211
+ const result = setArray(item, comment, value);
212
+
213
+ item.fragments = typeof result === 'boolean' ? undefined : result?.fragments;
214
+
215
+ if (typeof result === 'boolean') {
216
+ item.nodes = result ? item.text == null ? [] : [item.text] : undefined;
217
+ } else {
218
+ item.nodes = result?.nodes;
219
+ }
220
+ }
221
+
222
+ function setReactiveValueForSingle(
223
+ item: FragmentItem,
224
+ comment: Comment,
225
+ value: unknown,
226
+ ): void {
227
+ const valueIsFragment = isFragment(value);
228
+
229
+ item.fragments = valueIsFragment ? [value] : undefined;
230
+
231
+ if (valueIsFragment || isChildNode(value)) {
232
+ item.nodes = setNodes(item, comment, createNodes(value));
233
+ } else {
234
+ item.nodes = setText(item, comment, value);
235
+ }
236
+ }
237
+
192
238
  function setText(
193
- fragments: Fragment[] | undefined,
194
- nodes: ChildNode[] | undefined,
239
+ item: FragmentItem,
195
240
  comment: Comment,
196
- text: Text,
197
241
  value: unknown,
198
242
  ): ChildNode[] | undefined {
199
243
  const isNullable = isNullableOrWhitespace(value);
200
244
 
201
- text.textContent = isNullable ? '' : getString(value);
245
+ if (item.text != null) {
246
+ item.text.textContent = isNullable ? '' : getString(value);
247
+ }
202
248
 
203
249
  let result = false;
204
250
 
205
- if (nodes != null) {
206
- replaceNodes(nodes, [isNullable ? comment : text]);
251
+ if (item.nodes != null) {
252
+ replaceNodes(item.nodes, isNullable ? [comment] : item.text == null ? [] : [item.text]);
207
253
 
208
254
  result = !isNullable;
209
255
  } else if (isNullable && comment.parentNode == null) {
210
- text.replaceWith(comment);
211
- } else if (!isNullable && text.parentNode == null) {
212
- comment.replaceWith(text);
256
+ item.text?.replaceWith(comment);
257
+ } else if (!isNullable && item?.text?.parentNode == null) {
258
+ if (item.text != null) {
259
+ comment.replaceWith(item.text);
260
+ }
213
261
 
214
262
  result = true;
215
263
  }
216
264
 
217
- removeFragments(fragments);
265
+ removeFragments(item.fragments);
218
266
 
219
- return result ? [text] : undefined;
267
+ return result ? item.text == null ? [] : [item.text] : undefined;
220
268
  }
package/src/parse.ts CHANGED
@@ -31,17 +31,24 @@ function handleExpression(
31
31
  }
32
32
 
33
33
  export function parse(data: FragmentData): string {
34
+ if (data.template != null) {
35
+ return data.template;
36
+ }
37
+
34
38
  const {length} = data.strings;
35
39
 
36
- let template = '';
40
+ data.template = '';
37
41
 
38
42
  for (let index = 0; index < length; index += 1) {
39
- template += handleExpression(
43
+ data.template += handleExpression(
40
44
  data,
41
45
  data.strings[index],
42
46
  data.expressions[index],
43
47
  );
44
48
  }
45
49
 
46
- return template;
50
+ data.expressions = [];
51
+ data.strings = [] as never;
52
+
53
+ return data.template;
47
54
  }
@@ -0,0 +1,9 @@
1
+ export declare const ABORT_CONTROLLERS: WeakMap<HTMLOrSVGElement, AbortController>;
2
+ export declare const ATTRIBUTE_CLASS_PREFIX_LENGTH = 6;
3
+ export declare const EXPRESSION_ATTRIBUTE_CLASS: RegExp;
4
+ export declare const EXPRESSION_ATTRIBUTE_STYLE_FULL: RegExp;
5
+ export declare const EXPRESSION_ATTRIBUTE_STYLE_PREFIX: RegExp;
6
+ export declare const EXPRESSION_COMMENT_FULL: RegExp;
7
+ export declare const EXPRESSION_COMMENT_CONTENT: RegExp;
8
+ export declare const EXPRESSION_EVENT_NAME: RegExp;
9
+ export declare const REASON_EVENT_REMOVED = "Event removed as element was removed from document by Abydon";
@@ -1,8 +1,6 @@
1
- import type { Key } from '@oscarpalmer/atoms/models';
2
1
  export declare class Fragment {
3
- private readonly $fragment;
4
- private readonly data;
5
- get identifier(): Key | undefined;
2
+ #private;
3
+ get identifier(): unknown;
6
4
  constructor(strings: TemplateStringsArray, expressions: unknown[]);
7
5
  /**
8
6
  * Appends the fragment to the given element
@@ -12,7 +10,7 @@ export declare class Fragment {
12
10
  * Gets a list of the fragment's nodes
13
11
  */
14
12
  get(): ChildNode[];
15
- identify(identifier: Key): Fragment;
13
+ identify(identifier: unknown): Fragment;
16
14
  /**
17
15
  * Removes the fragment from the DOM
18
16
  */
package/types/models.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import type { Key } from '@oscarpalmer/atoms/models';
2
1
  import type { Reactive } from '@oscarpalmer/mora';
3
2
  import type { Fragment } from './fragment';
4
3
  export type FragmentData = {
5
4
  expressions: unknown[];
6
- identifier?: Key;
5
+ identifier?: unknown;
7
6
  items: FragmentItem[];
8
7
  mora: MoraData;
9
8
  strings: TemplateStringsArray;
@@ -1,27 +0,0 @@
1
- // Generated by dts-bundle-generator v9.5.1
2
-
3
- /**
4
- * A generic key type
5
- */
6
- export type Key = number | string;
7
- export declare class Fragment {
8
- private readonly $fragment;
9
- private readonly data;
10
- get identifier(): Key | undefined;
11
- constructor(strings: TemplateStringsArray, expressions: unknown[]);
12
- /**
13
- * Appends the fragment to the given element
14
- */
15
- appendTo(element: Element): void;
16
- /**
17
- * Gets a list of the fragment's nodes
18
- */
19
- get(): ChildNode[];
20
- identify(identifier: Key): Fragment;
21
- /**
22
- * Removes the fragment from the DOM
23
- */
24
- remove(): void;
25
- }
26
-
27
- export {};
@@ -1,7 +0,0 @@
1
- // Generated by dts-bundle-generator v9.5.1
2
-
3
- export declare function createNodes(value: unknown): ChildNode[];
4
- export declare function removeNodes(nodes: ChildNode[]): void;
5
- export declare function replaceNodes(from: ChildNode[], to: ChildNode[]): void;
6
-
7
- export {};
@@ -1,29 +0,0 @@
1
- // Generated by dts-bundle-generator v9.5.1
2
-
3
- /**
4
- * A generic key type
5
- */
6
- export type Key = number | string;
7
- declare class Fragment {
8
- private readonly $fragment;
9
- private readonly data;
10
- get identifier(): Key | undefined;
11
- constructor(strings: TemplateStringsArray, expressions: unknown[]);
12
- /**
13
- * Appends the fragment to the given element
14
- */
15
- appendTo(element: Element): void;
16
- /**
17
- * Gets a list of the fragment's nodes
18
- */
19
- get(): ChildNode[];
20
- identify(identifier: Key): Fragment;
21
- /**
22
- * Removes the fragment from the DOM
23
- */
24
- remove(): void;
25
- }
26
- export declare function compareArrays(first: unknown[], second: unknown[]): "added" | "dissimilar" | "removed";
27
- export declare function isFragment(value: unknown): value is Fragment;
28
-
29
- export {};