-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.js
151 lines (134 loc) · 3.51 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env node
const _ = require(`lodash`)
const yargs = require(`yargs`)
const jsonpath = require(`jsonpath`)
const utf8 = require(`utf8-stream`)
const map = require(`map-stream`)
const split = require(`split`)
const concat = require(`concat-stream`)
const fs = require(`fs`)
const path = require(`path`)
const version = require(`./package.json`).version
const argv = yargs
.usage(
`Pipe $0 onto a JSON source from the commandline to parse the output:
cat data.json | $0 [options] query`
)
.options({
p: {
alias: `path`,
describe: `Use JSON Path notation (https://github.com/dchester/jsonpath)`,
type: `boolean`
},
k: {
alias: `keys`,
describe: `Print object keys only`,
type: `boolean`
},
f: {
alias: `file`,
describe: `Read input from file`,
requiresArg: true,
type: `string`
},
i: {
alias: `indent`,
describe: `Number of spaces for indentation (ignored by --human)`,
requiresArg: true,
default: 2,
type: `number`,
coerce: x => (!isNaN(parseFloat(x)) && isFinite(x) ? Number(x) : x)
},
h: {
alias: `human`,
describe: `Print human-readable (non-JSON) format`,
type: `boolean`
},
b: {
alias: `break`,
describe: `Set break length of object/array for human format`,
requiresArg: true,
type: `number`
},
c: {
alias: `no-color`,
describe: `Disable color for human format`,
type: `boolean`
},
d: {
alias: `depth`,
describe: `Depth for human format`,
requiresArg: true,
type: `number`
},
L: {
alias: `line-by-line`,
describe: `Parse each line as a separate input`,
type: `boolean`
},
v: {
alias: `version`,
describe: `Print the version`,
type: `boolean`
}
})
.help()
.epilogue(
`Queries use the Lodash get method by default.
For more information, see https://github.com/therealklanni/jp`
).argv
const format = argv.human ? x => x : _.partialRight(JSON.stringify, null, argv.indent || 2)
const logOpts = {
colors: !argv.noColor,
breakLength: argv.break || null,
depth: argv.depth >= 0 ? argv.depth : null
}
/* eslint-disable no-console */
const log = argv.human
? _.partialRight(console.dir.bind(console), logOpts)
: console.log.bind(console)
/* eslint-enable no-console */
const print = _.flow(format, log)
const query = argv._[0]
const parseBuf = buf => {
let obj
let output
try {
obj = JSON.parse(buf.toString())
} catch (e) {
switch (true) {
case /Unexpected token/.test(e.toString()):
console.log(`Error: Unable to parse input as JSON`)
break
case /Unexpected end/.test(e.toString()):
console.log(`Error: Unexpected end of JSON input`)
break
default:
console.log(`Error: Unknown parse error`)
}
process.exit(1)
}
if (argv.path) {
output = query ? jsonpath.query(obj, query) : obj
} else {
output = query ? _.get(obj, query) : obj
}
print(argv.keys ? Object.keys(output) : output)
}
const parse = stream =>
stream
.pipe(utf8())
// Use utf8 effectively as a noop
.pipe(argv.L ? split() : utf8())
.pipe(argv.L ? map(parseBuf) : concat(parseBuf))
if (argv.v) {
/* eslint-disable no-console */
console.log(`v${version}`)
/* eslint-enable no-console */
} else if (!process.stdin.isTTY) {
parse(process.stdin)
} else if (argv.file) {
parse(fs.createReadStream(path.resolve(argv.file), `utf8`))
} else {
yargs.showHelp()
}