@c9up/helix 0.1.3 → 0.1.4

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 (189) hide show
  1. package/dist/cli/coverage/aggregate.d.ts +24 -0
  2. package/dist/cli/coverage/aggregate.d.ts.map +1 -0
  3. package/dist/cli/coverage/aggregate.js +215 -0
  4. package/dist/cli/coverage/aggregate.js.map +1 -0
  5. package/dist/cli/coverage/collect.d.ts +13 -0
  6. package/dist/cli/coverage/collect.d.ts.map +1 -0
  7. package/dist/cli/coverage/collect.js +66 -0
  8. package/dist/cli/coverage/collect.js.map +1 -0
  9. package/dist/cli/coverage/diff/base.d.ts +17 -0
  10. package/dist/cli/coverage/diff/base.d.ts.map +1 -0
  11. package/dist/cli/coverage/diff/base.js +44 -0
  12. package/dist/cli/coverage/diff/base.js.map +1 -0
  13. package/dist/cli/coverage/diff/index.d.ts +25 -0
  14. package/dist/cli/coverage/diff/index.d.ts.map +1 -0
  15. package/dist/cli/coverage/diff/index.js +119 -0
  16. package/dist/cli/coverage/diff/index.js.map +1 -0
  17. package/dist/cli/coverage/diff/overlay.d.ts +19 -0
  18. package/dist/cli/coverage/diff/overlay.d.ts.map +1 -0
  19. package/dist/cli/coverage/diff/overlay.js +58 -0
  20. package/dist/cli/coverage/diff/overlay.js.map +1 -0
  21. package/dist/cli/coverage/diff/parse.d.ts +27 -0
  22. package/dist/cli/coverage/diff/parse.d.ts.map +1 -0
  23. package/dist/cli/coverage/diff/parse.js +105 -0
  24. package/dist/cli/coverage/diff/parse.js.map +1 -0
  25. package/dist/cli/coverage/diff/reporters.d.ts +12 -0
  26. package/dist/cli/coverage/diff/reporters.d.ts.map +1 -0
  27. package/dist/cli/coverage/diff/reporters.js +59 -0
  28. package/dist/cli/coverage/diff/reporters.js.map +1 -0
  29. package/dist/cli/coverage/diff/types.d.ts +46 -0
  30. package/dist/cli/coverage/diff/types.d.ts.map +1 -0
  31. package/dist/cli/coverage/diff/types.js +15 -0
  32. package/dist/cli/coverage/diff/types.js.map +1 -0
  33. package/dist/cli/coverage/filter.d.ts +13 -0
  34. package/dist/cli/coverage/filter.d.ts.map +1 -0
  35. package/dist/cli/coverage/filter.js +60 -0
  36. package/dist/cli/coverage/filter.js.map +1 -0
  37. package/dist/cli/coverage/glob.d.ts +4 -0
  38. package/dist/cli/coverage/glob.d.ts.map +1 -0
  39. package/dist/cli/coverage/glob.js +0 -0
  40. package/dist/cli/coverage/glob.js.map +1 -0
  41. package/dist/cli/coverage/index.d.ts +40 -0
  42. package/dist/cli/coverage/index.d.ts.map +1 -0
  43. package/dist/cli/coverage/index.js +85 -0
  44. package/dist/cli/coverage/index.js.map +1 -0
  45. package/dist/cli/coverage/reporters/json.d.ts +13 -0
  46. package/dist/cli/coverage/reporters/json.d.ts.map +1 -0
  47. package/dist/cli/coverage/reporters/json.js +37 -0
  48. package/dist/cli/coverage/reporters/json.js.map +1 -0
  49. package/dist/cli/coverage/reporters/lcov.d.ts +13 -0
  50. package/dist/cli/coverage/reporters/lcov.d.ts.map +1 -0
  51. package/dist/cli/coverage/reporters/lcov.js +51 -0
  52. package/dist/cli/coverage/reporters/lcov.js.map +1 -0
  53. package/dist/cli/coverage/reporters/text.d.ts +8 -0
  54. package/dist/cli/coverage/reporters/text.d.ts.map +1 -0
  55. package/dist/cli/coverage/reporters/text.js +39 -0
  56. package/dist/cli/coverage/reporters/text.js.map +1 -0
  57. package/dist/cli/coverage/thresholds.d.ts +14 -0
  58. package/dist/cli/coverage/thresholds.d.ts.map +1 -0
  59. package/dist/cli/coverage/thresholds.js +58 -0
  60. package/dist/cli/coverage/thresholds.js.map +1 -0
  61. package/dist/cli/coverage/types.d.ts +118 -0
  62. package/dist/cli/coverage/types.d.ts.map +1 -0
  63. package/dist/cli/coverage/types.js +8 -0
  64. package/dist/cli/coverage/types.js.map +1 -0
  65. package/dist/cli/discover.d.ts +27 -0
  66. package/dist/cli/discover.d.ts.map +1 -0
  67. package/dist/cli/discover.js +142 -0
  68. package/dist/cli/discover.js.map +1 -0
  69. package/dist/cli/native.d.ts +43 -0
  70. package/dist/cli/native.d.ts.map +1 -0
  71. package/dist/cli/native.js +64 -0
  72. package/dist/cli/native.js.map +1 -0
  73. package/dist/cli/pool.d.ts +55 -0
  74. package/dist/cli/pool.d.ts.map +1 -0
  75. package/dist/cli/pool.js +404 -0
  76. package/dist/cli/pool.js.map +1 -0
  77. package/dist/cli/reporter.d.ts +51 -0
  78. package/dist/cli/reporter.d.ts.map +1 -0
  79. package/dist/cli/reporter.js +124 -0
  80. package/dist/cli/reporter.js.map +1 -0
  81. package/dist/cli/run.d.ts +61 -0
  82. package/dist/cli/run.d.ts.map +1 -0
  83. package/dist/cli/run.js +302 -0
  84. package/dist/cli/run.js.map +1 -0
  85. package/dist/cli/summary.d.ts +18 -0
  86. package/dist/cli/summary.d.ts.map +1 -0
  87. package/dist/cli/summary.js +20 -0
  88. package/dist/cli/summary.js.map +1 -0
  89. package/dist/cli/watch/loop.d.ts +26 -0
  90. package/dist/cli/watch/loop.d.ts.map +1 -0
  91. package/dist/cli/watch/loop.js +133 -0
  92. package/dist/cli/watch/loop.js.map +1 -0
  93. package/dist/cli/watch/types.d.ts +22 -0
  94. package/dist/cli/watch/types.d.ts.map +1 -0
  95. package/dist/cli/watch/types.js +6 -0
  96. package/dist/cli/watch/types.js.map +1 -0
  97. package/dist/cli/watch/watcher.d.ts +25 -0
  98. package/dist/cli/watch/watcher.d.ts.map +1 -0
  99. package/dist/cli/watch/watcher.js +122 -0
  100. package/dist/cli/watch/watcher.js.map +1 -0
  101. package/dist/container/index.d.ts +7 -0
  102. package/dist/container/index.d.ts.map +1 -0
  103. package/dist/container/index.js +6 -0
  104. package/dist/container/index.js.map +1 -0
  105. package/dist/container/override.d.ts +46 -0
  106. package/dist/container/override.d.ts.map +1 -0
  107. package/dist/container/override.js +67 -0
  108. package/dist/container/override.js.map +1 -0
  109. package/dist/container/spy.d.ts +21 -0
  110. package/dist/container/spy.d.ts.map +1 -0
  111. package/dist/container/spy.js +23 -0
  112. package/dist/container/spy.js.map +1 -0
  113. package/dist/index.d.ts +20 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +19 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/runtime/assertion-error.d.ts +20 -0
  118. package/dist/runtime/assertion-error.d.ts.map +1 -0
  119. package/dist/runtime/assertion-error.js +23 -0
  120. package/dist/runtime/assertion-error.js.map +1 -0
  121. package/dist/runtime/cli-worker.d.ts +25 -0
  122. package/dist/runtime/cli-worker.d.ts.map +1 -0
  123. package/dist/runtime/cli-worker.js +128 -0
  124. package/dist/runtime/cli-worker.js.map +1 -0
  125. package/dist/runtime/equals.d.ts +25 -0
  126. package/dist/runtime/equals.d.ts.map +1 -0
  127. package/dist/runtime/equals.js +343 -0
  128. package/dist/runtime/equals.js.map +1 -0
  129. package/dist/runtime/expect.d.ts +32 -0
  130. package/dist/runtime/expect.d.ts.map +1 -0
  131. package/dist/runtime/expect.js +121 -0
  132. package/dist/runtime/expect.js.map +1 -0
  133. package/dist/runtime/index.d.ts +28 -0
  134. package/dist/runtime/index.d.ts.map +1 -0
  135. package/dist/runtime/index.js +17 -0
  136. package/dist/runtime/index.js.map +1 -0
  137. package/dist/runtime/lifecycle.d.ts +11 -0
  138. package/dist/runtime/lifecycle.d.ts.map +1 -0
  139. package/dist/runtime/lifecycle.js +10 -0
  140. package/dist/runtime/lifecycle.js.map +1 -0
  141. package/dist/runtime/matchers.d.ts +42 -0
  142. package/dist/runtime/matchers.d.ts.map +1 -0
  143. package/dist/runtime/matchers.js +375 -0
  144. package/dist/runtime/matchers.js.map +1 -0
  145. package/dist/runtime/run.d.ts +55 -0
  146. package/dist/runtime/run.d.ts.map +1 -0
  147. package/dist/runtime/run.js +456 -0
  148. package/dist/runtime/run.js.map +1 -0
  149. package/dist/runtime/suite.d.ts +65 -0
  150. package/dist/runtime/suite.d.ts.map +1 -0
  151. package/dist/runtime/suite.js +203 -0
  152. package/dist/runtime/suite.js.map +1 -0
  153. package/dist/runtime/test-context.d.ts +25 -0
  154. package/dist/runtime/test-context.d.ts.map +1 -0
  155. package/dist/runtime/test-context.js +52 -0
  156. package/dist/runtime/test-context.js.map +1 -0
  157. package/dist/runtime/vi/fake-timers.d.ts +48 -0
  158. package/dist/runtime/vi/fake-timers.d.ts.map +1 -0
  159. package/dist/runtime/vi/fake-timers.js +317 -0
  160. package/dist/runtime/vi/fake-timers.js.map +1 -0
  161. package/dist/runtime/vi/index.d.ts +70 -0
  162. package/dist/runtime/vi/index.d.ts.map +1 -0
  163. package/dist/runtime/vi/index.js +209 -0
  164. package/dist/runtime/vi/index.js.map +1 -0
  165. package/dist/runtime/vi/spy.d.ts +54 -0
  166. package/dist/runtime/vi/spy.d.ts.map +1 -0
  167. package/dist/runtime/vi/spy.js +159 -0
  168. package/dist/runtime/vi/spy.js.map +1 -0
  169. package/dist/runtime/vi/spyOn.d.ts +28 -0
  170. package/dist/runtime/vi/spyOn.d.ts.map +1 -0
  171. package/dist/runtime/vi/spyOn.js +121 -0
  172. package/dist/runtime/vi/spyOn.js.map +1 -0
  173. package/dist/runtime/vi/system-time.d.ts +30 -0
  174. package/dist/runtime/vi/system-time.d.ts.map +1 -0
  175. package/dist/runtime/vi/system-time.js +100 -0
  176. package/dist/runtime/vi/system-time.js.map +1 -0
  177. package/dist/runtime/worker.d.ts +26 -0
  178. package/dist/runtime/worker.d.ts.map +1 -0
  179. package/dist/runtime/worker.js +195 -0
  180. package/dist/runtime/worker.js.map +1 -0
  181. package/dist/time/freeze.d.ts +80 -0
  182. package/dist/time/freeze.d.ts.map +1 -0
  183. package/dist/time/freeze.js +184 -0
  184. package/dist/time/freeze.js.map +1 -0
  185. package/dist/time/index.d.ts +16 -0
  186. package/dist/time/index.d.ts.map +1 -0
  187. package/dist/time/index.js +15 -0
  188. package/dist/time/index.js.map +1 -0
  189. package/package.json +1 -1
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Time freeze / travel — ergonomic surface over `vi.setSystemTime`
3
+ * with per-test auto-restore.
4
+ *
5
+ * **Helix is agnostic — no cross-package imports.** This module
6
+ * never imports `@c9up/chronos`. The clock pin happens entirely
7
+ * through `vi.setSystemTime` (which shims `globalThis.Date`); any
8
+ * code in user-land that calls `new Date()` — chronos `DateTime`
9
+ * included — picks up the frozen epoch automatically.
10
+ *
11
+ * Calendar arithmetic for `month` / `year` uses `Date.UTC` math
12
+ * locally so we don't take a runtime dependency on chronos.
13
+ *
14
+ * **Concurrency note.** `vi.setSystemTime` writes to the `vi`
15
+ * context that wraps the current test FILE (`withViContext`), not
16
+ * the per-test frame (`withTestContext`). Two `withTestContext`
17
+ * frames running in parallel inside the same file (e.g. via
18
+ * `Promise.all([withTestContext(A), withTestContext(B)])`) share
19
+ * one Date shim — A's freeze leaks into B. The helix runtime
20
+ * executes tests strictly sequentially (`runSuite`'s for-await
21
+ * loop), so this is not reachable through the documented test
22
+ * path. Callers who manually compose `withTestContext` in parallel
23
+ * inside a single file must serialise their freezes themselves.
24
+ */
25
+ import { inTestContext, registerTestCleanup } from "../runtime/test-context.js";
26
+ import { vi } from "../runtime/vi/index.js";
27
+ /** JS `Date` represents instants from `-8.64e15` to `+8.64e15` ms.
28
+ * Anything beyond becomes "Invalid Date" — refuse early so callers
29
+ * see a clear error instead of `setSystemTime(NaN)` downstream. */
30
+ const JS_DATE_MAX = 8_640_000_000_000_000;
31
+ /**
32
+ * Pin `Date.now()` / `new Date()` (and anything that reads through
33
+ * them — e.g. `DateTime.now()`) to the given moment. Auto-restored
34
+ * at end-of-test via the helix test frame, so a forgotten
35
+ * `unfreeze()` does not leak into the next test.
36
+ *
37
+ * Throws when called outside a test frame — a queued cleanup would
38
+ * never fire there, so the freeze would leak across tests silently.
39
+ */
40
+ export function freeze(input) {
41
+ requireTestContext("freeze");
42
+ const ms = inputToMs(input);
43
+ vi.setSystemTime(ms);
44
+ registerTestCleanup(() => {
45
+ vi.useRealSystemTime();
46
+ });
47
+ }
48
+ /**
49
+ * Advance the clock by `amount` × `unit`. If the clock isn't frozen
50
+ * yet, freezes it relative to the real `Date.now()` first, then
51
+ * applies the delta — so a one-shot `time.travel(7, 'day')` works
52
+ * without an explicit `freeze()`.
53
+ *
54
+ * Always queues a cleanup so the auto-restore path is uniform —
55
+ * cleanups are idempotent (each calls `vi.useRealSystemTime`),
56
+ * accumulating closures across many `travel` calls in one test is
57
+ * intentional and cheap.
58
+ *
59
+ * Throws when called outside a test frame, same reason as `freeze`.
60
+ */
61
+ export function travel(amount, unit = "ms") {
62
+ requireTestContext("travel");
63
+ if (!Number.isFinite(amount)) {
64
+ throw new Error(`helix.time.travel: amount must be finite, got ${amount}.`);
65
+ }
66
+ if ((unit === "month" || unit === "year") && !Number.isInteger(amount)) {
67
+ throw new Error(`helix.time.travel: '${unit}' requires an integer amount, got ${amount}. Calendar units don't compose cleanly with fractions.`);
68
+ }
69
+ const base = vi.getMockedSystemTime() ?? Date.now();
70
+ const next = applyDelta(base, amount, unit);
71
+ requireInDateRange(next, "travel");
72
+ vi.setSystemTime(next);
73
+ // Always queue — `vi.useRealSystemTime` is idempotent so duplicate
74
+ // cleanups across `freeze + travel` are harmless. Always-queue
75
+ // guards against the "user pinned via raw `vi.setSystemTime`,
76
+ // then called `travel`" trap where the heuristic would skip.
77
+ registerTestCleanup(() => {
78
+ vi.useRealSystemTime();
79
+ });
80
+ }
81
+ /**
82
+ * Travel TO a specific moment. Equivalent to `freeze(target)` —
83
+ * exists as an explicit verb so "travel to 2026" reads better than
84
+ * "freeze at 2026" in tests.
85
+ */
86
+ export function travelTo(target) {
87
+ freeze(target);
88
+ }
89
+ /**
90
+ * Restore the real system clock immediately. Idempotent — safe to
91
+ * call when not currently frozen. Auto-restore still fires at
92
+ * end-of-test, so calling `unfreeze` early is purely a
93
+ * test-readability choice.
94
+ */
95
+ export function unfreeze() {
96
+ vi.useRealSystemTime();
97
+ }
98
+ /**
99
+ * Read the currently frozen epoch, or `null` when running on real
100
+ * time. Useful for tests that compose `freeze` with their own clock
101
+ * arithmetic.
102
+ */
103
+ export function frozenAt() {
104
+ return vi.getMockedSystemTime();
105
+ }
106
+ function requireTestContext(verb) {
107
+ if (!inTestContext()) {
108
+ throw new Error(`helix.time.${verb}: must be called inside a test (no active test frame). Calls from top-level setup leak across tests — use vi.setSystemTime directly with manual cleanup if that is what you want.`);
109
+ }
110
+ }
111
+ function inputToMs(input) {
112
+ let ms;
113
+ if (typeof input === "number") {
114
+ ms = input;
115
+ }
116
+ else if (input instanceof Date) {
117
+ ms = input.getTime();
118
+ }
119
+ else if (typeof input === "string") {
120
+ ms = Date.parse(input);
121
+ if (Number.isNaN(ms)) {
122
+ throw new Error(`helix.time: cannot parse '${input}' as a date — pass an ISO 8601 string, Date, number (epoch ms), or an object with toMillis().`);
123
+ }
124
+ }
125
+ else if (typeof input === "object" &&
126
+ input !== null &&
127
+ typeof input.toMillis === "function") {
128
+ const result = input.toMillis();
129
+ if (typeof result !== "number") {
130
+ throw new Error(`helix.time: input.toMillis() must return a number, got ${typeof result}.`);
131
+ }
132
+ ms = result;
133
+ }
134
+ else {
135
+ throw new Error(`helix.time: unsupported input type ${typeof input}. Use string / Date / number / { toMillis() }.`);
136
+ }
137
+ requireInDateRange(ms, "freeze");
138
+ return ms;
139
+ }
140
+ function requireInDateRange(ms, verb) {
141
+ if (!Number.isFinite(ms)) {
142
+ throw new Error(`helix.time.${verb}: epoch must be finite, got ${ms}. (Did you pass an Invalid Date or a NaN?)`);
143
+ }
144
+ if (Math.abs(ms) > JS_DATE_MAX) {
145
+ throw new Error(`helix.time.${verb}: epoch ${ms} exceeds the JS Date range (±8.64e15 ms). The resulting clock would be 'Invalid Date'.`);
146
+ }
147
+ }
148
+ function applyDelta(base, amount, unit) {
149
+ switch (unit) {
150
+ case "ms":
151
+ return base + amount;
152
+ case "second":
153
+ return base + amount * 1_000;
154
+ case "minute":
155
+ return base + amount * 60_000;
156
+ case "hour":
157
+ return base + amount * 3_600_000;
158
+ case "day":
159
+ return base + amount * 86_400_000;
160
+ case "week":
161
+ return base + amount * 604_800_000;
162
+ case "month":
163
+ case "year": {
164
+ // UTC calendar math — JS `Date` mutators handle month
165
+ // overflow (e.g. month 13 → year+1 month 1) and clamp
166
+ // month-end days (e.g. Jan 31 + 1 month → Feb 28/29).
167
+ const d = new Date(base);
168
+ if (unit === "year") {
169
+ d.setUTCFullYear(d.getUTCFullYear() + amount);
170
+ }
171
+ else {
172
+ d.setUTCMonth(d.getUTCMonth() + amount);
173
+ }
174
+ return d.getTime();
175
+ }
176
+ default: {
177
+ // Defensive — TS narrows this branch to `never`, but a
178
+ // runtime cast (`unit as TimeUnit`) could land here.
179
+ const exhaustive = unit;
180
+ throw new Error(`helix.time.travel: unknown unit '${exhaustive}'.`);
181
+ }
182
+ }
183
+ }
184
+ //# sourceMappingURL=freeze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freeze.js","sourceRoot":"","sources":["../../src/time/freeze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@c9up/helix/time` — time freeze / travel for tests.
3
+ *
4
+ * Pins `Date.now()`, `new Date()`, and `DateTime.now()` to a fake
5
+ * epoch. Auto-restored after each test via the per-test frame.
6
+ *
7
+ * import { time } from "@c9up/helix";
8
+ *
9
+ * time.freeze("2026-01-01");
10
+ * // ... test that depends on a fixed clock
11
+ * time.travel(7, "day");
12
+ * expect(DateTime.now().toISO()).toMatch(/^2026-01-08/);
13
+ */
14
+ export type { TimeUnit } from "./freeze.js";
15
+ export { freeze, frozenAt, travel, travelTo, unfreeze } from "./freeze.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/time/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@c9up/helix/time` — time freeze / travel for tests.
3
+ *
4
+ * Pins `Date.now()`, `new Date()`, and `DateTime.now()` to a fake
5
+ * epoch. Auto-restored after each test via the per-test frame.
6
+ *
7
+ * import { time } from "@c9up/helix";
8
+ *
9
+ * time.freeze("2026-01-01");
10
+ * // ... test that depends on a fixed clock
11
+ * time.travel(7, "day");
12
+ * expect(DateTime.now().toISO()).toMatch(/^2026-01-08/);
13
+ */
14
+ export { freeze, frozenAt, travel, travelTo, unfreeze } from "./freeze.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/time/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/helix",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Helix — framework-agnostic test runtime for the Ream ecosystem (Vitest-compatible runner, spies, container overrides, time-travel). Per-package fakes live in each package's /testing.",
5
5
  "license": "MIT",
6
6
  "type": "module",