@thomas-siegfried/tapout 0.0.1 → 0.0.2

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 (47) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1205 -1205
  3. package/package.json +55 -55
  4. package/src/applyBindings.ts +372 -372
  5. package/src/arrayToDomMapping.ts +300 -300
  6. package/src/attributeInterpolationMarkup.ts +91 -91
  7. package/src/bindingContext.ts +207 -207
  8. package/src/bindingEvent.ts +198 -198
  9. package/src/bindingProvider.ts +260 -260
  10. package/src/bindings.ts +963 -963
  11. package/src/compareArrays.ts +122 -122
  12. package/src/componentBinding.ts +318 -318
  13. package/src/componentDecorator.ts +62 -62
  14. package/src/components.ts +367 -367
  15. package/src/computed.ts +439 -439
  16. package/src/configure.ts +52 -52
  17. package/src/controlFlowBindings.ts +206 -206
  18. package/src/core.ts +60 -60
  19. package/src/decorators.ts +407 -407
  20. package/src/dependencyDetection.ts +76 -76
  21. package/src/disposable.ts +36 -36
  22. package/src/domData.ts +42 -42
  23. package/src/domNodeDisposal.ts +94 -94
  24. package/src/effects.ts +29 -29
  25. package/src/event.ts +173 -173
  26. package/src/expressionRewriting.ts +219 -219
  27. package/src/extenders.ts +102 -102
  28. package/src/filters.ts +91 -91
  29. package/src/index.ts +150 -150
  30. package/src/interpolationMarkup.ts +130 -130
  31. package/src/memoization.ts +71 -71
  32. package/src/namespacedBindings.ts +132 -132
  33. package/src/observable.ts +48 -48
  34. package/src/observableArray.ts +397 -397
  35. package/src/options.ts +25 -25
  36. package/src/selectExtensions.ts +68 -68
  37. package/src/slotBinding.ts +84 -84
  38. package/src/subscribable.ts +266 -266
  39. package/src/tasks.ts +79 -79
  40. package/src/templateEngine.ts +108 -108
  41. package/src/templateRendering.ts +399 -399
  42. package/src/templateRewriting.ts +94 -94
  43. package/src/templateSources.ts +134 -134
  44. package/src/utils.ts +123 -123
  45. package/src/utilsDom.ts +87 -87
  46. package/src/virtualElements.ts +153 -153
  47. package/src/wireParams.ts +49 -49
@@ -1,76 +1,76 @@
1
- import { type Subscribable, isSubscribable } from './subscribable.js';
2
-
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- variance: detection is type-agnostic
4
- type AnySubscribable = Subscribable<any>;
5
-
6
- export interface TrackingFrame {
7
- callback: (subscribable: AnySubscribable, id: number) => void;
8
- computed?: {
9
- getDependenciesCount(): number;
10
- getDependencies(): AnySubscribable[];
11
- };
12
- isInitial?: boolean;
13
- }
14
-
15
- let lastId = 0;
16
- const outerFrames: Array<TrackingFrame | undefined> = [];
17
- let currentFrame: TrackingFrame | undefined;
18
-
19
- export function getId(): number {
20
- return ++lastId;
21
- }
22
-
23
- export function begin(frame?: TrackingFrame): void {
24
- outerFrames.push(currentFrame);
25
- currentFrame = frame;
26
- }
27
-
28
- export function end(): void {
29
- currentFrame = outerFrames.pop();
30
- }
31
-
32
- export function registerDependency(subscribable: AnySubscribable): void {
33
- if (currentFrame) {
34
- if (!isSubscribable(subscribable)) {
35
- throw new Error('Only subscribable things can act as dependencies');
36
- }
37
- currentFrame.callback(
38
- subscribable,
39
- subscribable._id || (subscribable._id = getId()),
40
- );
41
- }
42
- }
43
-
44
- export function ignore<R>(callback: () => R): R {
45
- try {
46
- begin();
47
- return callback();
48
- } finally {
49
- end();
50
- }
51
- }
52
-
53
- export function getDependenciesCount(): number | undefined {
54
- if (currentFrame?.computed) {
55
- return currentFrame.computed.getDependenciesCount();
56
- }
57
- return undefined;
58
- }
59
-
60
- export function getDependencies(): AnySubscribable[] | undefined {
61
- if (currentFrame?.computed) {
62
- return currentFrame.computed.getDependencies();
63
- }
64
- return undefined;
65
- }
66
-
67
- export function isInitial(): boolean | undefined {
68
- if (currentFrame) {
69
- return currentFrame.isInitial;
70
- }
71
- return undefined;
72
- }
73
-
74
- export function getCurrentComputed(): TrackingFrame['computed'] | undefined {
75
- return currentFrame?.computed;
76
- }
1
+ import { type Subscribable, isSubscribable } from './subscribable.js';
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- variance: detection is type-agnostic
4
+ type AnySubscribable = Subscribable<any>;
5
+
6
+ export interface TrackingFrame {
7
+ callback: (subscribable: AnySubscribable, id: number) => void;
8
+ computed?: {
9
+ getDependenciesCount(): number;
10
+ getDependencies(): AnySubscribable[];
11
+ };
12
+ isInitial?: boolean;
13
+ }
14
+
15
+ let lastId = 0;
16
+ const outerFrames: Array<TrackingFrame | undefined> = [];
17
+ let currentFrame: TrackingFrame | undefined;
18
+
19
+ export function getId(): number {
20
+ return ++lastId;
21
+ }
22
+
23
+ export function begin(frame?: TrackingFrame): void {
24
+ outerFrames.push(currentFrame);
25
+ currentFrame = frame;
26
+ }
27
+
28
+ export function end(): void {
29
+ currentFrame = outerFrames.pop();
30
+ }
31
+
32
+ export function registerDependency(subscribable: AnySubscribable): void {
33
+ if (currentFrame) {
34
+ if (!isSubscribable(subscribable)) {
35
+ throw new Error('Only subscribable things can act as dependencies');
36
+ }
37
+ currentFrame.callback(
38
+ subscribable,
39
+ subscribable._id || (subscribable._id = getId()),
40
+ );
41
+ }
42
+ }
43
+
44
+ export function ignore<R>(callback: () => R): R {
45
+ try {
46
+ begin();
47
+ return callback();
48
+ } finally {
49
+ end();
50
+ }
51
+ }
52
+
53
+ export function getDependenciesCount(): number | undefined {
54
+ if (currentFrame?.computed) {
55
+ return currentFrame.computed.getDependenciesCount();
56
+ }
57
+ return undefined;
58
+ }
59
+
60
+ export function getDependencies(): AnySubscribable[] | undefined {
61
+ if (currentFrame?.computed) {
62
+ return currentFrame.computed.getDependencies();
63
+ }
64
+ return undefined;
65
+ }
66
+
67
+ export function isInitial(): boolean | undefined {
68
+ if (currentFrame) {
69
+ return currentFrame.isInitial;
70
+ }
71
+ return undefined;
72
+ }
73
+
74
+ export function getCurrentComputed(): TrackingFrame['computed'] | undefined {
75
+ return currentFrame?.computed;
76
+ }
package/src/disposable.ts CHANGED
@@ -1,36 +1,36 @@
1
- export interface Disposable {
2
- dispose(): void;
3
- }
4
-
5
- export class DisposableGroup implements Disposable {
6
- private _disposables: Disposable[] = [];
7
- private _isDisposed = false;
8
-
9
- add<T extends Disposable>(disposable: T): T {
10
- if (this._isDisposed) {
11
- disposable.dispose();
12
- return disposable;
13
- }
14
- this._disposables.push(disposable);
15
- return disposable;
16
- }
17
-
18
- dispose(): void {
19
- if (!this._isDisposed) {
20
- this._isDisposed = true;
21
- const items = this._disposables;
22
- this._disposables = [];
23
- for (let i = 0; i < items.length; i++) {
24
- items[i].dispose();
25
- }
26
- }
27
- }
28
-
29
- get isDisposed(): boolean {
30
- return this._isDisposed;
31
- }
32
-
33
- get count(): number {
34
- return this._disposables.length;
35
- }
36
- }
1
+ export interface Disposable {
2
+ dispose(): void;
3
+ }
4
+
5
+ export class DisposableGroup implements Disposable {
6
+ private _disposables: Disposable[] = [];
7
+ private _isDisposed = false;
8
+
9
+ add<T extends Disposable>(disposable: T): T {
10
+ if (this._isDisposed) {
11
+ disposable.dispose();
12
+ return disposable;
13
+ }
14
+ this._disposables.push(disposable);
15
+ return disposable;
16
+ }
17
+
18
+ dispose(): void {
19
+ if (!this._isDisposed) {
20
+ this._isDisposed = true;
21
+ const items = this._disposables;
22
+ this._disposables = [];
23
+ for (let i = 0; i < items.length; i++) {
24
+ items[i].dispose();
25
+ }
26
+ }
27
+ }
28
+
29
+ get isDisposed(): boolean {
30
+ return this._isDisposed;
31
+ }
32
+
33
+ get count(): number {
34
+ return this._disposables.length;
35
+ }
36
+ }
package/src/domData.ts CHANGED
@@ -1,42 +1,42 @@
1
- const dataStore = new WeakMap<object, Map<string, unknown>>();
2
- let nextId = 0;
3
-
4
- export function domDataGet(node: object, key: string): unknown {
5
- return dataStore.get(node)?.get(key);
6
- }
7
-
8
- export function domDataSet(node: object, key: string, value: unknown): void {
9
- if (value === undefined) {
10
- const data = dataStore.get(node);
11
- if (data) {
12
- data.delete(key);
13
- if (data.size === 0) dataStore.delete(node);
14
- }
15
- return;
16
- }
17
- let data = dataStore.get(node);
18
- if (!data) {
19
- data = new Map();
20
- dataStore.set(node, data);
21
- }
22
- data.set(key, value);
23
- }
24
-
25
- export function domDataGetOrSet(node: object, key: string, value: unknown): unknown {
26
- let data = dataStore.get(node);
27
- if (!data) {
28
- data = new Map();
29
- dataStore.set(node, data);
30
- }
31
- if (data.has(key)) return data.get(key);
32
- data.set(key, value);
33
- return value;
34
- }
35
-
36
- export function domDataClear(node: object): boolean {
37
- return dataStore.delete(node);
38
- }
39
-
40
- export function domDataNextKey(): string {
41
- return `__tapout_${nextId++}`;
42
- }
1
+ const dataStore = new WeakMap<object, Map<string, unknown>>();
2
+ let nextId = 0;
3
+
4
+ export function domDataGet(node: object, key: string): unknown {
5
+ return dataStore.get(node)?.get(key);
6
+ }
7
+
8
+ export function domDataSet(node: object, key: string, value: unknown): void {
9
+ if (value === undefined) {
10
+ const data = dataStore.get(node);
11
+ if (data) {
12
+ data.delete(key);
13
+ if (data.size === 0) dataStore.delete(node);
14
+ }
15
+ return;
16
+ }
17
+ let data = dataStore.get(node);
18
+ if (!data) {
19
+ data = new Map();
20
+ dataStore.set(node, data);
21
+ }
22
+ data.set(key, value);
23
+ }
24
+
25
+ export function domDataGetOrSet(node: object, key: string, value: unknown): unknown {
26
+ let data = dataStore.get(node);
27
+ if (!data) {
28
+ data = new Map();
29
+ dataStore.set(node, data);
30
+ }
31
+ if (data.has(key)) return data.get(key);
32
+ data.set(key, value);
33
+ return value;
34
+ }
35
+
36
+ export function domDataClear(node: object): boolean {
37
+ return dataStore.delete(node);
38
+ }
39
+
40
+ export function domDataNextKey(): string {
41
+ return `__tapout_${nextId++}`;
42
+ }
@@ -1,94 +1,94 @@
1
- import { domDataGet, domDataSet, domDataClear, domDataNextKey } from './domData.js';
2
- import { ignore } from './dependencyDetection.js';
3
-
4
- type DisposeCallback = (node: Node) => void;
5
-
6
- const disposeCallbacksKey = domDataNextKey();
7
-
8
- const CLEANABLE: Record<number, boolean> = { 1: true, 8: true, 9: true };
9
- const CLEANABLE_WITH_DESCENDANTS: Record<number, boolean> = { 1: true, 9: true };
10
-
11
- function getCallbacks(node: Node, create: true): DisposeCallback[];
12
- function getCallbacks(node: Node, create: false): DisposeCallback[] | undefined;
13
- function getCallbacks(node: Node, create: boolean): DisposeCallback[] | undefined {
14
- let callbacks = domDataGet(node, disposeCallbacksKey) as DisposeCallback[] | undefined;
15
- if (!callbacks && create) {
16
- callbacks = [];
17
- domDataSet(node, disposeCallbacksKey, callbacks);
18
- }
19
- return callbacks;
20
- }
21
-
22
- function destroyCallbacks(node: Node): void {
23
- domDataSet(node, disposeCallbacksKey, undefined);
24
- }
25
-
26
- function cleanSingleNode(node: Node): void {
27
- const callbacks = getCallbacks(node, false);
28
- if (callbacks) {
29
- const snapshot = callbacks.slice(0);
30
- for (let i = 0; i < snapshot.length; i++) {
31
- snapshot[i](node);
32
- }
33
- }
34
-
35
- domDataClear(node);
36
-
37
- if (CLEANABLE_WITH_DESCENDANTS[node.nodeType]) {
38
- cleanNodesInList(node.childNodes, true);
39
- }
40
- }
41
-
42
- function cleanNodesInList(nodeList: ArrayLike<Node>, onlyComments?: boolean): void {
43
- const cleaned: Node[] = [];
44
- let lastCleaned: Node;
45
- for (let i = 0; i < nodeList.length; i++) {
46
- if (!onlyComments || nodeList[i].nodeType === 8) {
47
- cleanSingleNode(cleaned[cleaned.length] = lastCleaned = nodeList[i]);
48
- if (nodeList[i] !== lastCleaned) {
49
- while (i-- && cleaned.indexOf(nodeList[i]) === -1) { /* adjust index */ }
50
- }
51
- }
52
- }
53
- }
54
-
55
- export function addDisposeCallback(node: Node, callback: DisposeCallback): void {
56
- if (typeof callback !== 'function') {
57
- throw new Error('Callback must be a function');
58
- }
59
- getCallbacks(node, true).push(callback);
60
- }
61
-
62
- export function removeDisposeCallback(node: Node, callback: DisposeCallback): void {
63
- const callbacks = getCallbacks(node, false);
64
- if (callbacks) {
65
- const index = callbacks.indexOf(callback);
66
- if (index >= 0) {
67
- callbacks.splice(index, 1);
68
- if (callbacks.length === 0) {
69
- destroyCallbacks(node);
70
- }
71
- }
72
- }
73
- }
74
-
75
- export function cleanNode(node: Node): Node {
76
- ignore(() => {
77
- if (CLEANABLE[node.nodeType]) {
78
- cleanSingleNode(node);
79
-
80
- if (CLEANABLE_WITH_DESCENDANTS[node.nodeType]) {
81
- const descendants = (node as Element).getElementsByTagName('*');
82
- cleanNodesInList(descendants);
83
- }
84
- }
85
- });
86
- return node;
87
- }
88
-
89
- export function removeNode(node: Node): void {
90
- cleanNode(node);
91
- if (node.parentNode) {
92
- node.parentNode.removeChild(node);
93
- }
94
- }
1
+ import { domDataGet, domDataSet, domDataClear, domDataNextKey } from './domData.js';
2
+ import { ignore } from './dependencyDetection.js';
3
+
4
+ type DisposeCallback = (node: Node) => void;
5
+
6
+ const disposeCallbacksKey = domDataNextKey();
7
+
8
+ const CLEANABLE: Record<number, boolean> = { 1: true, 8: true, 9: true };
9
+ const CLEANABLE_WITH_DESCENDANTS: Record<number, boolean> = { 1: true, 9: true };
10
+
11
+ function getCallbacks(node: Node, create: true): DisposeCallback[];
12
+ function getCallbacks(node: Node, create: false): DisposeCallback[] | undefined;
13
+ function getCallbacks(node: Node, create: boolean): DisposeCallback[] | undefined {
14
+ let callbacks = domDataGet(node, disposeCallbacksKey) as DisposeCallback[] | undefined;
15
+ if (!callbacks && create) {
16
+ callbacks = [];
17
+ domDataSet(node, disposeCallbacksKey, callbacks);
18
+ }
19
+ return callbacks;
20
+ }
21
+
22
+ function destroyCallbacks(node: Node): void {
23
+ domDataSet(node, disposeCallbacksKey, undefined);
24
+ }
25
+
26
+ function cleanSingleNode(node: Node): void {
27
+ const callbacks = getCallbacks(node, false);
28
+ if (callbacks) {
29
+ const snapshot = callbacks.slice(0);
30
+ for (let i = 0; i < snapshot.length; i++) {
31
+ snapshot[i](node);
32
+ }
33
+ }
34
+
35
+ domDataClear(node);
36
+
37
+ if (CLEANABLE_WITH_DESCENDANTS[node.nodeType]) {
38
+ cleanNodesInList(node.childNodes, true);
39
+ }
40
+ }
41
+
42
+ function cleanNodesInList(nodeList: ArrayLike<Node>, onlyComments?: boolean): void {
43
+ const cleaned: Node[] = [];
44
+ let lastCleaned: Node;
45
+ for (let i = 0; i < nodeList.length; i++) {
46
+ if (!onlyComments || nodeList[i].nodeType === 8) {
47
+ cleanSingleNode(cleaned[cleaned.length] = lastCleaned = nodeList[i]);
48
+ if (nodeList[i] !== lastCleaned) {
49
+ while (i-- && cleaned.indexOf(nodeList[i]) === -1) { /* adjust index */ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ export function addDisposeCallback(node: Node, callback: DisposeCallback): void {
56
+ if (typeof callback !== 'function') {
57
+ throw new Error('Callback must be a function');
58
+ }
59
+ getCallbacks(node, true).push(callback);
60
+ }
61
+
62
+ export function removeDisposeCallback(node: Node, callback: DisposeCallback): void {
63
+ const callbacks = getCallbacks(node, false);
64
+ if (callbacks) {
65
+ const index = callbacks.indexOf(callback);
66
+ if (index >= 0) {
67
+ callbacks.splice(index, 1);
68
+ if (callbacks.length === 0) {
69
+ destroyCallbacks(node);
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ export function cleanNode(node: Node): Node {
76
+ ignore(() => {
77
+ if (CLEANABLE[node.nodeType]) {
78
+ cleanSingleNode(node);
79
+
80
+ if (CLEANABLE_WITH_DESCENDANTS[node.nodeType]) {
81
+ const descendants = (node as Element).getElementsByTagName('*');
82
+ cleanNodesInList(descendants);
83
+ }
84
+ }
85
+ });
86
+ return node;
87
+ }
88
+
89
+ export function removeNode(node: Node): void {
90
+ cleanNode(node);
91
+ if (node.parentNode) {
92
+ node.parentNode.removeChild(node);
93
+ }
94
+ }
package/src/effects.ts CHANGED
@@ -1,29 +1,29 @@
1
- import { PureComputed } from './computed.js';
2
-
3
- export interface EffectHandle {
4
- dispose(): void;
5
- }
6
-
7
- /**
8
- * Track reactive dependencies in `fn` and call `act` whenever they change.
9
- * Returns a handle to stop the effect.
10
- */
11
- export function observe<T>(fn: () => T, act: (val: T) => void): EffectHandle {
12
- const computed = new PureComputed(fn);
13
- computed.extend({ notify: 'always' });
14
- const subscription = computed.subscribe(act);
15
- return {
16
- dispose() {
17
- subscription.dispose();
18
- computed.dispose();
19
- },
20
- };
21
- }
22
-
23
- /**
24
- * Same as `observe`, but also runs `act` immediately with the current value.
25
- */
26
- export function effect<T>(fn: () => T, act: (val: T) => void): EffectHandle {
27
- act(fn());
28
- return observe(fn, act);
29
- }
1
+ import { PureComputed } from './computed.js';
2
+
3
+ export interface EffectHandle {
4
+ dispose(): void;
5
+ }
6
+
7
+ /**
8
+ * Track reactive dependencies in `fn` and call `act` whenever they change.
9
+ * Returns a handle to stop the effect.
10
+ */
11
+ export function observe<T>(fn: () => T, act: (val: T) => void): EffectHandle {
12
+ const computed = new PureComputed(fn);
13
+ computed.extend({ notify: 'always' });
14
+ const subscription = computed.subscribe(act);
15
+ return {
16
+ dispose() {
17
+ subscription.dispose();
18
+ computed.dispose();
19
+ },
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Same as `observe`, but also runs `act` immediately with the current value.
25
+ */
26
+ export function effect<T>(fn: () => T, act: (val: T) => void): EffectHandle {
27
+ act(fn());
28
+ return observe(fn, act);
29
+ }