Skip to content

Commit bf26083

Browse files
authored
feat(cli): process md for any kind of input (google#1078)
* feat(cli): process md for any kind of input closes google#1076 * fix(cli): fix updateArgv block
1 parent 49a82c4 commit bf26083

File tree

4 files changed

+92
-86
lines changed

4 files changed

+92
-86
lines changed

src/cli.ts

+72-76
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
fetch,
2727
fs,
2828
path,
29+
stdin,
2930
VERSION,
3031
} from './index.js'
3132
import { installDeps, parseDeps } from './deps.js'
@@ -113,100 +114,95 @@ export async function main() {
113114
await startRepl()
114115
return
115116
}
116-
if (argv.eval) {
117-
await runScript(argv.eval, argv.ext)
118-
return
119-
}
120-
const [firstArg] = argv._
121-
updateArgv(argv._.slice(firstArg === undefined ? 0 : 1))
122-
if (!firstArg || firstArg === '-') {
123-
const success = await scriptFromStdin(argv.ext)
124-
if (!success) {
125-
printUsage()
126-
process.exitCode = 1
127-
}
128-
return
129-
}
130-
if (/^https?:/.test(firstArg)) {
131-
await scriptFromHttp(firstArg, argv.ext)
132-
return
133-
}
134-
const filepath = firstArg.startsWith('file:')
135-
? url.fileURLToPath(firstArg)
136-
: path.resolve(firstArg)
137-
await importPath(filepath)
138-
}
139117

140-
export async function runScript(script: string, ext?: string) {
141-
const filepath = getFilepath($.cwd, 'zx', ext)
142-
await writeAndImport(script, filepath)
118+
const { script, scriptPath, tempPath } = await readScript()
119+
await runScript(script, scriptPath, tempPath)
143120
}
144121

145-
export async function scriptFromStdin(ext?: string): Promise<boolean> {
146-
let script = ''
147-
if (!process.stdin.isTTY) {
148-
process.stdin.setEncoding('utf8')
149-
for await (const chunk of process.stdin) {
150-
script += chunk
122+
async function runScript(
123+
script: string,
124+
scriptPath: string,
125+
tempPath: string
126+
): Promise<void> {
127+
const rmTemp = () => fs.rmSync(tempPath, { force: true })
128+
try {
129+
if (tempPath) {
130+
scriptPath = tempPath
131+
await fs.writeFile(tempPath, script)
151132
}
152133

153-
if (script.length > 0) {
154-
await runScript(script, ext)
155-
return true
134+
if (argv.install) {
135+
await installDeps(
136+
parseDeps(script),
137+
path.dirname(scriptPath),
138+
argv.registry
139+
)
156140
}
157-
}
158-
return false
159-
}
160141

161-
export async function scriptFromHttp(remote: string, _ext?: string) {
162-
const res = await fetch(remote)
163-
if (!res.ok) {
164-
console.error(`Error: Can't get ${remote}`)
165-
process.exit(1)
166-
}
167-
const script = await res.text()
168-
const pathname = new URL(remote).pathname
169-
const { name, ext } = path.parse(pathname)
170-
const filepath = getFilepath($.cwd, name, _ext || ext)
171-
await writeAndImport(script, filepath)
172-
}
142+
injectGlobalRequire(scriptPath)
143+
process.once('exit', rmTemp)
173144

174-
export async function writeAndImport(
175-
script: string | Buffer,
176-
filepath: string,
177-
origin = filepath
178-
) {
179-
await fs.writeFile(filepath, script)
180-
try {
181-
process.once('exit', () => fs.rmSync(filepath, { force: true }))
182-
await importPath(filepath, origin)
145+
// TODO: fix unanalyzable-dynamic-import to work correctly with jsr.io
146+
await import(url.pathToFileURL(scriptPath).toString())
183147
} finally {
184-
await fs.rm(filepath)
148+
rmTemp()
185149
}
186150
}
187151

188-
export async function importPath(
189-
filepath: string,
190-
origin = filepath
191-
): Promise<void> {
192-
const contents = await fs.readFile(filepath, 'utf8')
193-
const { ext, base, dir } = path.parse(filepath)
194-
const tempFilename = getFilepath(dir, base)
152+
async function readScript() {
153+
const [firstArg] = argv._
154+
let script = ''
155+
let scriptPath = ''
156+
let tempPath = ''
157+
let argSlice = 1
158+
159+
if (argv.eval) {
160+
argSlice = 0
161+
script = argv.eval
162+
tempPath = getFilepath($.cwd, 'zx', argv.ext)
163+
} else if (!firstArg || firstArg === '-') {
164+
script = await readScriptFromStdin()
165+
tempPath = getFilepath($.cwd, 'zx', argv.ext)
166+
if (script.length === 0) {
167+
printUsage()
168+
process.exitCode = 1
169+
throw new Error('No script provided')
170+
}
171+
} else if (/^https?:/.test(firstArg)) {
172+
const { name, ext = argv.ext } = path.parse(new URL(firstArg).pathname)
173+
script = await readScriptFromHttp(firstArg)
174+
tempPath = getFilepath($.cwd, name, ext)
175+
} else {
176+
script = await fs.readFile(firstArg, 'utf8')
177+
scriptPath = firstArg.startsWith('file:')
178+
? url.fileURLToPath(firstArg)
179+
: path.resolve(firstArg)
180+
}
195181

182+
const { ext, base, dir } = path.parse(tempPath || scriptPath)
196183
if (ext === '') {
197-
return writeAndImport(contents, tempFilename, origin)
184+
tempPath = getFilepath(dir, base)
198185
}
199186
if (ext === '.md') {
200-
return writeAndImport(transformMarkdown(contents), tempFilename, origin)
201-
}
202-
if (argv.install) {
203-
const deps = parseDeps(contents)
204-
await installDeps(deps, dir, argv.registry)
187+
script = transformMarkdown(script)
188+
tempPath = getFilepath(dir, base)
205189
}
190+
if (argSlice) updateArgv(argv._.slice(argSlice))
191+
192+
return { script, scriptPath, tempPath }
193+
}
194+
195+
async function readScriptFromStdin(): Promise<string> {
196+
return !process.stdin.isTTY ? stdin() : ''
197+
}
206198

207-
injectGlobalRequire(origin)
208-
// TODO: fix unanalyzable-dynamic-import to work correctly with jsr.io
209-
await import(url.pathToFileURL(filepath).toString())
199+
async function readScriptFromHttp(remote: string): Promise<string> {
200+
const res = await fetch(remote)
201+
if (!res.ok) {
202+
console.error(`Error: Can't get ${remote}`)
203+
process.exit(1)
204+
}
205+
return res.text()
210206
}
211207

212208
export function injectGlobalRequire(origin: string) {

test/cli.test.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ describe('cli', () => {
191191
const port = await getPort()
192192
const server = await getServer([resp]).start(port)
193193
const out =
194-
await $`node build/cli.js --verbose http://127.0.0.1:${port}/echo.mjs`
194+
await $`node build/cli.js --verbose http://127.0.0.1:${port}/script.mjs`
195195
assert.match(out.stderr, /test/)
196196
await server.stop()
197197
})
@@ -204,6 +204,16 @@ describe('cli', () => {
204204
await server.stop()
205205
})
206206

207+
test('scripts (md) from https', async () => {
208+
const resp = await fs.readFile(path.resolve('test/fixtures/md.http'))
209+
const port = await getPort()
210+
const server = await getServer([resp]).start(port)
211+
const out =
212+
await $`node build/cli.js --verbose http://127.0.0.1:${port}/script.md`
213+
assert.match(out.stderr, /md/)
214+
await server.stop()
215+
})
216+
207217
test('scripts with no extension', async () => {
208218
await $`node build/cli.js test/fixtures/no-extension`
209219
assert.ok(
@@ -237,10 +247,6 @@ describe('cli', () => {
237247
await $`node build/cli.js test/fixtures/markdown.md`
238248
})
239249

240-
test('markdown scripts are working', async () => {
241-
await $`node build/cli.js test/fixtures/markdown.md`
242-
})
243-
244250
test('markdown scripts are working for CRLF', async () => {
245251
const p = await $`node build/cli.js test/fixtures/markdown-crlf.md`
246252
assert.ok(p.stdout.includes('Hello, world!'))

test/export.test.js

-5
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,12 @@ describe('cli', () => {
7575
assert.equal(typeof cli.argv.v, 'boolean', 'cli.argv.v')
7676
assert.equal(typeof cli.argv.verbose, 'boolean', 'cli.argv.verbose')
7777
assert.equal(typeof cli.argv.version, 'boolean', 'cli.argv.version')
78-
assert.equal(typeof cli.importPath, 'function', 'cli.importPath')
7978
assert.equal(typeof cli.injectGlobalRequire, 'function', 'cli.injectGlobalRequire')
8079
assert.equal(typeof cli.isMain, 'function', 'cli.isMain')
8180
assert.equal(typeof cli.main, 'function', 'cli.main')
8281
assert.equal(typeof cli.normalizeExt, 'function', 'cli.normalizeExt')
8382
assert.equal(typeof cli.printUsage, 'function', 'cli.printUsage')
84-
assert.equal(typeof cli.runScript, 'function', 'cli.runScript')
85-
assert.equal(typeof cli.scriptFromHttp, 'function', 'cli.scriptFromHttp')
86-
assert.equal(typeof cli.scriptFromStdin, 'function', 'cli.scriptFromStdin')
8783
assert.equal(typeof cli.transformMarkdown, 'function', 'cli.transformMarkdown')
88-
assert.equal(typeof cli.writeAndImport, 'function', 'cli.writeAndImport')
8984
})
9085
})
9186

test/fixtures/md.http

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
HTTP/1.1 200 OK
2+
Content-Type: plain/text; charset=UTF-8
3+
Content-Length: 15
4+
Server: netcat!
5+
6+
# Title
7+
```js
8+
$`echo 'md'`
9+
```

0 commit comments

Comments
 (0)