Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,45 @@ The `"bin"` field is automatically written into your `package.json`:
}
```

For packages that expose multiple CLI tools, `"bin"` can also be an object mapping
each command name to its source file:

```jsonc
{
// package.json
"name": "my-cli",
"version": "1.0.0",
"type": "module",
"zshy": {
"bin": {
"my-cli": "./src/cli.ts",
"other": "./src/other.ts"
}
}
}
```

This generates a corresponding object `"bin"` field:

```diff
{
// package.json
"name": "my-cli",
"version": "1.0.0",
"zshy": {
"exports": "./src/index.ts",
"bin": {
"my-cli": "./src/cli.ts",
"other": "./src/other.ts"
}
},
"bin": {
"my-cli": "./dist/cli.cjs",
"other": "./dist/other.cjs"
}
}
```

Be sure to include a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) as the first line of your CLI entrypoint file:

```ts
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.4
0.3.5
129 changes: 129 additions & 0 deletions test/__snapshots__/zshy.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,135 @@ exports[`zshy with different tsconfig configurations > should skip CJS build whe
}
`;

exports[`zshy with different tsconfig configurations > should support multiple bin entries 1`] = `
{
"exitCode": 0,
"stderr": "",
"stdout": "╔═══════════════════════════════════════════════╗
║ zshy » the bundler-free TypeScript build tool ║
╚═══════════════════════════════════════════════╝
» Starting build...
» Verbose mode enabled
» Detected package manager: <pm>
» Dry run mode enabled. No files will be written or modified.
» Build will fail only on errors (default)
» Detected project root: <root>/test/multi-bin
» Reading package.json from ./package.json
» Parsed zshy config: {
"exports": {
".": "./src/index.ts"
},
"bin": {
"cli-one": "./src/cli-one.ts",
"cli-two": "./src/cli-two.ts"
}
}
» Reading tsconfig from ./tsconfig.basic.json
» Determining entrypoints...
╔═════════════════╤══════════════════╗
║ Subpath │ Entrypoint ║
╟─────────────────┼──────────────────╢
║ "multi-bin-pkg" │ ./src/index.ts ║
║ bin:cli-one │ ./src/cli-one.ts ║
║ bin:cli-two │ ./src/cli-two.ts ║
╚═════════════════╧══════════════════╝
» Resolved build paths:
╔══════════╤═══════════════╗
║ Location │ Resolved path ║
╟──────────┼───────────────╢
║ rootDir │ ./src ║
║ outDir │ ./dist ║
╚══════════╧═══════════════╝
» Package is an ES module (package.json#/type is "module")
» [dryrun] Cleaning up outDir...
» [dryrun] Cleaning up declarationDir...
» Resolved entrypoints: [
"./src/index.ts",
"./src/cli-one.ts",
"./src/cli-two.ts"
]
» Resolved compilerOptions: {
"lib": [
"lib.esnext.d.ts"
],
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Bundler",
"moduleDetection": 2,
"allowJs": true,
"declaration": true,
"jsx": 4,
"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true,
"verbatimModuleSyntax": false,
"noEmit": false,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false,
"sourceMap": true,
"declarationMap": true,
"resolveJsonModule": true,
"noImplicitOverride": true,
"noImplicitThis": true,
"outDir": "<root>/test/multi-bin/dist",
"rootDir": "<root>/test/multi-bin/src",
"composite": false,
"emitDeclarationOnly": false
}
» Building CJS... (rewriting .ts -> .cjs/.d.cts)
» Enabling CJS interop transform...
» Building ESM...
» [dryrun] Writing files (24 total)...
./dist/cli-one.cjs
./dist/cli-one.cjs.map
./dist/cli-one.d.cts
./dist/cli-one.d.cts.map
./dist/cli-one.d.ts
./dist/cli-one.d.ts.map
./dist/cli-one.js
./dist/cli-one.js.map
./dist/cli-two.cjs
./dist/cli-two.cjs.map
./dist/cli-two.d.cts
./dist/cli-two.d.cts.map
./dist/cli-two.d.ts
./dist/cli-two.d.ts.map
./dist/cli-two.js
./dist/cli-two.js.map
./dist/index.cjs
./dist/index.cjs.map
./dist/index.d.cts
./dist/index.d.cts.map
./dist/index.d.ts
./dist/index.d.ts.map
./dist/index.js
./dist/index.js.map
» [dryrun] Updating package.json...
» Setting "main": "./dist/index.cjs"
» Setting "module": "./dist/index.js"
» Setting "types": "./dist/index.d.cts"
» Setting "exports": {
".": {
"types": "./dist/index.d.cts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
}
» Setting "bin": {
"cli-one": "./dist/cli-one.cjs",
"cli-two": "./dist/cli-two.cjs"
}
» [dryrun] Skipping package.json modification
» Build complete!",
}
`;

exports[`zshy with different tsconfig configurations > should work with basic.test.tsconfig.json 1`] = `
{
"exitCode": 0,
Expand Down
36 changes: 36 additions & 0 deletions test/multi-bin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "multi-bin-pkg",
"version": "1.0.0",
"description": "Test fixture for zshy with multiple CLI bins",
"type": "module",
"devDependencies": {
"typescript": "^5.8.3"
},
"scripts": {
"build": "tsx ../../src/index.ts --project tsconfig.basic.json"
},
"zshy": {
"exports": "./src/index.ts",
"bin": {
"cli-one": "./src/cli-one.ts",
"cli-two": "./src/cli-two.ts"
}
},
"files": [
"dist"
],
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.cts",
"exports": {
".": {
"types": "./dist/index.d.cts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"bin": {
"cli-one": "./dist/cli-one.cjs",
"cli-two": "./dist/cli-two.cjs"
}
}
2 changes: 2 additions & 0 deletions test/multi-bin/src/cli-one.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log('cli-one');
2 changes: 2 additions & 0 deletions test/multi-bin/src/cli-two.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
console.log('cli-two');
1 change: 1 addition & 0 deletions test/multi-bin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const value = 42;
10 changes: 10 additions & 0 deletions test/multi-bin/tsconfig.basic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
30 changes: 30 additions & 0 deletions test/multi-bin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "es2020",
"module": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "auto",
"allowJs": true,
"declaration": true,
"jsx": "react-jsx",
"allowImportingTsExtensions": true,
"rewriteRelativeImportExtensions": true,
"verbatimModuleSyntax": false,
"noEmit": false,
"strict": true,
"skipLibCheck": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false,
"sourceMap": true,
"declarationMap": true,
"resolveJsonModule": true,
"noImplicitOverride": true,
"noImplicitThis": true
}
}
1 change: 0 additions & 1 deletion test/no-edit-package-json/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"exports": {
".": "./src/index.ts"
},

"noEdit": true
},
"files": [
Expand Down
8 changes: 8 additions & 0 deletions test/zshy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ describe("zshy with different tsconfig configurations", () => {
});
expect(snapshot).toMatchSnapshot();
});

it("should support multiple bin entries", () => {
const snapshot = runZshyWithTsconfig("tsconfig.basic.json", {
dryRun: true,
cwd: process.cwd() + "/test/multi-bin",
});
expect(snapshot).toMatchSnapshot();
});
});

function normalizeOutput(output: string): string {
Expand Down