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.
Files changed (3) hide show
  1. package/README.md +73 -38
  2. package/dist/mock-bin.js +1 -2
  3. 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 | Problem |
78
- |-----------------------|----------------------------------------------------------|
79
- | Stub `child_process` | Couples tests to the module boundary; misses edge cases. |
80
- | `nock` / HTTP mocking | Only works for HTTP, not arbitrary binaries. |
81
- | Real binaries in CI | Slow, requires secrets, produces flaky tests. |
82
- | **Type-A-Bin** | Mocks *any* binary at the `PATH` level — transparently. |
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 | Type | Description |
466
- |-------------------|---------------------------|-----------------------------------------------------|
466
+ | Parameter | Type | Description |
467
+ |----|----|----|
467
468
  | `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
468
- | `output` | `string` | The text the mock echoes (via `bash`) |
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 | Type | Description |
480
- |-------------------|---------------------------|-----------------------------------------------------|
480
+ | Parameter | Type | Description |
481
+ |----|----|----|
481
482
  | `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
482
- | `shebang` | `string` | Interpreter (e.g. `"bash"`, `"node"`) |
483
- | `code` | `string` | The script body that runs when the mock is invoked |
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 | Type | Description |
495
- |-------------------|---------------------------|-----------------------------------------------------|
495
+ | Parameter | Type | Description |
496
+ |----|----|----|
496
497
  | `binNameOrConfig` | `string \| MockBinConfig` | Binary name, or a config with `binName` + `pattern` |
497
- | `shebang` | `string` | Interpreter used to run the file |
498
- | `script` | `MockBinScriptFile` | `{ file: string }` pointing at a script on disk |
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.1 — only needed for Markdown
543
- formatting/linting (`pnpm lint:md` / `pnpm format:md`), not for using
544
- the library
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 | Description |
554
- |-------------------|-------------------------------------------------------|
555
- | `pnpm build` | Build the library (and workspace packages) to `dist/` |
556
- | `pnpm test` | Build, run unit tests, then run workspace tests |
557
- | `pnpm lint` | Run all linters (Biome, oxlint, ast-grep, pandoc) |
558
- | `pnpm format` | Run all formatters with auto-fix |
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 | Type-A-Bin | [mock-bin](https://github.com/stevemao/mock-bin) | [mock-a-bin](https://github.com/levibostian/mock-a-bin) |
652
- |------------------------------------|:----------:|:------------------------------------------------:|:-------------------------------------------------------:|
653
- | Mocks any binary via `PATH` | | | |
654
- | Runtime dependencies | 0 | several | several (Deno) |
655
- | TypeScript types & overloads | | | partial |
656
- | Output shorthand | | | |
657
- | Script-file mode (keeps extension) | | | |
658
- | Pattern-based conditional mocking | | | |
659
- | `run-original` pass-through | | | |
660
- | Cleanup function | | | |
661
- | Runtime | Node.js | Node.js | Deno |
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.0",
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": "pnpm del-cli dist && pnpm tsc && pnpm del-cli dist/tests",
27
+ "build:lib": "del-cli dist && tsc && del-cli dist/tests",
37
28
  "build": "pnpm build:lib && pnpm -r build",
38
- "format:arrows": "pnpm convert-to-arrow \"{src,packages/*/src}/**/*.{ts,tsx}\"",
39
- "format:biome": "pnpm biome format --write .",
40
- "format:braces": "pnpm strip-braces .",
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
+ }