@player-tools/fluent 0.12.1--canary.241.6077

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 (134) hide show
  1. package/dist/cjs/index.cjs +2396 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/index.legacy-esm.js +2276 -0
  4. package/dist/index.mjs +2276 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +38 -0
  7. package/src/core/base-builder/__tests__/fluent-builder-base.test.ts +2423 -0
  8. package/src/core/base-builder/__tests__/fluent-partial.test.ts +179 -0
  9. package/src/core/base-builder/__tests__/id-generator.test.ts +658 -0
  10. package/src/core/base-builder/__tests__/registry.test.ts +534 -0
  11. package/src/core/base-builder/__tests__/resolution-mixed-arrays.test.ts +319 -0
  12. package/src/core/base-builder/__tests__/resolution-pipeline.test.ts +416 -0
  13. package/src/core/base-builder/__tests__/resolution-switches.test.ts +468 -0
  14. package/src/core/base-builder/__tests__/resolution-templates.test.ts +255 -0
  15. package/src/core/base-builder/__tests__/switch.test.ts +815 -0
  16. package/src/core/base-builder/__tests__/template.test.ts +596 -0
  17. package/src/core/base-builder/__tests__/value-extraction.test.ts +200 -0
  18. package/src/core/base-builder/__tests__/value-storage.test.ts +459 -0
  19. package/src/core/base-builder/conditional/index.ts +64 -0
  20. package/src/core/base-builder/context.ts +152 -0
  21. package/src/core/base-builder/errors.ts +69 -0
  22. package/src/core/base-builder/fluent-builder-base.ts +308 -0
  23. package/src/core/base-builder/guards.ts +137 -0
  24. package/src/core/base-builder/id/generator.ts +290 -0
  25. package/src/core/base-builder/id/registry.ts +152 -0
  26. package/src/core/base-builder/index.ts +72 -0
  27. package/src/core/base-builder/resolution/path-resolver.ts +116 -0
  28. package/src/core/base-builder/resolution/pipeline.ts +103 -0
  29. package/src/core/base-builder/resolution/steps/__tests__/nested-asset-wrappers.test.ts +206 -0
  30. package/src/core/base-builder/resolution/steps/asset-id.ts +77 -0
  31. package/src/core/base-builder/resolution/steps/asset-wrappers.ts +64 -0
  32. package/src/core/base-builder/resolution/steps/builders.ts +84 -0
  33. package/src/core/base-builder/resolution/steps/mixed-arrays.ts +95 -0
  34. package/src/core/base-builder/resolution/steps/nested-asset-wrappers.ts +124 -0
  35. package/src/core/base-builder/resolution/steps/static-values.ts +35 -0
  36. package/src/core/base-builder/resolution/steps/switches.ts +71 -0
  37. package/src/core/base-builder/resolution/steps/templates.ts +40 -0
  38. package/src/core/base-builder/resolution/value-resolver.ts +333 -0
  39. package/src/core/base-builder/storage/auxiliary-storage.ts +82 -0
  40. package/src/core/base-builder/storage/value-storage.ts +282 -0
  41. package/src/core/base-builder/types.ts +266 -0
  42. package/src/core/base-builder/utils.ts +10 -0
  43. package/src/core/flow/__tests__/index.test.ts +292 -0
  44. package/src/core/flow/index.ts +118 -0
  45. package/src/core/index.ts +8 -0
  46. package/src/core/mocks/generated/action.builder.ts +92 -0
  47. package/src/core/mocks/generated/choice-item.builder.ts +120 -0
  48. package/src/core/mocks/generated/choice.builder.ts +134 -0
  49. package/src/core/mocks/generated/collection.builder.ts +93 -0
  50. package/src/core/mocks/generated/field-collection.builder.ts +86 -0
  51. package/src/core/mocks/generated/index.ts +10 -0
  52. package/src/core/mocks/generated/info.builder.ts +64 -0
  53. package/src/core/mocks/generated/input.builder.ts +63 -0
  54. package/src/core/mocks/generated/overview-collection.builder.ts +65 -0
  55. package/src/core/mocks/generated/splash-collection.builder.ts +93 -0
  56. package/src/core/mocks/generated/text.builder.ts +47 -0
  57. package/src/core/mocks/index.ts +1 -0
  58. package/src/core/mocks/types/action.ts +92 -0
  59. package/src/core/mocks/types/choice.ts +129 -0
  60. package/src/core/mocks/types/collection.ts +140 -0
  61. package/src/core/mocks/types/info.ts +7 -0
  62. package/src/core/mocks/types/input.ts +7 -0
  63. package/src/core/mocks/types/text.ts +5 -0
  64. package/src/core/schema/__tests__/index.test.ts +127 -0
  65. package/src/core/schema/index.ts +195 -0
  66. package/src/core/schema/types.ts +7 -0
  67. package/src/core/switch/__tests__/index.test.ts +156 -0
  68. package/src/core/switch/index.ts +81 -0
  69. package/src/core/tagged-template/README.md +448 -0
  70. package/src/core/tagged-template/__tests__/extract-bindings-from-schema.test.ts +207 -0
  71. package/src/core/tagged-template/__tests__/index.test.ts +190 -0
  72. package/src/core/tagged-template/__tests__/schema-std-integration.test.ts +580 -0
  73. package/src/core/tagged-template/binding.ts +95 -0
  74. package/src/core/tagged-template/expression.ts +92 -0
  75. package/src/core/tagged-template/extract-bindings-from-schema.ts +120 -0
  76. package/src/core/tagged-template/index.ts +5 -0
  77. package/src/core/tagged-template/std.ts +472 -0
  78. package/src/core/tagged-template/types.ts +123 -0
  79. package/src/core/template/__tests__/index.test.ts +380 -0
  80. package/src/core/template/index.ts +196 -0
  81. package/src/core/utils/index.ts +160 -0
  82. package/src/fp/README.md +411 -0
  83. package/src/fp/__tests__/index.test.ts +1178 -0
  84. package/src/fp/index.ts +386 -0
  85. package/src/gen/common.ts +15 -0
  86. package/src/index.ts +5 -0
  87. package/src/types.ts +203 -0
  88. package/types/core/base-builder/conditional/index.d.ts +21 -0
  89. package/types/core/base-builder/context.d.ts +39 -0
  90. package/types/core/base-builder/errors.d.ts +45 -0
  91. package/types/core/base-builder/fluent-builder-base.d.ts +147 -0
  92. package/types/core/base-builder/guards.d.ts +58 -0
  93. package/types/core/base-builder/id/generator.d.ts +69 -0
  94. package/types/core/base-builder/id/registry.d.ts +93 -0
  95. package/types/core/base-builder/index.d.ts +9 -0
  96. package/types/core/base-builder/resolution/path-resolver.d.ts +15 -0
  97. package/types/core/base-builder/resolution/pipeline.d.ts +27 -0
  98. package/types/core/base-builder/resolution/steps/asset-id.d.ts +14 -0
  99. package/types/core/base-builder/resolution/steps/asset-wrappers.d.ts +14 -0
  100. package/types/core/base-builder/resolution/steps/builders.d.ts +14 -0
  101. package/types/core/base-builder/resolution/steps/mixed-arrays.d.ts +14 -0
  102. package/types/core/base-builder/resolution/steps/nested-asset-wrappers.d.ts +14 -0
  103. package/types/core/base-builder/resolution/steps/static-values.d.ts +14 -0
  104. package/types/core/base-builder/resolution/steps/switches.d.ts +15 -0
  105. package/types/core/base-builder/resolution/steps/templates.d.ts +14 -0
  106. package/types/core/base-builder/resolution/value-resolver.d.ts +62 -0
  107. package/types/core/base-builder/storage/auxiliary-storage.d.ts +50 -0
  108. package/types/core/base-builder/storage/value-storage.d.ts +82 -0
  109. package/types/core/base-builder/types.d.ts +183 -0
  110. package/types/core/base-builder/utils.d.ts +2 -0
  111. package/types/core/flow/index.d.ts +23 -0
  112. package/types/core/index.d.ts +8 -0
  113. package/types/core/mocks/index.d.ts +2 -0
  114. package/types/core/mocks/types/action.d.ts +58 -0
  115. package/types/core/mocks/types/choice.d.ts +95 -0
  116. package/types/core/mocks/types/collection.d.ts +102 -0
  117. package/types/core/mocks/types/info.d.ts +7 -0
  118. package/types/core/mocks/types/input.d.ts +7 -0
  119. package/types/core/mocks/types/text.d.ts +5 -0
  120. package/types/core/schema/index.d.ts +34 -0
  121. package/types/core/schema/types.d.ts +5 -0
  122. package/types/core/switch/index.d.ts +21 -0
  123. package/types/core/tagged-template/binding.d.ts +19 -0
  124. package/types/core/tagged-template/expression.d.ts +11 -0
  125. package/types/core/tagged-template/extract-bindings-from-schema.d.ts +7 -0
  126. package/types/core/tagged-template/index.d.ts +6 -0
  127. package/types/core/tagged-template/std.d.ts +174 -0
  128. package/types/core/tagged-template/types.d.ts +69 -0
  129. package/types/core/template/index.d.ts +97 -0
  130. package/types/core/utils/index.d.ts +47 -0
  131. package/types/fp/index.d.ts +149 -0
  132. package/types/gen/common.d.ts +6 -0
  133. package/types/index.d.ts +3 -0
  134. package/types/types.d.ts +163 -0
@@ -0,0 +1,92 @@
1
+ import {
2
+ isTaggedTemplateValue,
3
+ TaggedTemplateValueSymbol,
4
+ type TaggedTemplateValue,
5
+ type TemplateRefOptions,
6
+ } from "./types";
7
+
8
+ /**
9
+ * Tagged template for creating expression literals
10
+ * Used for generating expressions with proper validation and formatting
11
+ * @param strings - Template string parts
12
+ * @param expressions - Values to interpolate
13
+ * @returns TaggedTemplateValue with expression context
14
+ * @throws Error if expression syntax is invalid
15
+ */
16
+ export function expression<T = unknown>(
17
+ strings: TemplateStringsArray,
18
+ ...expressions: Array<unknown>
19
+ ): TaggedTemplateValue<T> {
20
+ /**
21
+ * Validates expression syntax with balanced parentheses
22
+ * @throws Error if parentheses are unbalanced
23
+ */
24
+ const validateSyntax = (expr: string): void => {
25
+ let openParens = 0;
26
+ // Use position counter to match original behavior exactly
27
+ let position = 0;
28
+
29
+ // Validation loop using position counter
30
+ for (const char of expr) {
31
+ if (char === "(") openParens++;
32
+ if (char === ")") openParens--;
33
+ position++;
34
+
35
+ if (openParens < 0) {
36
+ throw new Error(
37
+ `Error: Unexpected ) at character ${position} in expression: \n ${expr.slice(
38
+ 0,
39
+ position,
40
+ )}█${expr.slice(position)}`,
41
+ );
42
+ }
43
+ }
44
+
45
+ if (openParens > 0) {
46
+ throw new Error(
47
+ `Error: Expected ) at character ${position} in expression: \n ${expr}█`,
48
+ );
49
+ }
50
+ };
51
+
52
+ let result = "";
53
+ const len = strings.length;
54
+
55
+ for (let i = 0; i < len; i++) {
56
+ result += strings[i];
57
+
58
+ if (i < expressions.length) {
59
+ const expr = expressions[i];
60
+ if (isTaggedTemplateValue(expr)) {
61
+ // Use appropriate reference formatting for nested templates
62
+ result += expr.toRefString({ nestedContext: "expression" });
63
+ } else {
64
+ // Convert other values to string
65
+ result += String(expr);
66
+ }
67
+ }
68
+ }
69
+
70
+ validateSyntax(result);
71
+
72
+ return {
73
+ [TaggedTemplateValueSymbol]: true,
74
+
75
+ toValue(): string {
76
+ return result;
77
+ },
78
+
79
+ toRefString(options?: TemplateRefOptions): string {
80
+ if (options?.nestedContext === "binding") {
81
+ return `\`${result}\``;
82
+ } else if (options?.nestedContext === "expression") {
83
+ return result;
84
+ }
85
+ return `@[${result}]@`;
86
+ },
87
+
88
+ toString(): string {
89
+ return `@[${result}]@`;
90
+ },
91
+ };
92
+ }
@@ -0,0 +1,120 @@
1
+ import type { Schema } from "@player-ui/types";
2
+ import { binding } from "./binding";
3
+ import type { TaggedTemplateValue, ExtractedBindings } from "./types";
4
+
5
+ /**
6
+ * Runtime implementation that builds the actual object structure
7
+ */
8
+ export function extractBindingsFromSchema<const S extends Schema.Schema>(
9
+ schema: S,
10
+ ): ExtractedBindings<S> {
11
+ const primitiveTypes = new Set(["StringType", "NumberType", "BooleanType"]);
12
+
13
+ const isPrimitive = (typeName: string): boolean => {
14
+ return primitiveTypes.has(typeName);
15
+ };
16
+
17
+ const createBinding = (
18
+ typeName: string,
19
+ path: string,
20
+ ): TaggedTemplateValue<unknown> => {
21
+ if (typeName === "StringType") {
22
+ return binding<string>`${path}`;
23
+ }
24
+ if (typeName === "NumberType") {
25
+ return binding<number>`${path}`;
26
+ }
27
+ if (typeName === "BooleanType") {
28
+ return binding<boolean>`${path}`;
29
+ }
30
+ return binding<string>`${path}`;
31
+ };
32
+
33
+ const processDataType = (
34
+ dataType: Schema.DataTypes,
35
+ schema: Schema.Schema,
36
+ path: string,
37
+ visited: Set<string> = new Set(),
38
+ ): TaggedTemplateValue<unknown> | Record<string, unknown> => {
39
+ const typeName = dataType.type;
40
+
41
+ // Prevent infinite recursion
42
+ if (visited.has(typeName)) {
43
+ return createBinding("StringType", path);
44
+ }
45
+
46
+ // Handle arrays
47
+ if ("isArray" in dataType && dataType.isArray) {
48
+ const arrayPath = path ? `${path}._current_` : "_current_";
49
+
50
+ if (isPrimitive(typeName)) {
51
+ // Special handling for primitive arrays
52
+ if (typeName === "StringType") {
53
+ return { name: createBinding(typeName, arrayPath) };
54
+ } else {
55
+ return { value: createBinding(typeName, arrayPath) };
56
+ }
57
+ } else {
58
+ const typeNode = schema[typeName];
59
+ if (typeNode) {
60
+ const newVisited = new Set(visited);
61
+ newVisited.add(typeName);
62
+ return processNode(
63
+ typeNode as Schema.Node,
64
+ schema,
65
+ arrayPath,
66
+ newVisited,
67
+ );
68
+ }
69
+ return createBinding("StringType", arrayPath);
70
+ }
71
+ }
72
+
73
+ // Handle records
74
+ if ("isRecord" in dataType && dataType.isRecord) {
75
+ const typeNode = schema[typeName];
76
+ if (typeNode) {
77
+ const newVisited = new Set(visited);
78
+ newVisited.add(typeName);
79
+ return processNode(typeNode as Schema.Node, schema, path, newVisited);
80
+ }
81
+ return createBinding("StringType", path);
82
+ }
83
+
84
+ // Handle primitives
85
+ if (isPrimitive(typeName)) {
86
+ return createBinding(typeName, path);
87
+ }
88
+
89
+ // Handle complex types
90
+ const typeNode = schema[typeName];
91
+ if (typeNode) {
92
+ const newVisited = new Set(visited);
93
+ newVisited.add(typeName);
94
+ return processNode(typeNode as Schema.Node, schema, path, newVisited);
95
+ }
96
+
97
+ // Fallback
98
+ return createBinding("StringType", path);
99
+ };
100
+
101
+ const processNode = (
102
+ node: Schema.Node,
103
+ schema: Schema.Schema,
104
+ basePath: string,
105
+ visited: Set<string> = new Set(),
106
+ ): Record<string, unknown> => {
107
+ const result: Record<string, unknown> = {};
108
+
109
+ // Process each property in the node
110
+ Object.entries(node).forEach(([key, dataType]) => {
111
+ const path = basePath ? `${basePath}.${key}` : key;
112
+ result[key] = processDataType(dataType, schema, path, visited);
113
+ });
114
+
115
+ return result;
116
+ };
117
+
118
+ // Start processing from ROOT
119
+ return processNode(schema.ROOT, schema, "") as ExtractedBindings<S>;
120
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./binding";
2
+ export * from "./expression";
3
+ export * from "./extract-bindings-from-schema";
4
+ export * from "./std";
5
+ export * from "./types";
@@ -0,0 +1,472 @@
1
+ import { isTaggedTemplateValue, type TaggedTemplateValue } from "./types";
2
+ import { expression } from "./expression";
3
+
4
+ /**
5
+ * Type-safe standard library of expressions for the Player-UI DSL
6
+ * Provides common logical, comparison, and arithmetic operations with full TypeScript type safety
7
+ * using phantom types from TaggedTemplateValue.
8
+ */
9
+
10
+ // ============================================================================
11
+ // Logical Operations
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Logical AND operation - returns true if all arguments are truthy
16
+ * @param args - Values or bindings to evaluate with AND logic
17
+ * @returns TaggedTemplateValue<boolean> representing the AND expression
18
+ */
19
+ export function and(
20
+ ...args: Array<TaggedTemplateValue<unknown> | boolean | string | number>
21
+ ): TaggedTemplateValue<boolean> {
22
+ const expressions = args.map((arg) => {
23
+ if (isTaggedTemplateValue(arg)) {
24
+ const expr = arg.toRefString({ nestedContext: "expression" });
25
+ // Wrap OR expressions in parentheses to maintain proper precedence
26
+ // (AND has higher precedence than OR)
27
+ if (expr.includes(" || ") && !expr.startsWith("(")) {
28
+ return `(${expr})`;
29
+ }
30
+ return expr;
31
+ }
32
+ return String(arg);
33
+ });
34
+
35
+ return expression`${expressions.join(" && ")}`;
36
+ }
37
+
38
+ /**
39
+ * Logical OR operation - returns true if any argument is truthy
40
+ * @param args - Values or bindings to evaluate with OR logic
41
+ * @returns TaggedTemplateValue<boolean> representing the OR expression
42
+ */
43
+ export function or(
44
+ ...args: Array<TaggedTemplateValue<unknown> | boolean | string | number>
45
+ ): TaggedTemplateValue<boolean> {
46
+ const expressions = args.map((arg) => {
47
+ if (isTaggedTemplateValue(arg)) {
48
+ return arg.toRefString({ nestedContext: "expression" });
49
+ }
50
+ return String(arg);
51
+ });
52
+
53
+ return expression`${expressions.join(" || ")}`;
54
+ }
55
+
56
+ /**
57
+ * Logical NOT operation - returns true if argument is falsy
58
+ * @param value - Value or binding to negate
59
+ * @returns TaggedTemplateValue<boolean> representing the NOT expression
60
+ */
61
+ export function not(
62
+ value: TaggedTemplateValue<unknown> | boolean | string | number,
63
+ ): TaggedTemplateValue<boolean> {
64
+ const expr = isTaggedTemplateValue(value)
65
+ ? value.toRefString({ nestedContext: "expression" })
66
+ : String(value);
67
+
68
+ return expression`!${expr}`;
69
+ }
70
+
71
+ /**
72
+ * Logical NOR operation - returns true if all arguments are falsy
73
+ * @param args - Values or bindings to evaluate with NOR logic
74
+ * @returns TaggedTemplateValue<boolean> representing the NOR expression
75
+ */
76
+ export function nor(
77
+ ...args: Array<TaggedTemplateValue<unknown> | boolean | string | number>
78
+ ): TaggedTemplateValue<boolean> {
79
+ return not(or(...args));
80
+ }
81
+
82
+ /**
83
+ * Logical NAND operation - returns false if all arguments are truthy
84
+ * @param args - Values or bindings to evaluate with NAND logic
85
+ * @returns TaggedTemplateValue<boolean> representing the NAND expression
86
+ */
87
+ export function nand(
88
+ ...args: Array<TaggedTemplateValue<unknown> | boolean | string | number>
89
+ ): TaggedTemplateValue<boolean> {
90
+ return not(and(...args));
91
+ }
92
+
93
+ /**
94
+ * Logical XOR operation - returns true if exactly one argument is truthy
95
+ * @param left - First value to compare
96
+ * @param right - Second value to compare
97
+ * @returns TaggedTemplateValue<boolean> representing the XOR expression
98
+ */
99
+ export function xor(
100
+ left: TaggedTemplateValue<unknown> | boolean | string | number,
101
+ right: TaggedTemplateValue<unknown> | boolean | string | number,
102
+ ): TaggedTemplateValue<boolean> {
103
+ const leftExpr = isTaggedTemplateValue(left)
104
+ ? left.toRefString({ nestedContext: "expression" })
105
+ : String(left);
106
+ const rightExpr = isTaggedTemplateValue(right)
107
+ ? right.toRefString({ nestedContext: "expression" })
108
+ : String(right);
109
+
110
+ return expression`(${leftExpr} && !${rightExpr}) || (!${leftExpr} && ${rightExpr})`;
111
+ }
112
+
113
+ // ============================================================================
114
+ // Comparison Operations
115
+ // ============================================================================
116
+
117
+ /**
118
+ * Equality comparison (loose equality ==)
119
+ * @param left - First value to compare
120
+ * @param right - Second value to compare
121
+ * @returns TaggedTemplateValue<boolean> representing the equality expression
122
+ */
123
+ export function equal<T>(
124
+ left: TaggedTemplateValue<T> | T,
125
+ right: TaggedTemplateValue<T> | T,
126
+ ): TaggedTemplateValue<boolean> {
127
+ const leftExpr = isTaggedTemplateValue(left)
128
+ ? left.toRefString({ nestedContext: "expression" })
129
+ : JSON.stringify(left);
130
+ const rightExpr = isTaggedTemplateValue(right)
131
+ ? right.toRefString({ nestedContext: "expression" })
132
+ : JSON.stringify(right);
133
+
134
+ return expression`${leftExpr} == ${rightExpr}`;
135
+ }
136
+
137
+ /**
138
+ * Strict equality comparison (===)
139
+ * @param left - First value to compare
140
+ * @param right - Second value to compare
141
+ * @returns TaggedTemplateValue<boolean> representing the strict equality expression
142
+ */
143
+ export function strictEqual<T>(
144
+ left: TaggedTemplateValue<T> | T,
145
+ right: TaggedTemplateValue<T> | T,
146
+ ): TaggedTemplateValue<boolean> {
147
+ const leftExpr = isTaggedTemplateValue(left)
148
+ ? left.toRefString({ nestedContext: "expression" })
149
+ : JSON.stringify(left);
150
+ const rightExpr = isTaggedTemplateValue(right)
151
+ ? right.toRefString({ nestedContext: "expression" })
152
+ : JSON.stringify(right);
153
+
154
+ return expression`${leftExpr} === ${rightExpr}`;
155
+ }
156
+
157
+ /**
158
+ * Inequality comparison (!=)
159
+ * @param left - First value to compare
160
+ * @param right - Second value to compare
161
+ * @returns TaggedTemplateValue<boolean> representing the inequality expression
162
+ */
163
+ export function notEqual<T>(
164
+ left: TaggedTemplateValue<T> | T,
165
+ right: TaggedTemplateValue<T> | T,
166
+ ): TaggedTemplateValue<boolean> {
167
+ const leftExpr = isTaggedTemplateValue(left)
168
+ ? left.toRefString({ nestedContext: "expression" })
169
+ : JSON.stringify(left);
170
+ const rightExpr = isTaggedTemplateValue(right)
171
+ ? right.toRefString({ nestedContext: "expression" })
172
+ : JSON.stringify(right);
173
+
174
+ return expression`${leftExpr} != ${rightExpr}`;
175
+ }
176
+
177
+ /**
178
+ * Strict inequality comparison (!==)
179
+ * @param left - First value to compare
180
+ * @param right - Second value to compare
181
+ * @returns TaggedTemplateValue<boolean> representing the strict inequality expression
182
+ */
183
+ export function strictNotEqual<T>(
184
+ left: TaggedTemplateValue<T> | T,
185
+ right: TaggedTemplateValue<T> | T,
186
+ ): TaggedTemplateValue<boolean> {
187
+ const leftExpr = isTaggedTemplateValue(left)
188
+ ? left.toRefString({ nestedContext: "expression" })
189
+ : JSON.stringify(left);
190
+ const rightExpr = isTaggedTemplateValue(right)
191
+ ? right.toRefString({ nestedContext: "expression" })
192
+ : JSON.stringify(right);
193
+
194
+ return expression`${leftExpr} !== ${rightExpr}`;
195
+ }
196
+
197
+ /**
198
+ * Greater than comparison (>)
199
+ * @param left - First value to compare
200
+ * @param right - Second value to compare
201
+ * @returns TaggedTemplateValue<boolean> representing the greater than expression
202
+ */
203
+ export function greaterThan<T extends number | string>(
204
+ left: TaggedTemplateValue<T> | T,
205
+ right: TaggedTemplateValue<T> | T,
206
+ ): TaggedTemplateValue<boolean> {
207
+ const leftExpr = isTaggedTemplateValue(left)
208
+ ? left.toRefString({ nestedContext: "expression" })
209
+ : JSON.stringify(left);
210
+ const rightExpr = isTaggedTemplateValue(right)
211
+ ? right.toRefString({ nestedContext: "expression" })
212
+ : JSON.stringify(right);
213
+
214
+ return expression`${leftExpr} > ${rightExpr}`;
215
+ }
216
+
217
+ /**
218
+ * Greater than or equal comparison (>=)
219
+ * @param left - First value to compare
220
+ * @param right - Second value to compare
221
+ * @returns TaggedTemplateValue<boolean> representing the greater than or equal expression
222
+ */
223
+ export function greaterThanOrEqual<T extends number | string>(
224
+ left: TaggedTemplateValue<T> | T,
225
+ right: TaggedTemplateValue<T> | T,
226
+ ): TaggedTemplateValue<boolean> {
227
+ const leftExpr = isTaggedTemplateValue(left)
228
+ ? left.toRefString({ nestedContext: "expression" })
229
+ : JSON.stringify(left);
230
+ const rightExpr = isTaggedTemplateValue(right)
231
+ ? right.toRefString({ nestedContext: "expression" })
232
+ : JSON.stringify(right);
233
+
234
+ return expression`${leftExpr} >= ${rightExpr}`;
235
+ }
236
+
237
+ /**
238
+ * Less than comparison (<)
239
+ * @param left - First value to compare
240
+ * @param right - Second value to compare
241
+ * @returns TaggedTemplateValue<boolean> representing the less than expression
242
+ */
243
+ export function lessThan<T extends number | string>(
244
+ left: TaggedTemplateValue<T> | T,
245
+ right: TaggedTemplateValue<T> | T,
246
+ ): TaggedTemplateValue<boolean> {
247
+ const leftExpr = isTaggedTemplateValue(left)
248
+ ? left.toRefString({ nestedContext: "expression" })
249
+ : JSON.stringify(left);
250
+ const rightExpr = isTaggedTemplateValue(right)
251
+ ? right.toRefString({ nestedContext: "expression" })
252
+ : JSON.stringify(right);
253
+
254
+ return expression`${leftExpr} < ${rightExpr}`;
255
+ }
256
+
257
+ /**
258
+ * Less than or equal comparison (<=)
259
+ * @param left - First value to compare
260
+ * @param right - Second value to compare
261
+ * @returns TaggedTemplateValue<boolean> representing the less than or equal expression
262
+ */
263
+ export function lessThanOrEqual<T extends number | string>(
264
+ left: TaggedTemplateValue<T> | T,
265
+ right: TaggedTemplateValue<T> | T,
266
+ ): TaggedTemplateValue<boolean> {
267
+ const leftExpr = isTaggedTemplateValue(left)
268
+ ? left.toRefString({ nestedContext: "expression" })
269
+ : JSON.stringify(left);
270
+ const rightExpr = isTaggedTemplateValue(right)
271
+ ? right.toRefString({ nestedContext: "expression" })
272
+ : JSON.stringify(right);
273
+
274
+ return expression`${leftExpr} <= ${rightExpr}`;
275
+ }
276
+
277
+ // ============================================================================
278
+ // Arithmetic Operations
279
+ // ============================================================================
280
+
281
+ /**
282
+ * Addition operation (+)
283
+ * @param args - Values or bindings to add together
284
+ * @returns TaggedTemplateValue<number> representing the addition expression
285
+ */
286
+ export function add(
287
+ ...args: Array<TaggedTemplateValue<number> | number>
288
+ ): TaggedTemplateValue<number> {
289
+ const expressions = args.map((arg) => {
290
+ if (isTaggedTemplateValue(arg)) {
291
+ return arg.toRefString({ nestedContext: "expression" });
292
+ }
293
+ return String(arg);
294
+ });
295
+
296
+ return expression`${expressions.join(" + ")}` as TaggedTemplateValue<number>;
297
+ }
298
+
299
+ /**
300
+ * Subtraction operation (-)
301
+ * @param left - Value to subtract from
302
+ * @param right - Value to subtract
303
+ * @returns TaggedTemplateValue<number> representing the subtraction expression
304
+ */
305
+ export function subtract(
306
+ left: TaggedTemplateValue<number> | number,
307
+ right: TaggedTemplateValue<number> | number,
308
+ ): TaggedTemplateValue<number> {
309
+ const leftExpr = isTaggedTemplateValue(left)
310
+ ? left.toRefString({ nestedContext: "expression" })
311
+ : String(left);
312
+ const rightExpr = isTaggedTemplateValue(right)
313
+ ? right.toRefString({ nestedContext: "expression" })
314
+ : String(right);
315
+
316
+ return expression`${leftExpr} - ${rightExpr}` as TaggedTemplateValue<number>;
317
+ }
318
+
319
+ /**
320
+ * Multiplication operation (*)
321
+ * @param args - Values or bindings to multiply together
322
+ * @returns TaggedTemplateValue<number> representing the multiplication expression
323
+ */
324
+ export function multiply(
325
+ ...args: Array<TaggedTemplateValue<number> | number>
326
+ ): TaggedTemplateValue<number> {
327
+ const expressions = args.map((arg) => {
328
+ if (isTaggedTemplateValue(arg)) {
329
+ return arg.toRefString({ nestedContext: "expression" });
330
+ }
331
+ return String(arg);
332
+ });
333
+
334
+ return expression`${expressions.join(" * ")}` as TaggedTemplateValue<number>;
335
+ }
336
+
337
+ /**
338
+ * Division operation (/)
339
+ * @param left - Dividend
340
+ * @param right - Divisor
341
+ * @returns TaggedTemplateValue<number> representing the division expression
342
+ */
343
+ export function divide(
344
+ left: TaggedTemplateValue<number> | number,
345
+ right: TaggedTemplateValue<number> | number,
346
+ ): TaggedTemplateValue<number> {
347
+ const leftExpr = isTaggedTemplateValue(left)
348
+ ? left.toRefString({ nestedContext: "expression" })
349
+ : String(left);
350
+ const rightExpr = isTaggedTemplateValue(right)
351
+ ? right.toRefString({ nestedContext: "expression" })
352
+ : String(right);
353
+
354
+ return expression`${leftExpr} / ${rightExpr}` as TaggedTemplateValue<number>;
355
+ }
356
+
357
+ /**
358
+ * Modulo operation (%)
359
+ * @param left - Dividend
360
+ * @param right - Divisor
361
+ * @returns TaggedTemplateValue<number> representing the modulo expression
362
+ */
363
+ export function modulo(
364
+ left: TaggedTemplateValue<number> | number,
365
+ right: TaggedTemplateValue<number> | number,
366
+ ): TaggedTemplateValue<number> {
367
+ const leftExpr = isTaggedTemplateValue(left)
368
+ ? left.toRefString({ nestedContext: "expression" })
369
+ : String(left);
370
+ const rightExpr = isTaggedTemplateValue(right)
371
+ ? right.toRefString({ nestedContext: "expression" })
372
+ : String(right);
373
+
374
+ return expression`${leftExpr} % ${rightExpr}` as TaggedTemplateValue<number>;
375
+ }
376
+
377
+ // ============================================================================
378
+ // Control Flow Operations
379
+ // ============================================================================
380
+
381
+ /**
382
+ * Conditional (ternary) operation - if-then-else logic
383
+ * @param condition - Condition to evaluate
384
+ * @param ifTrue - Value to return if condition is truthy
385
+ * @param ifFalse - Value to return if condition is falsy
386
+ * @returns TaggedTemplateValue<T> representing the conditional expression
387
+ */
388
+ export function conditional<T>(
389
+ condition: TaggedTemplateValue<boolean> | boolean,
390
+ ifTrue: TaggedTemplateValue<T> | T,
391
+ ifFalse: TaggedTemplateValue<T> | T,
392
+ ): TaggedTemplateValue<T> {
393
+ const conditionExpr = isTaggedTemplateValue(condition)
394
+ ? condition.toRefString({ nestedContext: "expression" })
395
+ : String(condition);
396
+
397
+ const trueExpr = isTaggedTemplateValue(ifTrue)
398
+ ? ifTrue.toRefString({ nestedContext: "expression" })
399
+ : JSON.stringify(ifTrue);
400
+
401
+ const falseExpr = isTaggedTemplateValue(ifFalse)
402
+ ? ifFalse.toRefString({ nestedContext: "expression" })
403
+ : JSON.stringify(ifFalse);
404
+
405
+ return expression`${conditionExpr} ? ${trueExpr} : ${falseExpr}` as TaggedTemplateValue<T>;
406
+ }
407
+
408
+ /**
409
+ * Function call expression
410
+ * @param functionName - Name of the function to call
411
+ * @param args - Arguments to pass to the function
412
+ * @returns TaggedTemplateValue<T> representing the function call expression
413
+ */
414
+ export function call<T = unknown>(
415
+ functionName: string,
416
+ ...args: Array<TaggedTemplateValue<unknown> | unknown>
417
+ ): TaggedTemplateValue<T> {
418
+ const argExpressions = args.map((arg) => {
419
+ if (isTaggedTemplateValue(arg)) {
420
+ return arg.toRefString({
421
+ nestedContext: "expression",
422
+ });
423
+ }
424
+ return JSON.stringify(arg);
425
+ });
426
+
427
+ return expression`${functionName}(${argExpressions.join(", ")})` as TaggedTemplateValue<T>;
428
+ }
429
+
430
+ // ============================================================================
431
+ // Type Utilities
432
+ // ============================================================================
433
+
434
+ /**
435
+ * Creates a literal value expression
436
+ * @param value - Literal value to create expression for
437
+ * @returns TaggedTemplateValue<T> representing the literal
438
+ */
439
+ export function literal<T>(value: T): TaggedTemplateValue<T> {
440
+ return expression`${JSON.stringify(value)}` as TaggedTemplateValue<T>;
441
+ }
442
+ // ============================================================================
443
+ // Shorthand Aliases
444
+ // ============================================================================
445
+
446
+ // Logical operations aliases
447
+ export { and as AND };
448
+ export { or as OR };
449
+ export { not as NOT };
450
+ export { nor as NOR };
451
+ export { nand as NAND };
452
+ export { xor as XOR };
453
+
454
+ // Comparison operations aliases
455
+ export { equal as eq };
456
+ export { strictEqual as strictEq };
457
+ export { notEqual as neq };
458
+ export { strictNotEqual as strictNeq };
459
+ export { greaterThan as gt };
460
+ export { greaterThanOrEqual as gte };
461
+ export { lessThan as lt };
462
+ export { lessThanOrEqual as lte };
463
+
464
+ // Arithmetic operations aliases
465
+ export { add as plus };
466
+ export { subtract as minus };
467
+ export { multiply as times };
468
+ export { divide as div };
469
+ export { modulo as mod };
470
+
471
+ // Control flow aliases
472
+ export { conditional as ternary, conditional as ifElse };