2023-04-08 01:17:17 +00:00
|
|
|
async function test(name, fn) {
|
|
|
|
try {
|
|
|
|
await fn(await import('node:assert/strict'))
|
|
|
|
console.log(`✓ ${name}`)
|
|
|
|
} catch (err) {
|
|
|
|
console.error(`✗ ${name}`)
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function run(json, code = '') {
|
|
|
|
const {spawnSync} = await import('node:child_process')
|
2023-04-18 12:10:17 +00:00
|
|
|
return spawnSync(`echo '${typeof json === 'string' ? json : JSON.stringify(json)}' | node index.js ${code}`, {
|
2023-04-08 01:17:17 +00:00
|
|
|
stdio: 'pipe',
|
|
|
|
encoding: 'utf8',
|
|
|
|
shell: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-09-14 10:13:23 +00:00
|
|
|
async function runSimple(code = '') {
|
|
|
|
const {spawnSync} = await import('node:child_process')
|
|
|
|
return spawnSync(`node index.js ${code}`, {
|
|
|
|
stdio: 'pipe',
|
|
|
|
encoding: 'utf8',
|
|
|
|
shell: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-04-08 01:17:17 +00:00
|
|
|
void async function main() {
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('properly formatted', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const {stdout} = await run([{'greeting': 'hello world'}])
|
2023-04-18 12:10:17 +00:00
|
|
|
t.deepEqual(stdout, '[\n {\n "greeting": "hello world"\n }\n]\n')
|
2023-04-08 01:17:17 +00:00
|
|
|
})
|
|
|
|
|
2023-09-01 09:02:24 +00:00
|
|
|
await test('format - escape newline', async t => {
|
2023-09-07 14:36:21 +00:00
|
|
|
const {stdout} = await run(`{"foo": "bar\\\\nbaz"}`)
|
2023-09-01 09:02:24 +00:00
|
|
|
t.equal(stdout, '{\n "foo": "bar\\nbaz"\n}\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('parseJson - valid json', async t => {
|
|
|
|
const obj = {a: 2.3e100, b: 'str', c: null, d: false, e: [1, 2, 3]}
|
|
|
|
const {stdout, stderr} = await run(obj)
|
|
|
|
t.equal(stderr, '')
|
|
|
|
t.equal(stdout, JSON.stringify(obj, null, 2) + '\n')
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('parseJson - invalid json', async t => {
|
|
|
|
const {stderr, status} = await run('{invalid}')
|
|
|
|
t.equal(status, 1)
|
|
|
|
t.ok(stderr.includes('SyntaxError'))
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('parseJson - invalid number', async t => {
|
|
|
|
const {stderr, status} = await run('{"num": 12.3.4}')
|
|
|
|
t.equal(status, 1)
|
|
|
|
t.ok(stderr.includes('SyntaxError'))
|
|
|
|
})
|
|
|
|
|
2023-09-07 14:36:21 +00:00
|
|
|
await test('parseJson - string control chars', async t => {
|
|
|
|
const {stderr, status} = await run('"\t"')
|
|
|
|
t.equal(status, 1)
|
|
|
|
t.ok(stderr.includes('SyntaxError'))
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('parseJson - numbers', async t => {
|
|
|
|
t.equal((await run('1.2e300')).stdout, '1.2e+300\n')
|
|
|
|
t.equal((await run('123456789012345678901234567890')).stdout, '123456789012345678901234567890\n')
|
|
|
|
t.equal((await run('23')).stdout, '23\n')
|
|
|
|
t.equal((await run('0')).stdout, '0\n')
|
|
|
|
t.equal((await run('0e+2')).stdout, '0\n')
|
|
|
|
t.equal((await run('0e+2')).stdout, '0\n')
|
|
|
|
t.equal((await run('0.0')).stdout, '0\n')
|
|
|
|
t.equal((await run('-0')).stdout, '0\n')
|
|
|
|
t.equal((await run('2.3')).stdout, '2.3\n')
|
|
|
|
t.equal((await run('2300e3')).stdout, '2300000\n')
|
|
|
|
t.equal((await run('2300e+3')).stdout, '2300000\n')
|
|
|
|
t.equal((await run('-2')).stdout, '-2\n')
|
|
|
|
t.equal((await run('2e-3')).stdout, '0.002\n')
|
|
|
|
t.equal((await run('2.3e-3')).stdout, '0.0023\n')
|
|
|
|
})
|
|
|
|
|
2023-04-19 10:01:54 +00:00
|
|
|
await test('parseJson - object tailing comma', async t => {
|
|
|
|
const {stdout} = await run('{"a": 1,}')
|
|
|
|
t.equal(stdout, '{\n "a": 1\n}\n')
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('parseJson - array tailing comma', async t => {
|
|
|
|
const {stdout} = await run('[1,]')
|
|
|
|
t.equal(stdout, '[\n 1\n]\n')
|
|
|
|
})
|
|
|
|
|
2023-04-19 10:11:54 +00:00
|
|
|
await test('parseJson - comments', async t => {
|
|
|
|
const {stdout} = await run('/* comment */ [1 // comment\n]')
|
|
|
|
t.equal(stdout, '[\n 1\n]\n')
|
|
|
|
})
|
|
|
|
|
2024-03-08 23:23:32 +00:00
|
|
|
await test('parseYaml', async t => {
|
|
|
|
const {stdout} = await run('- foo\n- bar', '--yaml')
|
|
|
|
t.equal(stdout, '[\n "foo",\n "bar"\n]\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - anonymous function', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const {stdout} = await run({'key': 'value'}, '\'function (x) { return x.key }\'')
|
|
|
|
t.equal(stdout, 'value\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - arrow function', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const {stdout} = await run({'key': 'value'}, '\'x => x.key\'')
|
|
|
|
t.equal(stdout, 'value\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - arrow function with param brackets', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run({'key': 'value'}, `'(x) => x.key'`)
|
2023-04-08 01:17:17 +00:00
|
|
|
t.equal(stdout, 'value\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - this is json', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run([1, 2, 3, 4, 5], `'this.map(x => x * this.length)'`)
|
2023-04-08 01:17:17 +00:00
|
|
|
t.deepEqual(JSON.parse(stdout), [5, 10, 15, 20, 25])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - chain works', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run({'items': ['foo', 'bar']}, `'this.items' '.' 'x => x[1]'`)
|
2023-04-08 01:17:17 +00:00
|
|
|
t.equal(stdout, 'bar\n')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - map works', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run([1, 2, 3], `'map(x * 2)'`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), [2, 4, 6])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - map works with dot', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run([{foo: 'bar'}], `'map(.foo)'`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), ['bar'])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - map works with func', async t => {
|
2023-04-10 11:06:34 +00:00
|
|
|
const {stdout} = await run([{foo: 'bar'}], `'map(x => x.foo)'`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), ['bar'])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - map passes index', async t => {
|
2023-04-11 08:46:24 +00:00
|
|
|
const {stdout} = await run([1, 2, 3], `'map((x, i) => x * i)'`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), [0, 2, 6])
|
|
|
|
})
|
|
|
|
|
2023-11-10 11:06:52 +00:00
|
|
|
await test('transform - @ works', async t => {
|
|
|
|
const {stdout} = await run([1, 2, 3], `'@x * 2'`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), [2, 4, 6])
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('transform - @ works with dot', async t => {
|
|
|
|
const {stdout} = await run([{foo: 'bar'}], `@.foo`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), ['bar'])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - flat map works', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const {stdout} = await run({master: {foo: [{bar: [{val: 1}]}]}}, '.master.foo[].bar[].val')
|
|
|
|
t.deepEqual(JSON.parse(stdout), [1])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - flat map works on the first level', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const {stdout} = await run([{val: 1}, {val: 2}], '.[].val')
|
|
|
|
t.deepEqual(JSON.parse(stdout), [1, 2])
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - sort & uniq', async t => {
|
2023-04-10 11:09:08 +00:00
|
|
|
const {stdout} = await run([2, 2, 3, 1], `sort uniq`)
|
|
|
|
t.deepEqual(JSON.parse(stdout), [1, 2, 3])
|
|
|
|
})
|
|
|
|
|
2023-04-19 09:04:08 +00:00
|
|
|
await test('transform - skip', async t => {
|
|
|
|
const {stdout} = await run(42, `skip`)
|
|
|
|
t.equal(stdout, '')
|
|
|
|
})
|
|
|
|
|
2023-04-18 12:10:17 +00:00
|
|
|
await test('transform - invalid code argument', async t => {
|
2023-04-08 01:17:17 +00:00
|
|
|
const json = {foo: 'bar'}
|
|
|
|
const code = '".foo.toUpperCase("'
|
|
|
|
const {stderr, status} = await run(json, code)
|
2023-04-10 11:06:34 +00:00
|
|
|
t.equal(status, 1)
|
2023-04-08 01:17:17 +00:00
|
|
|
t.ok(stderr.includes(`SyntaxError: Unexpected token '}'`))
|
|
|
|
})
|
2023-04-12 09:01:40 +00:00
|
|
|
|
2023-04-18 22:30:07 +00:00
|
|
|
await test('stream - objects', async t => {
|
2023-04-18 12:10:17 +00:00
|
|
|
const {stdout} = await run('{"foo": "bar"}\n{"foo": "baz"}')
|
|
|
|
t.equal(stdout, '{\n "foo": "bar"\n}\n{\n "foo": "baz"\n}\n')
|
2023-04-12 09:01:40 +00:00
|
|
|
})
|
2023-04-18 22:35:52 +00:00
|
|
|
|
2023-04-18 22:30:07 +00:00
|
|
|
await test('stream - strings', async t => {
|
|
|
|
const {stdout} = await run('"foo"\n"bar"')
|
|
|
|
t.equal(stdout, 'foo\nbar\n')
|
|
|
|
})
|
2023-04-18 12:10:17 +00:00
|
|
|
|
2023-04-18 22:30:07 +00:00
|
|
|
await test('flags - raw flag', async t => {
|
|
|
|
const {stdout} = await run(123, `-r 'x => typeof x'`)
|
|
|
|
t.equal(stdout, 'string\n')
|
|
|
|
})
|
2023-04-19 09:02:32 +00:00
|
|
|
|
|
|
|
await test('flags - slurp flag', async t => {
|
|
|
|
const {stdout} = await run('{"foo": "bar"}\n{"foo": "baz"}', `-s '.[1].foo'`)
|
|
|
|
t.equal(stdout, 'baz\n')
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('flags - slurp raw', async t => {
|
|
|
|
const {stdout} = await run('hello,\nworld!', `-rs '.join(" ")'`)
|
|
|
|
t.equal(stdout, 'hello, world!\n')
|
|
|
|
})
|
2023-09-14 10:13:23 +00:00
|
|
|
|
|
|
|
await test('cli - first arg is file', async t => {
|
|
|
|
const {stdout} = await runSimple(`package.json .name`)
|
|
|
|
t.equal(stdout, 'fx\n')
|
|
|
|
})
|
|
|
|
|
|
|
|
await test('cli - last arg is file', async t => {
|
|
|
|
const {stdout} = await runSimple(`.name package.json`)
|
|
|
|
t.equal(stdout, 'fx\n')
|
|
|
|
})
|
2023-04-08 01:17:17 +00:00
|
|
|
}()
|