@elaraai/east-node-std 0.0.1-beta.9 → 1.0.0

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 (157) hide show
  1. package/CLA.md +1 -1
  2. package/CONTRIBUTING.md +3 -3
  3. package/LICENSE.md +31 -0
  4. package/README.md +55 -19
  5. package/dist/src/console.d.ts.map +1 -0
  6. package/dist/{console.js → src/console.js} +3 -3
  7. package/dist/src/console.js.map +1 -0
  8. package/dist/src/crypto.d.ts.map +1 -0
  9. package/dist/{crypto.js → src/crypto.js} +4 -4
  10. package/dist/src/crypto.js.map +1 -0
  11. package/dist/{fetch.d.ts → src/fetch.d.ts} +129 -79
  12. package/dist/src/fetch.d.ts.map +1 -0
  13. package/dist/{fetch.js → src/fetch.js} +76 -6
  14. package/dist/src/fetch.js.map +1 -0
  15. package/dist/src/fs.d.ts.map +1 -0
  16. package/dist/{fs.js → src/fs.js} +8 -8
  17. package/dist/src/fs.js.map +1 -0
  18. package/dist/src/index.d.ts.map +1 -0
  19. package/dist/src/index.js.map +1 -0
  20. package/dist/src/path.d.ts.map +1 -0
  21. package/dist/{path.js → src/path.js} +5 -5
  22. package/dist/src/path.js.map +1 -0
  23. package/dist/src/platform.d.ts.map +1 -0
  24. package/dist/src/platform.js.map +1 -0
  25. package/dist/src/random/crypto-rng.d.ts.map +1 -0
  26. package/dist/src/random/crypto-rng.js.map +1 -0
  27. package/dist/src/random/distributions/bates.d.ts.map +1 -0
  28. package/dist/src/random/distributions/bates.js.map +1 -0
  29. package/dist/src/random/distributions/bernoulli.d.ts.map +1 -0
  30. package/dist/src/random/distributions/bernoulli.js.map +1 -0
  31. package/dist/src/random/distributions/binomial.d.ts.map +1 -0
  32. package/dist/src/random/distributions/binomial.js.map +1 -0
  33. package/dist/src/random/distributions/exponential.d.ts.map +1 -0
  34. package/dist/src/random/distributions/exponential.js.map +1 -0
  35. package/dist/src/random/distributions/geometric.d.ts.map +1 -0
  36. package/dist/src/random/distributions/geometric.js.map +1 -0
  37. package/dist/src/random/distributions/irwin-hall.d.ts.map +1 -0
  38. package/dist/src/random/distributions/irwin-hall.js.map +1 -0
  39. package/dist/src/random/distributions/log-normal.d.ts.map +1 -0
  40. package/dist/src/random/distributions/log-normal.js.map +1 -0
  41. package/dist/src/random/distributions/normal.d.ts.map +1 -0
  42. package/dist/src/random/distributions/normal.js.map +1 -0
  43. package/dist/src/random/distributions/pareto.d.ts.map +1 -0
  44. package/dist/src/random/distributions/pareto.js.map +1 -0
  45. package/dist/src/random/distributions/poisson.d.ts.map +1 -0
  46. package/dist/src/random/distributions/poisson.js.map +1 -0
  47. package/dist/src/random/distributions/uniform-int.d.ts.map +1 -0
  48. package/dist/src/random/distributions/uniform-int.js.map +1 -0
  49. package/dist/src/random/distributions/uniform.d.ts.map +1 -0
  50. package/dist/src/random/distributions/uniform.js.map +1 -0
  51. package/dist/src/random/rng.d.ts.map +1 -0
  52. package/dist/src/random/rng.js.map +1 -0
  53. package/dist/src/random/xorshift128.d.ts.map +1 -0
  54. package/dist/src/random/xorshift128.js.map +1 -0
  55. package/dist/{random.d.ts → src/random.d.ts} +2 -1
  56. package/dist/src/random.d.ts.map +1 -0
  57. package/dist/{random.js → src/random.js} +13 -13
  58. package/dist/src/random.js.map +1 -0
  59. package/dist/{test.d.ts → src/test.d.ts} +8 -1
  60. package/dist/src/test.d.ts.map +1 -0
  61. package/dist/src/test.js +364 -0
  62. package/dist/src/test.js.map +1 -0
  63. package/dist/{time.d.ts → src/time.d.ts} +50 -2
  64. package/dist/src/time.d.ts.map +1 -0
  65. package/dist/{time.js → src/time.js} +100 -4
  66. package/dist/src/time.js.map +1 -0
  67. package/package.json +24 -47
  68. package/dist/console.d.ts.map +0 -1
  69. package/dist/console.js.map +0 -1
  70. package/dist/crypto.d.ts.map +0 -1
  71. package/dist/crypto.js.map +0 -1
  72. package/dist/fetch.d.ts.map +0 -1
  73. package/dist/fetch.js.map +0 -1
  74. package/dist/fs.d.ts.map +0 -1
  75. package/dist/fs.js.map +0 -1
  76. package/dist/index.d.ts.map +0 -1
  77. package/dist/index.js.map +0 -1
  78. package/dist/path.d.ts.map +0 -1
  79. package/dist/path.js.map +0 -1
  80. package/dist/platform.d.ts.map +0 -1
  81. package/dist/platform.js.map +0 -1
  82. package/dist/random/crypto-rng.d.ts.map +0 -1
  83. package/dist/random/crypto-rng.js.map +0 -1
  84. package/dist/random/distributions/bates.d.ts.map +0 -1
  85. package/dist/random/distributions/bates.js.map +0 -1
  86. package/dist/random/distributions/bernoulli.d.ts.map +0 -1
  87. package/dist/random/distributions/bernoulli.js.map +0 -1
  88. package/dist/random/distributions/binomial.d.ts.map +0 -1
  89. package/dist/random/distributions/binomial.js.map +0 -1
  90. package/dist/random/distributions/exponential.d.ts.map +0 -1
  91. package/dist/random/distributions/exponential.js.map +0 -1
  92. package/dist/random/distributions/geometric.d.ts.map +0 -1
  93. package/dist/random/distributions/geometric.js.map +0 -1
  94. package/dist/random/distributions/irwin-hall.d.ts.map +0 -1
  95. package/dist/random/distributions/irwin-hall.js.map +0 -1
  96. package/dist/random/distributions/log-normal.d.ts.map +0 -1
  97. package/dist/random/distributions/log-normal.js.map +0 -1
  98. package/dist/random/distributions/normal.d.ts.map +0 -1
  99. package/dist/random/distributions/normal.js.map +0 -1
  100. package/dist/random/distributions/pareto.d.ts.map +0 -1
  101. package/dist/random/distributions/pareto.js.map +0 -1
  102. package/dist/random/distributions/poisson.d.ts.map +0 -1
  103. package/dist/random/distributions/poisson.js.map +0 -1
  104. package/dist/random/distributions/uniform-int.d.ts.map +0 -1
  105. package/dist/random/distributions/uniform-int.js.map +0 -1
  106. package/dist/random/distributions/uniform.d.ts.map +0 -1
  107. package/dist/random/distributions/uniform.js.map +0 -1
  108. package/dist/random/rng.d.ts.map +0 -1
  109. package/dist/random/rng.js.map +0 -1
  110. package/dist/random/xorshift128.d.ts.map +0 -1
  111. package/dist/random/xorshift128.js.map +0 -1
  112. package/dist/random.d.ts.map +0 -1
  113. package/dist/random.js.map +0 -1
  114. package/dist/test.d.ts.map +0 -1
  115. package/dist/test.js +0 -828
  116. package/dist/test.js.map +0 -1
  117. package/dist/time.d.ts.map +0 -1
  118. package/dist/time.js.map +0 -1
  119. package/dist/tsconfig.tsbuildinfo +0 -1
  120. /package/dist/{console.d.ts → src/console.d.ts} +0 -0
  121. /package/dist/{crypto.d.ts → src/crypto.d.ts} +0 -0
  122. /package/dist/{fs.d.ts → src/fs.d.ts} +0 -0
  123. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  124. /package/dist/{index.js → src/index.js} +0 -0
  125. /package/dist/{path.d.ts → src/path.d.ts} +0 -0
  126. /package/dist/{platform.d.ts → src/platform.d.ts} +0 -0
  127. /package/dist/{platform.js → src/platform.js} +0 -0
  128. /package/dist/{random → src/random}/crypto-rng.d.ts +0 -0
  129. /package/dist/{random → src/random}/crypto-rng.js +0 -0
  130. /package/dist/{random → src/random}/distributions/bates.d.ts +0 -0
  131. /package/dist/{random → src/random}/distributions/bates.js +0 -0
  132. /package/dist/{random → src/random}/distributions/bernoulli.d.ts +0 -0
  133. /package/dist/{random → src/random}/distributions/bernoulli.js +0 -0
  134. /package/dist/{random → src/random}/distributions/binomial.d.ts +0 -0
  135. /package/dist/{random → src/random}/distributions/binomial.js +0 -0
  136. /package/dist/{random → src/random}/distributions/exponential.d.ts +0 -0
  137. /package/dist/{random → src/random}/distributions/exponential.js +0 -0
  138. /package/dist/{random → src/random}/distributions/geometric.d.ts +0 -0
  139. /package/dist/{random → src/random}/distributions/geometric.js +0 -0
  140. /package/dist/{random → src/random}/distributions/irwin-hall.d.ts +0 -0
  141. /package/dist/{random → src/random}/distributions/irwin-hall.js +0 -0
  142. /package/dist/{random → src/random}/distributions/log-normal.d.ts +0 -0
  143. /package/dist/{random → src/random}/distributions/log-normal.js +0 -0
  144. /package/dist/{random → src/random}/distributions/normal.d.ts +0 -0
  145. /package/dist/{random → src/random}/distributions/normal.js +0 -0
  146. /package/dist/{random → src/random}/distributions/pareto.d.ts +0 -0
  147. /package/dist/{random → src/random}/distributions/pareto.js +0 -0
  148. /package/dist/{random → src/random}/distributions/poisson.d.ts +0 -0
  149. /package/dist/{random → src/random}/distributions/poisson.js +0 -0
  150. /package/dist/{random → src/random}/distributions/uniform-int.d.ts +0 -0
  151. /package/dist/{random → src/random}/distributions/uniform-int.js +0 -0
  152. /package/dist/{random → src/random}/distributions/uniform.d.ts +0 -0
  153. /package/dist/{random → src/random}/distributions/uniform.js +0 -0
  154. /package/dist/{random → src/random}/rng.d.ts +0 -0
  155. /package/dist/{random → src/random}/rng.js +0 -0
  156. /package/dist/{random → src/random}/xorshift128.d.ts +0 -0
  157. /package/dist/{random → src/random}/xorshift128.js +0 -0
package/dist/test.js DELETED
@@ -1,828 +0,0 @@
1
- /**
2
- * Copyright (c) 2025 Elara AI Pty Ltd
3
- * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
- */
5
- import assert from "node:assert/strict";
6
- import util from "node:util";
7
- import { test as testNode, describe as describeNode } from "node:test";
8
- import { writeFileSync, mkdirSync } from "node:fs";
9
- import { join } from "node:path";
10
- import { AsyncFunctionType, East, Expr, get_location, IRType, NullType, StringType, toJSONFor } from "@elaraai/east";
11
- const { str } = East;
12
- // Force node test to show full stack traces for easier debugging
13
- Error.stackTraceLimit = Infinity;
14
- // Force node to print full objects in console.log output
15
- util.inspect.defaultOptions.depth = null;
16
- /**
17
- * Platform function that indicates a test assertion passed.
18
- *
19
- * This is used by East test code to signal successful assertions.
20
- * When running in Node.js, this does nothing. Other platforms may log or track passes.
21
- */
22
- const testPass = East.platform("testPass", [], NullType);
23
- /**
24
- * Platform function that indicates a test assertion failed.
25
- *
26
- * This is used by East test code to signal failed assertions.
27
- * When running in Node.js, this throws an assertion error.
28
- *
29
- * @param message - The error message describing the assertion failure
30
- */
31
- const testFail = East.platform("testFail", [StringType], NullType);
32
- /**
33
- * Platform function that defines a single test case.
34
- *
35
- * This is used by East test code to define individual tests.
36
- * When running in Node.js, this runs the test using Node's test runner.
37
- *
38
- * @param name - The name of the test
39
- * @param body - The test body function
40
- */
41
- const test = East.asyncPlatform("test", [StringType, AsyncFunctionType([], NullType)], NullType);
42
- /**
43
- * Platform function that defines a test suite.
44
- *
45
- * This is used by East test code to group related tests.
46
- * When running in Node.js, this runs the suite using Node's describe.
47
- *
48
- * @param name - The name of the test suite
49
- * @param body - A function that calls test() to define tests
50
- */
51
- const describe = East.asyncPlatform("describe", [StringType, AsyncFunctionType([], NullType)], NullType);
52
- /**
53
- * Creates a test platform that uses Node.js assertions.
54
- *
55
- * @returns A platform object with `testPass`, `testFail`, `test`, and `describe` functions
56
- */
57
- export const TestImpl = [
58
- testPass.implement(() => { }), // Assertion passed - do nothing (test continues)
59
- testFail.implement((message) => {
60
- // Assertion failed - throw to fail the test
61
- assert.fail(message);
62
- }),
63
- test.implement((name, body) => testNode(name, async () => { await body(); })),
64
- describe.implement((name, body) => describeNode(name, async () => { await body(); })),
65
- ];
66
- const IRToJSON = toJSONFor(IRType);
67
- /**
68
- * Defines and runs an East test suite using platform functions.
69
- *
70
- * This creates a single East function that calls `describe` and `test` platform functions.
71
- * The entire suite can be exported as IR and run on any East implementation that provides
72
- * the test platform (testPass, testFail, test, describe).
73
- *
74
- * When the `EXPORT_TEST_IR` environment variable is set to a directory path, the IR for
75
- * each test suite is exported to `<path>/<suite_name>.json`.
76
- *
77
- * @param suiteName - The name of the test suite
78
- * @param builder - A function that receives a `test` function for defining tests
79
- *
80
- * @example
81
- * ```ts
82
- * describeEast("Array tests", (test) => {
83
- * test("addition", $ => {
84
- * $(assertEast.equal(East.value(1n).add(1n), 2n));
85
- * });
86
- * test("subtraction", $ => {
87
- * $(assertEast.equal(East.value(2n).subtract(1n), 1n));
88
- * });
89
- * });
90
- * ```
91
- *
92
- * @example
93
- * ```bash
94
- * # Export test IR to a directory
95
- * EXPORT_TEST_IR=./test-ir npm test
96
- * ```
97
- */
98
- export function describeEast(suiteName, builder, options) {
99
- const tests = [];
100
- // Collect all test names and bodies
101
- builder((name, body) => {
102
- tests.push({ name, body });
103
- });
104
- // Create a single East function that uses describe/test platform functions
105
- const suiteFunction = East.asyncFunction([], NullType, $ => {
106
- $(describe.call($, suiteName, East.asyncFunction([], NullType, $ => {
107
- // beforeAll hook
108
- if (options?.beforeAll) {
109
- options.beforeAll($);
110
- }
111
- for (const { name, body } of tests) {
112
- $(test.call($, name, East.asyncFunction([], NullType, $test => {
113
- // beforeEach hook (inside test body)
114
- if (options?.beforeEach) {
115
- options.beforeEach($test);
116
- }
117
- // Wrap test body in try-finally so afterEach runs even on failure
118
- if (options?.afterEach) {
119
- $test.try(body).finally(options.afterEach);
120
- }
121
- else {
122
- body($test);
123
- }
124
- })));
125
- }
126
- // afterAll hook
127
- if (options?.afterAll) {
128
- options.afterAll($);
129
- }
130
- })));
131
- });
132
- // Auto-export test IR if EXPORT_TEST_IR environment variable is set to a path
133
- if (process.env.EXPORT_TEST_IR) {
134
- const outputDir = process.env.EXPORT_TEST_IR;
135
- try {
136
- mkdirSync(outputDir, { recursive: true });
137
- const ir = suiteFunction.toIR();
138
- const irJSON = IRToJSON(ir.ir);
139
- const filename = join(outputDir, `${suiteName.replace(/[^a-zA-Z0-9]/g, '_')}.json`);
140
- writeFileSync(filename, JSON.stringify(irJSON, null, 2));
141
- console.log(`✓ Exported test IR: ${filename}`);
142
- }
143
- catch (err) {
144
- console.error(`✗ Failed to export test IR for "${suiteName}":`, err);
145
- }
146
- }
147
- if (options?.exportOnly !== true) {
148
- // Run the test suite using the Node.js platform implementation
149
- const compiled = suiteFunction.toIR().compile([...(options?.platformFns ?? [])]);
150
- return compiled();
151
- }
152
- }
153
- /**
154
- * East assertion functions that match Node.js assert API naming.
155
- *
156
- * These functions generate East expressions that perform runtime assertions
157
- * using platform functions, enabling testing of East code.
158
- */
159
- export const Assert = {
160
- /**
161
- * Asserts that two values are the same reference (meaning if one is mutated, the other reflects the change - and they are always equal).
162
- *
163
- * @typeParam E - The type of the actual expression
164
- * @param actual - The actual value to test
165
- * @param expected - The expected value to compare against
166
- * @returns An East expression that performs the equality check
167
- */
168
- is(actual, expected) {
169
- const location = get_location(2);
170
- const expected_expr = Expr.from(expected, Expr.type(actual));
171
- return Expr.tryCatch(Expr.block($ => {
172
- const act = $.let(actual);
173
- const exp = $.let(expected_expr);
174
- return East.is(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`));
175
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
176
- },
177
- /**
178
- * Asserts that two values are equal.
179
- *
180
- * @typeParam E - The type of the actual expression
181
- * @param actual - The actual value to test
182
- * @param expected - The expected value to compare against
183
- * @returns An East expression that performs the equality check
184
- */
185
- equal(actual, expected) {
186
- const location = get_location(2);
187
- const expected_expr = Expr.from(expected, Expr.type(actual));
188
- return Expr.tryCatch(Expr.block($ => {
189
- const act = $.let(actual);
190
- const exp = $.let(expected_expr);
191
- return East.equal(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to equal ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`));
192
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
193
- },
194
- /**
195
- * Asserts that two values are not equal.
196
- *
197
- * @typeParam E - The type of the actual expression
198
- * @param actual - The actual value to test
199
- * @param expected - The value that should not be equal
200
- * @returns An East expression that performs the inequality check
201
- */
202
- notEqual(actual, expected) {
203
- const location = get_location(2);
204
- const expected_expr = Expr.from(expected, Expr.type(actual));
205
- return Expr.tryCatch(Expr.block($ => {
206
- const act = $.let(actual);
207
- const exp = $.let(expected_expr);
208
- return East.notEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to not equal ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`));
209
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
210
- },
211
- /**
212
- * Asserts that actual is less than expected.
213
- *
214
- * @typeParam E - The type of the actual expression
215
- * @param actual - The actual value to test
216
- * @param expected - The value that actual should be less than
217
- * @returns An East expression that performs the less-than check
218
- */
219
- less(actual, expected) {
220
- const location = get_location(2);
221
- const expected_expr = Expr.from(expected, Expr.type(actual));
222
- return Expr.tryCatch(Expr.block($ => {
223
- const act = $.let(actual);
224
- const exp = $.let(expected_expr);
225
- return East.less(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be less than ${exp} (${`${location.filename} ${location.line}:${location.column}`})`));
226
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
227
- },
228
- /**
229
- * Asserts that actual is less than or equal to expected.
230
- *
231
- * @typeParam E - The type of the actual expression
232
- * @param actual - The actual value to test
233
- * @param expected - The value that actual should be less than or equal to
234
- * @returns An East expression that performs the less-than-or-equal check
235
- */
236
- lessEqual(actual, expected) {
237
- const location = get_location(2);
238
- const expected_expr = Expr.from(expected, Expr.type(actual));
239
- return Expr.tryCatch(Expr.block($ => {
240
- const act = $.let(actual);
241
- const exp = $.let(expected_expr);
242
- return East.lessEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be less than or equal to ${exp} (${`${location.filename} ${location.line}:${location.column}`})`));
243
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
244
- },
245
- /**
246
- * Asserts that actual is greater than expected.
247
- *
248
- * @typeParam E - The type of the actual expression
249
- * @param actual - The actual value to test
250
- * @param expected - The value that actual should be greater than
251
- * @returns An East expression that performs the greater-than check
252
- */
253
- greater(actual, expected) {
254
- const location = get_location(2);
255
- const expected_expr = Expr.from(expected, Expr.type(actual));
256
- return Expr.tryCatch(Expr.block($ => {
257
- const act = $.let(actual);
258
- const exp = $.let(expected_expr);
259
- return East.greater(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be greater than ${exp} (${`${location.filename} ${location.line}:${location.column}`})`));
260
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
261
- },
262
- /**
263
- * Asserts that actual is greater than or equal to expected.
264
- *
265
- * @typeParam E - The type of the actual expression
266
- * @param actual - The actual value to test
267
- * @param expected - The value that actual should be greater than or equal to
268
- * @returns An East expression that performs the greater-than-or-equal check
269
- */
270
- greaterEqual(actual, expected) {
271
- const location = get_location(2);
272
- const expected_expr = Expr.from(expected, Expr.type(actual));
273
- return Expr.tryCatch(Expr.block($ => {
274
- const act = $.let(actual);
275
- const exp = $.let(expected_expr);
276
- return East.greaterEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be greater than or equal to ${exp} (${`${location.filename} ${location.line}:${location.column}`})`));
277
- }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
278
- },
279
- /**
280
- * Asserts that actual is between min and max (inclusive).
281
- *
282
- * @typeParam E - The type of the actual expression
283
- * @param actual - The actual value to test
284
- * @param min - The minimum value (inclusive)
285
- * @param max - The maximum value (inclusive)
286
- * @returns An East expression that performs the range check
287
- */
288
- between(actual, min, max) {
289
- const location = get_location(2);
290
- const min_expr = Expr.from(min, Expr.type(actual));
291
- const max_expr = Expr.from(max, Expr.type(actual));
292
- return Expr.tryCatch(East.greaterEqual(actual, min_expr).ifElse(_$ => East.lessEqual(actual, max_expr).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${actual} to be less than or equal to ${max_expr} (${`${location.filename} ${location.line}:${location.column}`})`)), _$ => testFail(str `Expected ${actual} to be greater than or equal to ${min_expr}`)), (_$, message, stack) => testFail(East.String.printError(message, stack)));
293
- },
294
- /**
295
- * Asserts that an expression throws an error.
296
- *
297
- * @param fn - The expression that should throw an error when evaluated
298
- * @param pattern - Optional regex pattern to match against the error message
299
- * @returns An East expression that verifies an error is thrown
300
- */
301
- throws(fn, pattern) {
302
- const location = get_location(2);
303
- return Expr.tryCatch(Expr.block($ => {
304
- const result = $.let(fn);
305
- $(testFail(str `Expected error, got ${result} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`));
306
- return null;
307
- }), ($, message, stack) => {
308
- if (pattern) {
309
- // Validate error message matches the pattern
310
- return message.contains(pattern).ifElse(_$ => testPass(), _$ => testFail(str `Expected error message to match ${East.value(pattern.source)}, but got: ${East.String.printError(message, stack)}`));
311
- }
312
- else {
313
- // Just verify it threw
314
- return testPass();
315
- }
316
- });
317
- },
318
- /**
319
- * Fails a test with the given message.
320
- *
321
- * @param message
322
- * @returns An East expression that unconditionally fails the test
323
- */
324
- fail(message) {
325
- const location = get_location(2);
326
- const message_expr = Expr.from(message, StringType);
327
- return testFail(str `${message_expr} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`);
328
- }
329
- };
330
- // /**
331
- // * Copyright (c) 2025 Elara AI Pty Ltd
332
- // * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
333
- // */
334
- // import assert from "node:assert/strict";
335
- // import { test as testNode, describe as describeNode } from "node:test";
336
- // import { East, Expr, get_location, NullType, StringType, BlockBuilder, type SubtypeExprOrValue, type ExprType, type EastType, AsyncFunctionType } from "@elaraai/east";
337
- // import type { PlatformFunction } from "@elaraai/east/internal";
338
- // const { str } = East;
339
- // /**
340
- // * Signals that a test assertion passed.
341
- // *
342
- // * This platform function is used internally by East test assertions to indicate
343
- // * successful validation. When executed in Node.js, it performs no action (the test
344
- // * continues normally). Other platform implementations may log or track passes.
345
- // *
346
- // * This function is primarily used within the {@link Test} assertion helpers rather
347
- // * than being called directly in test code.
348
- // *
349
- // * @returns `null` - Has no meaningful return value
350
- // *
351
- // * @example
352
- // * ```ts
353
- // * import { East, NullType } from "@elaraai/east";
354
- // * import { Test } from "@elaraai/east-node-std";
355
- // *
356
- // * // Used internally by Test assertions
357
- // * const myTest = East.function([], NullType, $ => {
358
- // * // Test.equal internally calls testPass when the assertion succeeds
359
- // * $(Test.equal(East.value(42n), 42n));
360
- // * });
361
- // *
362
- // * const compiled = East.compile(myTest.toIR(), Test.Implementation);
363
- // * compiled(); // Test passes silently
364
- // * ```
365
- // *
366
- // * @remarks
367
- // * - Does not throw or produce output in Node.js implementation
368
- // * - Used by all {@link Test} assertion methods to signal success
369
- // * - Can be called directly for custom assertion logic
370
- // */
371
- // export const testPass = East.platform("testPass", [], NullType);
372
- // /**
373
- // * Signals that a test assertion failed with a message.
374
- // *
375
- // * This platform function is used internally by East test assertions to indicate
376
- // * validation failures. When executed in Node.js, it throws an assertion error with
377
- // * the provided message, causing the test to fail.
378
- // *
379
- // * This function is primarily used within the {@link Test} assertion helpers rather
380
- // * than being called directly, though it can be used for custom failure conditions.
381
- // *
382
- // * @param message - The error message describing why the assertion failed
383
- // * @returns `null` - Never actually returns (throws in implementation)
384
- // *
385
- // * @throws {AssertionError} Always throws with the provided message (Node.js implementation)
386
- // *
387
- // * @example
388
- // * ```ts
389
- // * import { East, StringType, NullType } from "@elaraai/east";
390
- // * import { Test } from "@elaraai/east-node-std";
391
- // *
392
- // * // Used internally by Test assertions
393
- // * const myTest = East.function([], NullType, $ => {
394
- // * // Test.equal internally calls testFail when the assertion fails
395
- // * $(Test.equal(East.value(42n), 99n));
396
- // * // Throws: "Expected 42 to equal 99 (...)"
397
- // * });
398
- // * ```
399
- // *
400
- // * @example
401
- // * ```ts
402
- // * // Direct usage for custom validation
403
- // * const validatePositive = East.function([IntegerType], NullType, ($, n) => {
404
- // * return n.greater(0n).ifElse(
405
- // * _ => Test.pass(),
406
- // * _ => Test.fail("Number must be positive")
407
- // * );
408
- // * });
409
- // *
410
- // * const compiled = East.compile(validatePositive.toIR(), Test.Implementation);
411
- // * compiled(-5n); // Throws: "Number must be positive"
412
- // * ```
413
- // *
414
- // * @remarks
415
- // * - Always throws in Node.js implementation (test fails immediately)
416
- // * - Used by all {@link Test} assertion methods to signal failure
417
- // * - Accepts location information in message for debugging
418
- // */
419
- // const testFail = East.platform("testFail", [StringType], NullType);
420
- // const test = East.asyncPlatform("test", [StringType, AsyncFunctionType([], NullType)], NullType);
421
- // const describe = East.asyncPlatform("describe", [StringType, AsyncFunctionType([], NullType)], NullType);
422
- // export const NodeTestTypes: any[] = [
423
- // testPass,
424
- // testFail,
425
- // test,
426
- // describe,
427
- // ];
428
- // export const NodeTest: PlatformFunction[] = [
429
- // testPass.implement(() => { }), // Assertion passed - do nothing (test continues)
430
- // testFail.implement((message: string) => {
431
- // // Assertion failed - throw to fail the test
432
- // assert.fail(message);
433
- // }),
434
- // test.implement(async (name: string, body: () => Promise<null>) => {
435
- // testNode(name, async () => {
436
- // await body();
437
- // });
438
- // }),
439
- // describe.implement(async (
440
- // name: string,
441
- // body: () => Promise<null>,
442
- // ) => {
443
- // describeNode(name, async () => {
444
- // await body();
445
- // });
446
- // }),
447
- // ];
448
- // /**
449
- // * Configuration options for East test suites.
450
- // */
451
- // export interface DescribeEastOptions {
452
- // /**
453
- // * Platform functions to include in all tests and hooks.
454
- // */
455
- // platformFns?: PlatformFunction[];
456
- // /**
457
- // * Setup function run once before all tests.
458
- // * Use for opening database connections, initializing resources, etc.
459
- // */
460
- // beforeAll?: ($: BlockBuilder<NullType>) => void;
461
- // /**
462
- // * Cleanup function run once after all tests.
463
- // * Use for closing database connections, cleaning up resources, etc.
464
- // * Runs even if tests fail.
465
- // */
466
- // afterAll?: ($: BlockBuilder<NullType>) => void;
467
- // /**
468
- // * Setup function run before each test.
469
- // */
470
- // beforeEach?: ($: BlockBuilder<NullType>) => void;
471
- // /**
472
- // * Cleanup function run after each test.
473
- // * Runs even if the test fails.
474
- // */
475
- // afterEach?: ($: BlockBuilder<NullType>) => void;
476
- // }
477
- // /**
478
- // * Wrapper around Node.js `describe` that also exports test IR for cross-platform testing.
479
- // *
480
- // * This function behaves exactly like Node.js `describe` - it runs all the tests normally.
481
- // * Additionally, it creates a single East function that runs all tests in sequence,
482
- // * making it easy to export the entire test suite for running in other East implementations.
483
- // *
484
- // * Supports lifecycle hooks (beforeAll, afterAll, beforeEach, afterEach) as East functions
485
- // * to properly set up and tear down resources like database connections.
486
- // *
487
- // * @param suiteName - The name of the test suite
488
- // * @param builder - A function that receives a `test` function for defining tests
489
- // * @param options - Configuration options including platform functions and lifecycle hooks
490
- // *
491
- // * @example
492
- // * ```ts
493
- // * // Basic usage with platform functions
494
- // * describeEast("Array tests", (test) => {
495
- // * test("addition", $ => {
496
- // * $(Test.equal(East.value(1n).add(1n), 2n));
497
- // * });
498
- // * }, { platformFns: [] });
499
- // * ```
500
- // *
501
- // * @example
502
- // * ```ts
503
- // * // With database cleanup hooks
504
- // * import { SQL } from "@elaraai/east-node-io";
505
- // *
506
- // * describeEast("Database tests", (test) => {
507
- // * test("query users", $ => {
508
- // * const conn = $.let(SQL.Postgres.connect(config));
509
- // * const result = $.let(SQL.Postgres.query(conn, "SELECT * FROM users", []));
510
- // * $(Test.equal(result.rows.length(), 2n));
511
- // * });
512
- // * }, {
513
- // * platformFns: SQL.Postgres.Implementation,
514
- // * afterEach: $ => {
515
- // * // Close connections even if test fails
516
- // * const conn = $.let(SQL.Postgres.connect(config));
517
- // * $(SQL.Postgres.close(conn));
518
- // * }
519
- // * });
520
- // * ```
521
- // */
522
- // export function describeEast(
523
- // suiteName: string,
524
- // builder: (test: (name: string, body: ($: BlockBuilder<NullType>) => void) => void) => void,
525
- // options: DescribeEastOptions = {}
526
- // ) {
527
- // const platformFns = options.platformFns ?? [];
528
- // const tests: Array<{ name: string, body: ($: BlockBuilder<NullType>) => void }> = [];
529
- // // Collect all test names and bodies
530
- // builder((name: string, body: ($: BlockBuilder<NullType>) => void) => tests.push({ name, body }));
531
- // // Create a single East function that uses describe/test platform functions
532
- // const suiteFunction = East.asyncFunction([], NullType, $ => {
533
- // $(describe.call(
534
- // $,
535
- // suiteName,
536
- // East.asyncFunction([], NullType, $ => {
537
- // if (options.beforeAll) $(test.call($, "beforeAll", East.asyncFunction([], NullType, options.beforeAll)));
538
- // for (const { name, body } of tests) {
539
- // if (options.beforeEach) $(test.call($, "beforeEach", East.asyncFunction([], NullType, options.beforeEach)));
540
- // $(test.call($, name, East.asyncFunction([], NullType, body)));
541
- // if (options.afterEach) $(test.call($, "afterEach", East.asyncFunction([], NullType, options.afterEach)));
542
- // }
543
- // if (options.afterAll) $(test.call($, "afterAll", East.asyncFunction([], NullType, options.afterAll)));
544
- // }),
545
- // ));
546
- // });
547
- // const funcs = [...NodeTest, ...platformFns]
548
- // if(funcs.some(f => f.type === 'async')) {
549
- // suiteFunction.toIR().compile([...NodeTest, ...platformFns]);
550
- // } else {
551
- // suiteFunction.toIR().compile([...NodeTest, ...platformFns]);
552
- // }
553
- // // Run the test suite using the Node.js platform implementation
554
- // }
555
- // /**
556
- // * East assertion functions that match Node.js assert API naming.
557
- // *
558
- // * These functions generate East expressions that perform runtime assertions
559
- // * using platform functions, enabling testing of East code.
560
- // */
561
- // /**
562
- // * East assertion functions that match Node.js assert API naming.
563
- // *
564
- // * These functions generate East expressions that perform runtime assertions
565
- // * using platform functions, enabling testing of East code.
566
- // */
567
- // export const Test = {
568
- // /**
569
- // * Platform function that signals a test assertion passed.
570
- // *
571
- // * Used internally by assertion methods to indicate successful validation.
572
- // * Does nothing in Node.js implementation - test continues normally.
573
- // *
574
- // * @returns An East expression that returns `null`
575
- // *
576
- // * @example
577
- // * ```ts
578
- // * import { East, NullType } from "@elaraai/east";
579
- // * import { Test } from "@elaraai/east-node-std";
580
- // *
581
- // * const customAssertion = East.function([], NullType, $ => {
582
- // * return East.value(true).ifElse(
583
- // * _ => Test.pass(),
584
- // * _ => Test.fail("Condition was false")
585
- // * );
586
- // * });
587
- // * ```
588
- // */
589
- // pass: testPass,
590
- // /**
591
- // * Platform function that signals a test assertion failed.
592
- // *
593
- // * Used internally by assertion methods to indicate validation failures.
594
- // * Throws an assertion error in Node.js implementation - test fails immediately.
595
- // *
596
- // * @param message - Error message describing the failure
597
- // * @returns An East expression that returns `null` (never actually returns - throws)
598
- // *
599
- // * @example
600
- // * ```ts
601
- // * import { East, StringType, NullType } from "@elaraai/east";
602
- // * import { Test } from "@elaraai/east-node-std";
603
- // *
604
- // * const validateRange = East.function([IntegerType], NullType, ($, value) => {
605
- // * return value.between(0n, 100n).ifElse(
606
- // * _ => Test.pass(),
607
- // * _ => Test.fail("Value must be between 0 and 100")
608
- // * );
609
- // * });
610
- // * ```
611
- // */
612
- // fail: testFail,
613
- // /**
614
- // * Asserts that two values are the same reference (meaning if one is mutated, the other reflects the change - and they are always equal).
615
- // *
616
- // * @typeParam E - The type of the actual expression
617
- // * @param actual - The actual value to test
618
- // * @param expected - The expected value to compare against
619
- // * @returns An East expression that performs the equality check
620
- // */
621
- // is<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
622
- // const location = get_location(2);
623
- // const expected_expr = Expr.from(expected, Expr.type(actual));
624
- // return Expr.tryCatch(
625
- // Expr.block($ => {
626
- // const act = $.let(actual);
627
- // const exp = $.let(expected_expr);
628
- // return East.is(act as any, exp as any).ifElse(
629
- // _$ => testPass(),
630
- // _$ => testFail(str`Expected ${act} to equal ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`)
631
- // );
632
- // }),
633
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
634
- // );
635
- // },
636
- // /**
637
- // * Asserts that two values are equal.
638
- // *
639
- // * @typeParam E - The type of the actual expression
640
- // * @param actual - The actual value to test
641
- // * @param expected - The expected value to compare against
642
- // * @returns An East expression that performs the equality check
643
- // */
644
- // equal<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
645
- // const location = get_location(2);
646
- // const expected_expr = Expr.from(expected, Expr.type(actual));
647
- // return Expr.tryCatch(
648
- // Expr.block($ => {
649
- // const act = $.let(actual);
650
- // const exp = $.let(expected_expr);
651
- // return East.equal(act as any, exp as any).ifElse(
652
- // _$ => testPass(),
653
- // _$ => testFail(str`Expected ${act} to equal ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`)
654
- // );
655
- // }),
656
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
657
- // );
658
- // },
659
- // /**
660
- // * Asserts that two values are not equal.
661
- // *
662
- // * @typeParam E - The type of the actual expression
663
- // * @param actual - The actual value to test
664
- // * @param expected - The value that should not be equal
665
- // * @returns An East expression that performs the inequality check
666
- // */
667
- // notEqual<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
668
- // const location = get_location(2);
669
- // const expected_expr = Expr.from(expected, Expr.type(actual));
670
- // return Expr.tryCatch(
671
- // Expr.block($ => {
672
- // const act = $.let(actual);
673
- // const exp = $.let(expected_expr);
674
- // return East.notEqual(act as any, exp as any).ifElse(
675
- // _$ => testPass(),
676
- // _$ => testFail(str`Expected ${act} to not equal ${exp} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`)
677
- // );
678
- // }),
679
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
680
- // );
681
- // },
682
- // /**
683
- // * Asserts that actual is less than expected.
684
- // *
685
- // * @typeParam E - The type of the actual expression
686
- // * @param actual - The actual value to test
687
- // * @param expected - The value that actual should be less than
688
- // * @returns An East expression that performs the less-than check
689
- // */
690
- // less<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
691
- // const location = get_location(2);
692
- // const expected_expr = Expr.from(expected, Expr.type(actual));
693
- // return Expr.tryCatch(
694
- // Expr.block($ => {
695
- // const act = $.let(actual);
696
- // const exp = $.let(expected_expr);
697
- // return East.less(act as any, exp as any).ifElse(
698
- // _$ => testPass(),
699
- // _$ => testFail(str`Expected ${act} to be less than ${exp} (${`${location.filename} ${location.line}:${location.column}`})`)
700
- // );
701
- // }),
702
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
703
- // );
704
- // },
705
- // /**
706
- // * Asserts that actual is less than or equal to expected.
707
- // *
708
- // * @typeParam E - The type of the actual expression
709
- // * @param actual - The actual value to test
710
- // * @param expected - The value that actual should be less than or equal to
711
- // * @returns An East expression that performs the less-than-or-equal check
712
- // */
713
- // lessEqual<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
714
- // const location = get_location(2);
715
- // const expected_expr = Expr.from(expected, Expr.type(actual));
716
- // return Expr.tryCatch(
717
- // Expr.block($ => {
718
- // const act = $.let(actual);
719
- // const exp = $.let(expected_expr);
720
- // return East.lessEqual(act as any, exp as any).ifElse(
721
- // _$ => testPass(),
722
- // _$ => testFail(str`Expected ${act} to be less than or equal to ${exp} (${`${location.filename} ${location.line}:${location.column}`})`)
723
- // );
724
- // }),
725
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
726
- // );
727
- // },
728
- // /**
729
- // * Asserts that actual is greater than expected.
730
- // *
731
- // * @typeParam E - The type of the actual expression
732
- // * @param actual - The actual value to test
733
- // * @param expected - The value that actual should be greater than
734
- // * @returns An East expression that performs the greater-than check
735
- // */
736
- // greater<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
737
- // const location = get_location(2);
738
- // const expected_expr = Expr.from(expected, Expr.type(actual));
739
- // return Expr.tryCatch(
740
- // Expr.block($ => {
741
- // const act = $.let(actual);
742
- // const exp = $.let(expected_expr);
743
- // return East.greater(act as any, exp as any).ifElse(
744
- // _$ => testPass(),
745
- // _$ => testFail(str`Expected ${act} to be greater than ${exp} (${`${location.filename} ${location.line}:${location.column}`})`)
746
- // );
747
- // }),
748
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
749
- // );
750
- // },
751
- // /**
752
- // * Asserts that actual is greater than or equal to expected.
753
- // *
754
- // * @typeParam E - The type of the actual expression
755
- // * @param actual - The actual value to test
756
- // * @param expected - The value that actual should be greater than or equal to
757
- // * @returns An East expression that performs the greater-than-or-equal check
758
- // */
759
- // greaterEqual<E extends EastType>(actual: Expr<E>, expected: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
760
- // const location = get_location(2);
761
- // const expected_expr = Expr.from(expected, Expr.type(actual));
762
- // return Expr.tryCatch(
763
- // Expr.block($ => {
764
- // const act = $.let(actual);
765
- // const exp = $.let(expected_expr);
766
- // return East.greaterEqual(act as any, exp as any).ifElse(
767
- // _$ => testPass(),
768
- // _$ => testFail(str`Expected ${act} to be greater than or equal to ${exp} (${`${location.filename} ${location.line}:${location.column}`})`)
769
- // );
770
- // }),
771
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
772
- // );
773
- // },
774
- // /**
775
- // * Asserts that actual is between min and max (inclusive).
776
- // *
777
- // * @typeParam E - The type of the actual expression
778
- // * @param actual - The actual value to test
779
- // * @param min - The minimum value (inclusive)
780
- // * @param max - The maximum value (inclusive)
781
- // * @returns An East expression that performs the range check
782
- // */
783
- // between<E extends EastType>(actual: Expr<E>, min: SubtypeExprOrValue<NoInfer<E>>, max: SubtypeExprOrValue<NoInfer<E>>): ExprType<NullType> {
784
- // const location = get_location(2);
785
- // const min_expr = Expr.from(min, Expr.type(actual));
786
- // const max_expr = Expr.from(max, Expr.type(actual));
787
- // return Expr.tryCatch(
788
- // East.greaterEqual(actual, min_expr as any).ifElse(
789
- // _$ => East.lessEqual(actual, max_expr as any).ifElse(
790
- // _$ => testPass(),
791
- // _$ => testFail(str`Expected ${actual} to be less than or equal to ${max_expr} (${`${location.filename} ${location.line}:${location.column}`})`)
792
- // ),
793
- // _$ => testFail(str`Expected ${actual} to be greater than or equal to ${min_expr}`)
794
- // ),
795
- // (_$, message, stack) => testFail(East.String.printError(message, stack))
796
- // );
797
- // },
798
- // /**
799
- // * Asserts that an expression throws an error.
800
- // *
801
- // * @param fn - The expression that should throw an error when evaluated
802
- // * @param pattern - Optional regex pattern to match against the error message
803
- // * @returns An East expression that verifies an error is thrown
804
- // */
805
- // throws(fn: Expr<any>, pattern?: RegExp): ExprType<NullType> {
806
- // const location = get_location(2);
807
- // return Expr.tryCatch(
808
- // Expr.block($ => {
809
- // const result = $.let(fn);
810
- // $(testFail(str`Expected error, got ${result} (${East.value(`${location.filename} ${location.line}:${location.column}`)})`));
811
- // return null;
812
- // }),
813
- // ($, message, stack) => {
814
- // if (pattern) {
815
- // // Validate error message matches the pattern
816
- // return message.contains(pattern).ifElse(
817
- // _$ => testPass(),
818
- // _$ => testFail(str`Expected error message to match ${East.value(pattern.source)}, but got: ${East.String.printError(message, stack)}`)
819
- // );
820
- // } else {
821
- // // Just verify it threw
822
- // return testPass();
823
- // }
824
- // }
825
- // );
826
- // },
827
- // };
828
- //# sourceMappingURL=test.js.map