@joist/templating 4.2.4-next.0 → 4.2.4-next.10

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 (74) hide show
  1. package/README.md +43 -164
  2. package/package.json +1 -1
  3. package/src/lib/bind.test.ts +72 -0
  4. package/src/lib/bind.ts +32 -9
  5. package/src/lib/define.ts +1 -0
  6. package/src/lib/elements/async.element.test.ts +90 -0
  7. package/src/lib/elements/async.element.ts +13 -2
  8. package/src/lib/elements/bind.element.test.ts +21 -2
  9. package/src/lib/elements/bind.element.ts +14 -17
  10. package/src/lib/elements/for.element.ts +16 -9
  11. package/src/lib/elements/if.element.test.ts +210 -0
  12. package/src/lib/elements/if.element.ts +16 -11
  13. package/src/lib/elements/scope.element.test.ts +32 -0
  14. package/src/lib/elements/scope.element.ts +19 -0
  15. package/src/lib/elements/value.element.test.ts +28 -0
  16. package/src/lib/elements/value.element.ts +9 -11
  17. package/src/lib/events.ts +10 -5
  18. package/src/lib/expression.test.ts +204 -0
  19. package/src/lib/expression.ts +179 -0
  20. package/target/lib/bind.d.ts +5 -1
  21. package/target/lib/bind.js +22 -8
  22. package/target/lib/bind.js.map +1 -1
  23. package/target/lib/bind.test.js +76 -0
  24. package/target/lib/bind.test.js.map +1 -0
  25. package/target/lib/define.d.ts +1 -0
  26. package/target/lib/define.js +1 -0
  27. package/target/lib/define.js.map +1 -1
  28. package/target/lib/elements/async.element.js +11 -2
  29. package/target/lib/elements/async.element.js.map +1 -1
  30. package/target/lib/elements/async.element.test.js +76 -0
  31. package/target/lib/elements/async.element.test.js.map +1 -1
  32. package/target/lib/elements/bind.element.d.ts +8 -3
  33. package/target/lib/elements/bind.element.js +11 -17
  34. package/target/lib/elements/bind.element.js.map +1 -1
  35. package/target/lib/elements/bind.element.test.js +18 -2
  36. package/target/lib/elements/bind.element.test.js.map +1 -1
  37. package/target/lib/elements/for.element.d.ts +1 -1
  38. package/target/lib/elements/for.element.js +13 -7
  39. package/target/lib/elements/for.element.js.map +1 -1
  40. package/target/lib/elements/if.element.js +12 -12
  41. package/target/lib/elements/if.element.js.map +1 -1
  42. package/target/lib/elements/if.element.test.js +184 -0
  43. package/target/lib/elements/if.element.test.js.map +1 -1
  44. package/target/lib/elements/scope.element.d.ts +8 -0
  45. package/target/lib/elements/scope.element.js +38 -0
  46. package/target/lib/elements/scope.element.js.map +1 -0
  47. package/target/lib/elements/scope.element.test.d.ts +2 -0
  48. package/target/lib/elements/scope.element.test.js +25 -0
  49. package/target/lib/elements/scope.element.test.js.map +1 -0
  50. package/target/lib/elements/value.element.js +7 -11
  51. package/target/lib/elements/value.element.js.map +1 -1
  52. package/target/lib/elements/value.element.test.js +24 -0
  53. package/target/lib/elements/value.element.test.js.map +1 -1
  54. package/target/lib/events.d.ts +8 -4
  55. package/target/lib/events.js +3 -3
  56. package/target/lib/events.js.map +1 -1
  57. package/target/lib/expression.d.ts +13 -0
  58. package/target/lib/expression.js +87 -0
  59. package/target/lib/expression.js.map +1 -0
  60. package/target/lib/expression.test.d.ts +1 -0
  61. package/target/lib/expression.test.js +171 -0
  62. package/target/lib/expression.test.js.map +1 -0
  63. package/src/lib/elements/scope.ts +0 -39
  64. package/src/lib/token.test.ts +0 -74
  65. package/src/lib/token.ts +0 -34
  66. package/target/lib/elements/scope.d.ts +0 -13
  67. package/target/lib/elements/scope.js +0 -56
  68. package/target/lib/elements/scope.js.map +0 -1
  69. package/target/lib/token.d.ts +0 -8
  70. package/target/lib/token.js +0 -27
  71. package/target/lib/token.js.map +0 -1
  72. package/target/lib/token.test.js +0 -56
  73. package/target/lib/token.test.js.map +0 -1
  74. /package/target/lib/{token.test.d.ts → bind.test.d.ts} +0 -0
@@ -0,0 +1,204 @@
1
+ import { assert } from "chai";
2
+
3
+ import { JExpression } from "./expression.js";
4
+
5
+ describe("JExpression", () => {
6
+ describe("constructor", () => {
7
+ it("should initialize with a raw token", () => {
8
+ const token = new JExpression("example.token");
9
+ assert.equal(token.rawToken, "example.token");
10
+ });
11
+
12
+ it("should set isNegated to true if the token starts with '!'", () => {
13
+ const token = new JExpression("!example.token");
14
+ assert.isTrue(token.isNegated);
15
+ });
16
+
17
+ it("should set isNegated to false if the token does not start with '!'", () => {
18
+ const token = new JExpression("example.token");
19
+ assert.isFalse(token.isNegated);
20
+ });
21
+
22
+ it("should correctly parse the bindTo property", () => {
23
+ const token = new JExpression("example.token");
24
+ assert.equal(token.bindTo, "example");
25
+ });
26
+
27
+ it("should correctly parse the path property", () => {
28
+ const token = new JExpression("example.token.part");
29
+ assert.deepEqual(token.path, ["token", "part"]);
30
+ });
31
+
32
+ it("should remove '!' from bindTo if present", () => {
33
+ const token = new JExpression("!example.token");
34
+ assert.equal(token.bindTo, "example");
35
+ });
36
+
37
+ it("should parse equals operator value", () => {
38
+ const token = new JExpression("example==value");
39
+ assert.equal(token.equalsValue, "value");
40
+ });
41
+
42
+ it("should handle equals operator with negation", () => {
43
+ const token = new JExpression("!example == value");
44
+ assert.equal(token.equalsValue, "value");
45
+ assert.isTrue(token.isNegated);
46
+ });
47
+
48
+ it("should handle equals operator with nested paths", () => {
49
+ const token = new JExpression("example.nested == value");
50
+ assert.equal(token.equalsValue, "value");
51
+ assert.deepEqual(token.path, ["nested"]);
52
+ });
53
+
54
+ it("should parse greater than operator value", () => {
55
+ const token = new JExpression("example > 5");
56
+ assert.equal(token.gtValue, "5");
57
+ });
58
+
59
+ it("should parse less than operator value", () => {
60
+ const token = new JExpression("example < 10");
61
+ assert.equal(token.ltValue, "10");
62
+ });
63
+
64
+ it("should handle greater than operator with negation", () => {
65
+ const token = new JExpression("!example > 5");
66
+ assert.equal(token.gtValue, "5");
67
+ assert.isTrue(token.isNegated);
68
+ });
69
+
70
+ it("should handle less than operator with nested paths", () => {
71
+ const token = new JExpression("example.count < 10");
72
+ assert.equal(token.ltValue, "10");
73
+ assert.deepEqual(token.path, ["count"]);
74
+ });
75
+ });
76
+
77
+ describe("readTokenValueFrom", () => {
78
+ it("should read the value from a nested object", () => {
79
+ const token = new JExpression("example.token.part");
80
+ const obj = { token: { part: 42 } };
81
+ const value = token.evaluate<number>(obj);
82
+ assert.equal(value, 42);
83
+ });
84
+
85
+ it("should return undefined if the path does not exist", () => {
86
+ const token = new JExpression("example.nonexistent.path");
87
+ const obj = { token: { part: 42 } };
88
+ const value = token.evaluate(obj);
89
+ assert.isUndefined(value);
90
+ });
91
+
92
+ it("should handle empty paths gracefully", () => {
93
+ const token = new JExpression("example");
94
+ const obj = { foo: 42 };
95
+ const value = token.evaluate(obj);
96
+
97
+ assert.deepEqual(value, { foo: 42 });
98
+ });
99
+
100
+ it("should parse values from strings", () => {
101
+ const token = new JExpression("example.length");
102
+ const value = token.evaluate("42");
103
+
104
+ assert.equal(value, 2);
105
+ });
106
+
107
+ it("should return true when equals against primative", () => {
108
+ const token = new JExpression("example == active");
109
+ const value = token.evaluate<boolean>("active");
110
+ assert.isTrue(value);
111
+ });
112
+
113
+ it("should return true when equals comparison matches", () => {
114
+ const token = new JExpression("example.status==active");
115
+ const obj = { status: "active" };
116
+ const value = token.evaluate<boolean>(obj);
117
+ assert.isTrue(value);
118
+ });
119
+
120
+ it("should return false when equals comparison does not match", () => {
121
+ const token = new JExpression("example.status==active");
122
+ const obj = { status: "inactive" };
123
+ const value = token.evaluate<boolean>(obj);
124
+ assert.isFalse(value);
125
+ });
126
+
127
+ it("should handle equals comparison with numbers", () => {
128
+ const token = new JExpression("example.count == 5");
129
+ const obj = { count: 5 };
130
+ const value = token.evaluate<boolean>(obj);
131
+ assert.isTrue(value);
132
+ });
133
+
134
+ it("should handle equals comparison with nested paths", () => {
135
+ const token = new JExpression("example.user.status == active");
136
+ const obj = { user: { status: "active" } };
137
+ const value = token.evaluate<boolean>(obj);
138
+ assert.isTrue(value);
139
+ });
140
+
141
+ it("should handle equals comparison with undefined values", () => {
142
+ const token = new JExpression("example.status == active");
143
+ const obj = { status: undefined };
144
+ const value = token.evaluate<boolean>(obj);
145
+ assert.isFalse(value);
146
+ });
147
+
148
+ it("should return true when greater than comparison matches", () => {
149
+ const token = new JExpression("example.count > 5");
150
+ const obj = { count: 10 };
151
+ const value = token.evaluate<boolean>(obj);
152
+ assert.isTrue(value);
153
+ });
154
+
155
+ it("should return false when greater than comparison does not match", () => {
156
+ const token = new JExpression("example.count > 5");
157
+ const obj = { count: 3 };
158
+ const value = token.evaluate<boolean>(obj);
159
+ assert.isFalse(value);
160
+ });
161
+
162
+ it("should return true when less than comparison matches", () => {
163
+ const token = new JExpression("example.count < 10");
164
+ const obj = { count: 5 };
165
+ const value = token.evaluate<boolean>(obj);
166
+ assert.isTrue(value);
167
+ });
168
+
169
+ it("should return false when less than comparison does not match", () => {
170
+ const token = new JExpression("example.count < 10");
171
+ const obj = { count: 15 };
172
+ const value = token.evaluate<boolean>(obj);
173
+ assert.isFalse(value);
174
+ });
175
+
176
+ it("should handle greater than comparison with string numbers", () => {
177
+ const token = new JExpression("example.count > 5");
178
+ const obj = { count: "10" };
179
+ const value = token.evaluate<boolean>(obj);
180
+ assert.isTrue(value);
181
+ });
182
+
183
+ it("should handle less than comparison with string numbers", () => {
184
+ const token = new JExpression("example.count < 10");
185
+ const obj = { count: "5" };
186
+ const value = token.evaluate<boolean>(obj);
187
+ assert.isTrue(value);
188
+ });
189
+
190
+ it("should handle greater than comparison with undefined values", () => {
191
+ const token = new JExpression("example.count > 5");
192
+ const obj = { count: undefined };
193
+ const value = token.evaluate<boolean>(obj);
194
+ assert.isFalse(value);
195
+ });
196
+
197
+ it("should handle less than comparison with undefined values", () => {
198
+ const token = new JExpression("example.count < 10");
199
+ const obj = { count: undefined };
200
+ const value = token.evaluate<boolean>(obj);
201
+ assert.isFalse(value);
202
+ });
203
+ });
204
+ });
@@ -0,0 +1,179 @@
1
+ type ComparisonOperator = "==" | "!=" | ">" | "<";
2
+
3
+ interface TokenParts {
4
+ path: string[];
5
+ value?: string;
6
+ operator?: ComparisonOperator;
7
+ }
8
+
9
+ /**
10
+ * JExpression represents a token that can be used to extract and compare values from objects.
11
+ *
12
+ * Supported operators:
13
+ * - `==` : Equality comparison (e.g., "status==active")
14
+ * - `!=` : Inequality comparison (e.g., "status!=active")
15
+ * - `>` : Greater than comparison (e.g., "count>5")
16
+ * - `<` : Less than comparison (e.g., "count<10")
17
+ *
18
+ * Examples:
19
+ * ```typescript
20
+ * // Basic path access
21
+ * new JExpression("user.name").readTokenValueFrom({ user: { name: "John" } }) // "John"
22
+ *
23
+ * // Equality comparison
24
+ * new JExpression("status == active").readTokenValueFrom({ status: "active" }) // true
25
+ *
26
+ * // Inequality comparison
27
+ * new JExpression("status != active").readTokenValueFrom({ status: "inactive" }) // true
28
+ *
29
+ * // Greater than comparison
30
+ * new JExpression("count > 5").readTokenValueFrom({ count: 10 }) // true
31
+ *
32
+ * // Less than comparison
33
+ * new JExpression("count < 10").readTokenValueFrom({ count: 5 }) // true
34
+ *
35
+ * // With negation
36
+ * new JExpression("!status == active").readTokenValueFrom({ status: "inactive" }) // true
37
+ *
38
+ * // Nested paths
39
+ * new JExpression("user.score > 100").readTokenValueFrom({ user: { score: 150 } }) // true
40
+ * ```
41
+ */
42
+ export class JExpression {
43
+ /** The raw token string as provided to the constructor */
44
+ rawToken: string;
45
+ /** Whether the token is negated (starts with '!') */
46
+ isNegated = false;
47
+ /** The first part of the path (before the first dot) */
48
+ bindTo: string;
49
+ /** The remaining parts of the path (after the first dot) */
50
+ path: string[] = [];
51
+ /** The value to compare against for equality (==) */
52
+ equalsValue: string | undefined;
53
+ /** The value to compare against for inequality (!=) */
54
+ notEqualsValue: string | undefined;
55
+ /** The value to compare against for greater than (>) */
56
+ gtValue: string | undefined;
57
+ /** The value to compare against for less than (<) */
58
+ ltValue: string | undefined;
59
+
60
+ /**
61
+ * Creates a new JExpression instance.
62
+ * @param rawToken - The token string to parse. Can include operators (==, !=, >, <) and negation (!)
63
+ */
64
+ constructor(rawToken: string) {
65
+ this.rawToken = rawToken;
66
+ this.isNegated = this.rawToken.startsWith("!");
67
+
68
+ const { path, value, operator } = this.#parseToken();
69
+ this.path = path;
70
+ this.bindTo = this.path.shift() ?? "";
71
+ this.bindTo = this.bindTo.replaceAll("!", "");
72
+
73
+ // Set the appropriate comparison value based on the operator
74
+ switch (operator) {
75
+ case "==":
76
+ this.equalsValue = value;
77
+ break;
78
+ case "!=":
79
+ this.notEqualsValue = value;
80
+ break;
81
+ case ">":
82
+ this.gtValue = value;
83
+ break;
84
+ case "<":
85
+ this.ltValue = value;
86
+ break;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Reads a value from the provided object using the token's path and performs any comparison.
92
+ * @param value - The object to read from
93
+ * @returns The value at the path, or the result of the comparison if an operator is present
94
+ * @template T - The expected return type
95
+ */
96
+ evaluate<T = unknown>(value: unknown): T {
97
+ if (typeof value !== "object" && typeof value !== "string") {
98
+ return value as T;
99
+ }
100
+
101
+ const pathValue = this.#getValueAtPath(value);
102
+
103
+ return this.#performComparison(pathValue) as T;
104
+ }
105
+
106
+ /**
107
+ * Parses the raw token into its components.
108
+ * @returns An object containing the path parts and any comparison operator/value
109
+ */
110
+ #parseToken(): TokenParts {
111
+ const operators: ComparisonOperator[] = ["==", "!=", ">", "<"];
112
+
113
+ for (const operator of operators) {
114
+ if (this.rawToken.includes(operator)) {
115
+ const [tokenPart, value] = this.rawToken.split(operator).map((part) => part.trim());
116
+ return {
117
+ path: tokenPart.split("."),
118
+ value,
119
+ operator,
120
+ };
121
+ }
122
+ }
123
+
124
+ return {
125
+ path: this.rawToken.split("."),
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Gets the value at the token's path in the provided object.
131
+ * @param value - The object to read from
132
+ * @returns The value at the path, or undefined if the path doesn't exist
133
+ */
134
+ #getValueAtPath(value: unknown): unknown {
135
+ if (value === null || value === undefined) {
136
+ return value;
137
+ }
138
+
139
+ if (!this.path.length) {
140
+ return value;
141
+ }
142
+
143
+ let pointer: any = value;
144
+
145
+ for (const part of this.path) {
146
+ pointer = pointer?.[part];
147
+ if (pointer === undefined) {
148
+ break;
149
+ }
150
+ }
151
+
152
+ return pointer;
153
+ }
154
+
155
+ /**
156
+ * Performs the comparison operation if an operator is present.
157
+ * @param value - The value to compare
158
+ * @returns The result of the comparison, or the original value if no operator is present
159
+ */
160
+ #performComparison(value: unknown): boolean | unknown {
161
+ if (this.equalsValue !== undefined) {
162
+ return String(value) === this.equalsValue;
163
+ }
164
+
165
+ if (this.notEqualsValue !== undefined) {
166
+ return String(value) !== this.notEqualsValue;
167
+ }
168
+
169
+ if (this.gtValue !== undefined) {
170
+ return Number(value) > Number(this.gtValue);
171
+ }
172
+
173
+ if (this.ltValue !== undefined) {
174
+ return Number(value) < Number(this.ltValue);
175
+ }
176
+
177
+ return value;
178
+ }
179
+ }
@@ -1 +1,5 @@
1
- export declare function bind<This extends HTMLElement, Value>(mapper?: (instance: This) => Value): (base: ClassAccessorDecoratorTarget<This, Value>, ctx: ClassAccessorDecoratorContext<This, Value>) => ClassAccessorDecoratorResult<This, Value>;
1
+ import { ObserveOpts } from "@joist/observable";
2
+ export interface BindOpts<This, Value> extends ObserveOpts<This, Value> {
3
+ alwaysUpdate?: boolean;
4
+ }
5
+ export declare function bind<This extends HTMLElement, Value>(opts?: BindOpts<This, Value>): (base: ClassAccessorDecoratorTarget<This, Value>, ctx: ClassAccessorDecoratorContext<This, Value>) => ClassAccessorDecoratorResult<This, Value>;
@@ -1,19 +1,33 @@
1
1
  import { instanceMetadataStore, observe } from "@joist/observable";
2
- export function bind(mapper) {
2
+ export function bind(opts = {}) {
3
3
  return function bindDecorator(base, ctx) {
4
- const internalObserve = observe(mapper)(base, ctx);
4
+ const internalObserve = observe(opts)(base, ctx);
5
5
  return {
6
6
  init(value) {
7
7
  this.addEventListener("joist::value", (e) => {
8
- if (e.token.bindTo === ctx.name) {
8
+ if (e.expression.bindTo === ctx.name) {
9
9
  const instanceMeta = instanceMetadataStore.read(this);
10
10
  e.stopPropagation();
11
- e.update({ oldValue: null, newValue: ctx.access.get(this) });
11
+ e.update({
12
+ oldValue: null,
13
+ newValue: ctx.access.get(this),
14
+ alwaysUpdate: opts.alwaysUpdate,
15
+ firstChange: true,
16
+ });
17
+ const name = ctx.name;
12
18
  instanceMeta.bindings.add((changes) => {
13
- const key = ctx.name;
14
- const res = changes.get(key);
15
- if (res) {
16
- e.update(res);
19
+ const change = changes.get(name);
20
+ if (change) {
21
+ e.update({ ...change, alwaysUpdate: opts.alwaysUpdate, firstChange: false });
22
+ }
23
+ else if (opts.alwaysUpdate) {
24
+ const value = ctx.access.get(this);
25
+ e.update({
26
+ oldValue: value,
27
+ newValue: value,
28
+ alwaysUpdate: opts.alwaysUpdate,
29
+ firstChange: false,
30
+ });
17
31
  }
18
32
  });
19
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bind.js","sourceRoot":"","sources":["../../src/lib/bind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,UAAU,IAAI,CAAkC,MAAkC;IACtF,OAAO,SAAS,aAAa,CAC3B,IAA+C,EAC/C,GAA+C;QAE/C,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAEnD,OAAO;YACL,IAAI,CAAC,KAAK;gBACR,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;oBAC1C,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;wBAChC,MAAM,YAAY,GAAG,qBAAqB,CAAC,IAAI,CAAO,IAAI,CAAC,CAAC;wBAE5D,CAAC,CAAC,eAAe,EAAE,CAAC;wBAEpB,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBAE7D,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;4BACpC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAkB,CAAC;4BACnC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;4BAE7B,IAAI,GAAG,EAAE,CAAC;gCACR,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAChB,CAAC;wBACH,CAAC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,IAAI,eAAe,CAAC,IAAI,EAAE,CAAC;oBACzB,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC;gBACzD,CAAC;gBAED,OAAO,KAAK,CAAC;YACf,CAAC;YACD,GAAG,EAAE,eAAe,CAAC,GAAG;YACxB,GAAG,EAAE,eAAe,CAAC,GAAG;SACzB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"bind.js","sourceRoot":"","sources":["../../src/lib/bind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAe,MAAM,mBAAmB,CAAC;AAUhF,MAAM,UAAU,IAAI,CAAkC,OAA8B,EAAE;IACpF,OAAO,SAAS,aAAa,CAC3B,IAA+C,EAC/C,GAA+C;QAE/C,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAEjD,OAAO;YACL,IAAI,CAAC,KAAK;gBACR,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;oBAC1C,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;wBACrC,MAAM,YAAY,GAAG,qBAAqB,CAAC,IAAI,CAAO,IAAI,CAAC,CAAC;wBAE5D,CAAC,CAAC,eAAe,EAAE,CAAC;wBAEpB,CAAC,CAAC,MAAM,CAAC;4BACP,QAAQ,EAAE,IAAI;4BACd,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;4BAC9B,YAAY,EAAE,IAAI,CAAC,YAAY;4BAC/B,WAAW,EAAE,IAAI;yBAClB,CAAC,CAAC;wBAEH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAkB,CAAC;wBAEpC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;4BACpC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;4BAEjC,IAAI,MAAM,EAAE,CAAC;gCACX,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;4BAC/E,CAAC;iCAAM,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gCAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gCAEnC,CAAC,CAAC,MAAM,CAAC;oCACP,QAAQ,EAAE,KAAK;oCACf,QAAQ,EAAE,KAAK;oCACf,YAAY,EAAE,IAAI,CAAC,YAAY;oCAC/B,WAAW,EAAE,KAAK;iCACnB,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,IAAI,eAAe,CAAC,IAAI,EAAE,CAAC;oBACzB,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC;gBACzD,CAAC;gBAED,OAAO,KAAK,CAAC;YACf,CAAC;YACD,GAAG,EAAE,eAAe,CAAC,GAAG;YACxB,GAAG,EAAE,eAAe,CAAC,GAAG;SACzB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { __esDecorate, __runInitializers } from "tslib";
2
+ import { assert } from "chai";
3
+ import { bind } from "./bind.js";
4
+ import { JoistValueEvent } from "./events.js";
5
+ import { JExpression } from "./expression.js";
6
+ describe("bind decorator", () => {
7
+ let TestElement = (() => {
8
+ let _classSuper = HTMLElement;
9
+ let _value_decorators;
10
+ let _value_initializers = [];
11
+ let _value_extraInitializers = [];
12
+ let _alwaysUpdateValue_decorators;
13
+ let _alwaysUpdateValue_initializers = [];
14
+ let _alwaysUpdateValue_extraInitializers = [];
15
+ return class TestElement extends _classSuper {
16
+ static {
17
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
18
+ _value_decorators = [bind()];
19
+ _alwaysUpdateValue_decorators = [bind({ alwaysUpdate: true })];
20
+ __esDecorate(this, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
21
+ __esDecorate(this, null, _alwaysUpdateValue_decorators, { kind: "accessor", name: "alwaysUpdateValue", static: false, private: false, access: { has: obj => "alwaysUpdateValue" in obj, get: obj => obj.alwaysUpdateValue, set: (obj, value) => { obj.alwaysUpdateValue = value; } }, metadata: _metadata }, _alwaysUpdateValue_initializers, _alwaysUpdateValue_extraInitializers);
22
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
23
+ }
24
+ #value_accessor_storage = __runInitializers(this, _value_initializers, "initial");
25
+ get value() { return this.#value_accessor_storage; }
26
+ set value(value) { this.#value_accessor_storage = value; }
27
+ #alwaysUpdateValue_accessor_storage = (__runInitializers(this, _value_extraInitializers), __runInitializers(this, _alwaysUpdateValue_initializers, "initial"));
28
+ get alwaysUpdateValue() { return this.#alwaysUpdateValue_accessor_storage; }
29
+ set alwaysUpdateValue(value) { this.#alwaysUpdateValue_accessor_storage = value; }
30
+ constructor() {
31
+ super(...arguments);
32
+ __runInitializers(this, _alwaysUpdateValue_extraInitializers);
33
+ }
34
+ };
35
+ })();
36
+ customElements.define("test-element", TestElement);
37
+ it("should initialize with default value", () => {
38
+ const element = new TestElement();
39
+ assert.equal(element.value, "initial");
40
+ });
41
+ it("should update value and trigger binding", async () => {
42
+ const element = new TestElement();
43
+ let oldValue = null;
44
+ let newValue = null;
45
+ element.dispatchEvent(new JoistValueEvent(new JExpression("value"), (update) => {
46
+ oldValue = update.oldValue;
47
+ newValue = update.newValue;
48
+ }));
49
+ assert.equal(oldValue, null);
50
+ assert.equal(newValue, "initial");
51
+ element.value = "updated";
52
+ await Promise.resolve();
53
+ assert.equal(oldValue, "initial");
54
+ assert.equal(newValue, "updated");
55
+ });
56
+ it("should trigger binding on every change with alwaysUpdate option", async () => {
57
+ const element = new TestElement();
58
+ let bindingCount = 0;
59
+ let oldValue;
60
+ let newValue;
61
+ element.dispatchEvent(new JoistValueEvent(new JExpression("alwaysUpdateValue"), (update) => {
62
+ bindingCount++;
63
+ oldValue = update.oldValue;
64
+ newValue = update.newValue;
65
+ }));
66
+ assert.equal(bindingCount, 1);
67
+ assert.equal(oldValue, null);
68
+ assert.equal(newValue, "initial");
69
+ element.value = "something else";
70
+ await Promise.resolve();
71
+ assert.equal(bindingCount, 2);
72
+ assert.equal(oldValue, "initial");
73
+ assert.equal(newValue, "initial");
74
+ });
75
+ });
76
+ //# sourceMappingURL=bind.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.test.js","sourceRoot":"","sources":["../../src/lib/bind.test.ts"],"names":[],"mappings":"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"}
@@ -3,3 +3,4 @@ import "./elements/for.element.js";
3
3
  import "./elements/if.element.js";
4
4
  import "./elements/bind.element.js";
5
5
  import "./elements/value.element.js";
6
+ import "./elements/scope.element.js";
@@ -3,4 +3,5 @@ import "./elements/for.element.js";
3
3
  import "./elements/if.element.js";
4
4
  import "./elements/bind.element.js";
5
5
  import "./elements/value.element.js";
6
+ import "./elements/scope.element.js";
6
7
  //# sourceMappingURL=define.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/lib/define.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,2BAA2B,CAAC;AACnC,OAAO,0BAA0B,CAAC;AAClC,OAAO,4BAA4B,CAAC;AACpC,OAAO,6BAA6B,CAAC"}
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/lib/define.ts"],"names":[],"mappings":"AAAA,OAAO,6BAA6B,CAAC;AACrC,OAAO,2BAA2B,CAAC;AACnC,OAAO,0BAA0B,CAAC;AAClC,OAAO,4BAA4B,CAAC;AACpC,OAAO,6BAA6B,CAAC;AACrC,OAAO,6BAA6B,CAAC"}
@@ -2,7 +2,7 @@ import { __esDecorate, __runInitializers } from "tslib";
2
2
  import { attr, element, queryAll, css, html } from "@joist/element";
3
3
  import { bind } from "../bind.js";
4
4
  import { JoistValueEvent } from "../events.js";
5
- import { JToken } from "../token.js";
5
+ import { JExpression } from "../expression.js";
6
6
  let JoistAsyncElement = (() => {
7
7
  let _classDecorators = [element({
8
8
  tagName: "j-async",
@@ -52,18 +52,27 @@ let JoistAsyncElement = (() => {
52
52
  error: templates.find((t) => t.hasAttribute("error")),
53
53
  success: templates.find((t) => t.hasAttribute("success")),
54
54
  };
55
- const token = new JToken(this.bind);
55
+ const token = new JExpression(this.bind);
56
56
  this.dispatchEvent(new JoistValueEvent(token, ({ newValue, oldValue }) => {
57
57
  if (newValue !== oldValue) {
58
58
  if (newValue instanceof Promise) {
59
59
  this.#handlePromise(newValue);
60
60
  }
61
+ else if (this.#isAsyncState(newValue)) {
62
+ this.#handleState(newValue);
63
+ }
61
64
  else {
62
65
  console.warn("j-async bind value must be a Promise or AsyncState");
63
66
  }
64
67
  }
65
68
  }));
66
69
  }
70
+ #isAsyncState(value) {
71
+ return (typeof value === "object" &&
72
+ value !== null &&
73
+ "status" in value &&
74
+ (value.status === "loading" || value.status === "error" || value.status === "success"));
75
+ }
67
76
  async #handlePromise(promise) {
68
77
  try {
69
78
  this.#handleState({ status: "loading" });
@@ -1 +1 @@
1
- {"version":3,"file":"async.element.js","sourceRoot":"","sources":["../../../src/lib/elements/async.element.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"async.element.js","sourceRoot":"","sources":["../../../src/lib/elements/async.element.ts"],"names":[],"mappings":"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"}