fx 20.0.2 → 24.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -82
- package/index.js +82 -157
- package/package.json +8 -43
- package/LICENSE +0 -21
- package/bang.js +0 -79
- package/config.js +0 -26
- package/find.js +0 -35
- package/fx.js +0 -717
- package/print.js +0 -117
- package/reduce.js +0 -51
- package/std.js +0 -33
- package/stream.js +0 -84
- package/test.js +0 -85
package/print.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const indent = require('indent-string')
|
|
3
|
-
const config = require('./config')
|
|
4
|
-
|
|
5
|
-
function format(value, style, highlightStyle, regexp, transform = x => x) {
|
|
6
|
-
if (!regexp) {
|
|
7
|
-
return style(transform(value))
|
|
8
|
-
}
|
|
9
|
-
const marked = value
|
|
10
|
-
.replace(regexp, s => '<highlight>' + s + '<highlight>')
|
|
11
|
-
|
|
12
|
-
return transform(marked)
|
|
13
|
-
.split(/<highlight>/g)
|
|
14
|
-
.map((s, i) => i % 2 !== 0 ? highlightStyle(s) : style(s))
|
|
15
|
-
.join('')
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function print(input, options = {}) {
|
|
19
|
-
const {expanded, highlight, currentPath} = options
|
|
20
|
-
const index = new Map()
|
|
21
|
-
let row = 0
|
|
22
|
-
|
|
23
|
-
function doPrint(v, path = '') {
|
|
24
|
-
index.set(row, path)
|
|
25
|
-
|
|
26
|
-
// Code for highlighting parts become cumbersome.
|
|
27
|
-
// Maybe we should refactor this part.
|
|
28
|
-
const highlightStyle = (currentPath === path) ? config.highlightCurrent : config.highlight
|
|
29
|
-
const formatStyle = (v, style) => format(v, style, highlightStyle, highlight)
|
|
30
|
-
const formatText = (v, style, path) => {
|
|
31
|
-
const highlightStyle = (currentPath === path) ? config.highlightCurrent : config.highlight
|
|
32
|
-
return format(v, style, highlightStyle, highlight, JSON.stringify)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const eol = () => {
|
|
36
|
-
row++
|
|
37
|
-
return '\n'
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (typeof v === 'undefined') {
|
|
41
|
-
return void 0
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (v === null) {
|
|
45
|
-
return formatStyle(JSON.stringify(v), config.null)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (typeof v === 'number' && Number.isFinite(v)) {
|
|
49
|
-
return formatStyle(JSON.stringify(v), config.number)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (typeof v === 'object' && v.isLosslessNumber) {
|
|
53
|
-
return formatStyle(v.toString(), config.number)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (typeof v === 'boolean') {
|
|
57
|
-
return formatStyle(JSON.stringify(v), config.boolean)
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (typeof v === 'string') {
|
|
62
|
-
return formatText(v, config.string, path)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (Array.isArray(v)) {
|
|
66
|
-
let output = config.bracket('[')
|
|
67
|
-
const len = v.length
|
|
68
|
-
|
|
69
|
-
if (len > 0) {
|
|
70
|
-
if (expanded && !expanded.has(path)) {
|
|
71
|
-
output += '\u2026'
|
|
72
|
-
} else {
|
|
73
|
-
output += eol()
|
|
74
|
-
let i = 0
|
|
75
|
-
for (let item of v) {
|
|
76
|
-
const value = typeof item === 'undefined' ? null : item // JSON.stringify compatibility
|
|
77
|
-
output += indent(doPrint(value, path + '[' + i + ']'), config.space)
|
|
78
|
-
output += i++ < len - 1 ? config.comma(',') : ''
|
|
79
|
-
output += eol()
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return output + config.bracket(']')
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (typeof v === 'object' && v.constructor === Object) {
|
|
88
|
-
let output = config.bracket('{')
|
|
89
|
-
|
|
90
|
-
const entries = Object.entries(v).filter(([key, value]) => typeof value !== 'undefined') // JSON.stringify compatibility
|
|
91
|
-
const len = entries.length
|
|
92
|
-
|
|
93
|
-
if (len > 0) {
|
|
94
|
-
if (expanded && !expanded.has(path)) {
|
|
95
|
-
output += '\u2026'
|
|
96
|
-
} else {
|
|
97
|
-
output += eol()
|
|
98
|
-
let i = 0
|
|
99
|
-
for (let [key, value] of entries) {
|
|
100
|
-
const part = formatText(key, config.key, path + '.' + key) + config.colon(':') + ' ' + doPrint(value, path + '.' + key)
|
|
101
|
-
output += indent(part, config.space)
|
|
102
|
-
output += i++ < len - 1 ? config.comma(',') : ''
|
|
103
|
-
output += eol()
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return output + config.bracket('}')
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return JSON.stringify(v, null, config.space)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return [doPrint(input), index]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = print
|
package/reduce.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const JSON = require('lossless-json') // override JSON for user's code
|
|
3
|
-
|
|
4
|
-
function reduce(json, code) {
|
|
5
|
-
if (process.env.FX_APPLY) {
|
|
6
|
-
return global[process.env.FX_APPLY](code)(json)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if ('.' === code) {
|
|
10
|
-
return json
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if ('?' === code) {
|
|
14
|
-
return Object.keys(json)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (/^(\.\w*)+\[]/.test(code)) {
|
|
18
|
-
function fold(s) {
|
|
19
|
-
if (s.length === 1) {
|
|
20
|
-
return 'x => x' + s[0]
|
|
21
|
-
}
|
|
22
|
-
let obj = s.shift()
|
|
23
|
-
obj = obj === '.' ? 'x' : 'x' + obj
|
|
24
|
-
return `x => Object.values(${obj}).flatMap(${fold(s)})`
|
|
25
|
-
}
|
|
26
|
-
code = fold(code.split('[]'))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (/^\.\[/.test(code)) {
|
|
30
|
-
return eval(`function fn() {
|
|
31
|
-
return this${code.substring(1)}
|
|
32
|
-
}; fn`).call(json)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (/^\./.test(code)) {
|
|
36
|
-
return eval(`function fn() {
|
|
37
|
-
return this${code}
|
|
38
|
-
}; fn`).call(json)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const fn = eval(`function fn() {
|
|
42
|
-
return ${code}
|
|
43
|
-
}; fn`).call(json)
|
|
44
|
-
|
|
45
|
-
if (typeof fn === 'function') {
|
|
46
|
-
return fn(json)
|
|
47
|
-
}
|
|
48
|
-
return fn
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
module.exports = reduce
|
package/std.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const JSON = require('lossless-json')
|
|
3
|
-
const skip = Symbol('skip')
|
|
4
|
-
|
|
5
|
-
function select(cb) {
|
|
6
|
-
return json => {
|
|
7
|
-
if (!cb(json)) {
|
|
8
|
-
throw skip
|
|
9
|
-
}
|
|
10
|
-
return json
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function filter(cb) {
|
|
15
|
-
return json => {
|
|
16
|
-
if (cb(json)) {
|
|
17
|
-
throw skip
|
|
18
|
-
}
|
|
19
|
-
return json
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function save(json) {
|
|
24
|
-
if (!global.FX_FILENAME) {
|
|
25
|
-
throw "No filename provided.\nTo edit-in-place, specify JSON file as first argument."
|
|
26
|
-
}
|
|
27
|
-
require('fs').writeFileSync(global.FX_FILENAME, JSON.stringify(json, null, 2))
|
|
28
|
-
return json
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
Object.assign(exports, {skip, select, filter, save})
|
|
32
|
-
Object.assign(global, exports)
|
|
33
|
-
global.std = exports
|
package/stream.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const JSON = require('lossless-json')
|
|
3
|
-
|
|
4
|
-
function apply(cb, input) {
|
|
5
|
-
let json
|
|
6
|
-
try {
|
|
7
|
-
json = JSON.parse(input)
|
|
8
|
-
} catch (e) {
|
|
9
|
-
process.stderr.write(e.toString() + '\n')
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
cb(json)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function stream(from, cb) {
|
|
16
|
-
let buff = ''
|
|
17
|
-
let lastChar = ''
|
|
18
|
-
let len = 0
|
|
19
|
-
let depth = 0
|
|
20
|
-
let isString = false
|
|
21
|
-
|
|
22
|
-
let count = 0
|
|
23
|
-
let head = ''
|
|
24
|
-
const check = (i) => {
|
|
25
|
-
if (depth <= 0) {
|
|
26
|
-
const input = buff.substring(0, len + i + 1)
|
|
27
|
-
|
|
28
|
-
if (count > 0) {
|
|
29
|
-
if (head !== '') {
|
|
30
|
-
apply(cb, head)
|
|
31
|
-
head = ''
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
apply(cb, input)
|
|
35
|
-
} else {
|
|
36
|
-
head = input
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
buff = buff.substring(len + i + 1)
|
|
40
|
-
len = -i - 1
|
|
41
|
-
count++
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
isStream() {
|
|
47
|
-
return count > 1
|
|
48
|
-
},
|
|
49
|
-
value() {
|
|
50
|
-
return head + buff
|
|
51
|
-
},
|
|
52
|
-
read() {
|
|
53
|
-
let chunk
|
|
54
|
-
|
|
55
|
-
while ((chunk = from.read())) {
|
|
56
|
-
len = buff.length
|
|
57
|
-
buff += chunk
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < chunk.length; i++) {
|
|
60
|
-
if (isString) {
|
|
61
|
-
if (chunk[i] === '"' && ((i === 0 && lastChar !== '\\') || (i > 0 && chunk[i - 1] !== '\\'))) {
|
|
62
|
-
isString = false
|
|
63
|
-
check(i)
|
|
64
|
-
}
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (chunk[i] === '{' || chunk[i] === '[') {
|
|
69
|
-
depth++
|
|
70
|
-
} else if (chunk[i] === '}' || chunk[i] === ']') {
|
|
71
|
-
depth--
|
|
72
|
-
check(i)
|
|
73
|
-
} else if (chunk[i] === '"') {
|
|
74
|
-
isString = true
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
lastChar = chunk[chunk.length - 1]
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = stream
|
package/test.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const test = require('ava')
|
|
3
|
-
const {execSync} = require('child_process')
|
|
4
|
-
const stream = require('./stream')
|
|
5
|
-
|
|
6
|
-
function fx(json, code = '') {
|
|
7
|
-
return execSync(`echo '${JSON.stringify(json)}' | node index.js ${code}`).toString('utf8')
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
test('pass', t => {
|
|
11
|
-
const r = fx([{'greeting': 'hello world'}])
|
|
12
|
-
t.deepEqual(JSON.parse(r), [{'greeting': 'hello world'}])
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('anon func', t => {
|
|
16
|
-
const r = fx({'key': 'value'}, '\'function (x) { return x.key }\'')
|
|
17
|
-
t.is(r, 'value\n')
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('arrow func', t => {
|
|
21
|
-
const r = fx({'key': 'value'}, '\'x => x.key\'')
|
|
22
|
-
t.is(r, 'value\n')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('arrow func ()', t => {
|
|
26
|
-
const r = fx({'key': 'value'}, '\'(x) => x.key\'')
|
|
27
|
-
t.is(r, 'value\n')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('this bind', t => {
|
|
31
|
-
const r = fx([1, 2, 3, 4, 5], '\'this.map(x => x * this.length)\'')
|
|
32
|
-
t.deepEqual(JSON.parse(r), [5, 10, 15, 20, 25])
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('chain', t => {
|
|
36
|
-
const r = fx({'items': ['foo', 'bar']}, '\'this.items\' \'.\' \'x => x[1]\'')
|
|
37
|
-
t.is(r, 'bar\n')
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('file argument', t => {
|
|
41
|
-
const r = execSync(`node index.js package.json .name`).toString('utf8')
|
|
42
|
-
t.is(r, 'fx\n')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('stream', t => {
|
|
46
|
-
const input = `
|
|
47
|
-
{"index": 0} {"index": 1}
|
|
48
|
-
{"index": 2, "quote": "\\""}
|
|
49
|
-
{"index": 3} "Hello" "world"
|
|
50
|
-
{"index": 6, "key": "one \\"two\\" three"}
|
|
51
|
-
`
|
|
52
|
-
t.plan(7 * (input.length - 1))
|
|
53
|
-
|
|
54
|
-
for (let i = 0; i < input.length; i++) {
|
|
55
|
-
const parts = [input.substring(0, i), input.substring(i)]
|
|
56
|
-
|
|
57
|
-
const reader = stream(
|
|
58
|
-
{
|
|
59
|
-
read() {
|
|
60
|
-
return parts.shift()
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
json => {
|
|
64
|
-
t.pass()
|
|
65
|
-
}
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
reader.read()
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('lossless number', t => {
|
|
73
|
-
const r = execSync(`echo '{"long": 123456789012345678901}' | node index.js .long`).toString('utf8')
|
|
74
|
-
t.is(r, '123456789012345678901\n')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('value iterator', t => {
|
|
78
|
-
const r = fx({master: {foo: [{bar: [{val: 1}]}]}}, '.master.foo[].bar[].val')
|
|
79
|
-
t.deepEqual(JSON.parse(r), [1])
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('value iterator simple', t => {
|
|
83
|
-
const r = fx([{val:1},{val:2}], '.[].val')
|
|
84
|
-
t.deepEqual(JSON.parse(r), [1, 2])
|
|
85
|
-
})
|