@aljazmc/testero 0.2.1 → 0.3.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/README.md CHANGED
@@ -12,6 +12,7 @@ testero math unit/ # run test files whose path matches a pattern
12
12
  testero -t "adds numbers" # run tests whose full name matches
13
13
  testero --verbose --bail # list every test, stop at the first failing file
14
14
  testero --listTests # print the test files instead of running them
15
+ testero --config # write the defaults to testero.config.ts, --config js to testero.config.js
15
16
  testero --help
16
17
  ```
17
18
 
package/bin/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // shared/config/src/config.ts
4
- import { existsSync, readdirSync, readFileSync } from "node:fs";
4
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import { join } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
 
@@ -87,6 +87,62 @@ var Config = class _Config {
87
87
  }
88
88
  return new _Config(defaults, root);
89
89
  }
90
+ /** Handles `--config`, writing the defaults to a TypeScript config file, or with `--config js` a JavaScript one. Returns whether it was given. */
91
+ static init(name, defaults, argv = process.argv.slice(2), root = process.cwd()) {
92
+ const index = argv.indexOf("--config");
93
+ if (index === -1) return false;
94
+ const next = argv[index + 1];
95
+ const extension = next === void 0 || next.startsWith("-") ? "ts" : next;
96
+ try {
97
+ console.log(
98
+ `created: ${_Config.export(name, defaults, extension, root)}`
99
+ );
100
+ } catch (error) {
101
+ console.error(error instanceof Error ? error.message : error);
102
+ process.exitCode = 1;
103
+ }
104
+ return true;
105
+ }
106
+ /** Writes the defaults to `<name>.config.<extension>` in the root, unless a config file is there already. */
107
+ static export(name, defaults, extension = "ts", root = process.cwd()) {
108
+ if (!_Config.extensions.includes(extension))
109
+ throw new Error(
110
+ `Unknown config file type ${extension}, use ts or js.`
111
+ );
112
+ for (const existing of _Config.extensions) {
113
+ const file2 = `${name}.config.${existing}`;
114
+ if (existsSync(join(root, file2)))
115
+ throw new Error(`${file2} already exists.`);
116
+ }
117
+ const file = `${name}.config.${extension}`;
118
+ writeFileSync(
119
+ join(root, file),
120
+ `export default ${_Config.#literal(defaults)};
121
+ `
122
+ );
123
+ return file;
124
+ }
125
+ /** A value as JavaScript source, objects one property per line, short arrays on one line. */
126
+ static #literal(value, indent = "") {
127
+ const inner = `${indent} `;
128
+ const lines = (items, open, close) => items.length === 0 ? `${open}${close}` : `${open}
129
+ ${items.map((item) => `${inner}${item},
130
+ `).join("")}${indent}${close}`;
131
+ if (Array.isArray(value)) {
132
+ const items = value.map((item) => _Config.#literal(item, inner));
133
+ const line = `[${items.join(", ")}]`;
134
+ return line.length <= 60 && !line.includes("\n") ? line : lines(items, "[", "]");
135
+ }
136
+ if (value?.constructor === Object)
137
+ return lines(
138
+ Object.entries(value).map(
139
+ ([key, item]) => `${/^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key)}: ${_Config.#literal(item, inner)}`
140
+ ),
141
+ "{",
142
+ "}"
143
+ );
144
+ return JSON.stringify(value);
145
+ }
90
146
  /** Deep merges plain objects, anything else in override replaces base. */
91
147
  static merge(base, override) {
92
148
  const plain = (value) => value?.constructor === Object;
@@ -148,6 +204,7 @@ Options:
148
204
  --listTests print the test files instead of running them
149
205
  --passWithNoTests succeed when there are no test files
150
206
  --testTimeout <ms> milliseconds a test or hook may take
207
+ --config [js] write the default testero.config.ts, or .js
151
208
  -h, --help show this help
152
209
  `;
153
210
  patterns = [];
@@ -1592,7 +1649,7 @@ import { dirname as dirname2, isAbsolute, relative } from "node:path";
1592
1649
  import { fileURLToPath } from "node:url";
1593
1650
 
1594
1651
  // packages/testero/src/transformer.ts
1595
- import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
1652
+ import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
1596
1653
  import { tmpdir } from "node:os";
1597
1654
  import { dirname, extname, join as join2, sep } from "node:path";
1598
1655
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -1618,7 +1675,7 @@ var Transformer = class _Transformer {
1618
1675
  #globals = join2(this.#directory, "globals.mjs");
1619
1676
  #count = 0;
1620
1677
  constructor() {
1621
- writeFileSync(this.#globals, Globals.source());
1678
+ writeFileSync2(this.#globals, Globals.source());
1622
1679
  }
1623
1680
  /** Bundles a test file, returns the URL of the module to import. */
1624
1681
  async compile(file) {
@@ -1641,7 +1698,7 @@ var Transformer = class _Transformer {
1641
1698
  logLevel: "silent",
1642
1699
  plugins: [this.#plugin()]
1643
1700
  });
1644
- writeFileSync(outfile, outputFiles[0]?.text ?? "");
1701
+ writeFileSync2(outfile, outputFiles[0]?.text ?? "");
1645
1702
  return pathToFileURL2(outfile).href;
1646
1703
  }
1647
1704
  /** Removes the compiled files. */
@@ -2125,6 +2182,7 @@ var Testero = class {
2125
2182
 
2126
2183
  // packages/testero/src/index.ts
2127
2184
  try {
2185
+ if (Config.init("testero", config_default)) process.exit();
2128
2186
  const args = new Arguments(process.argv.slice(2));
2129
2187
  if (args.help) process.stdout.write(Arguments.usage);
2130
2188
  else {
@@ -2,7 +2,7 @@ import type { Rules } from "./rules.js";
2
2
  import type { Options } from "./testero.js";
3
3
  /** Command line arguments, named like Jest's. */
4
4
  export default class Arguments {
5
- static readonly usage = "Usage: testero [patterns...] [options]\n\nRuns the test files whose paths match a pattern, every test file without patterns.\n\nOptions:\n -t, --testNamePattern <regex> run only tests whose name matches\n --bail stop after the first failing test file\n --verbose list every test\n --listTests print the test files instead of running them\n --passWithNoTests succeed when there are no test files\n --testTimeout <ms> milliseconds a test or hook may take\n -h, --help show this help\n";
5
+ static readonly usage = "Usage: testero [patterns...] [options]\n\nRuns the test files whose paths match a pattern, every test file without patterns.\n\nOptions:\n -t, --testNamePattern <regex> run only tests whose name matches\n --bail stop after the first failing test file\n --verbose list every test\n --listTests print the test files instead of running them\n --passWithNoTests succeed when there are no test files\n --testTimeout <ms> milliseconds a test or hook may take\n --config [js] write the default testero.config.ts, or .js\n -h, --help show this help\n";
6
6
  readonly patterns: string[];
7
7
  readonly rules: Partial<Rules>;
8
8
  namePattern: RegExp | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aljazmc/testero",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "A simple, Jest like test runner. Easy to understand, easy to customize and easy to extend.",
5
5
  "author": "aljazmc",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@
20
20
  "modular"
21
21
  ],
22
22
  "engines": {
23
- "node": "^20.19.0 || ^22.13.0 || ^24 || ^25 || ^26"
23
+ "node": "^22.18.0 || ^24 || ^25 || ^26"
24
24
  },
25
25
  "types": "./bin/types/testero.d.ts",
26
26
  "bin": "./bin/main.js",