type-a-bin 0.1.0 → 0.1.1
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 +67 -36
- package/dist/mock-bin.js +1 -2
- package/package.json +37 -29
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ fully typed, dependency-free library with richer features.
|
|
|
57
57
|
- [Packages](#packages)
|
|
58
58
|
- [Prerequisites](#prerequisites)
|
|
59
59
|
- [Scripts](#scripts)
|
|
60
|
+
- [Releasing](#releasing)
|
|
60
61
|
- [How it works under the hood](#how-it-works-under-the-hood)
|
|
61
62
|
- [Windows support](#windows-support)
|
|
62
63
|
- [Comparison with other tools](#comparison-with-other-tools)
|
|
@@ -74,12 +75,12 @@ slow, fragile, and impossible to reproduce deterministically.
|
|
|
74
75
|
|
|
75
76
|
There are a few common workarounds, each with drawbacks:
|
|
76
77
|
|
|
77
|
-
| Approach
|
|
78
|
-
|
|
79
|
-
| Stub `child_process`
|
|
80
|
-
| `nock` / HTTP mocking | Only works for HTTP, not arbitrary binaries.
|
|
81
|
-
| Real binaries in CI
|
|
82
|
-
| **Type-A-Bin**
|
|
78
|
+
| Approach | Problem |
|
|
79
|
+
|----|----|
|
|
80
|
+
| Stub `child_process` | Couples tests to the module boundary; misses edge cases. |
|
|
81
|
+
| `nock` / HTTP mocking | Only works for HTTP, not arbitrary binaries. |
|
|
82
|
+
| Real binaries in CI | Slow, requires secrets, produces flaky tests. |
|
|
83
|
+
| **Type-A-Bin** | Mocks *any* binary at the `PATH` level — transparently. |
|
|
83
84
|
|
|
84
85
|
Type-A-Bin works by creating a temporary executable with the same name
|
|
85
86
|
as the target binary and prepending its directory to `PATH`. When your
|
|
@@ -462,10 +463,10 @@ The function is overloaded with three signatures:
|
|
|
462
463
|
mockBin(binNameOrConfig, output): Promise<MockBinCleanup>
|
|
463
464
|
```
|
|
464
465
|
|
|
465
|
-
| Parameter
|
|
466
|
-
|
|
466
|
+
| Parameter | Type | Description |
|
|
467
|
+
|----|----|----|
|
|
467
468
|
| `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
|
|
468
|
-
| `output`
|
|
469
|
+
| `output` | `string` | The text the mock echoes (via `bash`) |
|
|
469
470
|
|
|
470
471
|
Mocks the binary so that every invocation prints `output`. The fastest
|
|
471
472
|
way to stub a command that just needs to return a string.
|
|
@@ -476,11 +477,11 @@ way to stub a command that just needs to return a string.
|
|
|
476
477
|
mockBin(binNameOrConfig, shebang, code): Promise<MockBinCleanup>
|
|
477
478
|
```
|
|
478
479
|
|
|
479
|
-
| Parameter
|
|
480
|
-
|
|
480
|
+
| Parameter | Type | Description |
|
|
481
|
+
|----|----|----|
|
|
481
482
|
| `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
|
|
482
|
-
| `shebang`
|
|
483
|
-
| `code`
|
|
483
|
+
| `shebang` | `string` | Interpreter (e.g. `"bash"`, `"node"`) |
|
|
484
|
+
| `code` | `string` | The script body that runs when the mock is invoked |
|
|
484
485
|
|
|
485
486
|
Gives full control. The `shebang` accepts a bare interpreter name
|
|
486
487
|
(wrapped in `#!/usr/bin/env …` automatically) or a full shebang line.
|
|
@@ -491,11 +492,11 @@ Gives full control. The `shebang` accepts a bare interpreter name
|
|
|
491
492
|
mockBin(binNameOrConfig, shebang, script): Promise<MockBinCleanup>
|
|
492
493
|
```
|
|
493
494
|
|
|
494
|
-
| Parameter
|
|
495
|
-
|
|
495
|
+
| Parameter | Type | Description |
|
|
496
|
+
|----|----|----|
|
|
496
497
|
| `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
|
|
497
|
-
| `shebang`
|
|
498
|
-
| `script`
|
|
498
|
+
| `shebang` | `string` | Interpreter used to run the file |
|
|
499
|
+
| `script` | `MockBinScriptFile` | `{ file: string }` pointing at a script on disk |
|
|
499
500
|
|
|
500
501
|
Runs a script file through the given interpreter, keeping the file’s
|
|
501
502
|
original extension so extension-aware loaders (e.g. `node --import tsx`)
|
|
@@ -539,7 +540,7 @@ library lives at the root; additional packages live under `packages/`:
|
|
|
539
540
|
|
|
540
541
|
- [Node.js](https://nodejs.org) 26 and [pnpm](https://pnpm.io) (enforced
|
|
541
542
|
via `engines` in `package.json`)
|
|
542
|
-
- [pandoc](https://pandoc.org) ≥ 3.
|
|
543
|
+
- [pandoc](https://pandoc.org) ≥ 3.10 — only needed for Markdown
|
|
543
544
|
formatting/linting (`pnpm lint:md` / `pnpm format:md`), not for using
|
|
544
545
|
the library
|
|
545
546
|
- On Windows: [Git for Windows](https://gitforwindows.org/) — its bash
|
|
@@ -550,13 +551,43 @@ library lives at the root; additional packages live under `packages/`:
|
|
|
550
551
|
|
|
551
552
|
Run from the repository root:
|
|
552
553
|
|
|
553
|
-
| Script
|
|
554
|
-
|
|
555
|
-
| `pnpm build`
|
|
556
|
-
| `pnpm test`
|
|
557
|
-
| `pnpm lint`
|
|
558
|
-
| `pnpm format`
|
|
559
|
-
| `pnpm test:watch` | Run unit tests in watch mode
|
|
554
|
+
| Script | Description |
|
|
555
|
+
|----|----|
|
|
556
|
+
| `pnpm build` | Build the library (and workspace packages) to `dist/` |
|
|
557
|
+
| `pnpm test` | Build, run unit tests, then run workspace tests |
|
|
558
|
+
| `pnpm lint` | Run all linters (Biome, oxlint, ast-grep, pandoc, audit, jscpd) |
|
|
559
|
+
| `pnpm format` | Run all formatters with auto-fix |
|
|
560
|
+
| `pnpm test:watch` | Run unit tests in watch mode |
|
|
561
|
+
|
|
562
|
+
## Releasing
|
|
563
|
+
|
|
564
|
+
Releases are published to npm by the manually triggered [Release
|
|
565
|
+
workflow](https://github.com/SynthLuvr/type-a-bin/actions/workflows/release.yml)
|
|
566
|
+
using OIDC trusted publishing — no npm token is stored in the
|
|
567
|
+
repository.
|
|
568
|
+
|
|
569
|
+
One-time setup on npm (required before the workflow can publish): on
|
|
570
|
+
npmjs.com, open the package **type-a-bin → Settings → Trusted
|
|
571
|
+
publishing** and add a GitHub Actions publisher with repository owner
|
|
572
|
+
`SynthLuvr`, repository `type-a-bin`, workflow filename `release.yml`,
|
|
573
|
+
an *empty* environment, and the `npm publish` action allowed.
|
|
574
|
+
|
|
575
|
+
To cut a release, run the workflow from `main` with a semver `bump` or
|
|
576
|
+
an exact `version`. It builds, tests, publishes to npm with provenance,
|
|
577
|
+
then commits the version bump, pushes the `vX.Y.Z` tag, and opens the
|
|
578
|
+
GitHub release. (Version `0.1.0` was published manually to claim the
|
|
579
|
+
package name; every later version goes through the workflow.)
|
|
580
|
+
|
|
581
|
+
If publishing fails, the workflow annotates the run with the fix. Both
|
|
582
|
+
known registry rejections are auth or provenance problems, not problems
|
|
583
|
+
with the package itself:
|
|
584
|
+
|
|
585
|
+
- `E404 Not Found - PUT https://registry.npmjs.org/type-a-bin` — npm
|
|
586
|
+
masks a rejected OIDC exchange as a 404: the trusted-publisher entry
|
|
587
|
+
is missing or does not match the exact values above.
|
|
588
|
+
- `E422` — provenance requires `package.json` to carry `repository.url`
|
|
589
|
+
matching the GitHub repository
|
|
590
|
+
(`https://github.com/SynthLuvr/type-a-bin`).
|
|
560
591
|
|
|
561
592
|
## How it works under the hood
|
|
562
593
|
|
|
@@ -648,17 +679,17 @@ any process that is not a mock shim.
|
|
|
648
679
|
|
|
649
680
|
## Comparison with other tools
|
|
650
681
|
|
|
651
|
-
| Feature
|
|
652
|
-
|
|
653
|
-
| Mocks any binary via `PATH`
|
|
654
|
-
| Runtime dependencies
|
|
655
|
-
| TypeScript types & overloads
|
|
656
|
-
| Output shorthand
|
|
657
|
-
| Script-file mode (keeps extension) |
|
|
658
|
-
| Pattern-based conditional mocking
|
|
659
|
-
| `run-original` pass-through
|
|
660
|
-
| Cleanup function
|
|
661
|
-
| Runtime
|
|
682
|
+
| Feature | Type-A-Bin | [mock-bin](https://github.com/stevemao/mock-bin) | [mock-a-bin](https://github.com/levibostian/mock-a-bin) |
|
|
683
|
+
|----|:--:|:--:|:--:|
|
|
684
|
+
| Mocks any binary via `PATH` | ✅ | ✅ | ✅ |
|
|
685
|
+
| Runtime dependencies | 0 | several | several (Deno) |
|
|
686
|
+
| TypeScript types & overloads | ✅ | ❌ | partial |
|
|
687
|
+
| Output shorthand | ✅ | ❌ | ❌ |
|
|
688
|
+
| Script-file mode (keeps extension) | ✅ | ❌ | ❌ |
|
|
689
|
+
| Pattern-based conditional mocking | ✅ | ❌ | ❌ |
|
|
690
|
+
| `run-original` pass-through | ✅ | ❌ | ✅ |
|
|
691
|
+
| Cleanup function | ✅ | ✅ | ✅ |
|
|
692
|
+
| Runtime | Node.js | Node.js | Deno |
|
|
662
693
|
|
|
663
694
|
## Contributing
|
|
664
695
|
|
package/dist/mock-bin.js
CHANGED
|
@@ -36,9 +36,8 @@ const toShebangLine = (interpreter) => interpreter.startsWith("#!") ? interprete
|
|
|
36
36
|
const resolveScriptFile = async (shebang, { file }) => {
|
|
37
37
|
const resolvedFile = path.resolve(file);
|
|
38
38
|
const stats = await stat(resolvedFile).catch(() => null);
|
|
39
|
-
if (!stats?.isFile())
|
|
39
|
+
if (!stats?.isFile())
|
|
40
40
|
throw new Error(`mockBin: script file not found: ${file}`);
|
|
41
|
-
}
|
|
42
41
|
// Accept either a bare interpreter ("node --import tsx") or a full
|
|
43
42
|
// shebang line ("#!/usr/bin/env node"); strip "#!" for the exec line.
|
|
44
43
|
const interpreter = shebang.startsWith("#!")
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "type-a-bin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Mock any executable binary for testing in Node.js",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/SynthLuvr/type-a-bin"
|
|
9
|
+
},
|
|
6
10
|
"type": "module",
|
|
7
11
|
"main": "./dist/index.js",
|
|
8
12
|
"types": "./dist/index.d.ts",
|
|
@@ -15,43 +19,47 @@
|
|
|
15
19
|
"files": [
|
|
16
20
|
"dist"
|
|
17
21
|
],
|
|
22
|
+
"packageManager": "pnpm@11.24.0",
|
|
18
23
|
"engines": {
|
|
19
24
|
"node": "==26"
|
|
20
25
|
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@ast-grep/cli": "^0.44.1",
|
|
23
|
-
"@ast-grep/cli-linux-x64-gnu": "^0.44.1",
|
|
24
|
-
"@biomejs/biome": "^2.5.4",
|
|
25
|
-
"@types/node": "^26.1.1",
|
|
26
|
-
"convert-to-arrow": "^1.1.4",
|
|
27
|
-
"del-cli": "^7.0.0",
|
|
28
|
-
"npm-run-all2": "^9.0.2",
|
|
29
|
-
"oxlint": "^1.74.0",
|
|
30
|
-
"oxlint-tsgolint": "^0.25.0",
|
|
31
|
-
"tsx": "^4.23.1",
|
|
32
|
-
"typescript": "^7.0.2",
|
|
33
|
-
"vitest": "^4.1.10"
|
|
34
|
-
},
|
|
35
26
|
"scripts": {
|
|
36
|
-
"build:lib": "
|
|
27
|
+
"build:lib": "del-cli dist && tsc && del-cli dist/tests",
|
|
37
28
|
"build": "pnpm build:lib && pnpm -r build",
|
|
38
|
-
"format:arrows": "
|
|
39
|
-
"format:biome": "
|
|
40
|
-
"format:braces": "
|
|
41
|
-
"format:check": "
|
|
29
|
+
"format:arrows": "convert-to-arrow \"{src,packages/*/src}/**/*.{ts,tsx}\"",
|
|
30
|
+
"format:biome": "biome format --write .",
|
|
31
|
+
"format:braces": "ast-grep scan --rule .ast-grep/rules/strip-braces.yml -U .",
|
|
32
|
+
"format:check": "biome check --write .",
|
|
42
33
|
"format": "npm-run-all format:arrows format:braces format:biome format:check format:md",
|
|
43
|
-
"lint:biome": "
|
|
44
|
-
"lint:oxlint": "
|
|
45
|
-
"lint": "npm-run-all lint:biome lint:oxlint lint:exports lint:functions lint:file-comment lint:md lint:peer-deps",
|
|
46
|
-
"
|
|
47
|
-
"lint:
|
|
48
|
-
"lint:
|
|
49
|
-
"lint:file-comment": "pnpm exec ast-grep scan --rule .ast-grep/rules/no-file-comment.yml --error=no-file-comment --globs '!**/*.d.ts' .",
|
|
34
|
+
"lint:biome": "biome check .",
|
|
35
|
+
"lint:oxlint": "tsx scripts/oxlint.mts --deny-warnings .",
|
|
36
|
+
"lint": "npm-run-all lint:biome lint:oxlint lint:exports lint:functions lint:file-comment lint:md lint:peer-deps lint:audit lint:duplicates",
|
|
37
|
+
"lint:exports": "ast-grep scan --rule .ast-grep/rules/no-inline-export.yml --error=no-inline-export --globs '!**/*.d.ts' .",
|
|
38
|
+
"lint:functions": "ast-grep scan --rule .ast-grep/rules/no-function-declaration.yml --error=no-function-declaration --globs '!**/*.d.ts' .",
|
|
39
|
+
"lint:file-comment": "ast-grep scan --rule .ast-grep/rules/no-file-comment.yml --error=no-file-comment --globs '!**/*.d.ts' .",
|
|
50
40
|
"lint:md": "tsx scripts/pandoc-md.mts --check",
|
|
41
|
+
"lint:audit": "pnpm audit --prod",
|
|
42
|
+
"lint:duplicates": "jscpd src --format typescript --min-lines 3 --threshold 5",
|
|
51
43
|
"lint:peer-deps": "tsx scripts/peer-deps.mts",
|
|
52
44
|
"format:md": "tsx scripts/pandoc-md.mts --write",
|
|
53
|
-
"test:lib": "vitest run",
|
|
45
|
+
"test:lib": "vitest run --coverage",
|
|
54
46
|
"test": "pnpm build:lib && pnpm test:lib && pnpm -r test",
|
|
55
47
|
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@ast-grep/cli": "^0.45.2",
|
|
51
|
+
"@ast-grep/cli-linux-x64-gnu": "^0.45.2",
|
|
52
|
+
"@biomejs/biome": "^2.5.10",
|
|
53
|
+
"@types/node": "^26.3.0",
|
|
54
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
55
|
+
"convert-to-arrow": "^1.1.4",
|
|
56
|
+
"del-cli": "^7.0.0",
|
|
57
|
+
"jscpd": "^5.0.16",
|
|
58
|
+
"npm-run-all2": "^9.0.3",
|
|
59
|
+
"oxlint": "^1.80.0",
|
|
60
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
61
|
+
"tsx": "^4.23.12",
|
|
62
|
+
"typescript": "^7.0.2",
|
|
63
|
+
"vitest": "^4.1.11"
|
|
56
64
|
}
|
|
57
|
-
}
|
|
65
|
+
}
|