Skip to content

Commit 8ae13f5

Browse files
authored
feat(cli): allow overriding default script extension (#930)
* feat(cli): allow to override default script extension closes #929 * test: up size-limit * docs: mention `--ext` flag in man * refactor: handle extensions without dot
1 parent 3f164e0 commit 8ae13f5

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

.size-limit.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
{
3131
"name": "all",
3232
"path": "build/*",
33-
"limit": "833 kB",
33+
"limit": "833.6 kB",
3434
"brotli": false,
3535
"gzip": false
3636
}

man/zx.1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ prefix all commands
2121
postfix all commands
2222
.SS --eval=<js>, -e
2323
evaluate script
24+
.SS --ext=<.mjs>
25+
default extension
2426
.SS --install, -i
2527
install dependencies
2628
.SS --repl

src/cli.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import { installDeps, parseDeps } from './deps.js'
2929
import { randomId } from './util.js'
3030
import { createRequire } from './vendor.js'
3131

32+
const EXT = '.mjs'
33+
3234
isMain() &&
3335
main().catch((err) => {
3436
if (err instanceof ProcessOutput) {
@@ -56,6 +58,7 @@ export function printUsage() {
5658
--postfix=<command> postfix all commands
5759
--cwd=<path> set current directory
5860
--eval=<js>, -e evaluate script
61+
--ext=<.mjs> default extension
5962
--install, -i install dependencies
6063
--version, -v print current zx version
6164
--help, -h print help
@@ -67,7 +70,7 @@ export function printUsage() {
6770
}
6871

6972
export const argv = minimist(process.argv.slice(2), {
70-
string: ['shell', 'prefix', 'postfix', 'eval', 'cwd'],
73+
string: ['shell', 'prefix', 'postfix', 'eval', 'cwd', 'ext'],
7174
boolean: [
7275
'version',
7376
'help',
@@ -83,6 +86,7 @@ export const argv = minimist(process.argv.slice(2), {
8386

8487
export async function main() {
8588
await import('./globals.js')
89+
argv.ext = normalizeExt(argv.ext)
8690
if (argv.cwd) $.cwd = argv.cwd
8791
if (argv.verbose) $.verbose = true
8892
if (argv.quiet) $.quiet = true
@@ -102,21 +106,21 @@ export async function main() {
102106
return
103107
}
104108
if (argv.eval) {
105-
await runScript(argv.eval)
109+
await runScript(argv.eval, argv.ext)
106110
return
107111
}
108112
const firstArg = argv._[0]
109113
updateArgv(argv._.slice(firstArg === undefined ? 0 : 1))
110114
if (!firstArg || firstArg === '-') {
111-
const success = await scriptFromStdin()
115+
const success = await scriptFromStdin(argv.ext)
112116
if (!success) {
113117
printUsage()
114118
process.exitCode = 1
115119
}
116120
return
117121
}
118122
if (/^https?:/.test(firstArg)) {
119-
await scriptFromHttp(firstArg)
123+
await scriptFromHttp(firstArg, argv.ext)
120124
return
121125
}
122126
const filepath = firstArg.startsWith('file:///')
@@ -125,12 +129,12 @@ export async function main() {
125129
await importPath(filepath)
126130
}
127131

128-
export async function runScript(script: string) {
129-
const filepath = path.join($.cwd ?? process.cwd(), `zx-${randomId()}.mjs`)
132+
export async function runScript(script: string, ext = EXT) {
133+
const filepath = path.join($.cwd ?? process.cwd(), `zx-${randomId()}${ext}`)
130134
await writeAndImport(script, filepath)
131135
}
132136

133-
export async function scriptFromStdin() {
137+
export async function scriptFromStdin(ext?: string) {
134138
let script = ''
135139
if (!process.stdin.isTTY) {
136140
process.stdin.setEncoding('utf8')
@@ -139,14 +143,14 @@ export async function scriptFromStdin() {
139143
}
140144

141145
if (script.length > 0) {
142-
await runScript(script)
146+
await runScript(script, ext)
143147
return true
144148
}
145149
}
146150
return false
147151
}
148152

149-
export async function scriptFromHttp(remote: string) {
153+
export async function scriptFromHttp(remote: string, _ext = EXT) {
150154
const res = await fetch(remote)
151155
if (!res.ok) {
152156
console.error(`Error: Can't get ${remote}`)
@@ -155,7 +159,7 @@ export async function scriptFromHttp(remote: string) {
155159
const script = await res.text()
156160
const pathname = new URL(remote).pathname
157161
const name = path.basename(pathname)
158-
const ext = path.extname(pathname) || '.mjs'
162+
const ext = path.extname(pathname) || _ext
159163
const cwd = $.cwd ?? process.cwd()
160164
const filepath = path.join(cwd, `${name}-${randomId()}${ext}`)
161165
await writeAndImport(script, filepath)
@@ -299,3 +303,9 @@ export function isMain(
299303

300304
return false
301305
}
306+
307+
export function normalizeExt(ext?: string) {
308+
if (!ext) return
309+
if (!/^\.?\w+(\.\w+)*$/.test(ext)) throw new Error(`Invalid extension ${ext}`)
310+
return ext[0] === '.' ? ext : `.${ext}`
311+
}

test/cli.test.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ import assert from 'node:assert'
1616
import { test, describe, before, after } from 'node:test'
1717
import { fileURLToPath } from 'node:url'
1818
import '../build/globals.js'
19-
import { isMain } from '../build/cli.js'
19+
import { isMain, normalizeExt } from '../build/cli.js'
2020

2121
const __filename = fileURLToPath(import.meta.url)
2222
const spawn = $.spawn
23+
const nodeMajor = +process.versions?.node?.split('.')[0]
24+
const test22 = nodeMajor >= 22 ? test : test.skip
25+
2326
describe('cli', () => {
2427
// Helps detect unresolved ProcessPromise.
2528
before(() => {
@@ -144,6 +147,12 @@ describe('cli', () => {
144147
)
145148
})
146149

150+
test22('scripts from stdin with explicit extension', async () => {
151+
const out =
152+
await $`node --experimental-strip-types build/cli.js --ext='.ts' <<< 'const foo: string = "bar"; console.log(foo)'`
153+
assert.match(out.stdout, /bar/)
154+
})
155+
147156
test('require() is working from stdin', async () => {
148157
const out =
149158
await $`node build/cli.js <<< 'console.log(require("./package.json").name)'`
@@ -258,4 +267,11 @@ describe('cli', () => {
258267
}
259268
})
260269
})
270+
271+
test('normalizeExt()', () => {
272+
assert.equal(normalizeExt('.ts'), '.ts')
273+
assert.equal(normalizeExt('ts'), '.ts')
274+
assert.equal(normalizeExt(), undefined)
275+
assert.throws(() => normalizeExt('.'))
276+
})
261277
})

0 commit comments

Comments
 (0)