@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,260 +1,260 @@
1
- import type { BindingContext } from './bindingContext.js';
2
- import type { AllBindingsAccessor } from './expressionRewriting.js';
3
- export type { AllBindingsAccessor } from './expressionRewriting.js';
4
- import { preProcessBindings } from './expressionRewriting.js';
5
- import { hasBindingValue, virtualNodeBindingValue } from './virtualElements.js';
6
- import { unwrapObservable } from './utils.js';
7
-
8
- const DATA_BIND_ATTR = 'data-bind';
9
-
10
- // ---- Binding Handler Interface ----
11
-
12
- export interface BindingHandler {
13
- init?(
14
- node: Node,
15
- valueAccessor: () => unknown,
16
- allBindings: AllBindingsAccessor,
17
- viewModel: unknown,
18
- bindingContext: BindingContext,
19
- ): void | { controlsDescendantBindings: boolean };
20
-
21
- update?(
22
- node: Node,
23
- valueAccessor: () => unknown,
24
- allBindings: AllBindingsAccessor,
25
- viewModel: unknown,
26
- bindingContext: BindingContext,
27
- ): void;
28
-
29
- preprocess?(
30
- value: string,
31
- key: string,
32
- addBinding: (key: string, val: string) => void,
33
- ): string | void;
34
-
35
- after?: string[];
36
-
37
- getNamespacedHandler?(name: string, namespace: string, namespacedName: string): BindingHandler;
38
- }
39
-
40
- // ---- Binding Handler Registry ----
41
-
42
- export const bindingHandlers: Record<string, BindingHandler> = {};
43
-
44
- let _getBindingHandlerImpl = (key: string): BindingHandler | undefined => bindingHandlers[key];
45
-
46
- export function getBindingHandler(key: string): BindingHandler | undefined {
47
- return _getBindingHandlerImpl(key);
48
- }
49
-
50
- // ---- Preprocessor Infrastructure ----
51
-
52
- export type PreprocessFn = (
53
- value: string,
54
- key: string,
55
- addBinding: (key: string, val: string) => void,
56
- ) => string | void;
57
-
58
- export type NodePreprocessFn = (node: Node) => Node[] | void;
59
-
60
- function getOrCreateHandler(bindingKeyOrHandler: string | BindingHandler): BindingHandler {
61
- if (typeof bindingKeyOrHandler === 'object') return bindingKeyOrHandler;
62
- return getBindingHandler(bindingKeyOrHandler) || (bindingHandlers[bindingKeyOrHandler] = {});
63
- }
64
-
65
- export function chainPreprocessor(
66
- handler: BindingHandler,
67
- fn: PreprocessFn,
68
- ): BindingHandler {
69
- const previous = handler.preprocess;
70
- if (previous) {
71
- handler.preprocess = function (value, key, addBinding) {
72
- const result = previous(value, key, addBinding);
73
- if (result !== undefined) {
74
- return fn(result, key, addBinding);
75
- }
76
- };
77
- } else {
78
- handler.preprocess = fn;
79
- }
80
- return handler;
81
- }
82
-
83
- export function addBindingPreprocessor(
84
- bindingKeyOrHandler: string | BindingHandler,
85
- preprocessFn: PreprocessFn,
86
- ): BindingHandler {
87
- return chainPreprocessor(getOrCreateHandler(bindingKeyOrHandler), preprocessFn);
88
- }
89
-
90
- export function addNodePreprocessor(preprocessFn: NodePreprocessFn): void {
91
- const provider = instance;
92
- const previous = provider.preprocessNode;
93
- if (previous) {
94
- provider.preprocessNode = function (node: Node): Node[] | void {
95
- const newNodes = previous.call(this, node);
96
- if (!newNodes) {
97
- return preprocessFn.call(this, node);
98
- }
99
- return newNodes;
100
- };
101
- } else {
102
- provider.preprocessNode = preprocessFn;
103
- }
104
- }
105
-
106
- export function addBindingHandlerCreator(
107
- matchRegex: RegExp,
108
- callbackFn: (match: RegExpMatchArray, bindingKey: string) => BindingHandler | undefined,
109
- ): void {
110
- const previousImpl = _getBindingHandlerImpl;
111
- _getBindingHandlerImpl = (key) => {
112
- const existing = previousImpl(key);
113
- if (existing) return existing;
114
- const match = key.match(matchRegex);
115
- return match ? callbackFn(match, key) : undefined;
116
- };
117
- }
118
-
119
- // ---- Filters Registry (injected by filters module) ----
120
-
121
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
122
- let _filters: Record<string, Function> = {};
123
-
124
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
125
- export function setFiltersRegistry(filters: Record<string, Function>): void {
126
- _filters = filters;
127
- }
128
-
129
- // ---- Compiled Binding Function Cache ----
130
-
131
- type BindingEvaluator = (context: BindingContext, element: Node) => Record<string, unknown> | null;
132
-
133
- function createBindingsStringEvaluator(
134
- bindingsString: string,
135
- options?: { valueAccessors?: boolean },
136
- ): BindingEvaluator {
137
- const rewrittenBindings = preProcessBindings(bindingsString, {
138
- valueAccessors: options?.valueAccessors,
139
- getBindingHandler,
140
- });
141
- const functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
142
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
143
- const innerFn = new Function("$context", "$element", "$unwrap", "$filters", functionBody) as
144
- (context: BindingContext, element: Node, unwrap: typeof unwrapObservable, filters: Record<string, Function>) => Record<string, unknown> | null;
145
- return (context, element) => innerFn(context, element, unwrapObservable, _filters);
146
- }
147
-
148
- function createBindingsStringEvaluatorViaCache(
149
- bindingsString: string,
150
- cache: Record<string, BindingEvaluator>,
151
- options?: { valueAccessors?: boolean },
152
- ): BindingEvaluator {
153
- const cacheKey = bindingsString + (options?.valueAccessors ? 'true' : '');
154
- return cache[cacheKey] || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
155
- }
156
-
157
- // ---- Custom Element Hook (set by componentBinding.ts to avoid circular imports) ----
158
-
159
- export type GetComponentNameForNodeFn = (node: Node) => string | undefined;
160
- export type AddBindingsForCustomElementFn = (
161
- allBindings: Record<string, unknown> | null,
162
- node: Node,
163
- bindingContext: BindingContext,
164
- valueAccessors?: boolean,
165
- ) => Record<string, unknown> | null;
166
-
167
- let _getComponentNameForNode: GetComponentNameForNodeFn | undefined;
168
- let _addBindingsForCustomElement: AddBindingsForCustomElementFn | undefined;
169
-
170
- export function setCustomElementHooks(
171
- getComponentNameForNode: GetComponentNameForNodeFn,
172
- addBindingsForCustomElement: AddBindingsForCustomElementFn,
173
- ): void {
174
- _getComponentNameForNode = getComponentNameForNode;
175
- _addBindingsForCustomElement = addBindingsForCustomElement;
176
- }
177
-
178
- // ---- Binding Provider ----
179
-
180
- export class BindingProvider {
181
- bindingCache: Record<string, BindingEvaluator> = {};
182
- preprocessNode?: NodePreprocessFn;
183
-
184
- nodeHasBindings(node: Node): boolean {
185
- switch (node.nodeType) {
186
- case 1: // Element
187
- return (node as Element).getAttribute(DATA_BIND_ATTR) != null
188
- || !!(_getComponentNameForNode && _getComponentNameForNode(node));
189
- case 8: // Comment
190
- return hasBindingValue(node);
191
- default:
192
- return false;
193
- }
194
- }
195
-
196
- getBindingsString(node: Node): string | null {
197
- switch (node.nodeType) {
198
- case 1: // Element
199
- return (node as Element).getAttribute(DATA_BIND_ATTR);
200
- case 8: // Comment
201
- return virtualNodeBindingValue(node);
202
- default:
203
- return null;
204
- }
205
- }
206
-
207
- getBindingAccessors(
208
- node: Node,
209
- bindingContext: BindingContext,
210
- ): Record<string, () => unknown> | null {
211
- const bindingsString = this.getBindingsString(node);
212
- let result = bindingsString
213
- ? this.parseBindingsString(bindingsString, bindingContext, node, { valueAccessors: true }) as Record<string, () => unknown> | null
214
- : null;
215
-
216
- if (_addBindingsForCustomElement) {
217
- result = _addBindingsForCustomElement(result, node, bindingContext, true) as typeof result;
218
- }
219
-
220
- return result;
221
- }
222
-
223
- getBindings(
224
- node: Node,
225
- bindingContext: BindingContext,
226
- ): Record<string, unknown> | null {
227
- const bindingsString = this.getBindingsString(node);
228
- let result = bindingsString
229
- ? this.parseBindingsString(bindingsString, bindingContext, node)
230
- : null;
231
-
232
- if (_addBindingsForCustomElement) {
233
- result = _addBindingsForCustomElement(result, node, bindingContext, false) as typeof result;
234
- }
235
-
236
- return result;
237
- }
238
-
239
- parseBindingsString(
240
- bindingsString: string,
241
- bindingContext: BindingContext,
242
- node: Node,
243
- options?: { valueAccessors?: boolean },
244
- ): Record<string, unknown> | null {
245
- try {
246
- const bindingFunction = createBindingsStringEvaluatorViaCache(
247
- bindingsString,
248
- this.bindingCache,
249
- options,
250
- );
251
- return bindingFunction(bindingContext, node);
252
- } catch (ex) {
253
- const err = ex as Error;
254
- err.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + err.message;
255
- throw err;
256
- }
257
- }
258
- }
259
-
260
- export const instance = new BindingProvider();
1
+ import type { BindingContext } from './bindingContext.js';
2
+ import type { AllBindingsAccessor } from './expressionRewriting.js';
3
+ export type { AllBindingsAccessor } from './expressionRewriting.js';
4
+ import { preProcessBindings } from './expressionRewriting.js';
5
+ import { hasBindingValue, virtualNodeBindingValue } from './virtualElements.js';
6
+ import { unwrapObservable } from './utils.js';
7
+
8
+ const DATA_BIND_ATTR = 'data-bind';
9
+
10
+ // ---- Binding Handler Interface ----
11
+
12
+ export interface BindingHandler {
13
+ init?(
14
+ node: Node,
15
+ valueAccessor: () => unknown,
16
+ allBindings: AllBindingsAccessor,
17
+ viewModel: unknown,
18
+ bindingContext: BindingContext,
19
+ ): void | { controlsDescendantBindings: boolean };
20
+
21
+ update?(
22
+ node: Node,
23
+ valueAccessor: () => unknown,
24
+ allBindings: AllBindingsAccessor,
25
+ viewModel: unknown,
26
+ bindingContext: BindingContext,
27
+ ): void;
28
+
29
+ preprocess?(
30
+ value: string,
31
+ key: string,
32
+ addBinding: (key: string, val: string) => void,
33
+ ): string | void;
34
+
35
+ after?: string[];
36
+
37
+ getNamespacedHandler?(name: string, namespace: string, namespacedName: string): BindingHandler;
38
+ }
39
+
40
+ // ---- Binding Handler Registry ----
41
+
42
+ export const bindingHandlers: Record<string, BindingHandler> = {};
43
+
44
+ let _getBindingHandlerImpl = (key: string): BindingHandler | undefined => bindingHandlers[key];
45
+
46
+ export function getBindingHandler(key: string): BindingHandler | undefined {
47
+ return _getBindingHandlerImpl(key);
48
+ }
49
+
50
+ // ---- Preprocessor Infrastructure ----
51
+
52
+ export type PreprocessFn = (
53
+ value: string,
54
+ key: string,
55
+ addBinding: (key: string, val: string) => void,
56
+ ) => string | void;
57
+
58
+ export type NodePreprocessFn = (node: Node) => Node[] | void;
59
+
60
+ function getOrCreateHandler(bindingKeyOrHandler: string | BindingHandler): BindingHandler {
61
+ if (typeof bindingKeyOrHandler === 'object') return bindingKeyOrHandler;
62
+ return getBindingHandler(bindingKeyOrHandler) || (bindingHandlers[bindingKeyOrHandler] = {});
63
+ }
64
+
65
+ export function chainPreprocessor(
66
+ handler: BindingHandler,
67
+ fn: PreprocessFn,
68
+ ): BindingHandler {
69
+ const previous = handler.preprocess;
70
+ if (previous) {
71
+ handler.preprocess = function (value, key, addBinding) {
72
+ const result = previous(value, key, addBinding);
73
+ if (result !== undefined) {
74
+ return fn(result, key, addBinding);
75
+ }
76
+ };
77
+ } else {
78
+ handler.preprocess = fn;
79
+ }
80
+ return handler;
81
+ }
82
+
83
+ export function addBindingPreprocessor(
84
+ bindingKeyOrHandler: string | BindingHandler,
85
+ preprocessFn: PreprocessFn,
86
+ ): BindingHandler {
87
+ return chainPreprocessor(getOrCreateHandler(bindingKeyOrHandler), preprocessFn);
88
+ }
89
+
90
+ export function addNodePreprocessor(preprocessFn: NodePreprocessFn): void {
91
+ const provider = instance;
92
+ const previous = provider.preprocessNode;
93
+ if (previous) {
94
+ provider.preprocessNode = function (node: Node): Node[] | void {
95
+ const newNodes = previous.call(this, node);
96
+ if (!newNodes) {
97
+ return preprocessFn.call(this, node);
98
+ }
99
+ return newNodes;
100
+ };
101
+ } else {
102
+ provider.preprocessNode = preprocessFn;
103
+ }
104
+ }
105
+
106
+ export function addBindingHandlerCreator(
107
+ matchRegex: RegExp,
108
+ callbackFn: (match: RegExpMatchArray, bindingKey: string) => BindingHandler | undefined,
109
+ ): void {
110
+ const previousImpl = _getBindingHandlerImpl;
111
+ _getBindingHandlerImpl = (key) => {
112
+ const existing = previousImpl(key);
113
+ if (existing) return existing;
114
+ const match = key.match(matchRegex);
115
+ return match ? callbackFn(match, key) : undefined;
116
+ };
117
+ }
118
+
119
+ // ---- Filters Registry (injected by filters module) ----
120
+
121
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
122
+ let _filters: Record<string, Function> = {};
123
+
124
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
125
+ export function setFiltersRegistry(filters: Record<string, Function>): void {
126
+ _filters = filters;
127
+ }
128
+
129
+ // ---- Compiled Binding Function Cache ----
130
+
131
+ type BindingEvaluator = (context: BindingContext, element: Node) => Record<string, unknown> | null;
132
+
133
+ function createBindingsStringEvaluator(
134
+ bindingsString: string,
135
+ options?: { valueAccessors?: boolean },
136
+ ): BindingEvaluator {
137
+ const rewrittenBindings = preProcessBindings(bindingsString, {
138
+ valueAccessors: options?.valueAccessors,
139
+ getBindingHandler,
140
+ });
141
+ const functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
142
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
143
+ const innerFn = new Function("$context", "$element", "$unwrap", "$filters", functionBody) as
144
+ (context: BindingContext, element: Node, unwrap: typeof unwrapObservable, filters: Record<string, Function>) => Record<string, unknown> | null;
145
+ return (context, element) => innerFn(context, element, unwrapObservable, _filters);
146
+ }
147
+
148
+ function createBindingsStringEvaluatorViaCache(
149
+ bindingsString: string,
150
+ cache: Record<string, BindingEvaluator>,
151
+ options?: { valueAccessors?: boolean },
152
+ ): BindingEvaluator {
153
+ const cacheKey = bindingsString + (options?.valueAccessors ? 'true' : '');
154
+ return cache[cacheKey] || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
155
+ }
156
+
157
+ // ---- Custom Element Hook (set by componentBinding.ts to avoid circular imports) ----
158
+
159
+ export type GetComponentNameForNodeFn = (node: Node) => string | undefined;
160
+ export type AddBindingsForCustomElementFn = (
161
+ allBindings: Record<string, unknown> | null,
162
+ node: Node,
163
+ bindingContext: BindingContext,
164
+ valueAccessors?: boolean,
165
+ ) => Record<string, unknown> | null;
166
+
167
+ let _getComponentNameForNode: GetComponentNameForNodeFn | undefined;
168
+ let _addBindingsForCustomElement: AddBindingsForCustomElementFn | undefined;
169
+
170
+ export function setCustomElementHooks(
171
+ getComponentNameForNode: GetComponentNameForNodeFn,
172
+ addBindingsForCustomElement: AddBindingsForCustomElementFn,
173
+ ): void {
174
+ _getComponentNameForNode = getComponentNameForNode;
175
+ _addBindingsForCustomElement = addBindingsForCustomElement;
176
+ }
177
+
178
+ // ---- Binding Provider ----
179
+
180
+ export class BindingProvider {
181
+ bindingCache: Record<string, BindingEvaluator> = {};
182
+ preprocessNode?: NodePreprocessFn;
183
+
184
+ nodeHasBindings(node: Node): boolean {
185
+ switch (node.nodeType) {
186
+ case 1: // Element
187
+ return (node as Element).getAttribute(DATA_BIND_ATTR) != null
188
+ || !!(_getComponentNameForNode && _getComponentNameForNode(node));
189
+ case 8: // Comment
190
+ return hasBindingValue(node);
191
+ default:
192
+ return false;
193
+ }
194
+ }
195
+
196
+ getBindingsString(node: Node): string | null {
197
+ switch (node.nodeType) {
198
+ case 1: // Element
199
+ return (node as Element).getAttribute(DATA_BIND_ATTR);
200
+ case 8: // Comment
201
+ return virtualNodeBindingValue(node);
202
+ default:
203
+ return null;
204
+ }
205
+ }
206
+
207
+ getBindingAccessors(
208
+ node: Node,
209
+ bindingContext: BindingContext,
210
+ ): Record<string, () => unknown> | null {
211
+ const bindingsString = this.getBindingsString(node);
212
+ let result = bindingsString
213
+ ? this.parseBindingsString(bindingsString, bindingContext, node, { valueAccessors: true }) as Record<string, () => unknown> | null
214
+ : null;
215
+
216
+ if (_addBindingsForCustomElement) {
217
+ result = _addBindingsForCustomElement(result, node, bindingContext, true) as typeof result;
218
+ }
219
+
220
+ return result;
221
+ }
222
+
223
+ getBindings(
224
+ node: Node,
225
+ bindingContext: BindingContext,
226
+ ): Record<string, unknown> | null {
227
+ const bindingsString = this.getBindingsString(node);
228
+ let result = bindingsString
229
+ ? this.parseBindingsString(bindingsString, bindingContext, node)
230
+ : null;
231
+
232
+ if (_addBindingsForCustomElement) {
233
+ result = _addBindingsForCustomElement(result, node, bindingContext, false) as typeof result;
234
+ }
235
+
236
+ return result;
237
+ }
238
+
239
+ parseBindingsString(
240
+ bindingsString: string,
241
+ bindingContext: BindingContext,
242
+ node: Node,
243
+ options?: { valueAccessors?: boolean },
244
+ ): Record<string, unknown> | null {
245
+ try {
246
+ const bindingFunction = createBindingsStringEvaluatorViaCache(
247
+ bindingsString,
248
+ this.bindingCache,
249
+ options,
250
+ );
251
+ return bindingFunction(bindingContext, node);
252
+ } catch (ex) {
253
+ const err = ex as Error;
254
+ err.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + err.message;
255
+ throw err;
256
+ }
257
+ }
258
+ }
259
+
260
+ export const instance = new BindingProvider();