@elaraai/east-node-std 0.0.1-beta.9 → 1.0.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.
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
@@ -1,4 +1,4 @@
1
- import { Expr, NullType, StringType, type SubtypeExprOrValue } from "@elaraai/east";
1
+ import { Expr, NullType, StringType, type SubtypeExprOrValue, type ExampleDef } from "@elaraai/east";
2
2
  import type { BlockBuilder, PlatformFunction, TypeSymbol } from "@elaraai/east/internal";
3
3
  /**
4
4
  * Creates a test platform that uses Node.js assertions.
@@ -169,5 +169,12 @@ export declare const Assert: {
169
169
  * @returns An East expression that unconditionally fails the test
170
170
  */
171
171
  fail(message: SubtypeExprOrValue<StringType>): import("@elaraai/east").NullExpr;
172
+ /**
173
+ * Runs all examples as tests, calling each with its inputs and asserting the result equals returns.
174
+ *
175
+ * @param test - The test function from describeEast's builder
176
+ * @param examples - A record of named ExampleDef exports (e.g. `import * as examples from "./array.examples.js"`)
177
+ */
178
+ examples(test: (name: string, body: ($: BlockBuilder<NullType>) => void) => void, examples: Record<string, ExampleDef>): void;
172
179
  };
173
180
  //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,364 @@
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, printLocations, StringType, toJSONFor, ArrayType, IntegerType, StructType } 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
+ /* Type-directed JSON serialization for the test IR export format:
67
+ * StructType({ ir: IRType, source_map: StructType({ stacks: Array(Array(Struct({column,filename,line}))) }) })
68
+ * Note: struct fields are sorted alphabetically in East's structural type system. */
69
+ const LocationType = StructType({ column: IntegerType, filename: StringType, line: IntegerType });
70
+ const SourceMapType = StructType({ stacks: ArrayType(ArrayType(LocationType)) });
71
+ const ExportWrapperType = StructType({ ir: IRType, source_map: SourceMapType });
72
+ const exportToJSON = toJSONFor(ExportWrapperType);
73
+ /**
74
+ * Defines and runs an East test suite using platform functions.
75
+ *
76
+ * This creates a single East function that calls `describe` and `test` platform functions.
77
+ * The entire suite can be exported as IR and run on any East implementation that provides
78
+ * the test platform (testPass, testFail, test, describe).
79
+ *
80
+ * When the `EXPORT_TEST_IR` environment variable is set to a directory path, the IR for
81
+ * each test suite is exported to `<path>/<suite_name>.json`.
82
+ *
83
+ * @param suiteName - The name of the test suite
84
+ * @param builder - A function that receives a `test` function for defining tests
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * describeEast("Array tests", (test) => {
89
+ * test("addition", $ => {
90
+ * $(assertEast.equal(East.value(1n).add(1n), 2n));
91
+ * });
92
+ * test("subtraction", $ => {
93
+ * $(assertEast.equal(East.value(2n).subtract(1n), 1n));
94
+ * });
95
+ * });
96
+ * ```
97
+ *
98
+ * @example
99
+ * ```bash
100
+ * # Export test IR to a directory
101
+ * EXPORT_TEST_IR=./test-ir npm test
102
+ * ```
103
+ */
104
+ export function describeEast(suiteName, builder, options) {
105
+ const tests = [];
106
+ // Collect all test names and bodies
107
+ builder((name, body) => {
108
+ tests.push({ name, body });
109
+ });
110
+ // Create a single East function that uses describe/test platform functions
111
+ const suiteFunction = East.asyncFunction([], NullType, $ => {
112
+ $(describe.call($, suiteName, East.asyncFunction([], NullType, $ => {
113
+ // beforeAll hook
114
+ if (options?.beforeAll) {
115
+ options.beforeAll($);
116
+ }
117
+ for (const { name, body } of tests) {
118
+ $(test.call($, name, East.asyncFunction([], NullType, $test => {
119
+ // beforeEach hook (inside test body)
120
+ if (options?.beforeEach) {
121
+ options.beforeEach($test);
122
+ }
123
+ // Wrap test body in try-finally so afterEach runs even on failure
124
+ if (options?.afterEach) {
125
+ $test.try(body)
126
+ .catch(($catch, message) => {
127
+ // Re-throw the error after finally runs
128
+ $catch.error(message);
129
+ })
130
+ .finally(options.afterEach);
131
+ }
132
+ else {
133
+ body($test);
134
+ }
135
+ })));
136
+ }
137
+ // afterAll hook
138
+ if (options?.afterAll) {
139
+ options.afterAll($);
140
+ }
141
+ })));
142
+ });
143
+ // Auto-export test IR if EXPORT_TEST_IR environment variable is set to a path
144
+ if (process.env.EXPORT_TEST_IR) {
145
+ const outputDir = process.env.EXPORT_TEST_IR;
146
+ try {
147
+ mkdirSync(outputDir, { recursive: true });
148
+ const ir = suiteFunction.toIR();
149
+ const stacks = (ir.source_map?.entries() ?? [[]]).map(stack => stack.map(frame => ({ column: frame.column, filename: frame.filename, line: frame.line })));
150
+ const wrapperValue = { ir: ir.ir, source_map: { stacks } };
151
+ const wrapperJSON = exportToJSON(wrapperValue);
152
+ const filename = join(outputDir, `${suiteName.replace(/[^a-zA-Z0-9]/g, '_')}.json`);
153
+ writeFileSync(filename, JSON.stringify(wrapperJSON, null, 2));
154
+ console.log(`✓ Exported test IR: ${filename}`);
155
+ }
156
+ catch (err) {
157
+ console.error(`✗ Failed to export test IR for "${suiteName}":`, err);
158
+ }
159
+ }
160
+ if (options?.exportOnly !== true) {
161
+ // Run the test suite using the Node.js platform implementation
162
+ const compiled = suiteFunction.toIR().compile([...(options?.platformFns ?? [])]);
163
+ return compiled();
164
+ }
165
+ }
166
+ /**
167
+ * East assertion functions that match Node.js assert API naming.
168
+ *
169
+ * These functions generate East expressions that perform runtime assertions
170
+ * using platform functions, enabling testing of East code.
171
+ */
172
+ export const Assert = {
173
+ /**
174
+ * Asserts that two values are the same reference (meaning if one is mutated, the other reflects the change - and they are always equal).
175
+ *
176
+ * @typeParam E - The type of the actual expression
177
+ * @param actual - The actual value to test
178
+ * @param expected - The expected value to compare against
179
+ * @returns An East expression that performs the equality check
180
+ */
181
+ is(actual, expected) {
182
+ const location = get_location();
183
+ const expected_expr = Expr.from(expected, Expr.type(actual));
184
+ return Expr.tryCatch(Expr.block($ => {
185
+ const act = $.let(actual);
186
+ const exp = $.let(expected_expr);
187
+ return East.is(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be ${exp} (${printLocations(location)})`));
188
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
189
+ },
190
+ /**
191
+ * Asserts that two values are equal.
192
+ *
193
+ * @typeParam E - The type of the actual expression
194
+ * @param actual - The actual value to test
195
+ * @param expected - The expected value to compare against
196
+ * @returns An East expression that performs the equality check
197
+ */
198
+ equal(actual, expected) {
199
+ const location = get_location();
200
+ const expected_expr = Expr.from(expected, Expr.type(actual));
201
+ return Expr.tryCatch(Expr.block($ => {
202
+ const act = $.let(actual);
203
+ const exp = $.let(expected_expr);
204
+ return East.equal(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to equal ${exp} (${printLocations(location)})`));
205
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
206
+ },
207
+ /**
208
+ * Asserts that two values are not equal.
209
+ *
210
+ * @typeParam E - The type of the actual expression
211
+ * @param actual - The actual value to test
212
+ * @param expected - The value that should not be equal
213
+ * @returns An East expression that performs the inequality check
214
+ */
215
+ notEqual(actual, expected) {
216
+ const location = get_location();
217
+ const expected_expr = Expr.from(expected, Expr.type(actual));
218
+ return Expr.tryCatch(Expr.block($ => {
219
+ const act = $.let(actual);
220
+ const exp = $.let(expected_expr);
221
+ return East.notEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to not equal ${exp} (${printLocations(location)})`));
222
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
223
+ },
224
+ /**
225
+ * Asserts that actual is less than expected.
226
+ *
227
+ * @typeParam E - The type of the actual expression
228
+ * @param actual - The actual value to test
229
+ * @param expected - The value that actual should be less than
230
+ * @returns An East expression that performs the less-than check
231
+ */
232
+ less(actual, expected) {
233
+ const location = get_location();
234
+ const expected_expr = Expr.from(expected, Expr.type(actual));
235
+ return Expr.tryCatch(Expr.block($ => {
236
+ const act = $.let(actual);
237
+ const exp = $.let(expected_expr);
238
+ return East.less(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be less than ${exp} (${printLocations(location)})`));
239
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
240
+ },
241
+ /**
242
+ * Asserts that actual is less than or equal to expected.
243
+ *
244
+ * @typeParam E - The type of the actual expression
245
+ * @param actual - The actual value to test
246
+ * @param expected - The value that actual should be less than or equal to
247
+ * @returns An East expression that performs the less-than-or-equal check
248
+ */
249
+ lessEqual(actual, expected) {
250
+ const location = get_location();
251
+ const expected_expr = Expr.from(expected, Expr.type(actual));
252
+ return Expr.tryCatch(Expr.block($ => {
253
+ const act = $.let(actual);
254
+ const exp = $.let(expected_expr);
255
+ return East.lessEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be less than or equal to ${exp} (${printLocations(location)})`));
256
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
257
+ },
258
+ /**
259
+ * Asserts that actual is greater than expected.
260
+ *
261
+ * @typeParam E - The type of the actual expression
262
+ * @param actual - The actual value to test
263
+ * @param expected - The value that actual should be greater than
264
+ * @returns An East expression that performs the greater-than check
265
+ */
266
+ greater(actual, expected) {
267
+ const location = get_location();
268
+ const expected_expr = Expr.from(expected, Expr.type(actual));
269
+ return Expr.tryCatch(Expr.block($ => {
270
+ const act = $.let(actual);
271
+ const exp = $.let(expected_expr);
272
+ return East.greater(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be greater than ${exp} (${printLocations(location)})`));
273
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
274
+ },
275
+ /**
276
+ * Asserts that actual is greater than or equal to expected.
277
+ *
278
+ * @typeParam E - The type of the actual expression
279
+ * @param actual - The actual value to test
280
+ * @param expected - The value that actual should be greater than or equal to
281
+ * @returns An East expression that performs the greater-than-or-equal check
282
+ */
283
+ greaterEqual(actual, expected) {
284
+ const location = get_location();
285
+ const expected_expr = Expr.from(expected, Expr.type(actual));
286
+ return Expr.tryCatch(Expr.block($ => {
287
+ const act = $.let(actual);
288
+ const exp = $.let(expected_expr);
289
+ return East.greaterEqual(act, exp).ifElse(_$ => testPass(), _$ => testFail(str `Expected ${act} to be greater than or equal to ${exp} (${printLocations(location)})`));
290
+ }), (_$, message, stack) => testFail(East.String.printError(message, stack)));
291
+ },
292
+ /**
293
+ * Asserts that actual is between min and max (inclusive).
294
+ *
295
+ * @typeParam E - The type of the actual expression
296
+ * @param actual - The actual value to test
297
+ * @param min - The minimum value (inclusive)
298
+ * @param max - The maximum value (inclusive)
299
+ * @returns An East expression that performs the range check
300
+ */
301
+ between(actual, min, max) {
302
+ const location = get_location();
303
+ const min_expr = Expr.from(min, Expr.type(actual));
304
+ const max_expr = Expr.from(max, Expr.type(actual));
305
+ 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} (${printLocations(location)})`)), _$ => testFail(str `Expected ${actual} to be greater than or equal to ${min_expr}`)), (_$, message, stack) => testFail(East.String.printError(message, stack)));
306
+ },
307
+ /**
308
+ * Asserts that an expression throws an error.
309
+ *
310
+ * @param fn - The expression that should throw an error when evaluated
311
+ * @param pattern - Optional regex pattern to match against the error message
312
+ * @returns An East expression that verifies an error is thrown
313
+ */
314
+ throws(fn, pattern) {
315
+ const location = get_location();
316
+ return Expr.tryCatch(Expr.block($ => {
317
+ const result = $.let(fn);
318
+ $(testFail(str `Expected error, got ${result} (${printLocations(location)})`));
319
+ return null;
320
+ }), ($, message, stack) => {
321
+ if (pattern) {
322
+ // Validate error message matches the pattern
323
+ return message.contains(pattern).ifElse(_$ => testPass(), _$ => testFail(str `Expected error message to match ${East.value(pattern.source)}, but got: ${East.String.printError(message, stack)}`));
324
+ }
325
+ else {
326
+ // Just verify it threw
327
+ return testPass();
328
+ }
329
+ });
330
+ },
331
+ /**
332
+ * Fails a test with the given message.
333
+ *
334
+ * @param message
335
+ * @returns An East expression that unconditionally fails the test
336
+ */
337
+ fail(message) {
338
+ const location = get_location();
339
+ const message_expr = Expr.from(message, StringType);
340
+ return testFail(str `${message_expr} (${printLocations(location)})`);
341
+ },
342
+ /**
343
+ * Runs all examples as tests, calling each with its inputs and asserting the result equals returns.
344
+ *
345
+ * @param test - The test function from describeEast's builder
346
+ * @param examples - A record of named ExampleDef exports (e.g. `import * as examples from "./array.examples.js"`)
347
+ */
348
+ examples(test, examples) {
349
+ for (const ex of Object.values(examples)) {
350
+ if (ex.returns !== undefined) {
351
+ test(ex.description, $ => {
352
+ const result = $.let(ex.fn(...ex.inputs));
353
+ $(Assert.equal(result, ex.returns));
354
+ });
355
+ }
356
+ else {
357
+ test(ex.description, $ => {
358
+ $.let(ex.fn(...ex.inputs));
359
+ });
360
+ }
361
+ }
362
+ },
363
+ };
364
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2025 Elara AI Pty Ltd
3
3
  * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
4
  */
5
- import { IntegerType, NullType } from "@elaraai/east";
5
+ import { IntegerType, NullType, DateTimeType, StringType } from "@elaraai/east";
6
6
  import type { PlatformFunction } from "@elaraai/east/internal";
7
7
  /**
8
8
  * Gets the current Unix timestamp in milliseconds.
@@ -50,6 +50,33 @@ export declare const time_now: import("@elaraai/east").PlatformDefinition<[], In
50
50
  * ```
51
51
  */
52
52
  export declare const time_sleep: import("@elaraai/east").AsyncPlatformDefinition<[IntegerType], NullType>;
53
+ /**
54
+ * Gets the UTC offset in minutes for an IANA timezone at a given UTC datetime.
55
+ *
56
+ * Returns the number of minutes that the given timezone is ahead of (positive)
57
+ * or behind (negative) UTC at the specified instant. This accounts for DST
58
+ * transitions — the same timezone can return different offsets depending on
59
+ * the datetime.
60
+ *
61
+ * The timezone must be a valid IANA timezone name (e.g., "Australia/Sydney",
62
+ * "America/New_York", "Europe/London", "Asia/Tokyo"). See the IANA Time Zone
63
+ * Database for the full list of valid names.
64
+ *
65
+ * @param datetime - A UTC datetime to compute the offset for
66
+ * @param zone - An IANA timezone name (e.g., "Australia/Sydney")
67
+ * @returns UTC offset in minutes (e.g., 660 for Sydney in summer, 600 in winter)
68
+ *
69
+ * @throws {EastError} When the timezone name is not a valid IANA timezone
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const toSydneyTime = East.function([DateTimeType], DateTimeType, ($, dt) => {
74
+ * const offset = $.let(Time.getTimezoneOffset(dt, "Australia/Sydney"));
75
+ * $.return(dt.addMinutes(offset));
76
+ * });
77
+ * ```
78
+ */
79
+ export declare const time_get_timezone_offset: import("@elaraai/east").PlatformDefinition<[DateTimeType, StringType], IntegerType>;
53
80
  /**
54
81
  * Node.js implementation of time platform functions.
55
82
  *
@@ -59,7 +86,7 @@ declare const TimeImpl: PlatformFunction[];
59
86
  /**
60
87
  * Grouped time platform functions.
61
88
  *
62
- * Provides time and sleep operations for East programs.
89
+ * Provides time, sleep, and timezone operations for East programs.
63
90
  *
64
91
  * @example
65
92
  * ```ts
@@ -119,6 +146,27 @@ export declare const Time: {
119
146
  * ```
120
147
  */
121
148
  readonly sleep: import("@elaraai/east").AsyncPlatformDefinition<[IntegerType], NullType>;
149
+ /**
150
+ * Gets the UTC offset in minutes for an IANA timezone at a given UTC datetime.
151
+ *
152
+ * Accounts for DST — the same timezone returns different offsets depending
153
+ * on the datetime. Use the result with `addMinutes` to convert a UTC datetime
154
+ * to local time.
155
+ *
156
+ * @param datetime - A UTC datetime
157
+ * @param zone - An IANA timezone name (e.g., "Australia/Sydney")
158
+ * @returns UTC offset in minutes
159
+ * @throws {EastError} When the timezone name is invalid
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * const toSydneyTime = East.function([DateTimeType], DateTimeType, ($, dt) => {
164
+ * const offset = $.let(Time.getTimezoneOffset(dt, "Australia/Sydney"));
165
+ * $.return(dt.addMinutes(offset));
166
+ * });
167
+ * ```
168
+ */
169
+ readonly getTimezoneOffset: import("@elaraai/east").PlatformDefinition<[DateTimeType, StringType], IntegerType>;
122
170
  /**
123
171
  * Node.js implementation of time platform functions.
124
172
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/time.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAQ,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAoC/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,6DAA6C,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,UAAU,0EAA4D,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,wBAAwB,qFAIpC,CAAC;AAEF;;;;GAIG;AACH,QAAA,MAAM,QAAQ,EAAE,gBAAgB,EAyC/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,IAAI;IACb;;;;;;;;;;;;;;;;;OAiBG;;IAGH;;;;;;;;;;;;;;;;;;;;;OAqBG;;IAGH;;;;;;;;;;;;;;;;;;;OAmBG;;IAGH;;;;OAIG;;CAEG,CAAC;AAGX,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -2,8 +2,37 @@
2
2
  * Copyright (c) 2025 Elara AI Pty Ltd
3
3
  * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
4
  */
5
- import { East, IntegerType, NullType } from "@elaraai/east";
5
+ import { East, IntegerType, NullType, DateTimeType, StringType } from "@elaraai/east";
6
6
  import { EastError } from "@elaraai/east/internal";
7
+ /**
8
+ * Computes the UTC offset in minutes for an IANA timezone at a given instant.
9
+ *
10
+ * Uses Intl.DateTimeFormat to format the datetime in both UTC and the target
11
+ * timezone, then computes the difference. This is reliable across all Node.js
12
+ * versions — it only depends on the date component formatting, not abbreviations.
13
+ */
14
+ function computeUtcOffsetMinutes(datetime, zone) {
15
+ const formatParts = (tz) => {
16
+ const fmt = new Intl.DateTimeFormat("en-US", {
17
+ timeZone: tz,
18
+ year: "numeric",
19
+ month: "2-digit",
20
+ day: "2-digit",
21
+ hour: "2-digit",
22
+ minute: "2-digit",
23
+ second: "2-digit",
24
+ hour12: false,
25
+ });
26
+ const parts = fmt.formatToParts(datetime);
27
+ const get = (type) => parseInt(parts.find(p => p.type === type).value);
28
+ return { year: get("year"), month: get("month"), day: get("day"), hour: get("hour"), minute: get("minute"), second: get("second") };
29
+ };
30
+ const utc = formatParts("UTC");
31
+ const local = formatParts(zone);
32
+ const utcMs = Date.UTC(utc.year, utc.month - 1, utc.day, utc.hour, utc.minute, utc.second);
33
+ const localMs = Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second);
34
+ return (localMs - utcMs) / 60000;
35
+ }
7
36
  /**
8
37
  * Gets the current Unix timestamp in milliseconds.
9
38
  *
@@ -50,6 +79,33 @@ export const time_now = East.platform("time_now", [], IntegerType);
50
79
  * ```
51
80
  */
52
81
  export const time_sleep = East.asyncPlatform("time_sleep", [IntegerType], NullType);
82
+ /**
83
+ * Gets the UTC offset in minutes for an IANA timezone at a given UTC datetime.
84
+ *
85
+ * Returns the number of minutes that the given timezone is ahead of (positive)
86
+ * or behind (negative) UTC at the specified instant. This accounts for DST
87
+ * transitions — the same timezone can return different offsets depending on
88
+ * the datetime.
89
+ *
90
+ * The timezone must be a valid IANA timezone name (e.g., "Australia/Sydney",
91
+ * "America/New_York", "Europe/London", "Asia/Tokyo"). See the IANA Time Zone
92
+ * Database for the full list of valid names.
93
+ *
94
+ * @param datetime - A UTC datetime to compute the offset for
95
+ * @param zone - An IANA timezone name (e.g., "Australia/Sydney")
96
+ * @returns UTC offset in minutes (e.g., 660 for Sydney in summer, 600 in winter)
97
+ *
98
+ * @throws {EastError} When the timezone name is not a valid IANA timezone
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const toSydneyTime = East.function([DateTimeType], DateTimeType, ($, dt) => {
103
+ * const offset = $.let(Time.getTimezoneOffset(dt, "Australia/Sydney"));
104
+ * $.return(dt.addMinutes(offset));
105
+ * });
106
+ * ```
107
+ */
108
+ export const time_get_timezone_offset = East.platform("time_get_timezone_offset", [DateTimeType, StringType], IntegerType);
53
109
  /**
54
110
  * Node.js implementation of time platform functions.
55
111
  *
@@ -62,7 +118,7 @@ const TimeImpl = [
62
118
  }
63
119
  catch (err) {
64
120
  throw new EastError(`Failed to get current time: ${err.message}`, {
65
- location: { filename: "time_now", line: 0n, column: 0n },
121
+ location: [{ filename: "time_now", line: 0n, column: 0n }],
66
122
  cause: err
67
123
  });
68
124
  }
@@ -73,7 +129,26 @@ const TimeImpl = [
73
129
  }
74
130
  catch (err) {
75
131
  throw new EastError(`Failed to sleep: ${err.message}`, {
76
- location: { filename: "time_sleep", line: 0n, column: 0n },
132
+ location: [{ filename: "time_sleep", line: 0n, column: 0n }],
133
+ cause: err
134
+ });
135
+ }
136
+ }),
137
+ time_get_timezone_offset.implement((datetime, zone) => {
138
+ try {
139
+ const offset = computeUtcOffsetMinutes(datetime, zone);
140
+ return BigInt(offset);
141
+ }
142
+ catch (err) {
143
+ if (err instanceof RangeError) {
144
+ throw new EastError(`Invalid IANA timezone: "${zone}". ` +
145
+ `Use a valid IANA timezone name such as "Australia/Sydney", "America/New_York", or "Europe/London". ` +
146
+ `See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for the full list.`, { location: [{ filename: "time_get_timezone_offset", line: 0n, column: 0n }], cause: err });
147
+ }
148
+ if (err instanceof EastError)
149
+ throw err;
150
+ throw new EastError(`Failed to get timezone offset for "${zone}": ${err.message}`, {
151
+ location: [{ filename: "time_get_timezone_offset", line: 0n, column: 0n }],
77
152
  cause: err
78
153
  });
79
154
  }
@@ -82,7 +157,7 @@ const TimeImpl = [
82
157
  /**
83
158
  * Grouped time platform functions.
84
159
  *
85
- * Provides time and sleep operations for East programs.
160
+ * Provides time, sleep, and timezone operations for East programs.
86
161
  *
87
162
  * @example
88
163
  * ```ts
@@ -142,6 +217,27 @@ export const Time = {
142
217
  * ```
143
218
  */
144
219
  sleep: time_sleep,
220
+ /**
221
+ * Gets the UTC offset in minutes for an IANA timezone at a given UTC datetime.
222
+ *
223
+ * Accounts for DST — the same timezone returns different offsets depending
224
+ * on the datetime. Use the result with `addMinutes` to convert a UTC datetime
225
+ * to local time.
226
+ *
227
+ * @param datetime - A UTC datetime
228
+ * @param zone - An IANA timezone name (e.g., "Australia/Sydney")
229
+ * @returns UTC offset in minutes
230
+ * @throws {EastError} When the timezone name is invalid
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * const toSydneyTime = East.function([DateTimeType], DateTimeType, ($, dt) => {
235
+ * const offset = $.let(Time.getTimezoneOffset(dt, "Australia/Sydney"));
236
+ * $.return(dt.addMinutes(offset));
237
+ * });
238
+ * ```
239
+ */
240
+ getTimezoneOffset: time_get_timezone_offset,
145
241
  /**
146
242
  * Node.js implementation of time platform functions.
147
243
  *
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/time.ts"],"names":[],"mappings":"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"}