@elaraai/east-node-std 0.0.1-beta.0 → 0.0.1-beta.1

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