type-a-bin 0.1.0 → 0.1.2
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 +73 -38
- package/dist/mock-bin.js +1 -2
- package/package.json +20 -33
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,9 +540,10 @@ 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
|
-
|
|
544
|
-
the
|
|
543
|
+
- [pandoc](https://pandoc.org) ≥ 3.10 — only needed for the Markdown
|
|
544
|
+
steps of `pnpm lint` / `pnpm format` (which run through
|
|
545
|
+
[ts-canon](https://github.com/SynthLuvr/ts-canon)), not for using the
|
|
546
|
+
library
|
|
545
547
|
- On Windows: [Git for Windows](https://gitforwindows.org/) — its bash
|
|
546
548
|
powers bash-interpreter mocks (node-interpreter mocks need nothing
|
|
547
549
|
beyond Node itself)
|
|
@@ -550,13 +552,46 @@ library lives at the root; additional packages live under `packages/`:
|
|
|
550
552
|
|
|
551
553
|
Run from the repository root:
|
|
552
554
|
|
|
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
|
|
555
|
+
| Script | Description |
|
|
556
|
+
|----|----|
|
|
557
|
+
| `pnpm build` | Build the library (and workspace packages) to `dist/` |
|
|
558
|
+
| `pnpm test` | Build, run unit tests, then run workspace tests |
|
|
559
|
+
| `pnpm lint` | Run all linters via ts-canon (Biome, oxlint, ast-grep, pandoc, peer-deps, audit, jscpd) |
|
|
560
|
+
| `pnpm format` | Run all formatters via ts-canon with auto-fix |
|
|
561
|
+
| `pnpm test:watch` | Run unit tests in watch mode |
|
|
562
|
+
|
|
563
|
+
## Releasing
|
|
564
|
+
|
|
565
|
+
Releases are published to npm by the manually triggered [Release
|
|
566
|
+
workflow](https://github.com/SynthLuvr/type-a-bin/actions/workflows/release.yml)
|
|
567
|
+
using OIDC trusted publishing — no npm token is stored in the
|
|
568
|
+
repository.
|
|
569
|
+
|
|
570
|
+
One-time setup on npm (required before the workflow can publish): on
|
|
571
|
+
npmjs.com, open the package **type-a-bin → Settings → Trusted
|
|
572
|
+
publishing** and add a GitHub Actions publisher with repository owner
|
|
573
|
+
`SynthLuvr`, repository `type-a-bin`, workflow filename `release.yml`,
|
|
574
|
+
an *empty* environment, and the `npm publish` action allowed.
|
|
575
|
+
|
|
576
|
+
To cut a release, run the workflow from `main` with a semver `bump` or
|
|
577
|
+
an exact `version`. It builds, tests, publishes to npm with provenance,
|
|
578
|
+
then lands the version bump on `main` via an automatically merged pull
|
|
579
|
+
request (the `main` ruleset requires all changes to go through a PR, so
|
|
580
|
+
the workflow cannot push to `main` directly), pushes the `vX.Y.Z` tag,
|
|
581
|
+
and opens the GitHub release. If the version is already on npm — e.g. a
|
|
582
|
+
previous run published but failed later — publish is skipped and only
|
|
583
|
+
the remaining bookkeeping runs, so re-running the same version is safe.
|
|
584
|
+
|
|
585
|
+
If publishing fails, the workflow annotates the run with the fix. Both
|
|
586
|
+
known registry rejections are auth or provenance problems, not problems
|
|
587
|
+
with the package itself:
|
|
588
|
+
|
|
589
|
+
- `E404 Not Found - PUT https://registry.npmjs.org/type-a-bin` — npm
|
|
590
|
+
masks a rejected OIDC exchange as a 404: the trusted-publisher entry
|
|
591
|
+
is missing or does not match the exact values above.
|
|
592
|
+
- `E422` — provenance requires `package.json` to carry `repository.url`
|
|
593
|
+
matching the GitHub repository
|
|
594
|
+
(`https://github.com/SynthLuvr/type-a-bin`).
|
|
560
595
|
|
|
561
596
|
## How it works under the hood
|
|
562
597
|
|
|
@@ -648,17 +683,17 @@ any process that is not a mock shim.
|
|
|
648
683
|
|
|
649
684
|
## Comparison with other tools
|
|
650
685
|
|
|
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
|
|
686
|
+
| Feature | Type-A-Bin | [mock-bin](https://github.com/stevemao/mock-bin) | [mock-a-bin](https://github.com/levibostian/mock-a-bin) |
|
|
687
|
+
|----|:--:|:--:|:--:|
|
|
688
|
+
| Mocks any binary via `PATH` | ✅ | ✅ | ✅ |
|
|
689
|
+
| Runtime dependencies | 0 | several | several (Deno) |
|
|
690
|
+
| TypeScript types & overloads | ✅ | ❌ | partial |
|
|
691
|
+
| Output shorthand | ✅ | ❌ | ❌ |
|
|
692
|
+
| Script-file mode (keeps extension) | ✅ | ❌ | ❌ |
|
|
693
|
+
| Pattern-based conditional mocking | ✅ | ❌ | ❌ |
|
|
694
|
+
| `run-original` pass-through | ✅ | ❌ | ✅ |
|
|
695
|
+
| Cleanup function | ✅ | ✅ | ✅ |
|
|
696
|
+
| Runtime | Node.js | Node.js | Deno |
|
|
662
697
|
|
|
663
698
|
## Contributing
|
|
664
699
|
|
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.2",
|
|
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,26 @@
|
|
|
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
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"format:check": "pnpm biome check --write .",
|
|
42
|
-
"format": "npm-run-all format:arrows format:braces format:biome format:check format:md",
|
|
43
|
-
"lint:biome": "pnpm biome check .",
|
|
44
|
-
"lint:oxlint": "pnpm oxlint .",
|
|
45
|
-
"lint": "npm-run-all lint:biome lint:oxlint lint:exports lint:functions lint:file-comment lint:md lint:peer-deps",
|
|
46
|
-
"strip-braces": "pnpm exec ast-grep scan --rule .ast-grep/rules/strip-braces.yml -U",
|
|
47
|
-
"lint:exports": "pnpm exec ast-grep scan --rule .ast-grep/rules/no-inline-export.yml --error=no-inline-export --globs '!**/*.d.ts' .",
|
|
48
|
-
"lint:functions": "pnpm exec ast-grep scan --rule .ast-grep/rules/no-function-declaration.yml --error=no-function-declaration --globs '!**/*.d.ts' .",
|
|
49
|
-
"lint:file-comment": "pnpm exec ast-grep scan --rule .ast-grep/rules/no-file-comment.yml --error=no-file-comment --globs '!**/*.d.ts' .",
|
|
50
|
-
"lint:md": "tsx scripts/pandoc-md.mts --check",
|
|
51
|
-
"lint:peer-deps": "tsx scripts/peer-deps.mts",
|
|
52
|
-
"format:md": "tsx scripts/pandoc-md.mts --write",
|
|
53
|
-
"test:lib": "vitest run",
|
|
29
|
+
"format": "ts-canon format",
|
|
30
|
+
"lint": "ts-canon lint",
|
|
31
|
+
"test:lib": "vitest run --coverage",
|
|
54
32
|
"test": "pnpm build:lib && pnpm test:lib && pnpm -r test",
|
|
55
33
|
"test:watch": "vitest"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^26.3.0",
|
|
37
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
38
|
+
"del-cli": "^7.0.0",
|
|
39
|
+
"ts-canon": "^0.1.3",
|
|
40
|
+
"tsx": "^4.23.12",
|
|
41
|
+
"typescript": "^7.0.2",
|
|
42
|
+
"vitest": "^4.1.11"
|
|
56
43
|
}
|
|
57
|
-
}
|
|
44
|
+
}
|