@executablemd/testing 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/esm/{testing/npm/src/src → src}/assertions.js +15 -24
  2. package/esm/{testing/npm/src/src → src}/handlers.js +140 -10
  3. package/esm/{testing/npm/src/src → src}/vocabulary.js +3 -0
  4. package/package.json +3 -3
  5. package/types/src/assertions.d.ts +11 -1
  6. package/types/src/handlers.d.ts +1 -0
  7. package/esm/core/mod.js +0 -55
  8. package/esm/core/src/api.js +0 -31
  9. package/esm/core/src/collect.js +0 -24
  10. package/esm/core/src/component-api.js +0 -47
  11. package/esm/core/src/content-context.js +0 -23
  12. package/esm/core/src/deno-compiler.js +0 -51
  13. package/esm/core/src/errors.js +0 -13
  14. package/esm/core/src/eval-context.js +0 -13
  15. package/esm/core/src/eval-handler.js +0 -79
  16. package/esm/core/src/eval-interpolate.js +0 -63
  17. package/esm/core/src/eval-transform.js +0 -378
  18. package/esm/core/src/execute.js +0 -378
  19. package/esm/core/src/expand.js +0 -988
  20. package/esm/core/src/frontmatter.js +0 -98
  21. package/esm/core/src/heal.js +0 -29
  22. package/esm/core/src/interpolate.js +0 -39
  23. package/esm/core/src/modifiers/daemon.js +0 -60
  24. package/esm/core/src/modifiers/persist.js +0 -35
  25. package/esm/core/src/modifiers/timeout.js +0 -55
  26. package/esm/core/src/modifiers.js +0 -113
  27. package/esm/core/src/output/normalize.js +0 -33
  28. package/esm/core/src/output/terminal.js +0 -20
  29. package/esm/core/src/render.js +0 -30
  30. package/esm/core/src/replay-stream.js +0 -58
  31. package/esm/core/src/sample-api.js +0 -45
  32. package/esm/core/src/scanner.js +0 -632
  33. package/esm/core/src/temp-file-compiler.js +0 -68
  34. package/esm/core/src/types.js +0 -7
  35. package/esm/core/src/validate.js +0 -82
  36. package/esm/durable-streams/combinators.js +0 -227
  37. package/esm/durable-streams/context.js +0 -13
  38. package/esm/durable-streams/divergence.js +0 -56
  39. package/esm/durable-streams/each.js +0 -193
  40. package/esm/durable-streams/effect.js +0 -273
  41. package/esm/durable-streams/ephemeral.js +0 -80
  42. package/esm/durable-streams/errors.js +0 -92
  43. package/esm/durable-streams/http-stream.js +0 -207
  44. package/esm/durable-streams/mod.js +0 -34
  45. package/esm/durable-streams/operations.js +0 -88
  46. package/esm/durable-streams/replay-guard.js +0 -87
  47. package/esm/durable-streams/replay-index.js +0 -132
  48. package/esm/durable-streams/run.js +0 -137
  49. package/esm/durable-streams/serialize.js +0 -65
  50. package/esm/durable-streams/stream.js +0 -56
  51. package/esm/durable-streams/types.js +0 -10
  52. package/esm/runtime/apis.js +0 -237
  53. package/esm/runtime/find-free-port.js +0 -33
  54. package/esm/runtime/mod.js +0 -20
  55. /package/esm/{testing/npm/src/_dnt.polyfills.js → _dnt.polyfills.js} +0 -0
  56. /package/esm/{testing/npm/src/_dnt.shims.js → _dnt.shims.js} +0 -0
  57. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/almost_equals.js +0 -0
  58. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/array_includes.js +0 -0
  59. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/assert.js +0 -0
  60. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/assertion_error.js +0 -0
  61. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/equal.js +0 -0
  62. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/equals.js +0 -0
  63. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/exists.js +0 -0
  64. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/fail.js +0 -0
  65. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/false.js +0 -0
  66. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/greater.js +0 -0
  67. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/greater_or_equal.js +0 -0
  68. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/instance_of.js +0 -0
  69. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/is_error.js +0 -0
  70. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/less.js +0 -0
  71. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/less_or_equal.js +0 -0
  72. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/match.js +0 -0
  73. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/mod.js +0 -0
  74. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/not_equals.js +0 -0
  75. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/not_instance_of.js +0 -0
  76. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/not_match.js +0 -0
  77. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/not_strict_equals.js +0 -0
  78. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/object_match.js +0 -0
  79. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/rejects.js +0 -0
  80. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/strict_equals.js +0 -0
  81. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/string_includes.js +0 -0
  82. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/throws.js +0 -0
  83. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/unimplemented.js +0 -0
  84. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/assert/1.0.19/unreachable.js +0 -0
  85. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/build_message.js +0 -0
  86. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/diff.js +0 -0
  87. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/diff_str.js +0 -0
  88. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/format.js +0 -0
  89. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/styles.js +0 -0
  90. /package/esm/{testing/npm/src/deps → deps}/jsr.io/@std/internal/1.0.14/types.js +0 -0
  91. /package/esm/{testing/npm/src/mod.js → mod.js} +0 -0
  92. /package/esm/{testing/npm/src/src → src}/journal.js +0 -0
  93. /package/esm/{testing/npm/src/src → src}/test-api.js +0 -0
  94. /package/esm/{testing/npm/src/src → src}/use-testing.js +0 -0
@@ -1,237 +0,0 @@
1
- /**
2
- * Runtime Context APIs — platform I/O operations with pluggable middleware.
3
- *
4
- * Five domain-specific context APIs built on `@effectionx/context-api`.
5
- * Each API provides default Node.js implementations. Use `.around()` to
6
- * install middleware (mocking, instrumentation, sandboxing) scoped to the
7
- * current Effection scope.
8
- *
9
- * ## Architecture
10
- *
11
- * Import operation functions for normal calls, and use `API` only when
12
- * installing middleware with `.around()`:
13
- *
14
- * ```typescript
15
- * import { readTextFile, stat, API } from "@executablemd/runtime";
16
- *
17
- * // normal calls
18
- * const file = yield* readTextFile("doc.md");
19
- *
20
- * // middleware
21
- * yield* API.Fs.around({
22
- * *readTextFile([path], next) {
23
- * return yield* next(path);
24
- * },
25
- * });
26
- * ```
27
- *
28
- * ## Why four separate APIs?
29
- *
30
- * - **Process** — subprocess lifecycle has its own cancellation semantics
31
- * (killing processes on scope teardown). Middleware targets exec only.
32
- * - **Fs** — readTextFile, stat, and glob form a cohesive file-IO surface
33
- * used together for component resolution and replay guards.
34
- * - **Fetch** — HTTP has distinct timeout/body/abort semantics. Merging
35
- * with Fs or Process would blur cancellation boundaries.
36
- * - **Env** — synchronous host metadata (env vars, platform). Kept as a
37
- * context-api despite being sync because tests use `.around()` to mock
38
- * platform/env for deterministic replay testing.
39
- *
40
- * ## Middleware
41
- *
42
- * ```typescript
43
- * yield* API.Fs.around({
44
- * *readTextFile([path], next) {
45
- * return "mocked content";
46
- * },
47
- * });
48
- * ```
49
- *
50
- * Middleware is **scoped** — it only affects operations within the
51
- * current Effection scope and its children. Install before calling
52
- * `execute()` or `durableRun()`.
53
- *
54
- * ## Test stubs
55
- *
56
- * Common stubs are provided by `@executablemd/runtime/test`:
57
- * `useStubFs(files)`, `useEchoExec()`, `useFailingExec(code, stderr)`.
58
- */
59
- import { createApi } from "@effectionx/context-api";
60
- import { relative, sep } from "node:path";
61
- import process from "node:process";
62
- import { fetch as effectionFetch } from "@effectionx/fetch";
63
- import { readTextFile as fsReadTextFile, stat as fsStat, globToRegExp, walk } from "@effectionx/fs";
64
- import { exec as processExec } from "@effectionx/process";
65
- import { each, race, sleep } from "effection";
66
- // ---------------------------------------------------------------------------
67
- // Private helpers
68
- // ---------------------------------------------------------------------------
69
- function* withTimeout(label, timeout, operation) {
70
- if (timeout === undefined) {
71
- return yield* operation;
72
- }
73
- if (!Number.isFinite(timeout) || timeout < 0) {
74
- throw new Error(`${label}: timeout must be a non-negative finite number`);
75
- }
76
- return (yield* race([
77
- operation,
78
- (function* () {
79
- yield* sleep(timeout);
80
- throw new Error(`${label} timed out after ${timeout}ms`);
81
- })(),
82
- ]));
83
- }
84
- // ---------------------------------------------------------------------------
85
- // Context APIs
86
- // ---------------------------------------------------------------------------
87
- export const API = {
88
- /**
89
- * Subprocess execution.
90
- *
91
- * Default implementation uses `@effectionx/process`.
92
- * Cancellation kills the process via Effection scope teardown.
93
- */
94
- Process: createApi("runtime.process", {
95
- *exec(options) {
96
- const { command, cwd, env, timeout } = options;
97
- const [cmd, ...args] = command;
98
- if (!cmd) {
99
- throw new Error("exec: command array must not be empty");
100
- }
101
- const result = yield* withTimeout(`exec(${cmd})`, timeout, processExec(cmd, {
102
- arguments: args,
103
- cwd,
104
- env,
105
- }).join());
106
- return {
107
- exitCode: result.code ?? 1,
108
- stdout: result.stdout,
109
- stderr: result.stderr,
110
- };
111
- },
112
- }),
113
- /**
114
- * Filesystem operations.
115
- *
116
- * Default implementation uses `@effectionx/fs`.
117
- */
118
- Fs: createApi("runtime.fs", {
119
- *readTextFile(path) {
120
- return yield* fsReadTextFile(path);
121
- },
122
- *stat(path) {
123
- try {
124
- const s = yield* fsStat(path);
125
- return {
126
- exists: true,
127
- isFile: s.isFile(),
128
- isDirectory: s.isDirectory(),
129
- };
130
- }
131
- catch (err) {
132
- if (err.code === "ENOENT") {
133
- return { exists: false, isFile: false, isDirectory: false };
134
- }
135
- throw err;
136
- }
137
- },
138
- *glob(options) {
139
- const { patterns, root, exclude = [] } = options;
140
- const results = [];
141
- // Convert include/exclude patterns to RegExp for matching
142
- // against relative paths from root
143
- const includeRegexes = patterns.map((p) => globToRegExp(p, { extended: true, globstar: true }));
144
- const excludeRegexes = exclude.map((e) => globToRegExp(e, { extended: true, globstar: true }));
145
- // Walk the directory tree and match relative paths
146
- const stream = walk(root, {
147
- includeFiles: true,
148
- includeDirs: false,
149
- skip: excludeRegexes.length > 0 ? excludeRegexes : undefined,
150
- });
151
- for (const entry of yield* each(stream)) {
152
- // Normalize to POSIX separators for consistent matching across platforms
153
- const relPath = relative(root, entry.path).split(sep).join("/");
154
- const matches = includeRegexes.some((re) => re.test(relPath));
155
- if (matches) {
156
- results.push({ path: relPath, isFile: entry.isFile });
157
- }
158
- yield* each.next();
159
- }
160
- return results;
161
- },
162
- }),
163
- /**
164
- * HTTP requests.
165
- *
166
- * Default implementation uses `@effectionx/fetch`.
167
- * Cancellation aborts the request via Effection scope teardown.
168
- */
169
- Fetch: createApi("runtime.fetch", {
170
- *fetch(input, init) {
171
- const timeout = init?.timeout;
172
- const response = yield* withTimeout(`fetch(${input})`, timeout, effectionFetch(input, {
173
- method: init?.method,
174
- headers: init?.headers,
175
- body: init?.body,
176
- }));
177
- return {
178
- status: response.status,
179
- headers: response.headers,
180
- *text() {
181
- return yield* withTimeout(`fetch(${input}).text()`, timeout, response.text());
182
- },
183
- };
184
- },
185
- }),
186
- /**
187
- * Environment variables and platform information.
188
- *
189
- * These are synchronous lookups wrapped as Operations to satisfy
190
- * context-api handler constraints.
191
- */
192
- Env: createApi("runtime.env", {
193
- // deno-lint-ignore require-yield
194
- *cwd() {
195
- return process.cwd();
196
- },
197
- // deno-lint-ignore require-yield
198
- *env(name) {
199
- return process.env[name];
200
- },
201
- // deno-lint-ignore require-yield
202
- *platform() {
203
- return {
204
- os: process.platform,
205
- arch: process.arch,
206
- };
207
- },
208
- }),
209
- /**
210
- * Block compilation.
211
- *
212
- * Default handler throws — platform-specific middleware must be
213
- * installed via `yield* API.Compiler.around(...)` before use.
214
- * See `core/src/deno-compiler.ts` for the Deno implementation.
215
- */
216
- Compiler: createApi("runtime.compiler", {
217
- // deno-lint-ignore require-yield
218
- *compile(_source, _options) {
219
- throw new Error("compiler not installed — install platform-specific middleware via API.Compiler.around()");
220
- },
221
- }),
222
- };
223
- // ---------------------------------------------------------------------------
224
- // Convenience operation exports
225
- //
226
- // Use these for normal operation calls. Use API.* only when installing
227
- // middleware with .around().
228
- // ---------------------------------------------------------------------------
229
- export const exec = API.Process.operations.exec;
230
- export const readTextFile = API.Fs.operations.readTextFile;
231
- export const stat = API.Fs.operations.stat;
232
- export const glob = API.Fs.operations.glob;
233
- export const fetch = API.Fetch.operations.fetch;
234
- export const env = API.Env.operations.env;
235
- export const cwd = API.Env.operations.cwd;
236
- export const platform = API.Env.operations.platform;
237
- export const compile = API.Compiler.operations.compile;
@@ -1,33 +0,0 @@
1
- /**
2
- * findFreePort — find an available TCP port using the OS.
3
- */
4
- import { race } from "effection";
5
- import { once } from "@effectionx/node";
6
- import { createServer } from "node:net";
7
- /**
8
- * Find an available TCP port by binding to port 0 and reading the
9
- * OS-assigned port number.
10
- */
11
- export function* findFreePort() {
12
- const server = createServer();
13
- const listening = once(server, "listening");
14
- const error = once(server, "error");
15
- server.listen(0);
16
- try {
17
- const rethrowError = {
18
- *[Symbol.iterator]() {
19
- const [err] = yield* error;
20
- throw err;
21
- },
22
- };
23
- yield* race([listening, rethrowError]);
24
- const addr = server.address();
25
- if (!addr || typeof addr !== "object") {
26
- throw new Error("findFreePort: unexpected address format");
27
- }
28
- return addr.port;
29
- }
30
- finally {
31
- server.close();
32
- }
33
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * @module
3
- * Runtime Context APIs for executable markdown.
4
- *
5
- * `API` is available for middleware (`.around()`).
6
- * For normal calls, import operations directly.
7
- *
8
- * Six domain APIs:
9
- * - `API.Process` — subprocess execution (`exec`)
10
- * - `API.Fs` — filesystem (`readTextFile`, `stat`, `glob`)
11
- * - `API.Fetch` — HTTP requests (`fetch`)
12
- * - `API.Env` — environment variables and platform info (`cwd`, `env`, `platform`)
13
- * - `API.Compiler` — block compilation (`compile`)
14
- *
15
- * See `apis.ts` for architecture rationale.
16
- * See `@executablemd/runtime/test` for composable test stubs.
17
- */
18
- export { API } from "./apis.ts";
19
- export { exec, readTextFile, stat, glob, fetch, cwd, env, platform, compile } from "./apis.ts";
20
- export { findFreePort } from "./find-free-port.ts";
File without changes
File without changes
File without changes
File without changes