Commit d9c4f9a
Changed files (5)
src/core.ts
@@ -52,6 +52,7 @@ import {
proxyOverride,
quote,
quotePowerShell,
+ snakeToCamel,
} from './util.js'
const CWD = Symbol('processCwd')
@@ -81,7 +82,7 @@ export interface Options {
verbose: boolean
sync: boolean
env: NodeJS.ProcessEnv
- shell: string | boolean
+ shell: string | true
nothrow: boolean
prefix: string
postfix: string
@@ -97,8 +98,9 @@ export interface Options {
killSignal?: NodeJS.Signals
halt?: boolean
}
+
// prettier-ignore
-export const defaults: Options = {
+export const defaults: Options = getZxDefaults({
[CWD]: process.cwd(),
[SYNC]: false,
verbose: false,
@@ -118,6 +120,38 @@ export const defaults: Options = {
kill,
killSignal: SIGTERM,
timeoutSignal: SIGTERM,
+})
+
+export function getZxDefaults(
+ defs: Options,
+ prefix: string = 'ZX_',
+ env = process.env
+) {
+ const types: Record<PropertyKey, Array<'string' | 'boolean'>> = {
+ preferLocal: ['string', 'boolean'],
+ detached: ['boolean'],
+ verbose: ['boolean'],
+ quiet: ['boolean'],
+ timeout: ['string'],
+ timeoutSignal: ['string'],
+ prefix: ['string'],
+ postfix: ['string'],
+ }
+
+ const o = Object.entries(env).reduce<Record<string, string | boolean>>(
+ (m, [k, v]) => {
+ if (v && k.startsWith(prefix)) {
+ const _k = snakeToCamel(k.slice(prefix.length))
+ const _v = { true: true, false: false }[v.toLowerCase()] ?? v
+ if (_k in types && types[_k].some((type) => type === typeof _v)) {
+ m[_k] = _v
+ }
+ }
+ return m
+ },
+ {}
+ )
+ return Object.assign(defs, o)
}
// prettier-ignore
src/util.ts
@@ -462,3 +462,18 @@ export const proxyOverride = <T extends object>(
)
},
}) as T
+
+// https://stackoverflow.com/a/7888303
+export const camelToSnake = (str: string) =>
+ str
+ .split(/(?=[A-Z])/)
+ .map((s) => s.toUpperCase())
+ .join('_')
+
+// https://stackoverflow.com/a/61375162
+export const snakeToCamel = (str: string) =>
+ str
+ .toLowerCase()
+ .replace(/([-_][a-z])/g, (group) =>
+ group.toUpperCase().replace('-', '').replace('_', '')
+ )
test/core.test.js
@@ -19,10 +19,47 @@ import { basename } from 'node:path'
import { WriteStream } from 'node:fs'
import { Readable, Transform, Writable } from 'node:stream'
import { Socket } from 'node:net'
-import { ProcessPromise, ProcessOutput } from '../build/index.js'
+import { ProcessPromise, ProcessOutput, getZxDefaults } from '../build/index.js'
import '../build/globals.js'
describe('core', () => {
+ describe('getZxDefaults', () => {
+ test('verbose rewrite', async () => {
+ const defaults = getZxDefaults({ verbose: false }, 'ZX_', {
+ ZX_VERBOSE: 'true',
+ })
+ assert.equal(defaults.verbose, true)
+ })
+
+ test('verbose ignore', async () => {
+ const defaults = getZxDefaults({ verbose: false }, 'ZX_', {
+ ZX_VERBOSE: 'true123',
+ })
+ assert.equal(defaults.verbose, false)
+ })
+
+ test('input ignored', async () => {
+ const defaults = getZxDefaults({}, 'ZX_', {
+ ZX_INPUT: 'input',
+ })
+ assert.equal(defaults.input, undefined)
+ })
+
+ test('preferLocal rewrite boolean', async () => {
+ const defaults = getZxDefaults({ preferLocal: false }, 'ZX_', {
+ ZX_PREFER_LOCAL: 'true',
+ })
+ assert.equal(defaults.preferLocal, true)
+ })
+
+ test('preferLocal rewrite string', async () => {
+ const defaults = getZxDefaults({ preferLocal: false }, 'ZX_', {
+ ZX_PREFER_LOCAL: 'true123',
+ })
+ assert.equal(defaults.preferLocal, 'true123')
+ })
+ })
+
describe('$', () => {
test('is a regular function', async () => {
const _$ = $.bind(null)
@@ -42,12 +79,14 @@ describe('core', () => {
process.env.ZX_TEST_FOO = 'foo'
const foo = await $`echo $ZX_TEST_FOO`
assert.equal(foo.stdout, 'foo\n')
+ delete process.env.ZX_TEST_FOO
})
test('env vars are safe to pass', async () => {
process.env.ZX_TEST_BAR = 'hi; exit 1'
const bar = await $`echo $ZX_TEST_BAR`
assert.equal(bar.stdout, 'hi; exit 1\n')
+ delete process.env.ZX_TEST_BAR
})
test('arguments are quoted', async () => {
test/util.test.js
@@ -31,6 +31,8 @@ import {
tempdir,
tempfile,
preferLocalBin,
+ camelToSnake,
+ snakeToCamel,
} from '../build/util.js'
describe('util', () => {
@@ -191,3 +193,17 @@ test('preferLocalBin()', () => {
`${process.cwd()}/node_modules/.bin:${process.cwd()}:${env.PATH}`
)
})
+
+test('camelToSnake()', () => {
+ assert.equal(camelToSnake('verbose'), 'VERBOSE')
+ assert.equal(camelToSnake('nothrow'), 'NOTHROW')
+ assert.equal(camelToSnake('preferLocal'), 'PREFER_LOCAL')
+ assert.equal(camelToSnake('someMoreBigStr'), 'SOME_MORE_BIG_STR')
+})
+
+test('snakeToCamel()', () => {
+ assert.equal(snakeToCamel('VERBOSE'), 'verbose')
+ assert.equal(snakeToCamel('NOTHROW'), 'nothrow')
+ assert.equal(snakeToCamel('PREFER_LOCAL'), 'preferLocal')
+ assert.equal(snakeToCamel('SOME_MORE_BIG_STR'), 'someMoreBigStr')
+})
.size-limit.json
@@ -2,14 +2,14 @@
{
"name": "zx/core",
"path": ["build/core.cjs", "build/util.cjs", "build/vendor-core.cjs"],
- "limit": "74 kB",
+ "limit": "76 kB",
"brotli": false,
"gzip": false
},
{
"name": "zx/index",
"path": "build/*.{js,cjs}",
- "limit": "801 kB",
+ "limit": "803 kB",
"brotli": false,
"gzip": false
},