@venn-lang/contracts 0.1.2 → 0.1.3

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/index.js CHANGED
@@ -1133,29 +1133,22 @@ function readBare(cur) {
1133
1133
  return raw !== "" && !Number.isNaN(num) ? num : raw;
1134
1134
  }
1135
1135
  //#endregion
1136
- //#region src/ports/manifest-provider/toml/safe-key.ts
1136
+ //#region src/ports/manifest-provider/toml/table.ts
1137
1137
  /**
1138
- * Keys that reach the prototype rather than the object.
1138
+ * An empty table for a manifest to fill.
1139
1139
  *
1140
- * A manifest is data that arrives with somebody else's project, and assigning
1141
- * one of these from it changes how every object in the process behaves. A
1142
- * `venn.toml` containing `[package.__proto__]` was enough to put a property on
1140
+ * Made without a prototype, so a key read from the file is a key and nothing
1141
+ * else. Assigning `__proto__` onto an ordinary object changes how every object
1142
+ * in the process behaves, and a manifest arrives with somebody else's project:
1143
+ * a `venn.toml` holding `[package.__proto__]` was enough to put a property on
1143
1144
  * `Object.prototype`.
1144
- */
1145
- const RESERVED$1 = /* @__PURE__ */ new Set([
1146
- "__proto__",
1147
- "constructor",
1148
- "prototype"
1149
- ]);
1150
- /**
1151
- * Whether a key read from a manifest may be assigned.
1152
1145
  *
1153
- * @param key The key exactly as it was written in the file.
1154
- * @returns `false` for a key that would reach the prototype, which the caller
1155
- * should skip rather than assign.
1146
+ * Refusing that one name would have closed that one door. Having no prototype
1147
+ * to reach removes the question, and the table is read with `Object.keys` and
1148
+ * `Object.entries`, which do not care that it has none.
1156
1149
  */
1157
- function isSafeKey(key) {
1158
- return !RESERVED$1.has(key);
1150
+ function emptyTable() {
1151
+ return Object.create(null);
1159
1152
  }
1160
1153
  //#endregion
1161
1154
  //#region src/ports/manifest-provider/toml/sections.ts
@@ -1163,7 +1156,7 @@ function isSafeKey(key) {
1163
1156
  function enterSection(root, path) {
1164
1157
  let node = root;
1165
1158
  for (const key of keysOf(path)) {
1166
- node[key] ??= {};
1159
+ node[key] ??= emptyTable();
1167
1160
  node = node[key];
1168
1161
  }
1169
1162
  return node;
@@ -1181,12 +1174,12 @@ function enterTableArray(root, path) {
1181
1174
  const parent = enterSection(root, keys.join("."));
1182
1175
  const found = Array.isArray(parent[last]) ? parent[last] : [];
1183
1176
  parent[last] = found;
1184
- const table = {};
1177
+ const table = emptyTable();
1185
1178
  found.push(table);
1186
1179
  return table;
1187
1180
  }
1188
1181
  function keysOf(path) {
1189
- return path.split(".").map((part) => part.trim().replace(/^["']|["']$/g, "")).filter((part) => part !== "" && isSafeKey(part));
1182
+ return path.split(".").map((part) => part.trim().replace(/^["']|["']$/g, "")).filter((part) => part !== "");
1190
1183
  }
1191
1184
  //#endregion
1192
1185
  //#region src/ports/manifest-provider/toml/parse-toml.ts
@@ -1201,7 +1194,7 @@ function keysOf(path) {
1201
1194
  * @returns the root table. Malformed lines are skipped, never thrown on.
1202
1195
  */
1203
1196
  function parseToml(content) {
1204
- const root = {};
1197
+ const root = emptyTable();
1205
1198
  let section = root;
1206
1199
  for (const raw of content.split(/\r?\n/)) {
1207
1200
  const line = stripComment(raw).trim();
@@ -1229,7 +1222,6 @@ function assign(section, line) {
1229
1222
  const eq = line.indexOf("=");
1230
1223
  if (eq < 0) return;
1231
1224
  const key = line.slice(0, eq).trim().replace(/^["']|["']$/g, "");
1232
- if (!isSafeKey(key)) return;
1233
1225
  section[key] = readValue(cursor(line.slice(eq + 1)));
1234
1226
  }
1235
1227
  //#endregion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["RESERVED"],"sources":["../src/capabilities/host-capability.ts","../src/dotenv/dotenv-files.ts","../src/dotenv/parse-dotenv.ts","../src/errors/venn-error.ts","../src/errors/contract-codes.ts","../src/logger/console-logger.ts","../src/logger/memory-logger.ts","../src/ports/clock/clock.port.ts","../src/ports/clock/system-clock.ts","../src/ports/clock/virtual-clock.ts","../src/ports/file-system/file-system.errors.ts","../src/ports/file-system/file-system.port.ts","../src/ports/file-system/memory-fs.ts","../src/ports/lock-provider/fake-lock.ts","../src/ports/lock-provider/in-process-lock.ts","../src/ports/lock-provider/lock-provider.port.ts","../src/ports/process-provider/fake-process.ts","../src/ports/process-provider/process-provider.port.ts","../src/ports/random/fixed-random.ts","../src/ports/random/random.port.ts","../src/ports/random/seeded-random.ts","../src/ports/secret-provider/secret.ts","../src/ports/secret-provider/env-secrets.ts","../src/ports/secret-provider/memory-secrets.ts","../src/ports/secret-provider/secret-provider.port.ts","../src/host/create-test-host.ts","../src/host/unavailable.ts","../src/host/create-worker-host.ts","../src/host/create-host.ts","../src/port/missing-capabilities.ts","../src/port/assert-capabilities.ts","../src/port/assert-port-shape.ts","../src/port/bind-port.ts","../src/ports/console/console.port.ts","../src/ports/console/memory-console.ts","../src/ports/manifest-provider/read/scalars.ts","../src/ports/manifest-provider/read/read-dependencies.ts","../src/ports/manifest-provider/read/read-package.ts","../src/ports/manifest-provider/read/read-profiles.ts","../src/ports/manifest-provider/read/read-targets.ts","../src/ports/manifest-provider/read/read-tooling.ts","../src/ports/manifest-provider/read/read-workspace.ts","../src/ports/manifest-provider/default-manifest.ts","../src/ports/manifest-provider/edit/table-span.ts","../src/ports/manifest-provider/edit/edit-dependency.ts","../src/ports/manifest-provider/manifest.port.ts","../src/ports/manifest-provider/memory-manifest.ts","../src/ports/manifest-provider/resolve-alias.ts","../src/ports/manifest-provider/toml/read-value.ts","../src/ports/manifest-provider/toml/safe-key.ts","../src/ports/manifest-provider/toml/sections.ts","../src/ports/manifest-provider/toml/parse-toml.ts","../src/ports/manifest-provider/toml-docs.ts","../src/ports/manifest-provider/read-run-settings.ts","../src/ports/manifest-provider/toml-manifest.ts","../src/ports/signal-source/fake-signals.ts","../src/ports/signal-source/signal-source.port.ts","../src/ports/signal-source/signal-source.types.ts"],"sourcesContent":["/**\n * Every capability a Host may expose. A port or plugin declares which it\n * requires, a host advertises which it provides, and negotiation compares the\n * two before anything binds.\n */\nexport const ALL_CAPABILITIES = [\n \"fs\",\n \"process\",\n \"net\",\n \"clock\",\n \"random\",\n \"secrets\",\n \"log\",\n \"io\",\n] as const;\n\n/** One capability name, drawn from {@link ALL_CAPABILITIES}. */\nexport type HostCapability = (typeof ALL_CAPABILITIES)[number];\n","// biome-ignore-all lint/suspicious/noTemplateCurlyInString: ${name} is a placeholder in a path, not a JavaScript template.\n\n/**\n * The dotenv files read when `venn.toml` does not name its own.\n *\n * The order is the precedence, lowest first: what everyone shares, then what\n * this environment adds, then what this machine keeps to itself. The `.local`\n * ones are what a `.gitignore` is for.\n */\nexport const DOTENV_CONVENTION: readonly string[] = [\n \".env\",\n \".env.${name}\",\n \".env.local\",\n \".env.${name}.local\",\n];\n\n/**\n * Which files to read, in order, for one environment.\n *\n * The runner and the editor both ask this, so they cannot disagree about where\n * a value lives.\n *\n * @param args.configured - `[env] files` from `venn.toml`. Empty or absent\n * falls back to {@link DOTENV_CONVENTION}.\n * @param args.name - the selected environment, substituted for `${name}`.\n */\nexport function dotenvFiles(args: { configured?: readonly string[]; name: string }): string[] {\n const names = args.configured?.length ? args.configured : DOTENV_CONVENTION;\n return names.map((each) => each.replaceAll(\"${name}\", args.name));\n}\n","/**\n * Read a `.env` file: `NAME=value`, one per line.\n *\n * Deliberately small. It understands comments, blank lines, an `export `\n * prefix, and quotes around a value that needs them. No variable expansion:\n * `${OTHER}` is left alone, because Venn already interpolates in its own\n * strings and two syntaxes for one idea is how people get surprised.\n *\n * @returns every name found, later lines winning over earlier ones.\n */\nexport function parseDotenv(content: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/)) {\n const entry = readLine(line);\n if (entry) out[entry.name] = entry.value;\n }\n return out;\n}\n\nconst LINE = /^\\s*(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*)$/;\n\nfunction readLine(line: string): { name: string; value: string } | undefined {\n if (/^\\s*(#|$)/.test(line)) return undefined;\n const match = LINE.exec(line);\n if (!match?.[1]) return undefined;\n return { name: match[1], value: unquote((match[2] ?? \"\").trim()) };\n}\n\n/** A quoted value keeps its spaces and its `#`; an unquoted one stops at a comment. */\nfunction unquote(raw: string): string {\n const quoted = /^(['\"])([\\s\\S]*)\\1$/.exec(raw);\n if (quoted) return quoted[2] as string;\n return (raw.split(\" #\")[0] ?? \"\").trim();\n}\n","/** Structured, serializable, redaction-safe detail attached to a {@link VennError}. */\nexport type VennErrorDetail = Readonly<Record<string, unknown>>;\n\n/**\n * The single error type that crosses a contracts boundary.\n *\n * Every failure carries a stable `VNxxxx` code, so conformance suites assert on\n * `.code` and never on prose. Messages stay free to improve.\n */\nexport class VennError extends Error {\n readonly code: string;\n readonly detail: VennErrorDetail | undefined;\n\n constructor(args: { code: string; message: string; detail?: VennErrorDetail }) {\n super(args.message);\n this.name = \"VennError\";\n this.code = args.code;\n this.detail = args.detail;\n }\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { VennError } from \"./venn-error.js\";\n\n/** VN2010: a port requires capabilities the host does not provide. */\nexport function hostMissingCapability(args: {\n portId: string;\n missing: readonly HostCapability[];\n present: readonly HostCapability[];\n}): VennError {\n const message =\n `Port \"${args.portId}\" requires capability ${quote(args.missing)}, ` +\n `which this host does not provide. Present: ${list(args.present)}.`;\n return new VennError({ code: \"VN2010\", message, detail: { ...args } });\n}\n\n/** VN2011: an implementation is missing one or more methods the port declares. */\nexport function portShapeMismatch(args: { portId: string; missing: readonly string[] }): VennError {\n const message = `Implementation of \"${args.portId}\" is missing method(s): ${args.missing.join(\", \")}.`;\n return new VennError({ code: \"VN2011\", message, detail: { ...args } });\n}\n\n/** VN2012: code reached a capability the host declared unavailable. */\nexport function capabilityUnavailable(args: {\n capability: HostCapability;\n method: string;\n}): VennError {\n const message = `Capability \"${args.capability}\" is not available on this host (called \"${args.method}\").`;\n return new VennError({ code: \"VN2012\", message, detail: { ...args } });\n}\n\nfunction quote(caps: readonly string[]): string {\n return caps.map((c) => `\"${c}\"`).join(\", \");\n}\n\nfunction list(caps: readonly string[]): string {\n return caps.length === 0 ? \"(none)\" : caps.join(\", \");\n}\n","import type { Logger } from \"./logger.types.js\";\n\n/** Logger backed by the global console, so it works in a Worker and in Node. */\nexport function createConsoleLogger(): Logger {\n return {\n log(entry) {\n const line = `[${entry.level}] ${entry.message}`;\n if (entry.level === \"error\") console.error(line);\n else console.log(line);\n },\n };\n}\n","import type { LogEntry, MemoryLogger } from \"./logger.types.js\";\n\n/** The double: keeps every entry in `entries` instead of printing it. */\nexport function createMemoryLogger(): MemoryLogger {\n const entries: LogEntry[] = [];\n return {\n entries,\n log(entry) {\n entries.push(entry);\n },\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Clock } from \"./clock.types.js\";\n\n/**\n * The {@link Clock} contract. Implementations: `system-clock`, `virtual-clock`.\n *\n * `advance` and `setTime` are absent on purpose: they are how a test drives a\n * virtual clock, not something a caller of the port may reach for.\n */\nexport const ClockPort: Port<Clock> = {\n id: \"venn.port.clock\",\n version: 1,\n requires: [\"clock\"],\n methods: [\"now\", \"sleep\"],\n};\n","import type { Clock } from \"./clock.types.js\";\n\n/** Wall-clock time, on the `Date` and `setTimeout` globals. */\nexport function createSystemClock(): Clock {\n return {\n now: () => Date.now(),\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n };\n}\n","import type { VirtualClock } from \"./clock.types.js\";\n\n/**\n * The double. `sleep` advances internal time and resolves at once, so a test\n * about a timeout costs nothing to run.\n *\n * @param args.start - the epoch this clock begins at. Defaults to 0.\n */\nexport function createVirtualClock(args: { start?: number } = {}): VirtualClock {\n let time = args.start ?? 0;\n const advance = (ms: number): void => {\n time += Math.max(0, ms);\n };\n return {\n now: () => time,\n sleep: async (ms) => advance(ms),\n advance,\n setTime: (epochMs) => {\n time = epochMs;\n },\n };\n}\n","import { VennError } from \"../../errors/index.js\";\n\n/** VN8010: a read or a remove targeted a path that does not exist. */\nexport function fsNotFound(args: { path: string }): VennError {\n return new VennError({\n code: \"VN8010\",\n message: `File not found: \"${args.path}\".`,\n detail: { path: args.path },\n });\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { FileSystem } from \"./file-system.types.js\";\n\n/**\n * The {@link FileSystem} contract. Implementations: `node-fs`, `memory-fs`.\n */\nexport const FileSystemPort: Port<FileSystem> = {\n id: \"venn.port.filesystem\",\n version: 1,\n requires: [\"fs\"],\n methods: [\"read\", \"write\", \"exists\", \"remove\", \"list\"],\n};\n","import { fsNotFound } from \"./file-system.errors.js\";\nimport type { DirEntry, FileSystem } from \"./file-system.types.js\";\n\n/** The double: byte-exact, isolated per instance, no disk. */\nexport function createMemoryFs(): FileSystem {\n const files = new Map<string, Uint8Array>();\n return {\n async read(path) {\n const bytes = files.get(path);\n if (!bytes) throw fsNotFound({ path });\n return bytes.slice();\n },\n async write(path, bytes) {\n files.set(path, bytes.slice());\n },\n async exists(path) {\n return files.has(path);\n },\n async remove(path) {\n if (!files.delete(path)) throw fsNotFound({ path });\n },\n async list(path) {\n return listUnder([...files.keys()], path);\n },\n };\n}\n\n/**\n * What a directory holds, worked out from the paths written.\n *\n * There are no directories here, only paths, so a directory is whatever a path\n * implies one to be. For everything the language does with a directory that is\n * the same answer the real file system gives, which is what lets the TCK ask\n * both the same questions.\n */\nfunction listUnder(paths: readonly string[], directory: string): DirEntry[] {\n const prefix =\n directory === \"\" || directory === \".\" ? \"\" : `${withoutTrailingSlashes(directory)}/`;\n const seen = new Map<string, boolean>();\n for (const path of paths) {\n if (!path.startsWith(prefix)) continue;\n const rest = path.slice(prefix.length);\n const slash = rest.indexOf(\"/\");\n if (rest !== \"\") seen.set(slash < 0 ? rest : rest.slice(0, slash), slash >= 0);\n }\n return [...seen].map(([name, isDirectory]) => ({ name, directory: isDirectory }));\n}\n\n/**\n * A path with its trailing slashes removed.\n *\n * Scanned rather than matched with `/\\/+$/`, which the engine retries at every\n * position when the string does not end in one: quadratic on a long path, and\n * a path is whatever it was handed.\n */\nfunction withoutTrailingSlashes(path: string): string {\n let end = path.length;\n while (end > 0 && path.charCodeAt(end - 1) === 47) end -= 1;\n return path.slice(0, end);\n}\n","import type { LockProvider } from \"./lock-provider.types.js\";\n\n/** The double: grants immediately and serialises nothing. */\nexport function createFakeLock(): LockProvider {\n return { acquire: async () => () => {} };\n}\n","import type { LockProvider, Release } from \"./lock-provider.types.js\";\n\n/**\n * The real one: a chained-promise mutex per name. Waiters are served in the\n * order they asked, and the chain lives only in this process.\n */\nexport function createInProcessLock(): LockProvider {\n const tails = new Map<string, Promise<void>>();\n return {\n acquire: (name) => acquire(tails, name),\n };\n}\n\nasync function acquire(tails: Map<string, Promise<void>>, name: string): Promise<Release> {\n const previous = tails.get(name) ?? Promise.resolve();\n let release: Release = () => {};\n const held = new Promise<void>((resolve) => {\n release = resolve;\n });\n tails.set(\n name,\n previous.then(() => held),\n );\n await previous;\n return release;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { LockProvider } from \"./lock-provider.types.js\";\n\n/**\n * The {@link LockProvider} contract. Implementations: `in-process-lock`,\n * `fake-lock`.\n *\n * Requires nothing: a mutex is bookkeeping, so it binds even on a host with no\n * capabilities at all.\n */\nexport const LockProviderPort: Port<LockProvider> = {\n id: \"venn.port.lock\",\n version: 1,\n requires: [],\n methods: [\"acquire\"],\n};\n","import type { ProcessHandle, ProcessProvider } from \"./process-provider.types.js\";\n\n/**\n * The double: a scripted process that never touches the OS.\n *\n * Output is streamed before the wait resolves, exactly as the real one does it,\n * so a caller that shows progress is exercised here and not only against a real\n * machine.\n *\n * @param args.exitCode - what every run reports. Defaults to 0.\n * @param args.output - what every run writes. Defaults to nothing.\n */\nexport function createFakeProcess(\n args: { exitCode?: number; output?: string } = {},\n): ProcessProvider {\n const code = args.exitCode ?? 0;\n const output = args.output ?? \"\";\n return {\n spawn: (spawned) => {\n if (output !== \"\") spawned.onOutput?.(output);\n return handle(code, output);\n },\n };\n}\n\nfunction handle(code: number, output: string): ProcessHandle {\n return {\n pid: 0,\n wait: async () => ({ code, output }),\n kill: () => {},\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { ProcessProvider } from \"./process-provider.types.js\";\n\n/**\n * The {@link ProcessProvider} contract. Implementations: `node-spawn`,\n * `fake-process`.\n */\nexport const ProcessProviderPort: Port<ProcessProvider> = {\n id: \"venn.port.process\",\n version: 1,\n requires: [\"process\"],\n methods: [\"spawn\"],\n};\n","import type { Random } from \"./random.types.js\";\n\n/** The double: always the same value, and always `min` from `int`. */\nexport function createFixedRandom(args: { value?: number } = {}): Random {\n const value = args.value ?? 0;\n return {\n next: () => value,\n int: (min) => min,\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Random } from \"./random.types.js\";\n\n/**\n * The {@link Random} contract. Implementations: `seeded-random`,\n * `fixed-random`.\n */\nexport const RandomPort: Port<Random> = {\n id: \"venn.port.random\",\n version: 1,\n requires: [\"random\"],\n methods: [\"next\", \"int\"],\n};\n","import type { Random } from \"./random.types.js\";\n\n/**\n * The real one: a mulberry32 PRNG, seeded once per worker. Same seed, same\n * sequence, so a run reproduces.\n */\nexport function createSeededRandom(args: { seed: number }): Random {\n let state = args.seed >>> 0;\n const next = (): number => {\n state = (state + 0x6d2b79f5) | 0;\n let t = Math.imul(state ^ (state >>> 15), 1 | state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n return {\n next,\n int: (min, max) => min + Math.floor(next() * (max - min + 1)),\n };\n}\n","import type { Secret } from \"./secret-provider.types.js\";\n\n/** What every serialised secret collapses to. */\nexport const REDACTED = \"‹redigido›\";\n\n/**\n * Wrap a raw value so it cannot leak through `toString` or `toJSON`.\n *\n * @param args.reveal - the raw value, reachable only via `Secret.reveal()`.\n */\nexport function makeSecret(args: { reveal: string }): Secret {\n return {\n reveal: () => args.reveal,\n toString: () => REDACTED,\n toJSON: () => REDACTED,\n };\n}\n","import { makeSecret } from \"./secret.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The real one: secrets from `process.env`.\n *\n * The `process` global is probed rather than imported, so this file stays\n * neutral and reports every name as absent in a Worker instead of throwing.\n */\nexport function createEnvSecrets(): SecretProvider {\n const env: Record<string, string | undefined> = typeof process === \"undefined\" ? {} : process.env;\n return {\n get: (name) => {\n const value = env[name];\n return value === undefined ? undefined : makeSecret({ reveal: value });\n },\n has: (name) => env[name] !== undefined,\n };\n}\n","import { makeSecret } from \"./secret.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The double: secrets given by name, wrapped so they still redact.\n *\n * @param args.values - the raw values, keyed by secret name.\n */\nexport function createMemorySecrets(args: { values: Record<string, string> }): SecretProvider {\n const values = args.values;\n return {\n get: (name) => (name in values ? makeSecret({ reveal: values[name] as string }) : undefined),\n has: (name) => name in values,\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The {@link SecretProvider} contract. Implementations: `env-secrets`,\n * `memory-secrets`.\n */\nexport const SecretProviderPort: Port<SecretProvider> = {\n id: \"venn.port.secrets\",\n version: 1,\n requires: [\"secrets\"],\n methods: [\"get\", \"has\"],\n};\n","import { ALL_CAPABILITIES } from \"../capabilities/index.js\";\nimport { createMemoryLogger } from \"../logger/index.js\";\nimport { createVirtualClock } from \"../ports/clock/index.js\";\nimport { createMemoryFs } from \"../ports/file-system/index.js\";\nimport { createInProcessLock } from \"../ports/lock-provider/index.js\";\nimport { createFakeProcess } from \"../ports/process-provider/index.js\";\nimport { createSeededRandom } from \"../ports/random/index.js\";\nimport { createMemorySecrets } from \"../ports/secret-provider/index.js\";\nimport type { Host } from \"./host.types.js\";\n\n/**\n * A host of doubles, every capability granted. The default for tests.\n *\n * @param overrides - replaces individual members, e.g. a real clock.\n */\nexport function createTestHost(overrides: Partial<Host> = {}): Host {\n return {\n fs: createMemoryFs(),\n proc: createFakeProcess(),\n clock: createVirtualClock(),\n random: createSeededRandom({ seed: 1 }),\n secrets: createMemorySecrets({ values: {} }),\n log: createMemoryLogger(),\n lock: createInProcessLock(),\n caps: ALL_CAPABILITIES,\n ...overrides,\n };\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { capabilityUnavailable } from \"../errors/index.js\";\n\n/**\n * A stand-in for a port the host cannot provide, such as `process` in a Worker.\n *\n * @param args.capability - the capability the host lacks, named in the error.\n * @param args.methods - the port's declared methods, usually `SomePort.methods`.\n * @returns an object shaped like `T` whose every method throws VN2012 when\n * called, rather than failing as a `TypeError` mid-run.\n */\nexport function unavailable<T>(args: {\n capability: HostCapability;\n methods: readonly string[];\n}): T {\n const bag: Record<string, unknown> = {};\n for (const method of args.methods) {\n bag[method] = () => {\n throw capabilityUnavailable({ capability: args.capability, method });\n };\n }\n return bag as T;\n}\n","import { createMemoryLogger } from \"../logger/index.js\";\nimport { createSystemClock } from \"../ports/clock/index.js\";\nimport { createMemoryFs } from \"../ports/file-system/index.js\";\nimport { createInProcessLock } from \"../ports/lock-provider/index.js\";\nimport type { ProcessProvider } from \"../ports/process-provider/index.js\";\nimport { ProcessProviderPort } from \"../ports/process-provider/index.js\";\nimport { createSeededRandom } from \"../ports/random/index.js\";\nimport { createMemorySecrets } from \"../ports/secret-provider/index.js\";\nimport type { Host } from \"./host.types.js\";\nimport { unavailable } from \"./unavailable.js\";\n\n/**\n * Host for a Web Worker: an in-memory file system, no `process`, no `net`.\n *\n * `proc` is a stand-in whose every method throws VN2012, so reaching for a\n * subprocess in the editor fails with a diagnostic instead of a `TypeError`.\n */\nexport function createWorkerHost(): Host {\n return {\n fs: createMemoryFs(),\n proc: unavailable<ProcessProvider>({\n capability: \"process\",\n methods: ProcessProviderPort.methods,\n }),\n clock: createSystemClock(),\n random: createSeededRandom({ seed: 1 }),\n secrets: createMemorySecrets({ values: {} }),\n log: createMemoryLogger(),\n lock: createInProcessLock(),\n caps: [\"fs\", \"clock\", \"random\", \"secrets\", \"log\"],\n };\n}\n","import { createTestHost } from \"./create-test-host.js\";\nimport { createWorkerHost } from \"./create-worker-host.js\";\n\n/**\n * The neutral host assemblers.\n *\n * `node` is deliberately absent: it pulls `node:*`, so it lives behind\n * `@venn-lang/contracts/node` as `createNodeHost` and this entry stays Worker-safe.\n */\nexport const createHost: {\n readonly worker: typeof createWorkerHost;\n readonly test: typeof createTestHost;\n} = {\n worker: createWorkerHost,\n test: createTestHost,\n};\n","import type { HostCapability } from \"../capabilities/index.js\";\n\n/**\n * The gap between what is required and what the host offers.\n *\n * @returns the required capabilities absent from `caps`, in the order required.\n */\nexport function missingCapabilities(args: {\n requires: readonly HostCapability[];\n caps: readonly HostCapability[];\n}): readonly HostCapability[] {\n const present = new Set(args.caps);\n return args.requires.filter((cap) => !present.has(cap));\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { hostMissingCapability } from \"../errors/index.js\";\nimport { missingCapabilities } from \"./missing-capabilities.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * Checks the host against what the port requires.\n *\n * @throws VennError VN2010 when a required capability is absent.\n */\nexport function assertCapabilities<T>(args: {\n port: Port<T>;\n caps: readonly HostCapability[];\n}): void {\n const missing = missingCapabilities({ requires: args.port.requires, caps: args.caps });\n if (missing.length === 0) return;\n throw hostMissingCapability({ portId: args.port.id, missing, present: args.caps });\n}\n","import { portShapeMismatch } from \"../errors/index.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * Checks the implementation against the methods the port declares.\n *\n * @throws VennError VN2011 when a declared method is missing or is not callable.\n */\nexport function assertPortShape<T>(args: { port: Port<T>; impl: unknown }): void {\n const missing = missingMethods(args.port, args.impl);\n if (missing.length === 0) return;\n throw portShapeMismatch({ portId: args.port.id, missing });\n}\n\nfunction missingMethods<T>(port: Port<T>, impl: unknown): readonly string[] {\n const bag = impl as Record<string, unknown> | null | undefined;\n return port.methods.filter((m) => typeof bag?.[m] !== \"function\");\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { assertCapabilities } from \"./assert-capabilities.js\";\nimport { assertPortShape } from \"./assert-port-shape.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * The single loader entry. Negotiates capabilities, checks the implementation's\n * shape, then hands it back typed as `T`.\n *\n * Both checks run before anything is bound, so a mismatch is reported at start\n * up rather than as a `TypeError` in the middle of a test.\n *\n * @param args.port - the descriptor to bind against.\n * @param args.impl - the candidate implementation, untrusted.\n * @param args.caps - the capabilities the host advertises.\n * @returns `args.impl` typed as `T`.\n * @throws VennError VN2010 when the host lacks a required capability, VN2011\n * when the implementation is missing a declared method.\n */\nexport function bindPort<T>(args: {\n port: Port<T>;\n impl: unknown;\n caps: readonly HostCapability[];\n}): T {\n assertCapabilities({ port: args.port, caps: args.caps });\n assertPortShape({ port: args.port, impl: args.impl });\n return args.impl as T;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Console } from \"./console.types.js\";\n\n/**\n * The {@link Console} contract. Implementations: `node-console`,\n * `memory-console`.\n */\nexport const ConsolePort: Port<Console> = {\n id: \"venn.port.console\",\n version: 1,\n requires: [\"io\"],\n methods: [\"write\", \"writeError\", \"readLine\", \"args\"],\n};\n","import type { Console } from \"./console.types.js\";\n\n/** A {@link Console} that keeps its transcript instead of printing it. */\nexport interface MemoryConsole extends Console {\n readonly out: string;\n readonly err: string;\n}\n\n/**\n * The double: records what was written, reads from a scripted input.\n *\n * @param args.input - the lines `readLine` hands back, in order.\n * @param args.argv - what `args()` reports.\n */\nexport function createMemoryConsole(\n args: { input?: readonly string[]; argv?: readonly string[] } = {},\n): MemoryConsole {\n const state = { out: \"\", err: \"\" };\n const input = [...(args.input ?? [])];\n return {\n write: (text) => {\n state.out += text;\n },\n writeError: (text) => {\n state.err += text;\n },\n readLine: () => Promise.resolve(input.length > 0 ? (input.shift() ?? null) : null),\n args: () => args.argv ?? [],\n get out() {\n return state.out;\n },\n get err() {\n return state.err;\n },\n };\n}\n","// Reading a parsed TOML value as the shape the manifest expects. None of these\n// throw: a malformed table reads as an empty one, so one bad line never stops a\n// project from opening.\n\nexport function asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nexport function asStringMap(value: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, item] of Object.entries(asRecord(value))) out[key] = String(item);\n return out;\n}\n\nexport function asList(value: unknown): readonly string[] {\n return Array.isArray(value) ? value.map(String) : [];\n}\n\nexport function asRecords(value: unknown): readonly Record<string, unknown>[] {\n return Array.isArray(value) ? value.map(asRecord) : [];\n}\n\nexport function asString(value: unknown): string | undefined {\n return value === undefined || value === null ? undefined : String(value);\n}\n\nexport function asNumber(value: unknown): number | undefined {\n const parsed = Number(value);\n return value === undefined || Number.isNaN(parsed) ? undefined : parsed;\n}\n\nexport function asBoolean(value: unknown): boolean | undefined {\n if (value === undefined) return undefined;\n return value === true || value === \"true\";\n}\n","import type { Dependency } from \"../project.types.js\";\nimport { asBoolean, asRecord, asString } from \"./scalars.js\";\n\n/**\n * A dependency table, in either spelling TOML allows.\n *\n * `zod = \"^4\"` and `zod = { version = \"^4\", optional = true }` say the same\n * thing about the version, so both read into one shape rather than two the rest\n * of the code would have to keep apart.\n */\nexport function readDependencies(value: unknown): Dependency[] {\n return Object.entries(asRecord(value)).map(([name, spec]) => readOne(name, spec));\n}\n\nfunction readOne(name: string, spec: unknown): Dependency {\n if (typeof spec === \"string\") {\n return { name, version: spec, fromWorkspace: false, optional: false };\n }\n const table = asRecord(spec);\n return {\n name,\n version: asString(table.version),\n path: asString(table.path),\n fromWorkspace: asBoolean(table.workspace) ?? false,\n optional: asBoolean(table.optional) ?? false,\n };\n}\n","import type { PackageInfo } from \"../project.types.js\";\nimport { asList, asRecord, asString } from \"./scalars.js\";\n\n/** `[package]`: who this is. A missing table reads as a nameless package. */\nexport function readPackage(data: Record<string, unknown>): PackageInfo {\n const table = asRecord(data.package);\n return {\n name: String(table.name ?? \"\"),\n version: asString(table.version),\n description: asString(table.description),\n license: asString(table.license),\n authors: asList(table.authors),\n edition: asString(table.edition),\n };\n}\n\n/**\n * The same table, reduced to what a member may inherit from its workspace.\n *\n * A name is never inherited, being the one thing that must differ between two\n * members, so `[workspace.package]` carrying one is read as carrying none.\n */\nexport function readInheritable(data: Record<string, unknown>): Partial<PackageInfo> {\n const table = asRecord(data);\n const found: Partial<PackageInfo> = {};\n for (const key of [\"version\", \"description\", \"license\", \"edition\"] as const) {\n const value = asString(table[key]);\n if (value !== undefined) found[key] = value;\n }\n const authors = asList(table.authors);\n return authors.length > 0 ? { ...found, authors } : found;\n}\n","import type { Profile } from \"../project.types.js\";\nimport { asBoolean, asRecord } from \"./scalars.js\";\n\n/**\n * What each build is for, and what that costs.\n *\n * `dev` reports what it finds and carries on, because a project being worked on\n * is half-written most of the time. `release` refuses to build over a problem.\n * Neither has to be written in a manifest for the defaults to apply.\n */\nexport const DEFAULT_PROFILES: Readonly<Record<string, Profile>> = {\n dev: { strict: false },\n release: { strict: true },\n};\n\n/** `[profile.<name>]`, merged over {@link DEFAULT_PROFILES}. */\nexport function readProfiles(data: Record<string, unknown>): Record<string, Profile> {\n const out: Record<string, Profile> = { ...DEFAULT_PROFILES };\n for (const [name, table] of Object.entries(asRecord(data.profile))) {\n out[name] = { ...out[name], ...readProfile(asRecord(table)) };\n }\n return out;\n}\n\nfunction readProfile(table: Record<string, unknown>): Profile {\n const found: Profile = {};\n for (const key of [\"strict\"] as const) {\n const value = asBoolean(table[key]);\n if (value !== undefined) found[key] = value;\n }\n return found;\n}\n","import type { BuildTarget } from \"../project.types.js\";\nimport { asRecord, asRecords, asString } from \"./scalars.js\";\n\n/** Where a `lib` target starts when the manifest does not say. */\nexport const LIB_ROOT = \"src/lib.vn\";\n/** Where the default `bin` target starts when the manifest does not say. */\nexport const MAIN_ROOT = \"src/main.vn\";\n/** Where additional `bin` targets are looked for by convention. */\nexport const BIN_DIR = \"src/bin\";\n\n/**\n * `[lib]` and `[[bin]]`: what this package builds.\n *\n * Only what the manifest *declares*. The conventional roots are filled in by\n * whoever can look at the disk, because a convention is a claim about files\n * existing and this reader is pure. A manifest declaring nothing is the common\n * case, not an empty one.\n */\nexport function readTargets(data: Record<string, unknown>, packageName: string): BuildTarget[] {\n const found: BuildTarget[] = [];\n if (data.lib !== undefined) found.push(readLib(asRecord(data.lib), packageName));\n for (const entry of asRecords(data.bin)) found.push(readBin(entry, packageName));\n return found;\n}\n\nfunction readLib(table: Record<string, unknown>, packageName: string): BuildTarget {\n return {\n kind: \"lib\",\n name: asString(table.name) ?? packageName,\n path: asString(table.path) ?? LIB_ROOT,\n };\n}\n\nfunction readBin(table: Record<string, unknown>, packageName: string): BuildTarget {\n const name = asString(table.name) ?? packageName;\n return { kind: \"bin\", name, path: asString(table.path) ?? `${BIN_DIR}/${name}.vn` };\n}\n","import type { PackageManagerName, ToolingSettings } from \"../project.types.js\";\nimport { asRecord, asString } from \"./scalars.js\";\n\nconst MANAGERS = new Set<string>([\"pnpm\", \"npm\", \"bun\", \"yarn\"]);\n\n/**\n * `[tooling]`: which package manager runs underneath.\n *\n * An unrecognised name falls back to pnpm rather than failing, so a manifest\n * written against a newer toolchain still opens.\n */\nexport function readTooling(data: Record<string, unknown>): ToolingSettings {\n const name = asString(asRecord(data.tooling).manager);\n return { manager: name && MANAGERS.has(name) ? (name as PackageManagerName) : \"pnpm\" };\n}\n","import type { WorkspaceSettings } from \"../project.types.js\";\nimport { readDependencies } from \"./read-dependencies.js\";\nimport { readInheritable } from \"./read-package.js\";\nimport { asList, asRecord } from \"./scalars.js\";\n\n/**\n * `[workspace]`, or undefined when the manifest is a plain package.\n *\n * A root may also be a package, so `[workspace]` and `[package]` are read\n * separately and never merged.\n */\nexport function readWorkspace(data: Record<string, unknown>): WorkspaceSettings | undefined {\n if (data.workspace === undefined) return undefined;\n const table = asRecord(data.workspace);\n return {\n members: asList(table.members),\n exclude: asList(table.exclude),\n defaultMembers: asList(table[\"default-members\"]),\n package: readInheritable(asRecord(table.package)),\n dependencies: readDependencies(table.dependencies),\n };\n}\n","import type { Manifest } from \"./manifest.types.js\";\nimport { DEFAULT_PROFILES } from \"./read/index.js\";\n\n/**\n * A manifest with nothing declared: what a project without a `venn.toml` is.\n *\n * The one place stating what a project gets for saying nothing at all, so a\n * caller who wants one field need not spell the other dozen.\n *\n * @param overrides - fields to state explicitly. `name` and `version` fall back\n * to `[package]` before falling back to the defaults.\n */\nexport function defaultManifest(overrides: Partial<Manifest> = {}): Manifest {\n const pkg = { name: \"\", authors: [], ...overrides.package };\n return {\n name: overrides.name ?? pkg.name,\n version: overrides.version ?? pkg.version ?? \"0.0.0\",\n package: pkg,\n targets: [],\n dependencies: [],\n devDependencies: [],\n patch: [],\n profiles: { ...DEFAULT_PROFILES },\n tooling: { manager: \"pnpm\" },\n env: {},\n envFiles: [],\n paths: {},\n format: {},\n ...overrides,\n };\n}\n","/** Where a table's entries live in a manifest's lines. */\nexport interface TableSpan {\n /** The line holding `[name]`. */\n header: number;\n /** First line after the header, and the line after the table's last entry. */\n from: number;\n to: number;\n}\n\n/**\n * Where a `[table]` is written, or undefined when the file has none.\n *\n * Found by reading lines rather than by re-serialising the parse tree. A\n * manifest carries its author's comments, blank lines and chosen order, and\n * rebuilding it from a tree would throw all of that away.\n */\nexport function tableSpan(lines: readonly string[], name: string): TableSpan | undefined {\n const header = lines.findIndex((line) => line.trim() === `[${name}]`);\n if (header < 0) return undefined;\n let to = header + 1;\n for (let at = header + 1; at < lines.length; at++) {\n if (lines[at]?.trimStart().startsWith(\"[\")) break;\n if (lines[at]?.trim() !== \"\") to = at + 1;\n }\n return { header, from: header + 1, to };\n}\n\n/** The key a `key = value` line writes, or undefined for a comment or a blank. */\nexport function keyOf(line: string): string | undefined {\n const text = line.trim();\n if (text === \"\" || text.startsWith(\"#\") || text.startsWith(\"[\")) return undefined;\n const equals = text.indexOf(\"=\");\n return equals < 0\n ? undefined\n : text\n .slice(0, equals)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n}\n","import { keyOf, tableSpan } from \"./table-span.js\";\n\n/** What to change, and in which table. */\nexport interface DependencyEdit {\n /** The manifest as written. */\n text: string;\n name: string;\n /** Defaults to {@link DEPENDENCIES}. Pass `\"dev-dependencies\"` for the other. */\n table?: string;\n}\n\n/** The table an edit touches unless told otherwise. */\nexport const DEPENDENCIES = \"dependencies\";\n\n/**\n * The manifest with one dependency written in, everything else untouched.\n *\n * Entries are kept in name order, so two people adding two packages produce two\n * one-line diffs rather than a conflict. A name already there is replaced where\n * it stands, because an upgrade should not move the line.\n *\n * @returns the whole manifest as text. A missing table is appended at the end.\n */\nexport function addDependency(args: DependencyEdit & { version: string }): string {\n const table = args.table ?? DEPENDENCIES;\n const lines = args.text.split(\"\\n\");\n const entry = `${args.name} = \"${args.version}\"`;\n const span = tableSpan(lines, table);\n if (!span) return appended(args.text, table, entry);\n const at = lines.findIndex((line, index) => inside(span, index) && keyOf(line) === args.name);\n if (at >= 0) return replaced(lines, at, entry);\n return replaced(lines, insertionPoint(lines, span, args.name), entry, \"insert\");\n}\n\n/**\n * The manifest without that dependency.\n *\n * @returns the text unchanged when the name is not there: absent is already the\n * wanted state.\n */\nexport function removeDependency(args: DependencyEdit): string {\n const table = args.table ?? DEPENDENCIES;\n const lines = args.text.split(\"\\n\");\n const span = tableSpan(lines, table);\n if (!span) return args.text;\n const at = lines.findIndex((line, index) => inside(span, index) && keyOf(line) === args.name);\n if (at < 0) return args.text;\n return [...lines.slice(0, at), ...lines.slice(at + 1)].join(\"\\n\");\n}\n\nfunction inside(span: { from: number; to: number }, index: number): boolean {\n return index >= span.from && index < span.to;\n}\n\n/** Where the name belongs, in order, among the entries already there. */\nfunction insertionPoint(\n lines: readonly string[],\n span: { from: number; to: number },\n name: string,\n): number {\n for (let at = span.from; at < span.to; at++) {\n const key = keyOf(lines[at] ?? \"\");\n if (key && key > name) return at;\n }\n return span.to;\n}\n\nfunction replaced(\n lines: readonly string[],\n at: number,\n entry: string,\n how: \"replace\" | \"insert\" = \"replace\",\n): string {\n const after = how === \"insert\" ? lines.slice(at) : lines.slice(at + 1);\n return [...lines.slice(0, at), entry, ...after].join(\"\\n\");\n}\n\n/** A table the manifest does not have yet, written at the end where it reads. */\nfunction appended(text: string, table: string, entry: string): string {\n const body = text.endsWith(\"\\n\") ? text : `${text}\\n`;\n return `${body}\\n[${table}]\\n${entry}\\n`;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { ManifestProvider } from \"./manifest.types.js\";\n\n/**\n * The {@link ManifestProvider} contract. Implementations: `toml-manifest`,\n * `memory-manifest`.\n *\n * Requires nothing: reading the file is the caller's job, and what arrives here\n * is already text.\n */\nexport const ManifestProviderPort: Port<ManifestProvider> = {\n id: \"venn.port.manifest\",\n version: 1,\n requires: [],\n methods: [\"load\"],\n};\n","import { defaultManifest } from \"./default-manifest.js\";\nimport type { Manifest, ManifestProvider } from \"./manifest.types.js\";\n\n/**\n * The double: a preset manifest, with no file involved.\n *\n * Takes only what the caller cares about. The rest is what a project that\n * declared nothing would get, which is exactly what the real provider gives a\n * `venn.toml` silent on those tables.\n */\nexport function createMemoryManifest(args: { manifest: Partial<Manifest> }): ManifestProvider {\n const manifest: Manifest = defaultManifest(args.manifest);\n return { load: () => manifest };\n}\n","/** Where a `#alias/…` specifier points. */\nexport interface AliasTarget {\n /** The directory `[paths]` maps the alias to. */\n dir: string;\n /** What followed the alias, with the separating slash removed. */\n rest: string;\n}\n\n/**\n * Split a `#alias/rest` import specifier against `[paths]` from `venn.toml`.\n *\n * @returns undefined when the specifier names no configured alias, which the\n * caller reads as a relative or bare path.\n */\nexport function resolveAlias(args: {\n spec: string;\n paths: Record<string, string>;\n}): AliasTarget | undefined {\n const alias = Object.keys(args.paths).find((key) => args.spec.startsWith(`${key}/`));\n if (!alias) return undefined;\n return { dir: args.paths[alias] as string, rest: args.spec.slice(alias.length + 1) };\n}\n","/** A position in the text being read. Mutable, because reading advances it. */\nexport interface Cursor {\n readonly text: string;\n index: number;\n}\n\n/** A cursor over `text`, positioned at the start. */\nexport function cursor(text: string): Cursor {\n return { text, index: 0 };\n}\n\n/**\n * One TOML value: a string, a number, a bool, an array, or an inline table.\n *\n * Reads by walking rather than by splitting, because a comma can sit inside a\n * value: splitting turns `[\"a,b\"]` into two items and leaves\n * `{ version = \"^4\" }` as the text it was written in.\n */\nexport function readValue(cur: Cursor): unknown {\n skipSpace(cur);\n const ch = cur.text[cur.index];\n if (ch === '\"' || ch === \"'\") return readString(cur);\n if (ch === \"[\") return readArray(cur);\n if (ch === \"{\") return readInlineTable(cur);\n return readBare(cur);\n}\n\nexport function skipSpace(cur: Cursor): void {\n while (/\\s/.test(cur.text[cur.index] ?? \"\")) cur.index++;\n}\n\n/** A basic string reads escapes; a literal one, in single quotes, does not. */\nfunction readString(cur: Cursor): string {\n const quote = cur.text[cur.index];\n cur.index++;\n let out = \"\";\n while (cur.index < cur.text.length && cur.text[cur.index] !== quote) {\n if (quote === '\"' && cur.text[cur.index] === \"\\\\\") out += unescaped(cur);\n else out += cur.text[cur.index++];\n }\n cur.index++;\n return out;\n}\n\nconst ESCAPES: Record<string, string> = { n: \"\\n\", t: \"\\t\", r: \"\\r\", \"\\\\\": \"\\\\\", '\"': '\"' };\n\nfunction unescaped(cur: Cursor): string {\n const code = cur.text[cur.index + 1] ?? \"\";\n cur.index += 2;\n return ESCAPES[code] ?? code;\n}\n\nfunction readArray(cur: Cursor): unknown[] {\n cur.index++;\n const out: unknown[] = [];\n while (!atClose(cur, \"]\")) {\n out.push(readValue(cur));\n skipSeparator(cur);\n }\n cur.index++;\n return out;\n}\n\nfunction readInlineTable(cur: Cursor): Record<string, unknown> {\n cur.index++;\n const out: Record<string, unknown> = {};\n while (!atClose(cur, \"}\")) {\n const key = readKey(cur);\n if (key === undefined) break;\n out[key] = readValue(cur);\n skipSeparator(cur);\n }\n cur.index++;\n return out;\n}\n\nfunction readKey(cur: Cursor): string | undefined {\n skipSpace(cur);\n const equals = cur.text.indexOf(\"=\", cur.index);\n if (equals < 0) return undefined;\n const raw = cur.text.slice(cur.index, equals).trim();\n cur.index = equals + 1;\n return raw.replace(/^[\"']|[\"']$/g, \"\");\n}\n\nfunction atClose(cur: Cursor, close: string): boolean {\n skipSpace(cur);\n return cur.index >= cur.text.length || cur.text[cur.index] === close;\n}\n\nfunction skipSeparator(cur: Cursor): void {\n skipSpace(cur);\n if (cur.text[cur.index] === \",\") cur.index++;\n}\n\n/** Anything unquoted: `true`, `12`, `1.5`, or a word the manifest gives meaning. */\nfunction readBare(cur: Cursor): unknown {\n const start = cur.index;\n while (cur.index < cur.text.length && !\",]}\".includes(cur.text[cur.index] ?? \"\")) cur.index++;\n const raw = cur.text.slice(start, cur.index).trim();\n if (raw === \"true\" || raw === \"false\") return raw === \"true\";\n const num = Number(raw);\n return raw !== \"\" && !Number.isNaN(num) ? num : raw;\n}\n","/**\n * Keys that reach the prototype rather than the object.\n *\n * A manifest is data that arrives with somebody else's project, and assigning\n * one of these from it changes how every object in the process behaves. A\n * `venn.toml` containing `[package.__proto__]` was enough to put a property on\n * `Object.prototype`.\n */\nconst RESERVED: ReadonlySet<string> = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/**\n * Whether a key read from a manifest may be assigned.\n *\n * @param key The key exactly as it was written in the file.\n * @returns `false` for a key that would reach the prototype, which the caller\n * should skip rather than assign.\n */\nexport function isSafeKey(key: string): boolean {\n return !RESERVED.has(key);\n}\n","// Opening `[a.b]` or `[[a.b]]`: working out where the keys that follow go.\n\nimport { isSafeKey } from \"./safe-key.js\";\n\n/** The table `[path]` names, created along the way if it is not there yet. */\nexport function enterSection(root: Record<string, unknown>, path: string): Record<string, unknown> {\n let node = root;\n for (const key of keysOf(path)) {\n node[key] ??= {};\n node = node[key] as Record<string, unknown>;\n }\n return node;\n}\n\n/**\n * `[[bin]]`: one more of something there may be several of.\n *\n * Returns the table just appended, so two `[[bin]]` sections give two bins\n * rather than one bin written twice.\n */\nexport function enterTableArray(\n root: Record<string, unknown>,\n path: string,\n): Record<string, unknown> {\n const keys = keysOf(path);\n const last = keys.pop();\n if (!last) return root;\n const parent = enterSection(root, keys.join(\".\"));\n const found = Array.isArray(parent[last]) ? (parent[last] as unknown[]) : [];\n parent[last] = found;\n const table: Record<string, unknown> = {};\n found.push(table);\n return table;\n}\n\nfunction keysOf(path: string): string[] {\n return path\n .split(\".\")\n .map((part) => part.trim().replace(/^[\"']|[\"']$/g, \"\"))\n .filter((part) => part !== \"\" && isSafeKey(part));\n}\n","import { cursor, readValue } from \"./read-value.js\";\nimport { isSafeKey } from \"./safe-key.js\";\nimport { enterSection, enterTableArray } from \"./sections.js\";\n\n/**\n * A TOML reader for `venn.toml`: sections, nested `[a.b]`, arrays of tables\n * (`[[bin]]`), `key = value`, strings, numbers, bools, arrays and inline tables.\n *\n * Not a full TOML parser. No dates, no multi-line strings, no dotted keys.\n * `venn.toml` is our own format, so the subset is a decision rather than a\n * shortfall.\n *\n * @returns the root table. Malformed lines are skipped, never thrown on.\n */\nexport function parseToml(content: string): Record<string, unknown> {\n const root: Record<string, unknown> = {};\n let section = root;\n for (const raw of content.split(/\\r?\\n/)) {\n const line = stripComment(raw).trim();\n if (line === \"\") continue;\n if (line.startsWith(\"[\")) section = openSection(root, line);\n else assign(section, line);\n }\n return root;\n}\n\n/** `[[bin]]` appends another table, `[bin]` opens the one and only. */\nfunction openSection(root: Record<string, unknown>, line: string): Record<string, unknown> {\n if (line.startsWith(\"[[\")) {\n return enterTableArray(root, line.slice(2, line.indexOf(\"]]\")));\n }\n return enterSection(root, line.slice(1, line.indexOf(\"]\")));\n}\n\nfunction stripComment(line: string): string {\n let quote: string | undefined;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === '\"' || ch === \"'\") quote = quote === ch ? undefined : (quote ?? ch);\n else if (ch === \"#\" && !quote) return line.slice(0, i);\n }\n return line;\n}\n\nfunction assign(section: Record<string, unknown>, line: string): void {\n const eq = line.indexOf(\"=\");\n if (eq < 0) return;\n const key = line\n .slice(0, eq)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n if (!isSafeKey(key)) return;\n section[key] = readValue(cursor(line.slice(eq + 1)));\n}\n","const COMMENT = /^\\s*#\\s?(.*)$/;\nconst KEY = /^\\s*([A-Za-z_][\\w-]*)\\s*=/;\n\n/**\n * The comment block written directly above a key, read as that key's\n * documentation. The same idea as `##` above a declaration in a `.vn`.\n *\n * A blank line breaks the block, so a comment separated from a key belongs to\n * nobody and is never attributed to the next one down.\n *\n * @returns documentation keyed by the key it sits above.\n */\nexport function tomlDocs(content: string): Record<string, string> {\n const docs: Record<string, string> = {};\n let block: string[] = [];\n for (const line of content.split(/\\r?\\n/)) {\n const comment = COMMENT.exec(line);\n if (comment) {\n block.push(comment[1] ?? \"\");\n continue;\n }\n const key = KEY.exec(line)?.[1];\n if (key && block.length > 0) docs[key] = block.join(\"\\n\").trim();\n block = [];\n }\n return docs;\n}\n","import type { FormatSettings, Manifest } from \"./manifest.types.js\";\nimport { asBoolean, asList, asNumber, asRecord, asStringMap } from \"./read/index.js\";\n\ntype RunSettings = Pick<Manifest, \"env\" | \"envFiles\" | \"paths\" | \"format\">;\n\n/**\n * How the project runs, as against what it is: environments, path aliases and\n * formatting.\n */\nexport function readRunSettings(data: Record<string, unknown>): RunSettings {\n return {\n env: readEnv(data.env),\n envFiles: asList(asRecord(data.env).files),\n paths: asStringMap(data.paths),\n format: readFormat(data.format),\n };\n}\n\nfunction readFormat(value: unknown): FormatSettings {\n const table = asRecord(value);\n return {\n indent: asNumber(table.indent),\n tabs: asBoolean(table.tabs),\n organize: asBoolean(table.organize),\n sort: asBoolean(table.sort),\n };\n}\n\n/** `files` configures where to read from; every other key names an environment. */\nconst RESERVED = new Set([\"files\"]);\n\nfunction readEnv(value: unknown): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n for (const [name, vars] of Object.entries(asRecord(value))) {\n if (!RESERVED.has(name)) out[name] = asStringMap(vars);\n }\n return out;\n}\n","import type { Manifest, ManifestProvider } from \"./manifest.types.js\";\nimport {\n readDependencies,\n readPackage,\n readProfiles,\n readTargets,\n readTooling,\n readWorkspace,\n} from \"./read/index.js\";\nimport { readRunSettings } from \"./read-run-settings.js\";\nimport { parseToml } from \"./toml/index.js\";\n\n/**\n * The real one: parse `venn.toml` into a {@link Manifest}.\n *\n * Parsing happens once, at construction, so repeated `load()` calls are free\n * and always agree.\n *\n * @param args.content - the manifest as written.\n */\nexport function createTomlManifest(args: { content: string }): ManifestProvider {\n const manifest = toManifest(parseToml(args.content));\n return { load: () => manifest };\n}\n\nfunction toManifest(data: Record<string, unknown>): Manifest {\n const pkg = readPackage(data);\n return {\n name: pkg.name,\n version: pkg.version ?? \"0.0.0\",\n package: pkg,\n targets: readTargets(data, pkg.name),\n dependencies: readDependencies(data.dependencies),\n devDependencies: readDependencies(data[\"dev-dependencies\"]),\n patch: readDependencies(data.patch),\n profiles: readProfiles(data),\n tooling: readTooling(data),\n workspace: readWorkspace(data),\n ...readRunSettings(data),\n };\n}\n","import type {\n SignalHandler,\n SignalSource,\n SystemSignal,\n Unsubscribe,\n} from \"./signal-source.types.js\";\n\n/** A {@link SignalSource} with the bell a test rings. */\nexport interface FakeSignals extends SignalSource {\n /** Deliver `signal` to everyone still listening for it. */\n raise(signal: SystemSignal): void;\n /** Which signals are currently being listened for, for assertions. */\n readonly listening: readonly SystemSignal[];\n}\n\n/**\n * The double: a signal arrives because a test said so. No process, no operating\n * system, no risk of stopping the test runner along with the code under test.\n */\nexport function createFakeSignals(): FakeSignals {\n const handlers = new Map<SystemSignal, Set<SignalHandler>>();\n return {\n get listening() {\n return [...handlers].filter(([, set]) => set.size > 0).map(([signal]) => signal);\n },\n on: (signal, handler) => subscribe({ handlers, signal, handler }),\n raise: (signal) => {\n for (const handler of [...(handlers.get(signal) ?? [])]) handler(signal);\n },\n };\n}\n\nfunction subscribe(args: {\n handlers: Map<SystemSignal, Set<SignalHandler>>;\n signal: SystemSignal;\n handler: SignalHandler;\n}): Unsubscribe {\n const set = args.handlers.get(args.signal) ?? new Set<SignalHandler>();\n set.add(args.handler);\n args.handlers.set(args.signal, set);\n return () => {\n set.delete(args.handler);\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { SignalSource } from \"./signal-source.types.js\";\n\n/**\n * The {@link SignalSource} contract. Implementations: `node-signals`,\n * `fake-signals`.\n */\nexport const SignalSourcePort: Port<SignalSource> = {\n id: \"venn.port.signals\",\n version: 1,\n requires: [\"process\"],\n methods: [\"on\"],\n};\n","/**\n * The ways a system asks a program to stop. `SIGBREAK` is Windows' Ctrl+Break,\n * `SIGHUP` is the terminal itself going away.\n */\nexport const ALL_SIGNALS = [\"SIGINT\", \"SIGTERM\", \"SIGBREAK\", \"SIGHUP\"] as const;\n\n/** One signal name, drawn from {@link ALL_SIGNALS}. */\nexport type SystemSignal = (typeof ALL_SIGNALS)[number];\n\n/** Called on every delivery of the signal it was registered for. */\nexport type SignalHandler = (signal: SystemSignal) => void;\n\n/** Drops a subscription. Calling it more than once is harmless. */\nexport type Unsubscribe = () => void;\n\n/**\n * Where a program hears the system asking it to stop.\n *\n * The double matters more than usual here: raising a true SIGINT inside a test\n * run stops the test runner, not the code under test.\n */\nexport interface SignalSource {\n on(signal: SystemSignal, handler: SignalHandler): Unsubscribe;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/capabilities/host-capability.ts","../src/dotenv/dotenv-files.ts","../src/dotenv/parse-dotenv.ts","../src/errors/venn-error.ts","../src/errors/contract-codes.ts","../src/logger/console-logger.ts","../src/logger/memory-logger.ts","../src/ports/clock/clock.port.ts","../src/ports/clock/system-clock.ts","../src/ports/clock/virtual-clock.ts","../src/ports/file-system/file-system.errors.ts","../src/ports/file-system/file-system.port.ts","../src/ports/file-system/memory-fs.ts","../src/ports/lock-provider/fake-lock.ts","../src/ports/lock-provider/in-process-lock.ts","../src/ports/lock-provider/lock-provider.port.ts","../src/ports/process-provider/fake-process.ts","../src/ports/process-provider/process-provider.port.ts","../src/ports/random/fixed-random.ts","../src/ports/random/random.port.ts","../src/ports/random/seeded-random.ts","../src/ports/secret-provider/secret.ts","../src/ports/secret-provider/env-secrets.ts","../src/ports/secret-provider/memory-secrets.ts","../src/ports/secret-provider/secret-provider.port.ts","../src/host/create-test-host.ts","../src/host/unavailable.ts","../src/host/create-worker-host.ts","../src/host/create-host.ts","../src/port/missing-capabilities.ts","../src/port/assert-capabilities.ts","../src/port/assert-port-shape.ts","../src/port/bind-port.ts","../src/ports/console/console.port.ts","../src/ports/console/memory-console.ts","../src/ports/manifest-provider/read/scalars.ts","../src/ports/manifest-provider/read/read-dependencies.ts","../src/ports/manifest-provider/read/read-package.ts","../src/ports/manifest-provider/read/read-profiles.ts","../src/ports/manifest-provider/read/read-targets.ts","../src/ports/manifest-provider/read/read-tooling.ts","../src/ports/manifest-provider/read/read-workspace.ts","../src/ports/manifest-provider/default-manifest.ts","../src/ports/manifest-provider/edit/table-span.ts","../src/ports/manifest-provider/edit/edit-dependency.ts","../src/ports/manifest-provider/manifest.port.ts","../src/ports/manifest-provider/memory-manifest.ts","../src/ports/manifest-provider/resolve-alias.ts","../src/ports/manifest-provider/toml/read-value.ts","../src/ports/manifest-provider/toml/table.ts","../src/ports/manifest-provider/toml/sections.ts","../src/ports/manifest-provider/toml/parse-toml.ts","../src/ports/manifest-provider/toml-docs.ts","../src/ports/manifest-provider/read-run-settings.ts","../src/ports/manifest-provider/toml-manifest.ts","../src/ports/signal-source/fake-signals.ts","../src/ports/signal-source/signal-source.port.ts","../src/ports/signal-source/signal-source.types.ts"],"sourcesContent":["/**\n * Every capability a Host may expose. A port or plugin declares which it\n * requires, a host advertises which it provides, and negotiation compares the\n * two before anything binds.\n */\nexport const ALL_CAPABILITIES = [\n \"fs\",\n \"process\",\n \"net\",\n \"clock\",\n \"random\",\n \"secrets\",\n \"log\",\n \"io\",\n] as const;\n\n/** One capability name, drawn from {@link ALL_CAPABILITIES}. */\nexport type HostCapability = (typeof ALL_CAPABILITIES)[number];\n","// biome-ignore-all lint/suspicious/noTemplateCurlyInString: ${name} is a placeholder in a path, not a JavaScript template.\n\n/**\n * The dotenv files read when `venn.toml` does not name its own.\n *\n * The order is the precedence, lowest first: what everyone shares, then what\n * this environment adds, then what this machine keeps to itself. The `.local`\n * ones are what a `.gitignore` is for.\n */\nexport const DOTENV_CONVENTION: readonly string[] = [\n \".env\",\n \".env.${name}\",\n \".env.local\",\n \".env.${name}.local\",\n];\n\n/**\n * Which files to read, in order, for one environment.\n *\n * The runner and the editor both ask this, so they cannot disagree about where\n * a value lives.\n *\n * @param args.configured - `[env] files` from `venn.toml`. Empty or absent\n * falls back to {@link DOTENV_CONVENTION}.\n * @param args.name - the selected environment, substituted for `${name}`.\n */\nexport function dotenvFiles(args: { configured?: readonly string[]; name: string }): string[] {\n const names = args.configured?.length ? args.configured : DOTENV_CONVENTION;\n return names.map((each) => each.replaceAll(\"${name}\", args.name));\n}\n","/**\n * Read a `.env` file: `NAME=value`, one per line.\n *\n * Deliberately small. It understands comments, blank lines, an `export `\n * prefix, and quotes around a value that needs them. No variable expansion:\n * `${OTHER}` is left alone, because Venn already interpolates in its own\n * strings and two syntaxes for one idea is how people get surprised.\n *\n * @returns every name found, later lines winning over earlier ones.\n */\nexport function parseDotenv(content: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/)) {\n const entry = readLine(line);\n if (entry) out[entry.name] = entry.value;\n }\n return out;\n}\n\nconst LINE = /^\\s*(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*)$/;\n\nfunction readLine(line: string): { name: string; value: string } | undefined {\n if (/^\\s*(#|$)/.test(line)) return undefined;\n const match = LINE.exec(line);\n if (!match?.[1]) return undefined;\n return { name: match[1], value: unquote((match[2] ?? \"\").trim()) };\n}\n\n/** A quoted value keeps its spaces and its `#`; an unquoted one stops at a comment. */\nfunction unquote(raw: string): string {\n const quoted = /^(['\"])([\\s\\S]*)\\1$/.exec(raw);\n if (quoted) return quoted[2] as string;\n return (raw.split(\" #\")[0] ?? \"\").trim();\n}\n","/** Structured, serializable, redaction-safe detail attached to a {@link VennError}. */\nexport type VennErrorDetail = Readonly<Record<string, unknown>>;\n\n/**\n * The single error type that crosses a contracts boundary.\n *\n * Every failure carries a stable `VNxxxx` code, so conformance suites assert on\n * `.code` and never on prose. Messages stay free to improve.\n */\nexport class VennError extends Error {\n readonly code: string;\n readonly detail: VennErrorDetail | undefined;\n\n constructor(args: { code: string; message: string; detail?: VennErrorDetail }) {\n super(args.message);\n this.name = \"VennError\";\n this.code = args.code;\n this.detail = args.detail;\n }\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { VennError } from \"./venn-error.js\";\n\n/** VN2010: a port requires capabilities the host does not provide. */\nexport function hostMissingCapability(args: {\n portId: string;\n missing: readonly HostCapability[];\n present: readonly HostCapability[];\n}): VennError {\n const message =\n `Port \"${args.portId}\" requires capability ${quote(args.missing)}, ` +\n `which this host does not provide. Present: ${list(args.present)}.`;\n return new VennError({ code: \"VN2010\", message, detail: { ...args } });\n}\n\n/** VN2011: an implementation is missing one or more methods the port declares. */\nexport function portShapeMismatch(args: { portId: string; missing: readonly string[] }): VennError {\n const message = `Implementation of \"${args.portId}\" is missing method(s): ${args.missing.join(\", \")}.`;\n return new VennError({ code: \"VN2011\", message, detail: { ...args } });\n}\n\n/** VN2012: code reached a capability the host declared unavailable. */\nexport function capabilityUnavailable(args: {\n capability: HostCapability;\n method: string;\n}): VennError {\n const message = `Capability \"${args.capability}\" is not available on this host (called \"${args.method}\").`;\n return new VennError({ code: \"VN2012\", message, detail: { ...args } });\n}\n\nfunction quote(caps: readonly string[]): string {\n return caps.map((c) => `\"${c}\"`).join(\", \");\n}\n\nfunction list(caps: readonly string[]): string {\n return caps.length === 0 ? \"(none)\" : caps.join(\", \");\n}\n","import type { Logger } from \"./logger.types.js\";\n\n/** Logger backed by the global console, so it works in a Worker and in Node. */\nexport function createConsoleLogger(): Logger {\n return {\n log(entry) {\n const line = `[${entry.level}] ${entry.message}`;\n if (entry.level === \"error\") console.error(line);\n else console.log(line);\n },\n };\n}\n","import type { LogEntry, MemoryLogger } from \"./logger.types.js\";\n\n/** The double: keeps every entry in `entries` instead of printing it. */\nexport function createMemoryLogger(): MemoryLogger {\n const entries: LogEntry[] = [];\n return {\n entries,\n log(entry) {\n entries.push(entry);\n },\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Clock } from \"./clock.types.js\";\n\n/**\n * The {@link Clock} contract. Implementations: `system-clock`, `virtual-clock`.\n *\n * `advance` and `setTime` are absent on purpose: they are how a test drives a\n * virtual clock, not something a caller of the port may reach for.\n */\nexport const ClockPort: Port<Clock> = {\n id: \"venn.port.clock\",\n version: 1,\n requires: [\"clock\"],\n methods: [\"now\", \"sleep\"],\n};\n","import type { Clock } from \"./clock.types.js\";\n\n/** Wall-clock time, on the `Date` and `setTimeout` globals. */\nexport function createSystemClock(): Clock {\n return {\n now: () => Date.now(),\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n };\n}\n","import type { VirtualClock } from \"./clock.types.js\";\n\n/**\n * The double. `sleep` advances internal time and resolves at once, so a test\n * about a timeout costs nothing to run.\n *\n * @param args.start - the epoch this clock begins at. Defaults to 0.\n */\nexport function createVirtualClock(args: { start?: number } = {}): VirtualClock {\n let time = args.start ?? 0;\n const advance = (ms: number): void => {\n time += Math.max(0, ms);\n };\n return {\n now: () => time,\n sleep: async (ms) => advance(ms),\n advance,\n setTime: (epochMs) => {\n time = epochMs;\n },\n };\n}\n","import { VennError } from \"../../errors/index.js\";\n\n/** VN8010: a read or a remove targeted a path that does not exist. */\nexport function fsNotFound(args: { path: string }): VennError {\n return new VennError({\n code: \"VN8010\",\n message: `File not found: \"${args.path}\".`,\n detail: { path: args.path },\n });\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { FileSystem } from \"./file-system.types.js\";\n\n/**\n * The {@link FileSystem} contract. Implementations: `node-fs`, `memory-fs`.\n */\nexport const FileSystemPort: Port<FileSystem> = {\n id: \"venn.port.filesystem\",\n version: 1,\n requires: [\"fs\"],\n methods: [\"read\", \"write\", \"exists\", \"remove\", \"list\"],\n};\n","import { fsNotFound } from \"./file-system.errors.js\";\nimport type { DirEntry, FileSystem } from \"./file-system.types.js\";\n\n/** The double: byte-exact, isolated per instance, no disk. */\nexport function createMemoryFs(): FileSystem {\n const files = new Map<string, Uint8Array>();\n return {\n async read(path) {\n const bytes = files.get(path);\n if (!bytes) throw fsNotFound({ path });\n return bytes.slice();\n },\n async write(path, bytes) {\n files.set(path, bytes.slice());\n },\n async exists(path) {\n return files.has(path);\n },\n async remove(path) {\n if (!files.delete(path)) throw fsNotFound({ path });\n },\n async list(path) {\n return listUnder([...files.keys()], path);\n },\n };\n}\n\n/**\n * What a directory holds, worked out from the paths written.\n *\n * There are no directories here, only paths, so a directory is whatever a path\n * implies one to be. For everything the language does with a directory that is\n * the same answer the real file system gives, which is what lets the TCK ask\n * both the same questions.\n */\nfunction listUnder(paths: readonly string[], directory: string): DirEntry[] {\n const prefix =\n directory === \"\" || directory === \".\" ? \"\" : `${withoutTrailingSlashes(directory)}/`;\n const seen = new Map<string, boolean>();\n for (const path of paths) {\n if (!path.startsWith(prefix)) continue;\n const rest = path.slice(prefix.length);\n const slash = rest.indexOf(\"/\");\n if (rest !== \"\") seen.set(slash < 0 ? rest : rest.slice(0, slash), slash >= 0);\n }\n return [...seen].map(([name, isDirectory]) => ({ name, directory: isDirectory }));\n}\n\n/**\n * A path with its trailing slashes removed.\n *\n * Scanned rather than matched with `/\\/+$/`, which the engine retries at every\n * position when the string does not end in one: quadratic on a long path, and\n * a path is whatever it was handed.\n */\nfunction withoutTrailingSlashes(path: string): string {\n let end = path.length;\n while (end > 0 && path.charCodeAt(end - 1) === 47) end -= 1;\n return path.slice(0, end);\n}\n","import type { LockProvider } from \"./lock-provider.types.js\";\n\n/** The double: grants immediately and serialises nothing. */\nexport function createFakeLock(): LockProvider {\n return { acquire: async () => () => {} };\n}\n","import type { LockProvider, Release } from \"./lock-provider.types.js\";\n\n/**\n * The real one: a chained-promise mutex per name. Waiters are served in the\n * order they asked, and the chain lives only in this process.\n */\nexport function createInProcessLock(): LockProvider {\n const tails = new Map<string, Promise<void>>();\n return {\n acquire: (name) => acquire(tails, name),\n };\n}\n\nasync function acquire(tails: Map<string, Promise<void>>, name: string): Promise<Release> {\n const previous = tails.get(name) ?? Promise.resolve();\n let release: Release = () => {};\n const held = new Promise<void>((resolve) => {\n release = resolve;\n });\n tails.set(\n name,\n previous.then(() => held),\n );\n await previous;\n return release;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { LockProvider } from \"./lock-provider.types.js\";\n\n/**\n * The {@link LockProvider} contract. Implementations: `in-process-lock`,\n * `fake-lock`.\n *\n * Requires nothing: a mutex is bookkeeping, so it binds even on a host with no\n * capabilities at all.\n */\nexport const LockProviderPort: Port<LockProvider> = {\n id: \"venn.port.lock\",\n version: 1,\n requires: [],\n methods: [\"acquire\"],\n};\n","import type { ProcessHandle, ProcessProvider } from \"./process-provider.types.js\";\n\n/**\n * The double: a scripted process that never touches the OS.\n *\n * Output is streamed before the wait resolves, exactly as the real one does it,\n * so a caller that shows progress is exercised here and not only against a real\n * machine.\n *\n * @param args.exitCode - what every run reports. Defaults to 0.\n * @param args.output - what every run writes. Defaults to nothing.\n */\nexport function createFakeProcess(\n args: { exitCode?: number; output?: string } = {},\n): ProcessProvider {\n const code = args.exitCode ?? 0;\n const output = args.output ?? \"\";\n return {\n spawn: (spawned) => {\n if (output !== \"\") spawned.onOutput?.(output);\n return handle(code, output);\n },\n };\n}\n\nfunction handle(code: number, output: string): ProcessHandle {\n return {\n pid: 0,\n wait: async () => ({ code, output }),\n kill: () => {},\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { ProcessProvider } from \"./process-provider.types.js\";\n\n/**\n * The {@link ProcessProvider} contract. Implementations: `node-spawn`,\n * `fake-process`.\n */\nexport const ProcessProviderPort: Port<ProcessProvider> = {\n id: \"venn.port.process\",\n version: 1,\n requires: [\"process\"],\n methods: [\"spawn\"],\n};\n","import type { Random } from \"./random.types.js\";\n\n/** The double: always the same value, and always `min` from `int`. */\nexport function createFixedRandom(args: { value?: number } = {}): Random {\n const value = args.value ?? 0;\n return {\n next: () => value,\n int: (min) => min,\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Random } from \"./random.types.js\";\n\n/**\n * The {@link Random} contract. Implementations: `seeded-random`,\n * `fixed-random`.\n */\nexport const RandomPort: Port<Random> = {\n id: \"venn.port.random\",\n version: 1,\n requires: [\"random\"],\n methods: [\"next\", \"int\"],\n};\n","import type { Random } from \"./random.types.js\";\n\n/**\n * The real one: a mulberry32 PRNG, seeded once per worker. Same seed, same\n * sequence, so a run reproduces.\n */\nexport function createSeededRandom(args: { seed: number }): Random {\n let state = args.seed >>> 0;\n const next = (): number => {\n state = (state + 0x6d2b79f5) | 0;\n let t = Math.imul(state ^ (state >>> 15), 1 | state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n return {\n next,\n int: (min, max) => min + Math.floor(next() * (max - min + 1)),\n };\n}\n","import type { Secret } from \"./secret-provider.types.js\";\n\n/** What every serialised secret collapses to. */\nexport const REDACTED = \"‹redigido›\";\n\n/**\n * Wrap a raw value so it cannot leak through `toString` or `toJSON`.\n *\n * @param args.reveal - the raw value, reachable only via `Secret.reveal()`.\n */\nexport function makeSecret(args: { reveal: string }): Secret {\n return {\n reveal: () => args.reveal,\n toString: () => REDACTED,\n toJSON: () => REDACTED,\n };\n}\n","import { makeSecret } from \"./secret.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The real one: secrets from `process.env`.\n *\n * The `process` global is probed rather than imported, so this file stays\n * neutral and reports every name as absent in a Worker instead of throwing.\n */\nexport function createEnvSecrets(): SecretProvider {\n const env: Record<string, string | undefined> = typeof process === \"undefined\" ? {} : process.env;\n return {\n get: (name) => {\n const value = env[name];\n return value === undefined ? undefined : makeSecret({ reveal: value });\n },\n has: (name) => env[name] !== undefined,\n };\n}\n","import { makeSecret } from \"./secret.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The double: secrets given by name, wrapped so they still redact.\n *\n * @param args.values - the raw values, keyed by secret name.\n */\nexport function createMemorySecrets(args: { values: Record<string, string> }): SecretProvider {\n const values = args.values;\n return {\n get: (name) => (name in values ? makeSecret({ reveal: values[name] as string }) : undefined),\n has: (name) => name in values,\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { SecretProvider } from \"./secret-provider.types.js\";\n\n/**\n * The {@link SecretProvider} contract. Implementations: `env-secrets`,\n * `memory-secrets`.\n */\nexport const SecretProviderPort: Port<SecretProvider> = {\n id: \"venn.port.secrets\",\n version: 1,\n requires: [\"secrets\"],\n methods: [\"get\", \"has\"],\n};\n","import { ALL_CAPABILITIES } from \"../capabilities/index.js\";\nimport { createMemoryLogger } from \"../logger/index.js\";\nimport { createVirtualClock } from \"../ports/clock/index.js\";\nimport { createMemoryFs } from \"../ports/file-system/index.js\";\nimport { createInProcessLock } from \"../ports/lock-provider/index.js\";\nimport { createFakeProcess } from \"../ports/process-provider/index.js\";\nimport { createSeededRandom } from \"../ports/random/index.js\";\nimport { createMemorySecrets } from \"../ports/secret-provider/index.js\";\nimport type { Host } from \"./host.types.js\";\n\n/**\n * A host of doubles, every capability granted. The default for tests.\n *\n * @param overrides - replaces individual members, e.g. a real clock.\n */\nexport function createTestHost(overrides: Partial<Host> = {}): Host {\n return {\n fs: createMemoryFs(),\n proc: createFakeProcess(),\n clock: createVirtualClock(),\n random: createSeededRandom({ seed: 1 }),\n secrets: createMemorySecrets({ values: {} }),\n log: createMemoryLogger(),\n lock: createInProcessLock(),\n caps: ALL_CAPABILITIES,\n ...overrides,\n };\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { capabilityUnavailable } from \"../errors/index.js\";\n\n/**\n * A stand-in for a port the host cannot provide, such as `process` in a Worker.\n *\n * @param args.capability - the capability the host lacks, named in the error.\n * @param args.methods - the port's declared methods, usually `SomePort.methods`.\n * @returns an object shaped like `T` whose every method throws VN2012 when\n * called, rather than failing as a `TypeError` mid-run.\n */\nexport function unavailable<T>(args: {\n capability: HostCapability;\n methods: readonly string[];\n}): T {\n const bag: Record<string, unknown> = {};\n for (const method of args.methods) {\n bag[method] = () => {\n throw capabilityUnavailable({ capability: args.capability, method });\n };\n }\n return bag as T;\n}\n","import { createMemoryLogger } from \"../logger/index.js\";\nimport { createSystemClock } from \"../ports/clock/index.js\";\nimport { createMemoryFs } from \"../ports/file-system/index.js\";\nimport { createInProcessLock } from \"../ports/lock-provider/index.js\";\nimport type { ProcessProvider } from \"../ports/process-provider/index.js\";\nimport { ProcessProviderPort } from \"../ports/process-provider/index.js\";\nimport { createSeededRandom } from \"../ports/random/index.js\";\nimport { createMemorySecrets } from \"../ports/secret-provider/index.js\";\nimport type { Host } from \"./host.types.js\";\nimport { unavailable } from \"./unavailable.js\";\n\n/**\n * Host for a Web Worker: an in-memory file system, no `process`, no `net`.\n *\n * `proc` is a stand-in whose every method throws VN2012, so reaching for a\n * subprocess in the editor fails with a diagnostic instead of a `TypeError`.\n */\nexport function createWorkerHost(): Host {\n return {\n fs: createMemoryFs(),\n proc: unavailable<ProcessProvider>({\n capability: \"process\",\n methods: ProcessProviderPort.methods,\n }),\n clock: createSystemClock(),\n random: createSeededRandom({ seed: 1 }),\n secrets: createMemorySecrets({ values: {} }),\n log: createMemoryLogger(),\n lock: createInProcessLock(),\n caps: [\"fs\", \"clock\", \"random\", \"secrets\", \"log\"],\n };\n}\n","import { createTestHost } from \"./create-test-host.js\";\nimport { createWorkerHost } from \"./create-worker-host.js\";\n\n/**\n * The neutral host assemblers.\n *\n * `node` is deliberately absent: it pulls `node:*`, so it lives behind\n * `@venn-lang/contracts/node` as `createNodeHost` and this entry stays Worker-safe.\n */\nexport const createHost: {\n readonly worker: typeof createWorkerHost;\n readonly test: typeof createTestHost;\n} = {\n worker: createWorkerHost,\n test: createTestHost,\n};\n","import type { HostCapability } from \"../capabilities/index.js\";\n\n/**\n * The gap between what is required and what the host offers.\n *\n * @returns the required capabilities absent from `caps`, in the order required.\n */\nexport function missingCapabilities(args: {\n requires: readonly HostCapability[];\n caps: readonly HostCapability[];\n}): readonly HostCapability[] {\n const present = new Set(args.caps);\n return args.requires.filter((cap) => !present.has(cap));\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { hostMissingCapability } from \"../errors/index.js\";\nimport { missingCapabilities } from \"./missing-capabilities.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * Checks the host against what the port requires.\n *\n * @throws VennError VN2010 when a required capability is absent.\n */\nexport function assertCapabilities<T>(args: {\n port: Port<T>;\n caps: readonly HostCapability[];\n}): void {\n const missing = missingCapabilities({ requires: args.port.requires, caps: args.caps });\n if (missing.length === 0) return;\n throw hostMissingCapability({ portId: args.port.id, missing, present: args.caps });\n}\n","import { portShapeMismatch } from \"../errors/index.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * Checks the implementation against the methods the port declares.\n *\n * @throws VennError VN2011 when a declared method is missing or is not callable.\n */\nexport function assertPortShape<T>(args: { port: Port<T>; impl: unknown }): void {\n const missing = missingMethods(args.port, args.impl);\n if (missing.length === 0) return;\n throw portShapeMismatch({ portId: args.port.id, missing });\n}\n\nfunction missingMethods<T>(port: Port<T>, impl: unknown): readonly string[] {\n const bag = impl as Record<string, unknown> | null | undefined;\n return port.methods.filter((m) => typeof bag?.[m] !== \"function\");\n}\n","import type { HostCapability } from \"../capabilities/index.js\";\nimport { assertCapabilities } from \"./assert-capabilities.js\";\nimport { assertPortShape } from \"./assert-port-shape.js\";\nimport type { Port } from \"./port.types.js\";\n\n/**\n * The single loader entry. Negotiates capabilities, checks the implementation's\n * shape, then hands it back typed as `T`.\n *\n * Both checks run before anything is bound, so a mismatch is reported at start\n * up rather than as a `TypeError` in the middle of a test.\n *\n * @param args.port - the descriptor to bind against.\n * @param args.impl - the candidate implementation, untrusted.\n * @param args.caps - the capabilities the host advertises.\n * @returns `args.impl` typed as `T`.\n * @throws VennError VN2010 when the host lacks a required capability, VN2011\n * when the implementation is missing a declared method.\n */\nexport function bindPort<T>(args: {\n port: Port<T>;\n impl: unknown;\n caps: readonly HostCapability[];\n}): T {\n assertCapabilities({ port: args.port, caps: args.caps });\n assertPortShape({ port: args.port, impl: args.impl });\n return args.impl as T;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { Console } from \"./console.types.js\";\n\n/**\n * The {@link Console} contract. Implementations: `node-console`,\n * `memory-console`.\n */\nexport const ConsolePort: Port<Console> = {\n id: \"venn.port.console\",\n version: 1,\n requires: [\"io\"],\n methods: [\"write\", \"writeError\", \"readLine\", \"args\"],\n};\n","import type { Console } from \"./console.types.js\";\n\n/** A {@link Console} that keeps its transcript instead of printing it. */\nexport interface MemoryConsole extends Console {\n readonly out: string;\n readonly err: string;\n}\n\n/**\n * The double: records what was written, reads from a scripted input.\n *\n * @param args.input - the lines `readLine` hands back, in order.\n * @param args.argv - what `args()` reports.\n */\nexport function createMemoryConsole(\n args: { input?: readonly string[]; argv?: readonly string[] } = {},\n): MemoryConsole {\n const state = { out: \"\", err: \"\" };\n const input = [...(args.input ?? [])];\n return {\n write: (text) => {\n state.out += text;\n },\n writeError: (text) => {\n state.err += text;\n },\n readLine: () => Promise.resolve(input.length > 0 ? (input.shift() ?? null) : null),\n args: () => args.argv ?? [],\n get out() {\n return state.out;\n },\n get err() {\n return state.err;\n },\n };\n}\n","// Reading a parsed TOML value as the shape the manifest expects. None of these\n// throw: a malformed table reads as an empty one, so one bad line never stops a\n// project from opening.\n\nexport function asRecord(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nexport function asStringMap(value: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, item] of Object.entries(asRecord(value))) out[key] = String(item);\n return out;\n}\n\nexport function asList(value: unknown): readonly string[] {\n return Array.isArray(value) ? value.map(String) : [];\n}\n\nexport function asRecords(value: unknown): readonly Record<string, unknown>[] {\n return Array.isArray(value) ? value.map(asRecord) : [];\n}\n\nexport function asString(value: unknown): string | undefined {\n return value === undefined || value === null ? undefined : String(value);\n}\n\nexport function asNumber(value: unknown): number | undefined {\n const parsed = Number(value);\n return value === undefined || Number.isNaN(parsed) ? undefined : parsed;\n}\n\nexport function asBoolean(value: unknown): boolean | undefined {\n if (value === undefined) return undefined;\n return value === true || value === \"true\";\n}\n","import type { Dependency } from \"../project.types.js\";\nimport { asBoolean, asRecord, asString } from \"./scalars.js\";\n\n/**\n * A dependency table, in either spelling TOML allows.\n *\n * `zod = \"^4\"` and `zod = { version = \"^4\", optional = true }` say the same\n * thing about the version, so both read into one shape rather than two the rest\n * of the code would have to keep apart.\n */\nexport function readDependencies(value: unknown): Dependency[] {\n return Object.entries(asRecord(value)).map(([name, spec]) => readOne(name, spec));\n}\n\nfunction readOne(name: string, spec: unknown): Dependency {\n if (typeof spec === \"string\") {\n return { name, version: spec, fromWorkspace: false, optional: false };\n }\n const table = asRecord(spec);\n return {\n name,\n version: asString(table.version),\n path: asString(table.path),\n fromWorkspace: asBoolean(table.workspace) ?? false,\n optional: asBoolean(table.optional) ?? false,\n };\n}\n","import type { PackageInfo } from \"../project.types.js\";\nimport { asList, asRecord, asString } from \"./scalars.js\";\n\n/** `[package]`: who this is. A missing table reads as a nameless package. */\nexport function readPackage(data: Record<string, unknown>): PackageInfo {\n const table = asRecord(data.package);\n return {\n name: String(table.name ?? \"\"),\n version: asString(table.version),\n description: asString(table.description),\n license: asString(table.license),\n authors: asList(table.authors),\n edition: asString(table.edition),\n };\n}\n\n/**\n * The same table, reduced to what a member may inherit from its workspace.\n *\n * A name is never inherited, being the one thing that must differ between two\n * members, so `[workspace.package]` carrying one is read as carrying none.\n */\nexport function readInheritable(data: Record<string, unknown>): Partial<PackageInfo> {\n const table = asRecord(data);\n const found: Partial<PackageInfo> = {};\n for (const key of [\"version\", \"description\", \"license\", \"edition\"] as const) {\n const value = asString(table[key]);\n if (value !== undefined) found[key] = value;\n }\n const authors = asList(table.authors);\n return authors.length > 0 ? { ...found, authors } : found;\n}\n","import type { Profile } from \"../project.types.js\";\nimport { asBoolean, asRecord } from \"./scalars.js\";\n\n/**\n * What each build is for, and what that costs.\n *\n * `dev` reports what it finds and carries on, because a project being worked on\n * is half-written most of the time. `release` refuses to build over a problem.\n * Neither has to be written in a manifest for the defaults to apply.\n */\nexport const DEFAULT_PROFILES: Readonly<Record<string, Profile>> = {\n dev: { strict: false },\n release: { strict: true },\n};\n\n/** `[profile.<name>]`, merged over {@link DEFAULT_PROFILES}. */\nexport function readProfiles(data: Record<string, unknown>): Record<string, Profile> {\n const out: Record<string, Profile> = { ...DEFAULT_PROFILES };\n for (const [name, table] of Object.entries(asRecord(data.profile))) {\n out[name] = { ...out[name], ...readProfile(asRecord(table)) };\n }\n return out;\n}\n\nfunction readProfile(table: Record<string, unknown>): Profile {\n const found: Profile = {};\n for (const key of [\"strict\"] as const) {\n const value = asBoolean(table[key]);\n if (value !== undefined) found[key] = value;\n }\n return found;\n}\n","import type { BuildTarget } from \"../project.types.js\";\nimport { asRecord, asRecords, asString } from \"./scalars.js\";\n\n/** Where a `lib` target starts when the manifest does not say. */\nexport const LIB_ROOT = \"src/lib.vn\";\n/** Where the default `bin` target starts when the manifest does not say. */\nexport const MAIN_ROOT = \"src/main.vn\";\n/** Where additional `bin` targets are looked for by convention. */\nexport const BIN_DIR = \"src/bin\";\n\n/**\n * `[lib]` and `[[bin]]`: what this package builds.\n *\n * Only what the manifest *declares*. The conventional roots are filled in by\n * whoever can look at the disk, because a convention is a claim about files\n * existing and this reader is pure. A manifest declaring nothing is the common\n * case, not an empty one.\n */\nexport function readTargets(data: Record<string, unknown>, packageName: string): BuildTarget[] {\n const found: BuildTarget[] = [];\n if (data.lib !== undefined) found.push(readLib(asRecord(data.lib), packageName));\n for (const entry of asRecords(data.bin)) found.push(readBin(entry, packageName));\n return found;\n}\n\nfunction readLib(table: Record<string, unknown>, packageName: string): BuildTarget {\n return {\n kind: \"lib\",\n name: asString(table.name) ?? packageName,\n path: asString(table.path) ?? LIB_ROOT,\n };\n}\n\nfunction readBin(table: Record<string, unknown>, packageName: string): BuildTarget {\n const name = asString(table.name) ?? packageName;\n return { kind: \"bin\", name, path: asString(table.path) ?? `${BIN_DIR}/${name}.vn` };\n}\n","import type { PackageManagerName, ToolingSettings } from \"../project.types.js\";\nimport { asRecord, asString } from \"./scalars.js\";\n\nconst MANAGERS = new Set<string>([\"pnpm\", \"npm\", \"bun\", \"yarn\"]);\n\n/**\n * `[tooling]`: which package manager runs underneath.\n *\n * An unrecognised name falls back to pnpm rather than failing, so a manifest\n * written against a newer toolchain still opens.\n */\nexport function readTooling(data: Record<string, unknown>): ToolingSettings {\n const name = asString(asRecord(data.tooling).manager);\n return { manager: name && MANAGERS.has(name) ? (name as PackageManagerName) : \"pnpm\" };\n}\n","import type { WorkspaceSettings } from \"../project.types.js\";\nimport { readDependencies } from \"./read-dependencies.js\";\nimport { readInheritable } from \"./read-package.js\";\nimport { asList, asRecord } from \"./scalars.js\";\n\n/**\n * `[workspace]`, or undefined when the manifest is a plain package.\n *\n * A root may also be a package, so `[workspace]` and `[package]` are read\n * separately and never merged.\n */\nexport function readWorkspace(data: Record<string, unknown>): WorkspaceSettings | undefined {\n if (data.workspace === undefined) return undefined;\n const table = asRecord(data.workspace);\n return {\n members: asList(table.members),\n exclude: asList(table.exclude),\n defaultMembers: asList(table[\"default-members\"]),\n package: readInheritable(asRecord(table.package)),\n dependencies: readDependencies(table.dependencies),\n };\n}\n","import type { Manifest } from \"./manifest.types.js\";\nimport { DEFAULT_PROFILES } from \"./read/index.js\";\n\n/**\n * A manifest with nothing declared: what a project without a `venn.toml` is.\n *\n * The one place stating what a project gets for saying nothing at all, so a\n * caller who wants one field need not spell the other dozen.\n *\n * @param overrides - fields to state explicitly. `name` and `version` fall back\n * to `[package]` before falling back to the defaults.\n */\nexport function defaultManifest(overrides: Partial<Manifest> = {}): Manifest {\n const pkg = { name: \"\", authors: [], ...overrides.package };\n return {\n name: overrides.name ?? pkg.name,\n version: overrides.version ?? pkg.version ?? \"0.0.0\",\n package: pkg,\n targets: [],\n dependencies: [],\n devDependencies: [],\n patch: [],\n profiles: { ...DEFAULT_PROFILES },\n tooling: { manager: \"pnpm\" },\n env: {},\n envFiles: [],\n paths: {},\n format: {},\n ...overrides,\n };\n}\n","/** Where a table's entries live in a manifest's lines. */\nexport interface TableSpan {\n /** The line holding `[name]`. */\n header: number;\n /** First line after the header, and the line after the table's last entry. */\n from: number;\n to: number;\n}\n\n/**\n * Where a `[table]` is written, or undefined when the file has none.\n *\n * Found by reading lines rather than by re-serialising the parse tree. A\n * manifest carries its author's comments, blank lines and chosen order, and\n * rebuilding it from a tree would throw all of that away.\n */\nexport function tableSpan(lines: readonly string[], name: string): TableSpan | undefined {\n const header = lines.findIndex((line) => line.trim() === `[${name}]`);\n if (header < 0) return undefined;\n let to = header + 1;\n for (let at = header + 1; at < lines.length; at++) {\n if (lines[at]?.trimStart().startsWith(\"[\")) break;\n if (lines[at]?.trim() !== \"\") to = at + 1;\n }\n return { header, from: header + 1, to };\n}\n\n/** The key a `key = value` line writes, or undefined for a comment or a blank. */\nexport function keyOf(line: string): string | undefined {\n const text = line.trim();\n if (text === \"\" || text.startsWith(\"#\") || text.startsWith(\"[\")) return undefined;\n const equals = text.indexOf(\"=\");\n return equals < 0\n ? undefined\n : text\n .slice(0, equals)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n}\n","import { keyOf, tableSpan } from \"./table-span.js\";\n\n/** What to change, and in which table. */\nexport interface DependencyEdit {\n /** The manifest as written. */\n text: string;\n name: string;\n /** Defaults to {@link DEPENDENCIES}. Pass `\"dev-dependencies\"` for the other. */\n table?: string;\n}\n\n/** The table an edit touches unless told otherwise. */\nexport const DEPENDENCIES = \"dependencies\";\n\n/**\n * The manifest with one dependency written in, everything else untouched.\n *\n * Entries are kept in name order, so two people adding two packages produce two\n * one-line diffs rather than a conflict. A name already there is replaced where\n * it stands, because an upgrade should not move the line.\n *\n * @returns the whole manifest as text. A missing table is appended at the end.\n */\nexport function addDependency(args: DependencyEdit & { version: string }): string {\n const table = args.table ?? DEPENDENCIES;\n const lines = args.text.split(\"\\n\");\n const entry = `${args.name} = \"${args.version}\"`;\n const span = tableSpan(lines, table);\n if (!span) return appended(args.text, table, entry);\n const at = lines.findIndex((line, index) => inside(span, index) && keyOf(line) === args.name);\n if (at >= 0) return replaced(lines, at, entry);\n return replaced(lines, insertionPoint(lines, span, args.name), entry, \"insert\");\n}\n\n/**\n * The manifest without that dependency.\n *\n * @returns the text unchanged when the name is not there: absent is already the\n * wanted state.\n */\nexport function removeDependency(args: DependencyEdit): string {\n const table = args.table ?? DEPENDENCIES;\n const lines = args.text.split(\"\\n\");\n const span = tableSpan(lines, table);\n if (!span) return args.text;\n const at = lines.findIndex((line, index) => inside(span, index) && keyOf(line) === args.name);\n if (at < 0) return args.text;\n return [...lines.slice(0, at), ...lines.slice(at + 1)].join(\"\\n\");\n}\n\nfunction inside(span: { from: number; to: number }, index: number): boolean {\n return index >= span.from && index < span.to;\n}\n\n/** Where the name belongs, in order, among the entries already there. */\nfunction insertionPoint(\n lines: readonly string[],\n span: { from: number; to: number },\n name: string,\n): number {\n for (let at = span.from; at < span.to; at++) {\n const key = keyOf(lines[at] ?? \"\");\n if (key && key > name) return at;\n }\n return span.to;\n}\n\nfunction replaced(\n lines: readonly string[],\n at: number,\n entry: string,\n how: \"replace\" | \"insert\" = \"replace\",\n): string {\n const after = how === \"insert\" ? lines.slice(at) : lines.slice(at + 1);\n return [...lines.slice(0, at), entry, ...after].join(\"\\n\");\n}\n\n/** A table the manifest does not have yet, written at the end where it reads. */\nfunction appended(text: string, table: string, entry: string): string {\n const body = text.endsWith(\"\\n\") ? text : `${text}\\n`;\n return `${body}\\n[${table}]\\n${entry}\\n`;\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { ManifestProvider } from \"./manifest.types.js\";\n\n/**\n * The {@link ManifestProvider} contract. Implementations: `toml-manifest`,\n * `memory-manifest`.\n *\n * Requires nothing: reading the file is the caller's job, and what arrives here\n * is already text.\n */\nexport const ManifestProviderPort: Port<ManifestProvider> = {\n id: \"venn.port.manifest\",\n version: 1,\n requires: [],\n methods: [\"load\"],\n};\n","import { defaultManifest } from \"./default-manifest.js\";\nimport type { Manifest, ManifestProvider } from \"./manifest.types.js\";\n\n/**\n * The double: a preset manifest, with no file involved.\n *\n * Takes only what the caller cares about. The rest is what a project that\n * declared nothing would get, which is exactly what the real provider gives a\n * `venn.toml` silent on those tables.\n */\nexport function createMemoryManifest(args: { manifest: Partial<Manifest> }): ManifestProvider {\n const manifest: Manifest = defaultManifest(args.manifest);\n return { load: () => manifest };\n}\n","/** Where a `#alias/…` specifier points. */\nexport interface AliasTarget {\n /** The directory `[paths]` maps the alias to. */\n dir: string;\n /** What followed the alias, with the separating slash removed. */\n rest: string;\n}\n\n/**\n * Split a `#alias/rest` import specifier against `[paths]` from `venn.toml`.\n *\n * @returns undefined when the specifier names no configured alias, which the\n * caller reads as a relative or bare path.\n */\nexport function resolveAlias(args: {\n spec: string;\n paths: Record<string, string>;\n}): AliasTarget | undefined {\n const alias = Object.keys(args.paths).find((key) => args.spec.startsWith(`${key}/`));\n if (!alias) return undefined;\n return { dir: args.paths[alias] as string, rest: args.spec.slice(alias.length + 1) };\n}\n","/** A position in the text being read. Mutable, because reading advances it. */\nexport interface Cursor {\n readonly text: string;\n index: number;\n}\n\n/** A cursor over `text`, positioned at the start. */\nexport function cursor(text: string): Cursor {\n return { text, index: 0 };\n}\n\n/**\n * One TOML value: a string, a number, a bool, an array, or an inline table.\n *\n * Reads by walking rather than by splitting, because a comma can sit inside a\n * value: splitting turns `[\"a,b\"]` into two items and leaves\n * `{ version = \"^4\" }` as the text it was written in.\n */\nexport function readValue(cur: Cursor): unknown {\n skipSpace(cur);\n const ch = cur.text[cur.index];\n if (ch === '\"' || ch === \"'\") return readString(cur);\n if (ch === \"[\") return readArray(cur);\n if (ch === \"{\") return readInlineTable(cur);\n return readBare(cur);\n}\n\nexport function skipSpace(cur: Cursor): void {\n while (/\\s/.test(cur.text[cur.index] ?? \"\")) cur.index++;\n}\n\n/** A basic string reads escapes; a literal one, in single quotes, does not. */\nfunction readString(cur: Cursor): string {\n const quote = cur.text[cur.index];\n cur.index++;\n let out = \"\";\n while (cur.index < cur.text.length && cur.text[cur.index] !== quote) {\n if (quote === '\"' && cur.text[cur.index] === \"\\\\\") out += unescaped(cur);\n else out += cur.text[cur.index++];\n }\n cur.index++;\n return out;\n}\n\nconst ESCAPES: Record<string, string> = { n: \"\\n\", t: \"\\t\", r: \"\\r\", \"\\\\\": \"\\\\\", '\"': '\"' };\n\nfunction unescaped(cur: Cursor): string {\n const code = cur.text[cur.index + 1] ?? \"\";\n cur.index += 2;\n return ESCAPES[code] ?? code;\n}\n\nfunction readArray(cur: Cursor): unknown[] {\n cur.index++;\n const out: unknown[] = [];\n while (!atClose(cur, \"]\")) {\n out.push(readValue(cur));\n skipSeparator(cur);\n }\n cur.index++;\n return out;\n}\n\nfunction readInlineTable(cur: Cursor): Record<string, unknown> {\n cur.index++;\n const out: Record<string, unknown> = {};\n while (!atClose(cur, \"}\")) {\n const key = readKey(cur);\n if (key === undefined) break;\n out[key] = readValue(cur);\n skipSeparator(cur);\n }\n cur.index++;\n return out;\n}\n\nfunction readKey(cur: Cursor): string | undefined {\n skipSpace(cur);\n const equals = cur.text.indexOf(\"=\", cur.index);\n if (equals < 0) return undefined;\n const raw = cur.text.slice(cur.index, equals).trim();\n cur.index = equals + 1;\n return raw.replace(/^[\"']|[\"']$/g, \"\");\n}\n\nfunction atClose(cur: Cursor, close: string): boolean {\n skipSpace(cur);\n return cur.index >= cur.text.length || cur.text[cur.index] === close;\n}\n\nfunction skipSeparator(cur: Cursor): void {\n skipSpace(cur);\n if (cur.text[cur.index] === \",\") cur.index++;\n}\n\n/** Anything unquoted: `true`, `12`, `1.5`, or a word the manifest gives meaning. */\nfunction readBare(cur: Cursor): unknown {\n const start = cur.index;\n while (cur.index < cur.text.length && !\",]}\".includes(cur.text[cur.index] ?? \"\")) cur.index++;\n const raw = cur.text.slice(start, cur.index).trim();\n if (raw === \"true\" || raw === \"false\") return raw === \"true\";\n const num = Number(raw);\n return raw !== \"\" && !Number.isNaN(num) ? num : raw;\n}\n","/**\n * An empty table for a manifest to fill.\n *\n * Made without a prototype, so a key read from the file is a key and nothing\n * else. Assigning `__proto__` onto an ordinary object changes how every object\n * in the process behaves, and a manifest arrives with somebody else's project:\n * a `venn.toml` holding `[package.__proto__]` was enough to put a property on\n * `Object.prototype`.\n *\n * Refusing that one name would have closed that one door. Having no prototype\n * to reach removes the question, and the table is read with `Object.keys` and\n * `Object.entries`, which do not care that it has none.\n */\nexport function emptyTable(): Record<string, unknown> {\n return Object.create(null) as Record<string, unknown>;\n}\n","// Opening `[a.b]` or `[[a.b]]`: working out where the keys that follow go.\n\nimport { emptyTable } from \"./table.js\";\n\n/** The table `[path]` names, created along the way if it is not there yet. */\nexport function enterSection(root: Record<string, unknown>, path: string): Record<string, unknown> {\n let node = root;\n for (const key of keysOf(path)) {\n node[key] ??= emptyTable();\n node = node[key] as Record<string, unknown>;\n }\n return node;\n}\n\n/**\n * `[[bin]]`: one more of something there may be several of.\n *\n * Returns the table just appended, so two `[[bin]]` sections give two bins\n * rather than one bin written twice.\n */\nexport function enterTableArray(\n root: Record<string, unknown>,\n path: string,\n): Record<string, unknown> {\n const keys = keysOf(path);\n const last = keys.pop();\n if (!last) return root;\n const parent = enterSection(root, keys.join(\".\"));\n const found = Array.isArray(parent[last]) ? (parent[last] as unknown[]) : [];\n parent[last] = found;\n const table = emptyTable();\n found.push(table);\n return table;\n}\n\nfunction keysOf(path: string): string[] {\n return path\n .split(\".\")\n .map((part) => part.trim().replace(/^[\"']|[\"']$/g, \"\"))\n .filter((part) => part !== \"\");\n}\n","import { cursor, readValue } from \"./read-value.js\";\nimport { enterSection, enterTableArray } from \"./sections.js\";\nimport { emptyTable } from \"./table.js\";\n\n/**\n * A TOML reader for `venn.toml`: sections, nested `[a.b]`, arrays of tables\n * (`[[bin]]`), `key = value`, strings, numbers, bools, arrays and inline tables.\n *\n * Not a full TOML parser. No dates, no multi-line strings, no dotted keys.\n * `venn.toml` is our own format, so the subset is a decision rather than a\n * shortfall.\n *\n * @returns the root table. Malformed lines are skipped, never thrown on.\n */\nexport function parseToml(content: string): Record<string, unknown> {\n const root = emptyTable();\n let section = root;\n for (const raw of content.split(/\\r?\\n/)) {\n const line = stripComment(raw).trim();\n if (line === \"\") continue;\n if (line.startsWith(\"[\")) section = openSection(root, line);\n else assign(section, line);\n }\n return root;\n}\n\n/** `[[bin]]` appends another table, `[bin]` opens the one and only. */\nfunction openSection(root: Record<string, unknown>, line: string): Record<string, unknown> {\n if (line.startsWith(\"[[\")) {\n return enterTableArray(root, line.slice(2, line.indexOf(\"]]\")));\n }\n return enterSection(root, line.slice(1, line.indexOf(\"]\")));\n}\n\nfunction stripComment(line: string): string {\n let quote: string | undefined;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === '\"' || ch === \"'\") quote = quote === ch ? undefined : (quote ?? ch);\n else if (ch === \"#\" && !quote) return line.slice(0, i);\n }\n return line;\n}\n\nfunction assign(section: Record<string, unknown>, line: string): void {\n const eq = line.indexOf(\"=\");\n if (eq < 0) return;\n const key = line\n .slice(0, eq)\n .trim()\n .replace(/^[\"']|[\"']$/g, \"\");\n section[key] = readValue(cursor(line.slice(eq + 1)));\n}\n","const COMMENT = /^\\s*#\\s?(.*)$/;\nconst KEY = /^\\s*([A-Za-z_][\\w-]*)\\s*=/;\n\n/**\n * The comment block written directly above a key, read as that key's\n * documentation. The same idea as `##` above a declaration in a `.vn`.\n *\n * A blank line breaks the block, so a comment separated from a key belongs to\n * nobody and is never attributed to the next one down.\n *\n * @returns documentation keyed by the key it sits above.\n */\nexport function tomlDocs(content: string): Record<string, string> {\n const docs: Record<string, string> = {};\n let block: string[] = [];\n for (const line of content.split(/\\r?\\n/)) {\n const comment = COMMENT.exec(line);\n if (comment) {\n block.push(comment[1] ?? \"\");\n continue;\n }\n const key = KEY.exec(line)?.[1];\n if (key && block.length > 0) docs[key] = block.join(\"\\n\").trim();\n block = [];\n }\n return docs;\n}\n","import type { FormatSettings, Manifest } from \"./manifest.types.js\";\nimport { asBoolean, asList, asNumber, asRecord, asStringMap } from \"./read/index.js\";\n\ntype RunSettings = Pick<Manifest, \"env\" | \"envFiles\" | \"paths\" | \"format\">;\n\n/**\n * How the project runs, as against what it is: environments, path aliases and\n * formatting.\n */\nexport function readRunSettings(data: Record<string, unknown>): RunSettings {\n return {\n env: readEnv(data.env),\n envFiles: asList(asRecord(data.env).files),\n paths: asStringMap(data.paths),\n format: readFormat(data.format),\n };\n}\n\nfunction readFormat(value: unknown): FormatSettings {\n const table = asRecord(value);\n return {\n indent: asNumber(table.indent),\n tabs: asBoolean(table.tabs),\n organize: asBoolean(table.organize),\n sort: asBoolean(table.sort),\n };\n}\n\n/** `files` configures where to read from; every other key names an environment. */\nconst RESERVED = new Set([\"files\"]);\n\nfunction readEnv(value: unknown): Record<string, Record<string, string>> {\n const out: Record<string, Record<string, string>> = {};\n for (const [name, vars] of Object.entries(asRecord(value))) {\n if (!RESERVED.has(name)) out[name] = asStringMap(vars);\n }\n return out;\n}\n","import type { Manifest, ManifestProvider } from \"./manifest.types.js\";\nimport {\n readDependencies,\n readPackage,\n readProfiles,\n readTargets,\n readTooling,\n readWorkspace,\n} from \"./read/index.js\";\nimport { readRunSettings } from \"./read-run-settings.js\";\nimport { parseToml } from \"./toml/index.js\";\n\n/**\n * The real one: parse `venn.toml` into a {@link Manifest}.\n *\n * Parsing happens once, at construction, so repeated `load()` calls are free\n * and always agree.\n *\n * @param args.content - the manifest as written.\n */\nexport function createTomlManifest(args: { content: string }): ManifestProvider {\n const manifest = toManifest(parseToml(args.content));\n return { load: () => manifest };\n}\n\nfunction toManifest(data: Record<string, unknown>): Manifest {\n const pkg = readPackage(data);\n return {\n name: pkg.name,\n version: pkg.version ?? \"0.0.0\",\n package: pkg,\n targets: readTargets(data, pkg.name),\n dependencies: readDependencies(data.dependencies),\n devDependencies: readDependencies(data[\"dev-dependencies\"]),\n patch: readDependencies(data.patch),\n profiles: readProfiles(data),\n tooling: readTooling(data),\n workspace: readWorkspace(data),\n ...readRunSettings(data),\n };\n}\n","import type {\n SignalHandler,\n SignalSource,\n SystemSignal,\n Unsubscribe,\n} from \"./signal-source.types.js\";\n\n/** A {@link SignalSource} with the bell a test rings. */\nexport interface FakeSignals extends SignalSource {\n /** Deliver `signal` to everyone still listening for it. */\n raise(signal: SystemSignal): void;\n /** Which signals are currently being listened for, for assertions. */\n readonly listening: readonly SystemSignal[];\n}\n\n/**\n * The double: a signal arrives because a test said so. No process, no operating\n * system, no risk of stopping the test runner along with the code under test.\n */\nexport function createFakeSignals(): FakeSignals {\n const handlers = new Map<SystemSignal, Set<SignalHandler>>();\n return {\n get listening() {\n return [...handlers].filter(([, set]) => set.size > 0).map(([signal]) => signal);\n },\n on: (signal, handler) => subscribe({ handlers, signal, handler }),\n raise: (signal) => {\n for (const handler of [...(handlers.get(signal) ?? [])]) handler(signal);\n },\n };\n}\n\nfunction subscribe(args: {\n handlers: Map<SystemSignal, Set<SignalHandler>>;\n signal: SystemSignal;\n handler: SignalHandler;\n}): Unsubscribe {\n const set = args.handlers.get(args.signal) ?? new Set<SignalHandler>();\n set.add(args.handler);\n args.handlers.set(args.signal, set);\n return () => {\n set.delete(args.handler);\n };\n}\n","import type { Port } from \"../../port/index.js\";\nimport type { SignalSource } from \"./signal-source.types.js\";\n\n/**\n * The {@link SignalSource} contract. Implementations: `node-signals`,\n * `fake-signals`.\n */\nexport const SignalSourcePort: Port<SignalSource> = {\n id: \"venn.port.signals\",\n version: 1,\n requires: [\"process\"],\n methods: [\"on\"],\n};\n","/**\n * The ways a system asks a program to stop. `SIGBREAK` is Windows' Ctrl+Break,\n * `SIGHUP` is the terminal itself going away.\n */\nexport const ALL_SIGNALS = [\"SIGINT\", \"SIGTERM\", \"SIGBREAK\", \"SIGHUP\"] as const;\n\n/** One signal name, drawn from {@link ALL_SIGNALS}. */\nexport type SystemSignal = (typeof ALL_SIGNALS)[number];\n\n/** Called on every delivery of the signal it was registered for. */\nexport type SignalHandler = (signal: SystemSignal) => void;\n\n/** Drops a subscription. Calling it more than once is harmless. */\nexport type Unsubscribe = () => void;\n\n/**\n * Where a program hears the system asking it to stop.\n *\n * The double matters more than usual here: raising a true SIGINT inside a test\n * run stops the test runner, not the code under test.\n */\nexport interface SignalSource {\n on(signal: SystemSignal, handler: SignalHandler): Unsubscribe;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venn-lang/contracts",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "The ports the Venn core runs on, their implementations, and the host that carries them.",
5
5
  "keywords": [
6
6
  "venn",
@@ -1,6 +1,6 @@
1
1
  import { cursor, readValue } from "./read-value.js";
2
- import { isSafeKey } from "./safe-key.js";
3
2
  import { enterSection, enterTableArray } from "./sections.js";
3
+ import { emptyTable } from "./table.js";
4
4
 
5
5
  /**
6
6
  * A TOML reader for `venn.toml`: sections, nested `[a.b]`, arrays of tables
@@ -13,7 +13,7 @@ import { enterSection, enterTableArray } from "./sections.js";
13
13
  * @returns the root table. Malformed lines are skipped, never thrown on.
14
14
  */
15
15
  export function parseToml(content: string): Record<string, unknown> {
16
- const root: Record<string, unknown> = {};
16
+ const root = emptyTable();
17
17
  let section = root;
18
18
  for (const raw of content.split(/\r?\n/)) {
19
19
  const line = stripComment(raw).trim();
@@ -49,6 +49,5 @@ function assign(section: Record<string, unknown>, line: string): void {
49
49
  .slice(0, eq)
50
50
  .trim()
51
51
  .replace(/^["']|["']$/g, "");
52
- if (!isSafeKey(key)) return;
53
52
  section[key] = readValue(cursor(line.slice(eq + 1)));
54
53
  }
@@ -1,12 +1,12 @@
1
1
  // Opening `[a.b]` or `[[a.b]]`: working out where the keys that follow go.
2
2
 
3
- import { isSafeKey } from "./safe-key.js";
3
+ import { emptyTable } from "./table.js";
4
4
 
5
5
  /** The table `[path]` names, created along the way if it is not there yet. */
6
6
  export function enterSection(root: Record<string, unknown>, path: string): Record<string, unknown> {
7
7
  let node = root;
8
8
  for (const key of keysOf(path)) {
9
- node[key] ??= {};
9
+ node[key] ??= emptyTable();
10
10
  node = node[key] as Record<string, unknown>;
11
11
  }
12
12
  return node;
@@ -28,7 +28,7 @@ export function enterTableArray(
28
28
  const parent = enterSection(root, keys.join("."));
29
29
  const found = Array.isArray(parent[last]) ? (parent[last] as unknown[]) : [];
30
30
  parent[last] = found;
31
- const table: Record<string, unknown> = {};
31
+ const table = emptyTable();
32
32
  found.push(table);
33
33
  return table;
34
34
  }
@@ -37,5 +37,5 @@ function keysOf(path: string): string[] {
37
37
  return path
38
38
  .split(".")
39
39
  .map((part) => part.trim().replace(/^["']|["']$/g, ""))
40
- .filter((part) => part !== "" && isSafeKey(part));
40
+ .filter((part) => part !== "");
41
41
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * An empty table for a manifest to fill.
3
+ *
4
+ * Made without a prototype, so a key read from the file is a key and nothing
5
+ * else. Assigning `__proto__` onto an ordinary object changes how every object
6
+ * in the process behaves, and a manifest arrives with somebody else's project:
7
+ * a `venn.toml` holding `[package.__proto__]` was enough to put a property on
8
+ * `Object.prototype`.
9
+ *
10
+ * Refusing that one name would have closed that one door. Having no prototype
11
+ * to reach removes the question, and the table is read with `Object.keys` and
12
+ * `Object.entries`, which do not care that it has none.
13
+ */
14
+ export function emptyTable(): Record<string, unknown> {
15
+ return Object.create(null) as Record<string, unknown>;
16
+ }
@@ -1,20 +0,0 @@
1
- /**
2
- * Keys that reach the prototype rather than the object.
3
- *
4
- * A manifest is data that arrives with somebody else's project, and assigning
5
- * one of these from it changes how every object in the process behaves. A
6
- * `venn.toml` containing `[package.__proto__]` was enough to put a property on
7
- * `Object.prototype`.
8
- */
9
- const RESERVED: ReadonlySet<string> = new Set(["__proto__", "constructor", "prototype"]);
10
-
11
- /**
12
- * Whether a key read from a manifest may be assigned.
13
- *
14
- * @param key The key exactly as it was written in the file.
15
- * @returns `false` for a key that would reach the prototype, which the caller
16
- * should skip rather than assign.
17
- */
18
- export function isSafeKey(key: string): boolean {
19
- return !RESERVED.has(key);
20
- }