@dral/toml-tests 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dral/toml-tests",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Testing utility that loads TOML test suites and runs them against a function",
5
5
  "type": "module",
6
6
  "exports": {
@@ -10,11 +10,13 @@
10
10
  }
11
11
  },
12
12
  "keywords": [],
13
- "author": "",
13
+ "author": "Michiel Dral <michiel@dral.dev>",
14
+ "repository": {
15
+ "url": "https://github.com/dralletje/javascript-toml-tests"
16
+ },
14
17
  "license": "ISC",
15
18
  "dependencies": {
16
19
  "smol-toml": "^1.6.0",
17
20
  "zod": "^4.3.6"
18
- },
19
- "packageManager": "pnpm@12.0.0"
20
- }
21
+ }
22
+ }
package/src/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { SuiteOpts, TestOpts } from "./test-adapters.js";
2
+ export { adapters } from "./test-adapters.js";
1
3
  /**
2
4
  * A value expressible in TOML: primitives, Dates, arrays, or string-keyed objects thereof.
3
5
  */
@@ -17,9 +19,9 @@ export type TomlTestFn<Input extends TomlValue = TomlValue, Options extends Reco
17
19
  */
18
20
  export interface TestHarness {
19
21
  /** Register a test suite / group (like `describe` in most frameworks) */
20
- describe: (name: string, fn: () => void) => void;
22
+ describe: (name: string, options: SuiteOpts, fn: () => void) => void;
21
23
  /** Register a single test case (like `it` or `test`) */
22
- it: (name: string, fn: () => void | Promise<void>) => void;
24
+ it: (name: string, options: TestOpts, fn: () => void | Promise<void>) => void;
23
25
  /**
24
26
  * Assert deep equality between actual and expected values.
25
27
  * Should throw on mismatch.
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { parse } from "smol-toml";
2
2
  import { z } from "zod";
3
+ import { adapters } from "./test-adapters.js";
3
4
  var TomlValueSchema = z.lazy(
4
5
  () => z.union([
5
6
  z.string(),
@@ -17,7 +18,11 @@ var TestCaseSchema = z.object({
17
18
  output: TomlValueSchema.optional(),
18
19
  throws: z.union([z.literal(true), z.string()]).optional(),
19
20
  doesntThrow: z.literal(true).optional(),
20
- options: z.record(z.string(), TomlValueSchema).optional()
21
+ options: z.record(z.string(), TomlValueSchema).optional(),
22
+ /// Would love to implement these universally, but I'm afraid
23
+ only: z.boolean().optional().default(false),
24
+ skip: z.boolean().optional().default(false),
25
+ todo: z.string().optional()
21
26
  }).refine(
22
27
  (t) => {
23
28
  const count = [
@@ -34,6 +39,9 @@ var TestCaseSchema = z.object({
34
39
  var TestSuiteSchema = z.lazy(
35
40
  () => z.object({
36
41
  name: z.string().optional(),
42
+ only: z.boolean().optional(),
43
+ skip: z.boolean().optional(),
44
+ todo: z.string().optional(),
37
45
  options: z.record(z.string(), TomlValueSchema).optional(),
38
46
  tests: z.array(TestCaseSchema).optional(),
39
47
  suites: z.array(TestSuiteSchema).optional()
@@ -130,18 +138,21 @@ function processSuite(suite, parentOptions, fn, harness, lineInfo, source) {
130
138
  if (Array.isArray(tests)) {
131
139
  for (let testIndex = 0; testIndex < tests.length; testIndex++) {
132
140
  const test = tests[testIndex];
133
- const t = test;
134
- const testName = t.name ?? String(t.input);
135
- harness.it(testName, async () => {
136
- const testOptions = t.options ?? {};
141
+ const testName = test.name ?? `${source ?? "Unknown"} #${testIndex + 1}`;
142
+ harness.it(testName, {
143
+ only: test.only,
144
+ skip: test.skip,
145
+ todo: test.todo
146
+ }, async () => {
147
+ const testOptions = test.options ?? {};
137
148
  const finalOptions = { ...mergedOptions, ...testOptions };
138
149
  const line = lineInfo.testLines[testIndex];
139
150
  const location = line ? source ? `${source}:${line}` : `line ${line}` : void 0;
140
151
  try {
141
- const actual = await fn(t.input, finalOptions);
142
- const hasOutput = t.output !== void 0;
143
- const hasThrows = t.throws !== void 0;
144
- const hasDoesntThrow = t.doesntThrow !== void 0;
152
+ const actual = await fn(test.input, finalOptions);
153
+ const hasOutput = test.output !== void 0;
154
+ const hasThrows = test.throws !== void 0;
155
+ const hasDoesntThrow = test.doesntThrow !== void 0;
145
156
  if (hasOutput) {
146
157
  const nonTomlPaths = findNonTomlPaths(actual);
147
158
  if (nonTomlPaths.length > 0) {
@@ -149,15 +160,15 @@ function processSuite(suite, parentOptions, fn, harness, lineInfo, source) {
149
160
  `Result contains non-TOML-expressible values at: ${nonTomlPaths.join(", ")}`
150
161
  );
151
162
  }
152
- await harness.equal(actual, t.output);
163
+ await harness.equal(actual, test.output);
153
164
  } else if (hasThrows) {
154
165
  throw new Error("Expected function to throw");
155
166
  } else if (hasDoesntThrow) {
156
167
  }
157
168
  } catch (err) {
158
- const hasThrows = t.throws !== void 0;
169
+ const hasThrows = test.throws !== void 0;
159
170
  if (hasThrows && err instanceof Error) {
160
- const throwsValue = t.throws;
171
+ const throwsValue = test.throws;
161
172
  if (throwsValue === true) {
162
173
  return;
163
174
  } else if (typeof throwsValue === "string") {
@@ -176,7 +187,13 @@ function processSuite(suite, parentOptions, fn, harness, lineInfo, source) {
176
187
  }
177
188
  }
178
189
  if (err instanceof Error && location) {
179
- err.message = `${location}: ${err.message}`;
190
+ try {
191
+ err.message = `${location}: ${err.message}`;
192
+ } catch {
193
+ let newerror = new Error(`In test ${location}`, { cause: err });
194
+ newerror.stack = void 0;
195
+ err = newerror;
196
+ }
180
197
  }
181
198
  throw err;
182
199
  }
@@ -202,11 +219,7 @@ function processSuite(suite, parentOptions, fn, harness, lineInfo, source) {
202
219
  }
203
220
  }
204
221
  };
205
- if (suite.name && typeof suite.name === "string") {
206
- harness.describe(suite.name, runContents);
207
- } else {
208
- runContents();
209
- }
222
+ harness.describe(suite.name ?? "Unnamed", { only: suite.only, skip: suite.skip, todo: suite.todo }, runContents);
210
223
  }
211
224
  function toml_test(toml, fn, harness, source) {
212
225
  const suite = parse(toml);
@@ -216,8 +229,8 @@ function toml_test(toml, fn, harness, source) {
216
229
  for (const issue of validationResult.error.issues) {
217
230
  const path = issue.path.length > 0 ? issue.path.join(".") : "root";
218
231
  const errorMessage = `Validation error at ${path}: ${issue.message}`;
219
- harness.it(`Schema validation error: ${path}`, () => {
220
- throw new Error(errorMessage);
232
+ harness.it(`Schema validation error: ${path}`, {}, () => {
233
+ throw new Error(`${errorMessage} in ${source}`);
221
234
  });
222
235
  }
223
236
  return;
@@ -225,5 +238,6 @@ function toml_test(toml, fn, harness, source) {
225
238
  processSuite(suite, {}, fn, harness, lineInfo, source);
226
239
  }
227
240
  export {
241
+ adapters,
228
242
  toml_test
229
243
  };
package/src/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
- "sourcesContent": ["import { parse } from \"smol-toml\";\nimport { z } from \"zod\";\n\n/**\n * A value expressible in TOML: primitives, Dates, arrays, or string-keyed objects thereof.\n */\nexport type TomlValue =\n | string\n | number\n | bigint\n | boolean\n | Date\n | TomlValue[]\n | { [key: string]: TomlValue };\n\n/**\n * Type alias for the function under test.\n * Generic over Input, Options, and Output so callers can narrow the types.\n * Defaults preserve backward compatibility with untyped usage.\n */\nexport type TomlTestFn<\n Input extends TomlValue = TomlValue,\n Options extends Record<string, TomlValue> = Record<string, TomlValue>,\n Output extends TomlValue = TomlValue,\n> = (input: Input, options: Options) => Output | Promise<Output>;\n\n/**\n * Recursive structure mirroring suite nesting, containing only line numbers.\n */\ninterface SuiteLineInfo {\n testLines: number[]; // line number for each [[tests]] entry at this level\n suiteLines: SuiteLineInfo[]; // line info for each [[suites]] entry\n}\n\n/**\n * Zod schemas for validating the TOML test document structure.\n */\n\n// A TOML value: string, number, bigint, boolean, Date, or recursively arrays/objects of TOML values\nconst TomlValueSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.bigint(),\n z.boolean(),\n z.instanceof(Date),\n z.array(TomlValueSchema),\n z.record(z.string(), TomlValueSchema),\n ]),\n);\n\n// A single test case \u2014 name is optional (falls back to stringified input)\n// Exactly one of: output, throws, doesntThrow must be present\nconst TestCaseSchema = z\n .object({\n name: z.string().optional(),\n input: TomlValueSchema,\n output: TomlValueSchema.optional(),\n throws: z.union([z.literal(true), z.string()]).optional(),\n doesntThrow: z.literal(true).optional(),\n options: z.record(z.string(), TomlValueSchema).optional(),\n })\n .refine(\n (t) => {\n const count = [\n t.output !== undefined,\n t.throws !== undefined,\n t.doesntThrow !== undefined,\n ].filter(Boolean).length;\n return count === 1;\n },\n {\n message:\n \"Each test must have exactly one of: output, throws, or doesntThrow\",\n },\n );\n\n// Recursive suite schema\nconst TestSuiteSchema: z.ZodType<any> = z.lazy(() =>\n z.object({\n name: z.string().optional(),\n options: z.record(z.string(), TomlValueSchema).optional(),\n tests: z.array(TestCaseSchema).optional(),\n suites: z.array(TestSuiteSchema).optional(),\n }),\n);\n\n/**\n * Framework-agnostic test harness interface.\n * The caller provides these functions from whatever test framework they use\n * (node:test, vitest, jest, mocha, etc.).\n */\nexport interface TestHarness {\n /** Register a test suite / group (like `describe` in most frameworks) */\n describe: (name: string, fn: () => void) => void;\n /** Register a single test case (like `it` or `test`) */\n it: (name: string, fn: () => void | Promise<void>) => void;\n /**\n * Assert deep equality between actual and expected values.\n * Should throw on mismatch.\n */\n equal: (actual: unknown, expected: unknown) => void;\n}\n\n/**\n * Scans TOML source for array-of-tables headers and builds a tree of line numbers\n * mirroring the suite nesting structure.\n */\nfunction scanTestLines(toml: string): SuiteLineInfo {\n const lines = toml.split(\"\\n\");\n const headerRegex = /^\\s*\\[\\[(.+?)\\]\\]\\s*$/;\n\n // Collect all array-of-tables headers with their line numbers\n const headers: Array<{ path: string; line: number }> = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line) {\n const match = line.match(headerRegex);\n if (match && match[1]) {\n headers.push({ path: match[1].trim(), line: i + 1 }); // 1-indexed\n }\n }\n }\n\n // Build the tree from the flat list of headers\n const root: SuiteLineInfo = { testLines: [], suiteLines: [] };\n\n for (const { path, line } of headers) {\n // Split path into segments: \"suites.suites.tests\" -> [\"suites\", \"suites\", \"tests\"]\n const segments = path.split(\".\");\n\n // Navigate to the right suite\n let current: SuiteLineInfo = root;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i];\n if (seg === \"suites\") {\n // Navigate into the last suite at this level\n if (current.suiteLines.length > 0) {\n current = current.suiteLines[current.suiteLines.length - 1]!;\n }\n }\n // Skip other segments \u2014 they're not suite navigation\n }\n\n const lastSegment = segments[segments.length - 1];\n if (lastSegment === \"tests\") {\n current.testLines.push(line);\n } else if (lastSegment === \"suites\") {\n current.suiteLines.push({ testLines: [], suiteLines: [] });\n }\n // Ignore other paths like \"tests.options\", \"suites.options\" etc.\n }\n\n return root;\n}\n\n/**\n * Recursively finds all paths in a value that contain non-TOML-expressible types.\n * TOML-expressible types are: string, number, bigint, boolean, Date, plain objects, and arrays.\n * Returns an array of dot-path strings where non-TOML values are found.\n */\nfunction findNonTomlPaths(value: unknown, path: string = \"result\"): string[] {\n const nonTomlPaths: string[] = [];\n\n function isPlainObject(obj: unknown): boolean {\n if (obj === null || typeof obj !== \"object\") return false;\n const proto = Object.getPrototypeOf(obj) as unknown;\n return proto === Object.prototype || proto === null;\n }\n\n function isTomlExpressible(val: unknown): boolean {\n const type = typeof val;\n\n // Primitive TOML types\n if (\n type === \"string\"\n || type === \"number\"\n || type === \"bigint\"\n || type === \"boolean\"\n ) {\n return true;\n }\n\n // Date instances (including smol-toml's TomlDate)\n if (val instanceof Date) {\n return true;\n }\n\n // null is NOT TOML-expressible\n if (val === null) {\n return false;\n }\n\n // Arrays: check elements recursively\n if (Array.isArray(val)) {\n return true;\n }\n\n // Plain objects: check values recursively\n if (isPlainObject(val)) {\n return true;\n }\n\n // Everything else (undefined, Symbol, Function, Set, Map, RegExp, class instances, etc.)\n return false;\n }\n\n function walk(val: unknown, currentPath: string): void {\n if (!isTomlExpressible(val)) {\n nonTomlPaths.push(currentPath);\n return;\n }\n\n if (Array.isArray(val)) {\n for (let i = 0; i < val.length; i++) {\n walk(val[i], `${currentPath}[${i}]`);\n }\n return;\n }\n\n if (val !== null && typeof val === \"object\" && isPlainObject(val)) {\n for (const [key, value] of Object.entries(\n val as Record<string, unknown>,\n )) {\n walk(value, `${currentPath}.${key}`);\n }\n return;\n }\n }\n\n walk(value, path);\n return nonTomlPaths;\n}\n\n/**\n * Processes a test suite recursively, creating describe/it blocks as needed.\n * Handles options merging from parent to child scope.\n */\nfunction processSuite<\n Input extends TomlValue,\n Options extends Record<string, TomlValue>,\n Output extends TomlValue,\n>(\n suite: Record<string, unknown>,\n parentOptions: Record<string, unknown>,\n fn: TomlTestFn<Input, Options, Output>,\n harness: TestHarness,\n lineInfo: SuiteLineInfo,\n source?: string,\n): void {\n // Merge options: parent options + suite options\n const suiteOptions = (suite.options ?? {}) as Record<string, unknown>;\n const mergedOptions = { ...parentOptions, ...suiteOptions };\n\n const runContents = () => {\n // Process test cases\n const tests = suite.tests;\n if (Array.isArray(tests)) {\n for (let testIndex = 0; testIndex < tests.length; testIndex++) {\n const test = tests[testIndex];\n const t = test as Record<string, unknown>;\n\n // Use name if provided, otherwise fall back to stringified input\n const testName = (t.name as string | undefined) ?? String(t.input);\n\n harness.it(testName, async () => {\n // Merge test-level options on top of suite options\n const testOptions = (t.options ?? {}) as Record<string, unknown>;\n const finalOptions = { ...mergedOptions, ...testOptions };\n\n // Get line number for this test\n const line = lineInfo.testLines[testIndex];\n const location =\n line ?\n source ? `${source}:${line}`\n : `line ${line}`\n : undefined;\n\n try {\n // Call the test function (await in case it's async)\n const actual = await fn(t.input as Input, finalOptions as Options);\n\n // Determine which assertion type is being used\n const hasOutput = t.output !== undefined;\n const hasThrows = t.throws !== undefined;\n const hasDoesntThrow = t.doesntThrow !== undefined;\n\n if (hasOutput) {\n // output assertion: validate non-TOML types, then compare\n const nonTomlPaths = findNonTomlPaths(actual);\n if (nonTomlPaths.length > 0) {\n throw new Error(\n `Result contains non-TOML-expressible values at: ${nonTomlPaths.join(\", \")}`,\n );\n }\n await harness.equal(actual, t.output);\n } else if (hasThrows) {\n // throws assertion: should have thrown, but didn't\n throw new Error(\"Expected function to throw\");\n } else if (hasDoesntThrow) {\n // doesntThrow assertion: just verify it didn't throw (already passed)\n // No additional checks needed\n }\n } catch (err) {\n // Check if this is a \"throws\" test that actually threw\n const hasThrows = t.throws !== undefined;\n if (hasThrows && err instanceof Error) {\n const throwsValue = t.throws;\n if (throwsValue === true) {\n // Any error is fine, test passes\n return;\n } else if (typeof throwsValue === \"string\") {\n // Check if error message matches the pattern\n const pattern = new RegExp(throwsValue);\n if (pattern.test(err.message)) {\n // Pattern matches, test passes\n return;\n } else {\n // Pattern doesn't match, fail with descriptive message\n const newErr = new Error(\n `Expected error message to match pattern \"${throwsValue}\", but got: \"${err.message}\"`,\n );\n if (location) {\n newErr.message = `${location}: ${newErr.message}`;\n }\n throw newErr;\n }\n }\n }\n\n // For non-throws tests or other errors, add location and re-throw\n if (err instanceof Error && location) {\n err.message = `${location}: ${err.message}`;\n }\n throw err;\n }\n });\n }\n }\n\n // Process nested suites\n const suites = suite.suites;\n if (Array.isArray(suites)) {\n for (let suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {\n const nestedSuite = suites[suiteIndex];\n const nestedLineInfo = lineInfo.suiteLines[suiteIndex] ?? {\n testLines: [],\n suiteLines: [],\n };\n processSuite(\n nestedSuite as Record<string, unknown>,\n mergedOptions,\n fn,\n harness,\n nestedLineInfo,\n source,\n );\n }\n }\n };\n\n // If the suite has a name, wrap in describe block\n if (suite.name && typeof suite.name === \"string\") {\n harness.describe(suite.name, runContents);\n } else {\n // Nameless suites run contents directly at the current nesting level\n runContents();\n }\n}\n\n/**\n * Parses a TOML test document and registers test suites/cases using the\n * provided test harness. Framework-agnostic \u2014 works with node:test, vitest,\n * jest, mocha, or any framework that provides describe/it/equal.\n *\n * @param toml - TOML source string describing the test suite\n * @param fn - The function under test\n * @param harness - Test framework bindings (describe, it, equal)\n * @param source - Optional source label (e.g. filename) for error messages\n */\nexport function toml_test<\n Input extends TomlValue = TomlValue,\n Options extends Record<string, TomlValue> = Record<string, TomlValue>,\n Output extends TomlValue = TomlValue,\n>(\n toml: string,\n fn: TomlTestFn<Input, Options, Output>,\n harness: TestHarness,\n source?: string,\n): void {\n const suite = parse(toml);\n const lineInfo = scanTestLines(toml);\n\n // Validate the parsed suite against the schema\n const validationResult = TestSuiteSchema.safeParse(suite);\n\n if (!validationResult.success) {\n // Register failing tests for each validation error\n for (const issue of validationResult.error.issues) {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"root\";\n const errorMessage = `Validation error at ${path}: ${issue.message}`;\n harness.it(`Schema validation error: ${path}`, () => {\n throw new Error(errorMessage);\n });\n }\n return;\n }\n\n processSuite(suite, {}, fn, harness, lineInfo, source);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { parse } from \"smol-toml\";\nimport { z } from \"zod\";\nimport type { SuiteOpts, TestOpts } from \"./test-adapters.ts\";\n\nexport { adapters } from \"./test-adapters.ts\";\n\n/**\n * A value expressible in TOML: primitives, Dates, arrays, or string-keyed objects thereof.\n */\nexport type TomlValue =\n | string\n | number\n | bigint\n | boolean\n | Date\n | TomlValue[]\n | { [key: string]: TomlValue };\n\n/**\n * Type alias for the function under test.\n * Generic over Input, Options, and Output so callers can narrow the types.\n * Defaults preserve backward compatibility with untyped usage.\n */\nexport type TomlTestFn<\n Input extends TomlValue = TomlValue,\n Options extends Record<string, TomlValue> = Record<string, TomlValue>,\n Output extends TomlValue = TomlValue,\n> = (input: Input, options: Options) => Output | Promise<Output>;\n\n/**\n * Recursive structure mirroring suite nesting, containing only line numbers.\n */\ninterface SuiteLineInfo {\n testLines: number[]; // line number for each [[tests]] entry at this level\n suiteLines: SuiteLineInfo[]; // line info for each [[suites]] entry\n}\n\n/**\n * Zod schemas for validating the TOML test document structure.\n */\n\n// A TOML value: string, number, bigint, boolean, Date, or recursively arrays/objects of TOML values\nconst TomlValueSchema: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.bigint(),\n z.boolean(),\n z.instanceof(Date),\n z.array(TomlValueSchema),\n z.record(z.string(), TomlValueSchema),\n ]),\n);\n\n// A single test case \u2014 name is optional (falls back to stringified input)\n// Exactly one of: output, throws, doesntThrow must be present\nconst TestCaseSchema = z\n .object({\n name: z.string().optional(),\n input: TomlValueSchema,\n output: TomlValueSchema.optional(),\n throws: z.union([z.literal(true), z.string()]).optional(),\n doesntThrow: z.literal(true).optional(),\n options: z.record(z.string(), TomlValueSchema).optional(),\n\n /// Would love to implement these universally, but I'm afraid\n only: z.boolean().optional().default(false),\n skip: z.boolean().optional().default(false),\n todo: z.string().optional(),\n })\n .refine(\n (t) => {\n const count = [\n t.output !== undefined,\n t.throws !== undefined,\n t.doesntThrow !== undefined,\n ].filter(Boolean).length;\n return count === 1;\n },\n {\n message:\n \"Each test must have exactly one of: output, throws, or doesntThrow\",\n },\n );\n\ntype TestSuite = {\n name?: string;\n only?: boolean;\n skip?: boolean;\n todo?: string;\n options?: Record<string, unknown>;\n tests?: Array<z.infer<typeof TestCaseSchema>>;\n suites?: Array<TestSuite>;\n}\n\n// Recursive suite schema\nconst TestSuiteSchema: z.ZodType<TestSuite> = z.lazy(() =>\n z.object({\n name: z.string().optional(),\n only: z.boolean().optional(),\n skip: z.boolean().optional(),\n todo: z.string().optional(),\n options: z.record(z.string(), TomlValueSchema).optional(),\n tests: z.array(TestCaseSchema).optional(),\n suites: z.array(TestSuiteSchema).optional(),\n }),\n);\n\n/**\n * Framework-agnostic test harness interface.\n * The caller provides these functions from whatever test framework they use\n * (node:test, vitest, jest, mocha, etc.).\n */\nexport interface TestHarness {\n /** Register a test suite / group (like `describe` in most frameworks) */\n describe: (name: string, options: SuiteOpts, fn: () => void) => void;\n /** Register a single test case (like `it` or `test`) */\n it: (name: string, options: TestOpts, fn: () => void | Promise<void>) => void;\n /**\n * Assert deep equality between actual and expected values.\n * Should throw on mismatch.\n */\n equal: (actual: unknown, expected: unknown) => void;\n}\n\n/**\n * Scans TOML source for array-of-tables headers and builds a tree of line numbers\n * mirroring the suite nesting structure.\n */\nfunction scanTestLines(toml: string): SuiteLineInfo {\n const lines = toml.split(\"\\n\");\n const headerRegex = /^\\s*\\[\\[(.+?)\\]\\]\\s*$/;\n\n // Collect all array-of-tables headers with their line numbers\n const headers: Array<{ path: string; line: number }> = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line) {\n const match = line.match(headerRegex);\n if (match && match[1]) {\n headers.push({ path: match[1].trim(), line: i + 1 }); // 1-indexed\n }\n }\n }\n\n // Build the tree from the flat list of headers\n const root: SuiteLineInfo = { testLines: [], suiteLines: [] };\n\n for (const { path, line } of headers) {\n // Split path into segments: \"suites.suites.tests\" -> [\"suites\", \"suites\", \"tests\"]\n const segments = path.split(\".\");\n\n // Navigate to the right suite\n let current: SuiteLineInfo = root;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i];\n if (seg === \"suites\") {\n // Navigate into the last suite at this level\n if (current.suiteLines.length > 0) {\n current = current.suiteLines[current.suiteLines.length - 1]!;\n }\n }\n // Skip other segments \u2014 they're not suite navigation\n }\n\n const lastSegment = segments[segments.length - 1];\n if (lastSegment === \"tests\") {\n current.testLines.push(line);\n } else if (lastSegment === \"suites\") {\n current.suiteLines.push({ testLines: [], suiteLines: [] });\n }\n // Ignore other paths like \"tests.options\", \"suites.options\" etc.\n }\n\n return root;\n}\n\n/**\n * Recursively finds all paths in a value that contain non-TOML-expressible types.\n * TOML-expressible types are: string, number, bigint, boolean, Date, plain objects, and arrays.\n * Returns an array of dot-path strings where non-TOML values are found.\n */\nfunction findNonTomlPaths(value: unknown, path: string = \"result\"): string[] {\n const nonTomlPaths: string[] = [];\n\n function isPlainObject(obj: unknown): boolean {\n if (obj === null || typeof obj !== \"object\") return false;\n const proto = Object.getPrototypeOf(obj) as unknown;\n return proto === Object.prototype || proto === null;\n }\n\n function isTomlExpressible(val: unknown): boolean {\n const type = typeof val;\n\n // Primitive TOML types\n if (\n type === \"string\"\n || type === \"number\"\n || type === \"bigint\"\n || type === \"boolean\"\n ) {\n return true;\n }\n\n // Date instances (including smol-toml's TomlDate)\n if (val instanceof Date) {\n return true;\n }\n\n // null is NOT TOML-expressible\n if (val === null) {\n return false;\n }\n\n // Arrays: check elements recursively\n if (Array.isArray(val)) {\n return true;\n }\n\n // Plain objects: check values recursively\n if (isPlainObject(val)) {\n return true;\n }\n\n // Everything else (undefined, Symbol, Function, Set, Map, RegExp, class instances, etc.)\n return false;\n }\n\n function walk(val: unknown, currentPath: string): void {\n if (!isTomlExpressible(val)) {\n nonTomlPaths.push(currentPath);\n return;\n }\n\n if (Array.isArray(val)) {\n for (let i = 0; i < val.length; i++) {\n walk(val[i], `${currentPath}[${i}]`);\n }\n return;\n }\n\n if (val !== null && typeof val === \"object\" && isPlainObject(val)) {\n for (const [key, value] of Object.entries(\n val as Record<string, unknown>,\n )) {\n walk(value, `${currentPath}.${key}`);\n }\n return;\n }\n }\n\n walk(value, path);\n return nonTomlPaths;\n}\n\n/**\n * Processes a test suite recursively, creating describe/it blocks as needed.\n * Handles options merging from parent to child scope.\n */\nfunction processSuite<\n Input extends TomlValue,\n Options extends Record<string, TomlValue>,\n Output extends TomlValue,\n>(\n suite: TestSuite,\n parentOptions: Record<string, unknown>,\n fn: TomlTestFn<Input, Options, Output>,\n harness: TestHarness,\n lineInfo: SuiteLineInfo,\n source?: string,\n): void {\n // Merge options: parent options + suite options\n const suiteOptions = (suite.options ?? {})\n const mergedOptions = { ...parentOptions, ...suiteOptions };\n\n const runContents = () => {\n // Process test cases\n const tests = suite.tests;\n if (Array.isArray(tests)) {\n for (let testIndex = 0; testIndex < tests.length; testIndex++) {\n const test = tests[testIndex]!;\n\n // Use name if provided, otherwise fall back to stringified input\n const testName = (test.name ) ?? `${source ?? \"Unknown\"} #${testIndex + 1}`;\n\n harness.it(testName, {\n only: test.only,\n skip: test.skip,\n todo: test.todo,\n }, async () => {\n // Merge test-level options on top of suite options\n const testOptions = (test.options ?? {}) as Record<string, unknown>;\n const finalOptions = { ...mergedOptions, ...testOptions };\n\n // Get line number for this test\n const line = lineInfo.testLines[testIndex];\n const location =\n line ?\n source ? `${source}:${line}`\n : `line ${line}`\n : undefined;\n\n try {\n // Call the test function (await in case it's async)\n const actual = await fn(test.input as Input, finalOptions as Options);\n\n // Determine which assertion type is being used\n const hasOutput = test.output !== undefined;\n const hasThrows = test.throws !== undefined;\n const hasDoesntThrow = test.doesntThrow !== undefined;\n\n if (hasOutput) {\n // output assertion: validate non-TOML types, then compare\n const nonTomlPaths = findNonTomlPaths(actual);\n if (nonTomlPaths.length > 0) {\n throw new Error(\n `Result contains non-TOML-expressible values at: ${nonTomlPaths.join(\", \")}`,\n );\n }\n await harness.equal(actual, test.output);\n } else if (hasThrows) {\n // throws assertion: should have thrown, but didn't\n throw new Error(\"Expected function to throw\");\n } else if (hasDoesntThrow) {\n // doesntThrow assertion: just verify it didn't throw (already passed)\n // No additional checks needed\n }\n } catch (err) {\n // Check if this is a \"throws\" test that actually threw\n const hasThrows = test.throws !== undefined;\n if (hasThrows && err instanceof Error) {\n const throwsValue = test.throws;\n if (throwsValue === true) {\n // Any error is fine, test passes\n return;\n } else if (typeof throwsValue === \"string\") {\n // Check if error message matches the pattern\n const pattern = new RegExp(throwsValue);\n if (pattern.test(err.message)) {\n // Pattern matches, test passes\n return;\n } else {\n // Pattern doesn't match, fail with descriptive message\n const newErr = new Error(\n `Expected error message to match pattern \"${throwsValue}\", but got: \"${err.message}\"`,\n );\n if (location) {\n newErr.message = `${location}: ${newErr.message}`;\n }\n throw newErr;\n }\n }\n }\n\n // For non-throws tests or other errors, add location and re-throw\n if (err instanceof Error && location) {\n try {\n err.message = `${location}: ${err.message}`;\n } catch {\n let newerror = new Error(`In test ${location}`, { cause: err });\n newerror.stack = undefined\n err = newerror;\n }\n }\n throw err;\n }\n });\n }\n }\n\n // Process nested suites\n const suites = suite.suites;\n if (Array.isArray(suites)) {\n for (let suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {\n const nestedSuite = suites[suiteIndex];\n const nestedLineInfo = lineInfo.suiteLines[suiteIndex] ?? {\n testLines: [],\n suiteLines: [],\n };\n processSuite(\n nestedSuite as Record<string, unknown>,\n mergedOptions,\n fn,\n harness,\n nestedLineInfo,\n source,\n );\n }\n }\n };\n\n // If the suite has a name, wrap in describe block\n harness.describe(suite.name ?? \"Unnamed\", { only: suite.only, skip: suite.skip, todo: suite.todo }, runContents);\n}\n\n/**\n * Parses a TOML test document and registers test suites/cases using the\n * provided test harness. Framework-agnostic \u2014 works with node:test, vitest,\n * jest, mocha, or any framework that provides describe/it/equal.\n *\n * @param toml - TOML source string describing the test suite\n * @param fn - The function under test\n * @param harness - Test framework bindings (describe, it, equal)\n * @param source - Optional source label (e.g. filename) for error messages\n */\nexport function toml_test<\n Input extends TomlValue = TomlValue,\n Options extends Record<string, TomlValue> = Record<string, TomlValue>,\n Output extends TomlValue = TomlValue,\n>(\n toml: string,\n fn: TomlTestFn<Input, Options, Output>,\n harness: TestHarness,\n source?: string,\n): void {\n const suite = parse(toml);\n const lineInfo = scanTestLines(toml);\n\n // Validate the parsed suite against the schema\n const validationResult = TestSuiteSchema.safeParse(suite);\n\n if (!validationResult.success) {\n // Register failing tests for each validation error\n for (const issue of validationResult.error.issues) {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"root\";\n const errorMessage = `Validation error at ${path}: ${issue.message}`;\n harness.it(`Schema validation error: ${path}`, {}, () => {\n throw new Error(`${errorMessage} in ${source}`);\n });\n }\n return;\n }\n\n processSuite(suite, {}, fn, harness, lineInfo, source);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["value"]
7
7
  }
@@ -0,0 +1,53 @@
1
+ export type TestFn = (...args: any[]) => any;
2
+ export type TestOpts = {
3
+ skip?: boolean | string;
4
+ only?: boolean;
5
+ todo?: boolean | string;
6
+ timeout?: number;
7
+ [k: string]: unknown;
8
+ };
9
+ export declare const testAdapters: {
10
+ node: (t: any) => any;
11
+ vitest: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
12
+ jest: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
13
+ bun: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
14
+ playwright: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
15
+ };
16
+ export type SuiteFn = () => void | Promise<void>;
17
+ export type SuiteOpts = {
18
+ skip?: boolean | string;
19
+ only?: boolean;
20
+ todo?: boolean | string;
21
+ concurrency?: boolean | number;
22
+ timeout?: number;
23
+ [k: string]: unknown;
24
+ };
25
+ export declare const suiteAdapters: {
26
+ node: (s: any) => any;
27
+ vitest: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
28
+ jest: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
29
+ bun: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
30
+ playwright: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
31
+ };
32
+ export declare let adapters: {
33
+ node: {
34
+ test: (t: any) => any;
35
+ suite: (s: any) => any;
36
+ };
37
+ vitest: {
38
+ test: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
39
+ suite: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
40
+ };
41
+ jest: {
42
+ test: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
43
+ suite: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
44
+ };
45
+ bun: {
46
+ test: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
47
+ suite: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
48
+ };
49
+ playwright: {
50
+ test: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => any;
51
+ suite: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => any;
52
+ };
53
+ };
@@ -0,0 +1,83 @@
1
+ var testAdapters = {
2
+ node: (t) => t,
3
+ vitest: (t) => (name, opts, fn) => {
4
+ if (opts.todo) return t.todo(name);
5
+ if (opts.skip) return t.skip(name, opts, fn);
6
+ if (opts.only) return t.only(name, opts, fn);
7
+ return t(name, opts, fn);
8
+ },
9
+ jest: (t) => (name, opts, fn) => {
10
+ if (opts.todo) return t.todo(name);
11
+ const runner = opts.skip || opts.todo ? t.skip : opts.only ? t.only : t;
12
+ return runner(name, fn, opts.timeout);
13
+ },
14
+ bun: (t) => (name, opts, fn) => {
15
+ if (opts.todo) return t.todo(name);
16
+ const runner = opts.skip ? t.skip : opts.only ? t.only : t;
17
+ return runner(name, fn, opts.timeout);
18
+ },
19
+ playwright: (t) => (name, opts, fn) => {
20
+ const runner = opts.only ? t.only : t;
21
+ return runner(name, async (fixtures, info) => {
22
+ if (opts.skip) t.skip(true, typeof opts.skip === "string" ? opts.skip : void 0);
23
+ if (opts.todo) t.fixme(true, typeof opts.todo === "string" ? opts.todo : void 0);
24
+ if (opts.timeout) info.setTimeout(opts.timeout);
25
+ if (fn) return await fn(fixtures, info);
26
+ });
27
+ }
28
+ };
29
+ var suiteAdapters = {
30
+ node: (s) => s,
31
+ vitest: (s) => (name, opts, fn) => {
32
+ if (opts.todo) return s.todo(name);
33
+ if (opts.skip) return s.skip(name, opts, fn);
34
+ if (opts.only) return s.only(name, opts, fn);
35
+ if (opts.concurrency) return s.concurrent(name, opts, fn);
36
+ return s(name, opts, fn);
37
+ },
38
+ jest: (s) => (name, opts, fn) => {
39
+ if (opts.todo) return s.todo(name);
40
+ const runner = opts.skip ? s.skip : opts.only ? s.only : s;
41
+ return runner(name, fn);
42
+ },
43
+ bun: (s) => (name, opts, fn) => {
44
+ if (opts.todo) return s.todo(name);
45
+ const runner = opts.skip ? s.skip : opts.only ? s.only : s;
46
+ return runner(name, fn);
47
+ },
48
+ playwright: (s) => (name, opts, fn) => {
49
+ let runner = opts.only ? s.only : opts.skip ? s.skip : s;
50
+ if (opts.concurrency) runner = runner.parallel ?? runner;
51
+ return runner(name, () => {
52
+ if (opts.todo) s.fixme();
53
+ fn();
54
+ });
55
+ }
56
+ };
57
+ var adapters = {
58
+ node: {
59
+ test: testAdapters.node,
60
+ suite: suiteAdapters.node
61
+ },
62
+ vitest: {
63
+ test: testAdapters.vitest,
64
+ suite: suiteAdapters.vitest
65
+ },
66
+ jest: {
67
+ test: testAdapters.jest,
68
+ suite: suiteAdapters.jest
69
+ },
70
+ bun: {
71
+ test: testAdapters.bun,
72
+ suite: suiteAdapters.bun
73
+ },
74
+ playwright: {
75
+ test: testAdapters.playwright,
76
+ suite: suiteAdapters.playwright
77
+ }
78
+ };
79
+ export {
80
+ adapters,
81
+ suiteAdapters,
82
+ testAdapters
83
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/test-adapters.ts"],
4
+ "sourcesContent": ["export type TestFn = (...args: any[]) => any;\nexport type TestOpts = {\n skip?: boolean | string;\n only?: boolean;\n todo?: boolean | string;\n timeout?: number;\n [k: string]: unknown;\n};\n\nexport const testAdapters = {\n node: (t: any) => t,\n\n vitest: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => {\n if (opts.todo) return t.todo(name);\n if (opts.skip) return t.skip(name, opts, fn);\n if (opts.only) return t.only(name, opts, fn);\n return t(name, opts, fn);\n },\n\n jest: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => {\n if (opts.todo) return t.todo(name);\n const runner = opts.skip || opts.todo ? t.skip : opts.only ? t.only : t;\n return runner(name, fn, opts.timeout);\n },\n\n bun: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => {\n if (opts.todo) return t.todo(name);\n const runner = opts.skip ? t.skip : opts.only ? t.only : t;\n return runner(name, fn, opts.timeout);\n },\n\n playwright: (t: any) => (name: string, opts: TestOpts, fn?: TestFn) => {\n const runner = opts.only ? t.only : t;\n return runner(name, async (fixtures: any, info: any) => {\n if (opts.skip) t.skip(true, typeof opts.skip === 'string' ? opts.skip : undefined);\n if (opts.todo) t.fixme(true, typeof opts.todo === 'string' ? opts.todo : undefined);\n if (opts.timeout) info.setTimeout(opts.timeout);\n if (fn) return await fn(fixtures, info);\n });\n },\n};\n\nexport type SuiteFn = () => void | Promise<void>;\nexport type SuiteOpts = {\n skip?: boolean | string;\n only?: boolean;\n todo?: boolean | string;\n concurrency?: boolean | number;\n timeout?: number;\n [k: string]: unknown;\n};\n\nexport const suiteAdapters = {\n node: (s: any) => s,\n\n vitest: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => {\n if (opts.todo) return s.todo(name);\n if (opts.skip) return s.skip(name, opts, fn);\n if (opts.only) return s.only(name, opts, fn);\n if (opts.concurrency) return s.concurrent(name, opts, fn);\n return s(name, opts, fn);\n },\n\n jest: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => {\n if (opts.todo) return s.todo(name);\n const runner = opts.skip ? s.skip : opts.only ? s.only : s;\n return runner(name, fn);\n },\n\n bun: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => {\n if (opts.todo) return s.todo(name);\n const runner = opts.skip ? s.skip : opts.only ? s.only : s;\n return runner(name, fn);\n },\n\n playwright: (s: any) => (name: string, opts: SuiteOpts, fn: SuiteFn) => {\n let runner = opts.only ? s.only : opts.skip ? s.skip : s;\n if (opts.concurrency) runner = runner.parallel ?? runner;\n return runner(name, () => {\n if (opts.todo) s.fixme();\n fn();\n });\n },\n};\n\nexport let adapters = {\n node: {\n test: testAdapters.node,\n suite: suiteAdapters.node,\n },\n vitest: {\n test: testAdapters.vitest,\n suite: suiteAdapters.vitest,\n },\n jest: {\n test: testAdapters.jest,\n suite: suiteAdapters.jest,\n },\n bun: {\n test: testAdapters.bun,\n suite: suiteAdapters.bun,\n },\n playwright: {\n test: testAdapters.playwright,\n suite: suiteAdapters.playwright,\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }