@regardio/dev 1.16.2 → 1.17.0
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 +1 -1
- package/dist/bin/ship/production.js +11 -16
- package/dist/bin/ship/staging.js +2 -1
- package/package.json +11 -12
- package/src/bin/ship/production.ts +28 -34
- package/src/bin/ship/staging.ts +8 -1
- package/dist/bin/exec/ts.d.ts +0 -3
- package/dist/bin/exec/ts.d.ts.map +0 -1
- package/dist/bin/exec/ts.js +0 -36
- package/dist/bin/exec/ts.test.d.ts +0 -2
- package/dist/bin/exec/ts.test.d.ts.map +0 -1
- package/dist/bin/exec/ts.test.js +0 -39
- package/src/bin/exec/ts.test.ts +0 -54
- package/src/bin/exec/ts.ts +0 -52
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The goal is code that's correct, consistent, and a pleasure to work with.
|
|
|
27
27
|
| **Testing** | Vitest, Playwright, Testing Library |
|
|
28
28
|
| **Build** | TypeScript, tsx, Vite |
|
|
29
29
|
| **Workflow** | Husky, GitLab Flow |
|
|
30
|
-
| **CLI utilities** | exec-clean, exec-p, exec-s, exec-
|
|
30
|
+
| **CLI utilities** | exec-clean, exec-p, exec-s, exec-tsc, ship-staging, ship-production, ship-hotfix, lint-biome, lint-md, lint-package |
|
|
31
31
|
|
|
32
32
|
## Quick Start
|
|
33
33
|
|
|
@@ -31,9 +31,10 @@ if (!branchExists('production')) {
|
|
|
31
31
|
+ ' git checkout -b production && git push -u origin production');
|
|
32
32
|
process.exit(1);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
git('pull', '--ff-only', 'origin', 'main');
|
|
35
|
+
const ahead = gitRead('log', 'origin/production..HEAD', '--oneline');
|
|
35
36
|
if (!ahead) {
|
|
36
|
-
console.error('
|
|
37
|
+
console.error('main is already in sync with production. Nothing to ship.');
|
|
37
38
|
process.exit(1);
|
|
38
39
|
}
|
|
39
40
|
console.log('\nCommits to be shipped to production:');
|
|
@@ -48,16 +49,12 @@ if (!confirm(`\nShip ${packageName} as a ${bumpType} release?`)) {
|
|
|
48
49
|
console.log('Aborted.');
|
|
49
50
|
process.exit(0);
|
|
50
51
|
}
|
|
51
|
-
console.log('\
|
|
52
|
-
git('checkout', 'staging');
|
|
53
|
-
git('pull', '--ff-only', 'origin', 'staging');
|
|
54
|
-
console.log('\nRunning quality checks on staging...');
|
|
52
|
+
console.log('\nRunning quality checks on main...');
|
|
55
53
|
try {
|
|
56
54
|
runQualityChecks();
|
|
57
55
|
}
|
|
58
56
|
catch {
|
|
59
|
-
console.error('\nQuality checks failed on
|
|
60
|
-
git('checkout', 'main');
|
|
57
|
+
console.error('\nQuality checks failed on main. Fix issues before shipping.');
|
|
61
58
|
process.exit(1);
|
|
62
59
|
}
|
|
63
60
|
console.log('✅ Quality checks passed');
|
|
@@ -86,19 +83,17 @@ catch {
|
|
|
86
83
|
}
|
|
87
84
|
git('add', '-A');
|
|
88
85
|
git('commit', '-m', `chore(release): ${packageName}@${newVersion}`, '-m', changeBody);
|
|
89
|
-
console.log('\nMerging
|
|
86
|
+
console.log('\nMerging main into production...');
|
|
90
87
|
git('checkout', 'production');
|
|
91
88
|
git('pull', '--ff-only', 'origin', 'production');
|
|
92
|
-
git('merge', '--ff-only', '
|
|
89
|
+
git('merge', '--ff-only', 'main');
|
|
93
90
|
git('push', 'origin', 'production');
|
|
94
|
-
console.log('\nSyncing
|
|
95
|
-
git('checkout', 'main');
|
|
96
|
-
git('pull', '--ff-only', 'origin', 'main');
|
|
97
|
-
git('merge', '--ff-only', 'production');
|
|
98
|
-
git('push', 'origin', 'main');
|
|
91
|
+
console.log('\nSyncing staging with production...');
|
|
99
92
|
git('checkout', 'staging');
|
|
100
|
-
git('
|
|
93
|
+
git('pull', '--ff-only', 'origin', 'staging');
|
|
94
|
+
git('merge', '--ff-only', 'production');
|
|
101
95
|
git('push', 'origin', 'staging');
|
|
102
96
|
git('checkout', 'main');
|
|
97
|
+
git('pull', '--ff-only', 'origin', 'main');
|
|
103
98
|
console.log(`\n✅ Shipped ${packageName}@${newVersion} to production`);
|
|
104
99
|
console.log('You are on main and ready to keep working.');
|
package/dist/bin/ship/staging.js
CHANGED
|
@@ -59,4 +59,5 @@ git('push', 'origin', 'staging');
|
|
|
59
59
|
git('checkout', 'main');
|
|
60
60
|
git('push', 'origin', 'main');
|
|
61
61
|
console.log('\n✅ Changes deployed to staging');
|
|
62
|
-
console.log('Run ship-production <patch|minor|major> when ready to
|
|
62
|
+
console.log('Run ship-production <patch|minor|major> when ready to ship to production.');
|
|
63
|
+
console.log('(Or ship directly from main to production without using ship-staging first.)');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "@regardio/dev",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.17.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Regardio developer tooling for testing, linting, and build workflows",
|
|
7
7
|
"keywords": [
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"exec-husky": "dist/bin/exec/husky.js",
|
|
60
60
|
"exec-p": "dist/bin/exec/p.js",
|
|
61
61
|
"exec-s": "dist/bin/exec/s.js",
|
|
62
|
-
"exec-ts": "dist/bin/exec/ts.js",
|
|
63
62
|
"exec-tsc": "dist/bin/exec/tsc.js",
|
|
64
63
|
"lint-biome": "dist/bin/lint/biome.js",
|
|
65
64
|
"lint-commit": "dist/bin/lint/commit.js",
|
|
@@ -91,28 +90,28 @@
|
|
|
91
90
|
"typecheck": "tsc --noEmit"
|
|
92
91
|
},
|
|
93
92
|
"dependencies": {
|
|
94
|
-
"@biomejs/biome": "2.4.
|
|
95
|
-
"@commitlint/cli": "20.
|
|
96
|
-
"@commitlint/config-conventional": "20.
|
|
93
|
+
"@biomejs/biome": "2.4.7",
|
|
94
|
+
"@commitlint/cli": "20.5.0",
|
|
95
|
+
"@commitlint/config-conventional": "20.5.0",
|
|
97
96
|
"@playwright/test": "1.58.2",
|
|
98
97
|
"@testing-library/jest-dom": "6.9.1",
|
|
99
98
|
"@testing-library/react": "16.3.2",
|
|
100
99
|
"@total-typescript/ts-reset": "0.6.1",
|
|
101
|
-
"@types/node": "25.
|
|
102
|
-
"@vitest/coverage-v8": "4.0
|
|
103
|
-
"@vitest/ui": "4.0
|
|
100
|
+
"@types/node": "25.5.0",
|
|
101
|
+
"@vitest/coverage-v8": "4.1.0",
|
|
102
|
+
"@vitest/ui": "4.1.0",
|
|
104
103
|
"husky": "9.1.7",
|
|
105
|
-
"jsdom": "
|
|
104
|
+
"jsdom": "29.0.0",
|
|
106
105
|
"markdownlint-cli2": "0.21.0",
|
|
107
106
|
"npm-run-all": "4.1.5",
|
|
108
|
-
"postcss": "8.5.
|
|
107
|
+
"postcss": "8.5.8",
|
|
109
108
|
"rimraf": "6.1.3",
|
|
110
109
|
"rollup": "4.59.0",
|
|
111
110
|
"sort-package-json": "3.6.1",
|
|
112
111
|
"tsx": "4.21.0",
|
|
113
112
|
"typescript": "5.9.3",
|
|
114
|
-
"vite": "
|
|
115
|
-
"vitest": "4.0
|
|
113
|
+
"vite": "8.0.0",
|
|
114
|
+
"vitest": "4.1.0"
|
|
116
115
|
},
|
|
117
116
|
"peerDependencies": {
|
|
118
117
|
"postcss": "8.4"
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* ship-production: Version and promote
|
|
3
|
+
* ship-production: Version and promote main to production following the GitLab workflow.
|
|
4
4
|
*
|
|
5
5
|
* Usage: ship-production <patch|minor|major>
|
|
6
6
|
*
|
|
7
7
|
* GitLab workflow:
|
|
8
|
-
*
|
|
8
|
+
* main → (version bump commit) → production → staging → main
|
|
9
9
|
*
|
|
10
10
|
* Versioning is intentionally deferred to this step so that version numbers
|
|
11
11
|
* only ever correspond to production-verified code.
|
|
12
12
|
*
|
|
13
13
|
* This script:
|
|
14
14
|
* 1. Ensures the current branch is main and the working tree is clean
|
|
15
|
-
* 2. Verifies
|
|
16
|
-
* 3. Runs quality checks on
|
|
15
|
+
* 2. Verifies main is ahead of production (there is something to ship)
|
|
16
|
+
* 3. Runs quality checks on main
|
|
17
17
|
* 4. Bumps the version in package.json
|
|
18
|
-
* 5. Collects change descriptions from git log between production and
|
|
18
|
+
* 5. Collects change descriptions from git log between production and main
|
|
19
19
|
* 6. Updates CHANGELOG.md
|
|
20
|
-
* 7. Commits the version bump on
|
|
21
|
-
* 8. Merges
|
|
22
|
-
* 9. Merges production
|
|
23
|
-
* 10.
|
|
20
|
+
* 7. Commits the version bump on main
|
|
21
|
+
* 8. Merges main into production (fast-forward) and pushes
|
|
22
|
+
* 9. Merges production into staging to keep it in sync
|
|
23
|
+
* 10. Merges production back into main to ensure consistency
|
|
24
24
|
* 11. Returns to main
|
|
25
25
|
*/
|
|
26
26
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -85,11 +85,12 @@ if (!branchExists('production')) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// ---------------------------------------------------------------------------
|
|
88
|
-
// Verify
|
|
88
|
+
// Verify main has commits not yet in production
|
|
89
89
|
// ---------------------------------------------------------------------------
|
|
90
|
-
|
|
90
|
+
git('pull', '--ff-only', 'origin', 'main');
|
|
91
|
+
const ahead = gitRead('log', 'origin/production..HEAD', '--oneline');
|
|
91
92
|
if (!ahead) {
|
|
92
|
-
console.error('
|
|
93
|
+
console.error('main is already in sync with production. Nothing to ship.');
|
|
93
94
|
process.exit(1);
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -114,24 +115,19 @@ if (!confirm(`\nShip ${packageName} as a ${bumpType} release?`)) {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
// ---------------------------------------------------------------------------
|
|
117
|
-
// Quality checks on
|
|
118
|
+
// Quality checks on main
|
|
118
119
|
// ---------------------------------------------------------------------------
|
|
119
|
-
console.log('\
|
|
120
|
-
git('checkout', 'staging');
|
|
121
|
-
git('pull', '--ff-only', 'origin', 'staging');
|
|
122
|
-
|
|
123
|
-
console.log('\nRunning quality checks on staging...');
|
|
120
|
+
console.log('\nRunning quality checks on main...');
|
|
124
121
|
try {
|
|
125
122
|
runQualityChecks();
|
|
126
123
|
} catch {
|
|
127
|
-
console.error('\nQuality checks failed on
|
|
128
|
-
git('checkout', 'main');
|
|
124
|
+
console.error('\nQuality checks failed on main. Fix issues before shipping.');
|
|
129
125
|
process.exit(1);
|
|
130
126
|
}
|
|
131
127
|
console.log('✅ Quality checks passed');
|
|
132
128
|
|
|
133
129
|
// ---------------------------------------------------------------------------
|
|
134
|
-
// Read version from
|
|
130
|
+
// Read version from main package.json and bump
|
|
135
131
|
// ---------------------------------------------------------------------------
|
|
136
132
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as {
|
|
137
133
|
name: string;
|
|
@@ -180,36 +176,34 @@ try {
|
|
|
180
176
|
}
|
|
181
177
|
|
|
182
178
|
// ---------------------------------------------------------------------------
|
|
183
|
-
// Commit version bump on
|
|
179
|
+
// Commit version bump on main
|
|
184
180
|
// ---------------------------------------------------------------------------
|
|
185
181
|
git('add', '-A');
|
|
186
182
|
git('commit', '-m', `chore(release): ${packageName}@${newVersion}`, '-m', changeBody);
|
|
187
183
|
|
|
188
184
|
// ---------------------------------------------------------------------------
|
|
189
|
-
// Merge
|
|
185
|
+
// Merge main → production
|
|
190
186
|
// ---------------------------------------------------------------------------
|
|
191
|
-
console.log('\nMerging
|
|
187
|
+
console.log('\nMerging main into production...');
|
|
192
188
|
git('checkout', 'production');
|
|
193
189
|
git('pull', '--ff-only', 'origin', 'production');
|
|
194
|
-
git('merge', '--ff-only', '
|
|
190
|
+
git('merge', '--ff-only', 'main');
|
|
195
191
|
git('push', 'origin', 'production');
|
|
196
192
|
|
|
197
193
|
// ---------------------------------------------------------------------------
|
|
198
|
-
//
|
|
194
|
+
// Sync staging with production
|
|
199
195
|
// ---------------------------------------------------------------------------
|
|
200
|
-
console.log('\nSyncing
|
|
201
|
-
git('checkout', '
|
|
202
|
-
git('pull', '--ff-only', 'origin', '
|
|
196
|
+
console.log('\nSyncing staging with production...');
|
|
197
|
+
git('checkout', 'staging');
|
|
198
|
+
git('pull', '--ff-only', 'origin', 'staging');
|
|
203
199
|
git('merge', '--ff-only', 'production');
|
|
204
|
-
git('push', 'origin', '
|
|
200
|
+
git('push', 'origin', 'staging');
|
|
205
201
|
|
|
206
202
|
// ---------------------------------------------------------------------------
|
|
207
|
-
//
|
|
203
|
+
// Return to main and sync
|
|
208
204
|
// ---------------------------------------------------------------------------
|
|
209
|
-
git('checkout', 'staging');
|
|
210
|
-
git('merge', '--ff-only', 'main');
|
|
211
|
-
git('push', 'origin', 'staging');
|
|
212
205
|
git('checkout', 'main');
|
|
206
|
+
git('pull', '--ff-only', 'origin', 'main');
|
|
213
207
|
|
|
214
208
|
console.log(`\n✅ Shipped ${packageName}@${newVersion} to production`);
|
|
215
209
|
console.log('You are on main and ready to keep working.');
|
package/src/bin/ship/staging.ts
CHANGED
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* GitLab workflow:
|
|
8
8
|
* main → staging (staging deploy, no version bump yet)
|
|
9
9
|
*
|
|
10
|
+
* This script is OPTIONAL. You can ship directly to production using ship-production,
|
|
11
|
+
* which will automatically sync staging afterward.
|
|
12
|
+
*
|
|
13
|
+
* Use ship-staging when you want to test changes in a staging environment before
|
|
14
|
+
* shipping to production. Otherwise, skip this step and use ship-production directly.
|
|
15
|
+
*
|
|
10
16
|
* Versioning happens at ship time (ship-production), not here.
|
|
11
17
|
* This keeps version numbers reserved for production-verified code.
|
|
12
18
|
*
|
|
@@ -120,4 +126,5 @@ git('checkout', 'main');
|
|
|
120
126
|
git('push', 'origin', 'main');
|
|
121
127
|
|
|
122
128
|
console.log('\n✅ Changes deployed to staging');
|
|
123
|
-
console.log('Run ship-production <patch|minor|major> when ready to
|
|
129
|
+
console.log('Run ship-production <patch|minor|major> when ready to ship to production.');
|
|
130
|
+
console.log('(Or ship directly from main to production without using ship-staging first.)');
|
package/dist/bin/exec/ts.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ts.d.ts","sourceRoot":"","sources":["../../../src/bin/exec/ts.ts"],"names":[],"mappings":";AAcA,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAYjE"}
|
package/dist/bin/exec/ts.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
export function resolveTsxBin(require) {
|
|
7
|
-
const pkgPath = require.resolve('tsx/package.json');
|
|
8
|
-
const pkg = require(pkgPath);
|
|
9
|
-
const binRel = pkg.bin;
|
|
10
|
-
const binEntry = typeof binRel === 'string'
|
|
11
|
-
? binRel
|
|
12
|
-
: typeof binRel === 'object' && binRel !== null && 'tsx' in binRel
|
|
13
|
-
? binRel.tsx
|
|
14
|
-
: undefined;
|
|
15
|
-
if (!binEntry)
|
|
16
|
-
return null;
|
|
17
|
-
return path.join(path.dirname(pkgPath), binEntry);
|
|
18
|
-
}
|
|
19
|
-
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
|
|
20
|
-
const args = process.argv.slice(2);
|
|
21
|
-
if (args.length === 0) {
|
|
22
|
-
console.error('Usage: exec-ts <script.ts> [args...]');
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
const [scriptArg, ...rest] = args;
|
|
26
|
-
const script = scriptArg ?? '';
|
|
27
|
-
const require = createRequire(import.meta.url);
|
|
28
|
-
const bin = resolveTsxBin(require);
|
|
29
|
-
if (!bin) {
|
|
30
|
-
console.error('Unable to locate tsx binary from package.json bin field');
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
const spawnOptions = { stdio: 'inherit' };
|
|
34
|
-
const child = spawn(process.execPath, [bin, script, ...rest], spawnOptions);
|
|
35
|
-
child.on('exit', (code) => process.exit(code ?? 0));
|
|
36
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ts.test.d.ts","sourceRoot":"","sources":["../../../src/bin/exec/ts.test.ts"],"names":[],"mappings":""}
|
package/dist/bin/exec/ts.test.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { resolveTsxBin } from './ts.js';
|
|
5
|
-
function makeRequire(pkgPath, pkg) {
|
|
6
|
-
const req = (id) => (id === pkgPath ? pkg : undefined);
|
|
7
|
-
req.resolve = (_id) => pkgPath;
|
|
8
|
-
return req;
|
|
9
|
-
}
|
|
10
|
-
describe('resolveTsxBin', () => {
|
|
11
|
-
it('resolves when bin is a string', () => {
|
|
12
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
13
|
-
const req = makeRequire(pkgPath, { bin: './dist/cli.mjs' });
|
|
14
|
-
const result = resolveTsxBin(req);
|
|
15
|
-
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
16
|
-
});
|
|
17
|
-
it('resolves when bin is an object with a tsx key', () => {
|
|
18
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
19
|
-
const req = makeRequire(pkgPath, { bin: { tsx: './dist/cli.mjs' } });
|
|
20
|
-
const result = resolveTsxBin(req);
|
|
21
|
-
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
22
|
-
});
|
|
23
|
-
it('returns null when bin field is missing', () => {
|
|
24
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
25
|
-
const req = makeRequire(pkgPath, {});
|
|
26
|
-
expect(resolveTsxBin(req)).toBeNull();
|
|
27
|
-
});
|
|
28
|
-
it('returns null when bin object has no tsx key', () => {
|
|
29
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
30
|
-
const req = makeRequire(pkgPath, { bin: { other: './dist/other.js' } });
|
|
31
|
-
expect(resolveTsxBin(req)).toBeNull();
|
|
32
|
-
});
|
|
33
|
-
it('resolves against the real tsx package', () => {
|
|
34
|
-
const req = createRequire(import.meta.url);
|
|
35
|
-
const result = resolveTsxBin(req);
|
|
36
|
-
expect(result).not.toBeNull();
|
|
37
|
-
expect(path.isAbsolute(result ?? '')).toBe(true);
|
|
38
|
-
});
|
|
39
|
-
});
|
package/src/bin/exec/ts.test.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
|
|
5
|
-
import { resolveTsxBin } from './ts.js';
|
|
6
|
-
|
|
7
|
-
function makeRequire(pkgPath: string, pkg: unknown): NodeRequire {
|
|
8
|
-
const req = (id: string): unknown => (id === pkgPath ? pkg : undefined);
|
|
9
|
-
req.resolve = (_id: string) => pkgPath;
|
|
10
|
-
return req as unknown as NodeRequire;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
describe('resolveTsxBin', () => {
|
|
14
|
-
it('resolves when bin is a string', () => {
|
|
15
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
16
|
-
const req = makeRequire(pkgPath, { bin: './dist/cli.mjs' });
|
|
17
|
-
|
|
18
|
-
const result = resolveTsxBin(req);
|
|
19
|
-
|
|
20
|
-
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('resolves when bin is an object with a tsx key', () => {
|
|
24
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
25
|
-
const req = makeRequire(pkgPath, { bin: { tsx: './dist/cli.mjs' } });
|
|
26
|
-
|
|
27
|
-
const result = resolveTsxBin(req);
|
|
28
|
-
|
|
29
|
-
expect(result).toBe(path.join('/node_modules/tsx', 'dist/cli.mjs'));
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('returns null when bin field is missing', () => {
|
|
33
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
34
|
-
const req = makeRequire(pkgPath, {});
|
|
35
|
-
|
|
36
|
-
expect(resolveTsxBin(req)).toBeNull();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('returns null when bin object has no tsx key', () => {
|
|
40
|
-
const pkgPath = '/node_modules/tsx/package.json';
|
|
41
|
-
const req = makeRequire(pkgPath, { bin: { other: './dist/other.js' } });
|
|
42
|
-
|
|
43
|
-
expect(resolveTsxBin(req)).toBeNull();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('resolves against the real tsx package', () => {
|
|
47
|
-
const req = createRequire(import.meta.url);
|
|
48
|
-
|
|
49
|
-
const result = resolveTsxBin(req);
|
|
50
|
-
|
|
51
|
-
expect(result).not.toBeNull();
|
|
52
|
-
expect(path.isAbsolute(result ?? '')).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
});
|
package/src/bin/exec/ts.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* exec-ts: Run a local TypeScript file via tsx with TS support.
|
|
4
|
-
* Usage: exec-ts path/to/script.ts [args...]
|
|
5
|
-
*/
|
|
6
|
-
import { type SpawnOptions, spawn } from 'node:child_process';
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
import { fileURLToPath } from 'node:url';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Resolve the absolute path to the tsx binary from its package.json bin field.
|
|
13
|
-
* Returns the resolved path, or null if it cannot be determined.
|
|
14
|
-
*/
|
|
15
|
-
export function resolveTsxBin(require: NodeRequire): string | null {
|
|
16
|
-
const pkgPath = require.resolve('tsx/package.json');
|
|
17
|
-
const pkg = require(pkgPath) as { bin?: unknown };
|
|
18
|
-
const binRel = pkg.bin;
|
|
19
|
-
const binEntry: string | undefined =
|
|
20
|
-
typeof binRel === 'string'
|
|
21
|
-
? binRel
|
|
22
|
-
: typeof binRel === 'object' && binRel !== null && 'tsx' in binRel
|
|
23
|
-
? (binRel as Record<string, string>).tsx
|
|
24
|
-
: undefined;
|
|
25
|
-
if (!binEntry) return null;
|
|
26
|
-
return path.join(path.dirname(pkgPath), binEntry);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// CLI entry point — only runs when executed directly
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
|
|
33
|
-
const args = process.argv.slice(2);
|
|
34
|
-
if (args.length === 0) {
|
|
35
|
-
console.error('Usage: exec-ts <script.ts> [args...]');
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const [scriptArg, ...rest] = args;
|
|
40
|
-
const script = scriptArg ?? '';
|
|
41
|
-
|
|
42
|
-
const require = createRequire(import.meta.url);
|
|
43
|
-
const bin = resolveTsxBin(require);
|
|
44
|
-
if (!bin) {
|
|
45
|
-
console.error('Unable to locate tsx binary from package.json bin field');
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const spawnOptions: SpawnOptions = { stdio: 'inherit' };
|
|
50
|
-
const child = spawn(process.execPath, [bin, script, ...rest], spawnOptions);
|
|
51
|
-
child.on('exit', (code: number | null) => process.exit(code ?? 0));
|
|
52
|
-
}
|