Skip to content

Commit d9c4f9a

Browse files
pafik13antongolub
andauthored
feat: provide configuration via env vars (google#988)
* fear(util): add extractFromEnv * chore(config): increase size limits * test(core): clean up env var some tests * test(util): cover extractFromEnv * feat(util): remove extractFromEnv and snakeToCamel, add camelToSnake * feat(core): implement getZxDefaults * test: add tests for getZxDefaults and camelToSnake * chore: up size limit * feat(util): add snakeToCamel * refactor(core): remove extra param from getZxDefaults * test(util): cover snakeToCamel * test(core): actualize getZxDefaults * feat(core): extend types in getZxDefaults and use it as allowed list * test(core): update suites * chore(core): swap getZxDefaults definition and usage for better git blame * chore(core): remove one tab for defaults * chore: update .size-limit.json --------- Co-authored-by: Anton Golub <antongolub@antongolub.com> Co-authored-by: Anton Golub <golub.anton@gmail.com>
1 parent 3e5bcb0 commit d9c4f9a

File tree

5 files changed

+109
-5
lines changed

5 files changed

+109
-5
lines changed

.size-limit.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
{
33
"name": "zx/core",
44
"path": ["build/core.cjs", "build/util.cjs", "build/vendor-core.cjs"],
5-
"limit": "74 kB",
5+
"limit": "76 kB",
66
"brotli": false,
77
"gzip": false
88
},
99
{
1010
"name": "zx/index",
1111
"path": "build/*.{js,cjs}",
12-
"limit": "801 kB",
12+
"limit": "803 kB",
1313
"brotli": false,
1414
"gzip": false
1515
},

src/core.ts

+36-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
proxyOverride,
5353
quote,
5454
quotePowerShell,
55+
snakeToCamel,
5556
} from './util.js'
5657

5758
const CWD = Symbol('processCwd')
@@ -81,7 +82,7 @@ export interface Options {
8182
verbose: boolean
8283
sync: boolean
8384
env: NodeJS.ProcessEnv
84-
shell: string | boolean
85+
shell: string | true
8586
nothrow: boolean
8687
prefix: string
8788
postfix: string
@@ -97,8 +98,9 @@ export interface Options {
9798
killSignal?: NodeJS.Signals
9899
halt?: boolean
99100
}
101+
100102
// prettier-ignore
101-
export const defaults: Options = {
103+
export const defaults: Options = getZxDefaults({
102104
[CWD]: process.cwd(),
103105
[SYNC]: false,
104106
verbose: false,
@@ -118,6 +120,38 @@ export const defaults: Options = {
118120
kill,
119121
killSignal: SIGTERM,
120122
timeoutSignal: SIGTERM,
123+
})
124+
125+
export function getZxDefaults(
126+
defs: Options,
127+
prefix: string = 'ZX_',
128+
env = process.env
129+
) {
130+
const types: Record<PropertyKey, Array<'string' | 'boolean'>> = {
131+
preferLocal: ['string', 'boolean'],
132+
detached: ['boolean'],
133+
verbose: ['boolean'],
134+
quiet: ['boolean'],
135+
timeout: ['string'],
136+
timeoutSignal: ['string'],
137+
prefix: ['string'],
138+
postfix: ['string'],
139+
}
140+
141+
const o = Object.entries(env).reduce<Record<string, string | boolean>>(
142+
(m, [k, v]) => {
143+
if (v && k.startsWith(prefix)) {
144+
const _k = snakeToCamel(k.slice(prefix.length))
145+
const _v = { true: true, false: false }[v.toLowerCase()] ?? v
146+
if (_k in types && types[_k].some((type) => type === typeof _v)) {
147+
m[_k] = _v
148+
}
149+
}
150+
return m
151+
},
152+
{}
153+
)
154+
return Object.assign(defs, o)
121155
}
122156

123157
// prettier-ignore

src/util.ts

+15
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,18 @@ export const proxyOverride = <T extends object>(
462462
)
463463
},
464464
}) as T
465+
466+
// https://stackoverflow.com/a/7888303
467+
export const camelToSnake = (str: string) =>
468+
str
469+
.split(/(?=[A-Z])/)
470+
.map((s) => s.toUpperCase())
471+
.join('_')
472+
473+
// https://stackoverflow.com/a/61375162
474+
export const snakeToCamel = (str: string) =>
475+
str
476+
.toLowerCase()
477+
.replace(/([-_][a-z])/g, (group) =>
478+
group.toUpperCase().replace('-', '').replace('_', '')
479+
)

test/core.test.js

+40-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,47 @@ import { basename } from 'node:path'
1919
import { WriteStream } from 'node:fs'
2020
import { Readable, Transform, Writable } from 'node:stream'
2121
import { Socket } from 'node:net'
22-
import { ProcessPromise, ProcessOutput } from '../build/index.js'
22+
import { ProcessPromise, ProcessOutput, getZxDefaults } from '../build/index.js'
2323
import '../build/globals.js'
2424

2525
describe('core', () => {
26+
describe('getZxDefaults', () => {
27+
test('verbose rewrite', async () => {
28+
const defaults = getZxDefaults({ verbose: false }, 'ZX_', {
29+
ZX_VERBOSE: 'true',
30+
})
31+
assert.equal(defaults.verbose, true)
32+
})
33+
34+
test('verbose ignore', async () => {
35+
const defaults = getZxDefaults({ verbose: false }, 'ZX_', {
36+
ZX_VERBOSE: 'true123',
37+
})
38+
assert.equal(defaults.verbose, false)
39+
})
40+
41+
test('input ignored', async () => {
42+
const defaults = getZxDefaults({}, 'ZX_', {
43+
ZX_INPUT: 'input',
44+
})
45+
assert.equal(defaults.input, undefined)
46+
})
47+
48+
test('preferLocal rewrite boolean', async () => {
49+
const defaults = getZxDefaults({ preferLocal: false }, 'ZX_', {
50+
ZX_PREFER_LOCAL: 'true',
51+
})
52+
assert.equal(defaults.preferLocal, true)
53+
})
54+
55+
test('preferLocal rewrite string', async () => {
56+
const defaults = getZxDefaults({ preferLocal: false }, 'ZX_', {
57+
ZX_PREFER_LOCAL: 'true123',
58+
})
59+
assert.equal(defaults.preferLocal, 'true123')
60+
})
61+
})
62+
2663
describe('$', () => {
2764
test('is a regular function', async () => {
2865
const _$ = $.bind(null)
@@ -42,12 +79,14 @@ describe('core', () => {
4279
process.env.ZX_TEST_FOO = 'foo'
4380
const foo = await $`echo $ZX_TEST_FOO`
4481
assert.equal(foo.stdout, 'foo\n')
82+
delete process.env.ZX_TEST_FOO
4583
})
4684

4785
test('env vars are safe to pass', async () => {
4886
process.env.ZX_TEST_BAR = 'hi; exit 1'
4987
const bar = await $`echo $ZX_TEST_BAR`
5088
assert.equal(bar.stdout, 'hi; exit 1\n')
89+
delete process.env.ZX_TEST_BAR
5190
})
5291

5392
test('arguments are quoted', async () => {

test/util.test.js

+16
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import {
3131
tempdir,
3232
tempfile,
3333
preferLocalBin,
34+
camelToSnake,
35+
snakeToCamel,
3436
} from '../build/util.js'
3537

3638
describe('util', () => {
@@ -191,3 +193,17 @@ test('preferLocalBin()', () => {
191193
`${process.cwd()}/node_modules/.bin:${process.cwd()}:${env.PATH}`
192194
)
193195
})
196+
197+
test('camelToSnake()', () => {
198+
assert.equal(camelToSnake('verbose'), 'VERBOSE')
199+
assert.equal(camelToSnake('nothrow'), 'NOTHROW')
200+
assert.equal(camelToSnake('preferLocal'), 'PREFER_LOCAL')
201+
assert.equal(camelToSnake('someMoreBigStr'), 'SOME_MORE_BIG_STR')
202+
})
203+
204+
test('snakeToCamel()', () => {
205+
assert.equal(snakeToCamel('VERBOSE'), 'verbose')
206+
assert.equal(snakeToCamel('NOTHROW'), 'nothrow')
207+
assert.equal(snakeToCamel('PREFER_LOCAL'), 'preferLocal')
208+
assert.equal(snakeToCamel('SOME_MORE_BIG_STR'), 'someMoreBigStr')
209+
})

0 commit comments

Comments
 (0)