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
4 changes: 1 addition & 3 deletions .github/workflows/publish-latest.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
name: Publish --latest

on:
workflow_dispatch: # allow manual trigger for testing
push:
paths:
- 'VERSION.txt'
Comment on lines +4 to 7
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The workflow file changes (reordering triggers and changing from 'VERSION.txt' to 'package.json') appear to be unrelated to the PR's stated purpose of "Add simple bin test" and ensuring it doesn't set exports. Consider separating these workflow changes into a separate commit or PR for clarity.

Copilot uses AI. Check for mistakes.
branches:
- main

# Allow manual trigger for testing
workflow_dispatch:

jobs:
publish:
name: Main
Expand Down
7 changes: 5 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,11 @@ Examples:
if (typeof rawConfig.exports === "string") {
rawConfig.exports = { ".": rawConfig.exports };
} else if (typeof rawConfig.exports === "undefined") {
log.error(`❌ Missing "exports" key in package.json#/${CONFIG_KEY}`);
process.exit(1);
// exports is optional if bin is specified
if (!rawConfig.bin) {
log.error(`❌ Missing "exports" key in package.json#/${CONFIG_KEY}`);
process.exit(1);
}
} else if (typeof rawConfig.exports !== "object") {
log.error(`❌ Invalid "exports" key in package.json#/${CONFIG_KEY}`);
process.exit(1);
Expand Down
87 changes: 87 additions & 0 deletions test/__snapshots__/zshy.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,93 @@ exports[`zshy with different tsconfig configurations > should skip CJS build whe
}
`;

exports[`zshy with different tsconfig configurations > should support bin without exports (should not overwrite existing exports) 1`] = `
{
"exitCode": 0,
"stderr": "",
"stdout": "╔═══════════════════════════════════════════════╗
║ zshy » the bundler-free TypeScript build tool ║
╚═══════════════════════════════════════════════╝
» Starting build...
» Verbose mode enabled
» Detected package manager: <pm>
» Build will fail only on errors (default)
» Detected project root: <root>/test/bin
» Reading package.json from ./package.json
» Parsed zshy config: {
"bin": "./src/cli.ts"
}
» Reading tsconfig from ./tsconfig.json
» Determining entrypoints...
╔══════════════════╤══════════════╗
║ Subpath │ Entrypoint ║
╟──────────────────┼──────────────╢
║ bin:bin-only-pkg │ ./src/cli.ts ║
╚══════════════════╧══════════════╝
» Resolved build paths:
╔══════════╤═══════════════╗
║ Location │ Resolved path ║
╟──────────┼───────────────╢
║ rootDir │ ./src ║
║ outDir │ ./dist ║
╚══════════╧═══════════════╝
» Package is an ES module (package.json#/type is "module")
» Cleaning up outDir...
» Cleaning up declarationDir...
» Resolved entrypoints: [
"./src/cli.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/bin/dist",
"emitDeclarationOnly": false,
"composite": false
}
» Building CJS... (rewriting .ts -> .cjs/.d.cts)
» Enabling CJS interop transform...
» Building ESM...
» Writing files (8 total)...
./dist/cli.cjs
./dist/cli.cjs.map
./dist/cli.d.cts
./dist/cli.d.cts.map
./dist/cli.d.ts
./dist/cli.d.ts.map
./dist/cli.js
./dist/cli.js.map
» Updating package.json...
» Setting "bin": "./dist/cli.cjs"
» Build complete!",
}
`;

exports[`zshy with different tsconfig configurations > should support multiple bin entries 1`] = `
{
"exitCode": 0,
Expand Down
4 changes: 4 additions & 0 deletions test/bin/dist/cli.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node
"use strict";
console.log("Hello from CLI!");
//# sourceMappingURL=cli.js.map
1 change: 1 addition & 0 deletions test/bin/dist/cli.cjs.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/bin/dist/cli.d.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
//# sourceMappingURL=cli.d.ts.map
1 change: 1 addition & 0 deletions test/bin/dist/cli.d.cts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/bin/dist/cli.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
//# sourceMappingURL=cli.d.ts.map
1 change: 1 addition & 0 deletions test/bin/dist/cli.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions test/bin/dist/cli.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/bin/dist/cli.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions test/bin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "bin-only-pkg",
"version": "1.0.0",
"description": "Test fixture for zshy - bin only (no exports in zshy config)",
"type": "module",
"scripts": {
"build": "tsx ../../src/index.ts --project tsconfig.json"
},
"devDependencies": {
"typescript": "^5.8.3"
},
"zshy": {
"bin": "./src/cli.ts"
},
"files": [
"dist"
],
"exports": {
"./some-existing-export": "./some-path.js"
},
"bin": "./dist/cli.cjs"
}
4 changes: 4 additions & 0 deletions test/bin/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env node

console.log("Hello from CLI!");

9 changes: 9 additions & 0 deletions test/bin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.default.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.d.ts"]
}

23 changes: 23 additions & 0 deletions test/zshy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,29 @@ describe("zshy with different tsconfig configurations", () => {
expect(snapshot).toMatchSnapshot();
});

it("should support bin without exports (should not overwrite existing exports)", () => {
const cwd = process.cwd() + "/test/bin";
const packageJsonPath = cwd + "/package.json";

// Read original exports field
const originalPackageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
const originalExports = originalPackageJson.exports;

const snapshot = runZshyWithTsconfig("tsconfig.json", {
dryRun: false,
cwd,
});

// Verify exports were not modified
const newPackageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
expect(newPackageJson.exports).toEqual(originalExports);

// Verify bin was updated
expect(newPackageJson.bin).toBe("./dist/cli.cjs");

expect(snapshot).toMatchSnapshot();
});

it("should support tsconfig paths aliases with at-sign", () => {
const snapshot = runZshyWithTsconfig("tsconfig.json", {
dryRun: false,
Expand Down