@thomas-siegfried/tapout 0.0.1 → 0.0.3

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.
Files changed (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1207 -1205
  3. package/decorator-config.md +220 -0
  4. package/dist/wireParams.d.ts.map +1 -1
  5. package/dist/wireParams.js +27 -4
  6. package/dist/wireParams.js.map +1 -1
  7. package/llms.txt +360 -0
  8. package/package.json +57 -55
  9. package/src/applyBindings.ts +372 -372
  10. package/src/arrayToDomMapping.ts +300 -300
  11. package/src/attributeInterpolationMarkup.ts +91 -91
  12. package/src/bindingContext.ts +207 -207
  13. package/src/bindingEvent.ts +198 -198
  14. package/src/bindingProvider.ts +260 -260
  15. package/src/bindings.ts +963 -963
  16. package/src/compareArrays.ts +122 -122
  17. package/src/componentBinding.ts +318 -318
  18. package/src/componentDecorator.ts +62 -62
  19. package/src/components.ts +367 -367
  20. package/src/computed.ts +439 -439
  21. package/src/configure.ts +52 -52
  22. package/src/controlFlowBindings.ts +206 -206
  23. package/src/core.ts +60 -60
  24. package/src/decorators.ts +407 -407
  25. package/src/dependencyDetection.ts +76 -76
  26. package/src/disposable.ts +36 -36
  27. package/src/domData.ts +42 -42
  28. package/src/domNodeDisposal.ts +94 -94
  29. package/src/effects.ts +29 -29
  30. package/src/event.ts +173 -173
  31. package/src/expressionRewriting.ts +219 -219
  32. package/src/extenders.ts +102 -102
  33. package/src/filters.ts +91 -91
  34. package/src/index.ts +150 -150
  35. package/src/interpolationMarkup.ts +130 -130
  36. package/src/memoization.ts +71 -71
  37. package/src/namespacedBindings.ts +132 -132
  38. package/src/observable.ts +48 -48
  39. package/src/observableArray.ts +397 -397
  40. package/src/options.ts +25 -25
  41. package/src/selectExtensions.ts +68 -68
  42. package/src/slotBinding.ts +84 -84
  43. package/src/subscribable.ts +266 -266
  44. package/src/tasks.ts +79 -79
  45. package/src/templateEngine.ts +108 -108
  46. package/src/templateRendering.ts +399 -399
  47. package/src/templateRewriting.ts +94 -94
  48. package/src/templateSources.ts +134 -134
  49. package/src/utils.ts +123 -123
  50. package/src/utilsDom.ts +87 -87
  51. package/src/virtualElements.ts +153 -153
  52. package/src/wireParams.ts +69 -49
@@ -1,153 +1,153 @@
1
- import { domDataGet, domDataSet } from './domData.js';
2
- import { removeNode } from './domNodeDisposal.js';
3
-
4
- const startCommentRegex = /^\s*tap(?:\s+([\s\S]+))?\s*$/;
5
- const endCommentRegex = /^\s*\/tap\s*$/;
6
- const matchedEndCommentDataKey = '__tap_matchedEndComment__';
7
-
8
- export const allowedVirtualElementBindings: Record<string, boolean> = {};
9
-
10
- export function isStartComment(node: Node): boolean {
11
- return node.nodeType === 8 && startCommentRegex.test(node.nodeValue || '');
12
- }
13
-
14
- function isEndComment(node: Node): boolean {
15
- return node.nodeType === 8 && endCommentRegex.test(node.nodeValue || '');
16
- }
17
-
18
- function isUnmatchedEndComment(node: Node): boolean {
19
- return isEndComment(node) && !domDataGet(node, matchedEndCommentDataKey);
20
- }
21
-
22
- function getVirtualChildren(startComment: Node, allowUnbalanced?: boolean): Node[] | null {
23
- let currentNode = startComment.nextSibling;
24
- let depth = 1;
25
- const children: Node[] = [];
26
- while (currentNode) {
27
- if (isEndComment(currentNode)) {
28
- domDataSet(currentNode, matchedEndCommentDataKey, true);
29
- depth--;
30
- if (depth === 0) return children;
31
- }
32
- children.push(currentNode);
33
- if (isStartComment(currentNode)) depth++;
34
- currentNode = currentNode.nextSibling;
35
- }
36
- if (!allowUnbalanced) {
37
- throw new Error('Cannot find closing comment tag to match: ' + startComment.nodeValue);
38
- }
39
- return null;
40
- }
41
-
42
- function getMatchingEndComment(startComment: Node, allowUnbalanced?: boolean): Node | null {
43
- const allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
44
- if (allVirtualChildren) {
45
- if (allVirtualChildren.length > 0) {
46
- return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
47
- }
48
- return startComment.nextSibling;
49
- }
50
- return null;
51
- }
52
-
53
- export function virtualChildNodes(node: Node): Node[] | NodeListOf<ChildNode> {
54
- return isStartComment(node) ? getVirtualChildren(node)! : node.childNodes;
55
- }
56
-
57
- export function virtualEmptyNode(node: Node): void {
58
- if (!isStartComment(node)) {
59
- while (node.firstChild) {
60
- removeNode(node.firstChild);
61
- }
62
- } else {
63
- const children = getVirtualChildren(node)!;
64
- for (let i = 0; i < children.length; i++) {
65
- removeNode(children[i]);
66
- }
67
- }
68
- }
69
-
70
- export function virtualSetChildren(node: Node, childNodes: Node[]): void {
71
- if (!isStartComment(node)) {
72
- while (node.firstChild) {
73
- removeNode(node.firstChild);
74
- }
75
- for (let i = 0; i < childNodes.length; i++) {
76
- node.appendChild(childNodes[i]);
77
- }
78
- } else {
79
- virtualEmptyNode(node);
80
- const endCommentNode = node.nextSibling!;
81
- for (let i = 0; i < childNodes.length; i++) {
82
- endCommentNode.parentNode!.insertBefore(childNodes[i], endCommentNode);
83
- }
84
- }
85
- }
86
-
87
- export function virtualPrepend(containerNode: Node, nodeToPrepend: Node): void {
88
- let insertBeforeNode: Node | null;
89
- let parent: Node;
90
-
91
- if (isStartComment(containerNode)) {
92
- insertBeforeNode = containerNode.nextSibling;
93
- parent = containerNode.parentNode!;
94
- } else {
95
- insertBeforeNode = containerNode.firstChild;
96
- parent = containerNode;
97
- }
98
-
99
- if (!insertBeforeNode) {
100
- parent.appendChild(nodeToPrepend);
101
- } else {
102
- parent.insertBefore(nodeToPrepend, insertBeforeNode);
103
- }
104
- }
105
-
106
- export function virtualInsertAfter(containerNode: Node, nodeToInsert: Node, insertAfterNode: Node | null): void {
107
- if (!insertAfterNode) {
108
- virtualPrepend(containerNode, nodeToInsert);
109
- return;
110
- }
111
-
112
- const insertBeforeNode = insertAfterNode.nextSibling;
113
- const parent = isStartComment(containerNode) ? containerNode.parentNode! : containerNode;
114
-
115
- if (!insertBeforeNode) {
116
- parent.appendChild(nodeToInsert);
117
- } else {
118
- parent.insertBefore(nodeToInsert, insertBeforeNode);
119
- }
120
- }
121
-
122
- export function virtualFirstChild(node: Node): Node | null {
123
- if (!isStartComment(node)) {
124
- const first = node.firstChild;
125
- if (first && isEndComment(first)) {
126
- return first.nextSibling;
127
- }
128
- return first;
129
- }
130
- if (!node.nextSibling || isEndComment(node.nextSibling)) {
131
- return null;
132
- }
133
- return node.nextSibling;
134
- }
135
-
136
- export function virtualNextSibling(node: Node): Node | null {
137
- if (isStartComment(node)) {
138
- node = getMatchingEndComment(node)!;
139
- }
140
- if (node.nextSibling && isEndComment(node.nextSibling)) {
141
- return null;
142
- }
143
- return node.nextSibling;
144
- }
145
-
146
- export function hasBindingValue(node: Node): boolean {
147
- return isStartComment(node);
148
- }
149
-
150
- export function virtualNodeBindingValue(node: Node): string | null {
151
- const match = (node.nodeValue || '').match(startCommentRegex);
152
- return match ? match[1]?.trim() ?? null : null;
153
- }
1
+ import { domDataGet, domDataSet } from './domData.js';
2
+ import { removeNode } from './domNodeDisposal.js';
3
+
4
+ const startCommentRegex = /^\s*tap(?:\s+([\s\S]+))?\s*$/;
5
+ const endCommentRegex = /^\s*\/tap\s*$/;
6
+ const matchedEndCommentDataKey = '__tap_matchedEndComment__';
7
+
8
+ export const allowedVirtualElementBindings: Record<string, boolean> = {};
9
+
10
+ export function isStartComment(node: Node): boolean {
11
+ return node.nodeType === 8 && startCommentRegex.test(node.nodeValue || '');
12
+ }
13
+
14
+ function isEndComment(node: Node): boolean {
15
+ return node.nodeType === 8 && endCommentRegex.test(node.nodeValue || '');
16
+ }
17
+
18
+ function isUnmatchedEndComment(node: Node): boolean {
19
+ return isEndComment(node) && !domDataGet(node, matchedEndCommentDataKey);
20
+ }
21
+
22
+ function getVirtualChildren(startComment: Node, allowUnbalanced?: boolean): Node[] | null {
23
+ let currentNode = startComment.nextSibling;
24
+ let depth = 1;
25
+ const children: Node[] = [];
26
+ while (currentNode) {
27
+ if (isEndComment(currentNode)) {
28
+ domDataSet(currentNode, matchedEndCommentDataKey, true);
29
+ depth--;
30
+ if (depth === 0) return children;
31
+ }
32
+ children.push(currentNode);
33
+ if (isStartComment(currentNode)) depth++;
34
+ currentNode = currentNode.nextSibling;
35
+ }
36
+ if (!allowUnbalanced) {
37
+ throw new Error('Cannot find closing comment tag to match: ' + startComment.nodeValue);
38
+ }
39
+ return null;
40
+ }
41
+
42
+ function getMatchingEndComment(startComment: Node, allowUnbalanced?: boolean): Node | null {
43
+ const allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
44
+ if (allVirtualChildren) {
45
+ if (allVirtualChildren.length > 0) {
46
+ return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
47
+ }
48
+ return startComment.nextSibling;
49
+ }
50
+ return null;
51
+ }
52
+
53
+ export function virtualChildNodes(node: Node): Node[] | NodeListOf<ChildNode> {
54
+ return isStartComment(node) ? getVirtualChildren(node)! : node.childNodes;
55
+ }
56
+
57
+ export function virtualEmptyNode(node: Node): void {
58
+ if (!isStartComment(node)) {
59
+ while (node.firstChild) {
60
+ removeNode(node.firstChild);
61
+ }
62
+ } else {
63
+ const children = getVirtualChildren(node)!;
64
+ for (let i = 0; i < children.length; i++) {
65
+ removeNode(children[i]);
66
+ }
67
+ }
68
+ }
69
+
70
+ export function virtualSetChildren(node: Node, childNodes: Node[]): void {
71
+ if (!isStartComment(node)) {
72
+ while (node.firstChild) {
73
+ removeNode(node.firstChild);
74
+ }
75
+ for (let i = 0; i < childNodes.length; i++) {
76
+ node.appendChild(childNodes[i]);
77
+ }
78
+ } else {
79
+ virtualEmptyNode(node);
80
+ const endCommentNode = node.nextSibling!;
81
+ for (let i = 0; i < childNodes.length; i++) {
82
+ endCommentNode.parentNode!.insertBefore(childNodes[i], endCommentNode);
83
+ }
84
+ }
85
+ }
86
+
87
+ export function virtualPrepend(containerNode: Node, nodeToPrepend: Node): void {
88
+ let insertBeforeNode: Node | null;
89
+ let parent: Node;
90
+
91
+ if (isStartComment(containerNode)) {
92
+ insertBeforeNode = containerNode.nextSibling;
93
+ parent = containerNode.parentNode!;
94
+ } else {
95
+ insertBeforeNode = containerNode.firstChild;
96
+ parent = containerNode;
97
+ }
98
+
99
+ if (!insertBeforeNode) {
100
+ parent.appendChild(nodeToPrepend);
101
+ } else {
102
+ parent.insertBefore(nodeToPrepend, insertBeforeNode);
103
+ }
104
+ }
105
+
106
+ export function virtualInsertAfter(containerNode: Node, nodeToInsert: Node, insertAfterNode: Node | null): void {
107
+ if (!insertAfterNode) {
108
+ virtualPrepend(containerNode, nodeToInsert);
109
+ return;
110
+ }
111
+
112
+ const insertBeforeNode = insertAfterNode.nextSibling;
113
+ const parent = isStartComment(containerNode) ? containerNode.parentNode! : containerNode;
114
+
115
+ if (!insertBeforeNode) {
116
+ parent.appendChild(nodeToInsert);
117
+ } else {
118
+ parent.insertBefore(nodeToInsert, insertBeforeNode);
119
+ }
120
+ }
121
+
122
+ export function virtualFirstChild(node: Node): Node | null {
123
+ if (!isStartComment(node)) {
124
+ const first = node.firstChild;
125
+ if (first && isEndComment(first)) {
126
+ return first.nextSibling;
127
+ }
128
+ return first;
129
+ }
130
+ if (!node.nextSibling || isEndComment(node.nextSibling)) {
131
+ return null;
132
+ }
133
+ return node.nextSibling;
134
+ }
135
+
136
+ export function virtualNextSibling(node: Node): Node | null {
137
+ if (isStartComment(node)) {
138
+ node = getMatchingEndComment(node)!;
139
+ }
140
+ if (node.nextSibling && isEndComment(node.nextSibling)) {
141
+ return null;
142
+ }
143
+ return node.nextSibling;
144
+ }
145
+
146
+ export function hasBindingValue(node: Node): boolean {
147
+ return isStartComment(node);
148
+ }
149
+
150
+ export function virtualNodeBindingValue(node: Node): string | null {
151
+ const match = (node.nodeValue || '').match(startCommentRegex);
152
+ return match ? match[1]?.trim() ?? null : null;
153
+ }
package/src/wireParams.ts CHANGED
@@ -1,49 +1,69 @@
1
- import { Observable } from './observable.js';
2
- import { Computed } from './computed.js';
3
- import { isSubscribable } from './subscribable.js';
4
- import type { Subscription } from './subscribable.js';
5
- import { getObservable, replaceObservable } from './decorators.js';
6
- import { addDisposeCallback } from './domNodeDisposal.js';
7
-
8
- const SKIP_KEYS = new Set(['$raw']);
9
-
10
- export interface WireParamsResult {
11
- subscriptions: Subscription<unknown>[];
12
- }
13
-
14
- export function wireParams(
15
- instance: object,
16
- params: Record<string, unknown>,
17
- element?: Node,
18
- ): WireParamsResult {
19
- const subscriptions: Subscription<unknown>[] = [];
20
-
21
- for (const key of Object.keys(params)) {
22
- if (SKIP_KEYS.has(key)) continue;
23
-
24
- const paramValue = params[key];
25
- const childObs = getObservable(instance, key);
26
- const childIsReactive = childObs !== undefined && isSubscribable(childObs);
27
-
28
- if (paramValue instanceof Observable) {
29
- if (childIsReactive) {
30
- replaceObservable(instance, key, paramValue);
31
- } else {
32
- (instance as Record<string, unknown>)[key] = paramValue.get();
33
- }
34
- } else if (paramValue instanceof Computed) {
35
- (instance as Record<string, unknown>)[key] = paramValue.get();
36
- const sub = paramValue.subscribe((newValue: unknown) => {
37
- (instance as Record<string, unknown>)[key] = newValue;
38
- });
39
- subscriptions.push(sub);
40
- if (element) {
41
- addDisposeCallback(element, () => sub.dispose());
42
- }
43
- } else {
44
- (instance as Record<string, unknown>)[key] = paramValue;
45
- }
46
- }
47
-
48
- return { subscriptions };
49
- }
1
+ import { Observable } from './observable.js';
2
+ import { Computed } from './computed.js';
3
+ import { isSubscribable } from './subscribable.js';
4
+ import type { Subscription } from './subscribable.js';
5
+ import { getObservable, replaceObservable } from './decorators.js';
6
+ import { addDisposeCallback } from './domNodeDisposal.js';
7
+
8
+ const SKIP_KEYS = new Set(['$raw']);
9
+
10
+ function getWritableChildTarget(instance: object, key: string): Observable<unknown> | Computed<unknown> | undefined {
11
+ const decorated = getObservable(instance, key);
12
+ if (decorated instanceof Observable) return decorated;
13
+ if (decorated instanceof Computed && decorated.hasWriteFunction) return decorated;
14
+
15
+ const directValue = (instance as Record<string, unknown>)[key];
16
+ if (directValue instanceof Observable) return directValue;
17
+ if (directValue instanceof Computed && directValue.hasWriteFunction) return directValue;
18
+
19
+ return undefined;
20
+ }
21
+
22
+ export interface WireParamsResult {
23
+ subscriptions: Subscription<unknown>[];
24
+ }
25
+
26
+ export function wireParams(
27
+ instance: object,
28
+ params: Record<string, unknown>,
29
+ element?: Node,
30
+ ): WireParamsResult {
31
+ const subscriptions: Subscription<unknown>[] = [];
32
+
33
+ for (const key of Object.keys(params)) {
34
+ if (SKIP_KEYS.has(key)) continue;
35
+
36
+ const paramValue = params[key];
37
+ const childTarget = getWritableChildTarget(instance, key);
38
+ const childIsReactive = childTarget !== undefined && isSubscribable(childTarget);
39
+
40
+ if (paramValue instanceof Observable) {
41
+ if (childIsReactive) {
42
+ replaceObservable(instance, key, paramValue);
43
+ } else {
44
+ (instance as Record<string, unknown>)[key] = paramValue.get();
45
+ }
46
+ } else if (paramValue instanceof Computed) {
47
+ if (childTarget) {
48
+ childTarget.set(paramValue.get());
49
+ } else {
50
+ (instance as Record<string, unknown>)[key] = paramValue.get();
51
+ }
52
+ const sub = paramValue.subscribe((newValue: unknown) => {
53
+ if (childTarget) {
54
+ childTarget.set(newValue);
55
+ } else {
56
+ (instance as Record<string, unknown>)[key] = newValue;
57
+ }
58
+ });
59
+ subscriptions.push(sub);
60
+ if (element) {
61
+ addDisposeCallback(element, () => sub.dispose());
62
+ }
63
+ } else {
64
+ (instance as Record<string, unknown>)[key] = paramValue;
65
+ }
66
+ }
67
+
68
+ return { subscriptions };
69
+ }