@peter_marklund/json 0.0.4 → 0.0.5
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 +51 -0
- package/bin/json.js +32 -1
- package/package.json +1 -1
- package/src/helpers.js +11 -4
- package/test/input/array.json +17 -0
- package/test/input/array.jsonl +3 -0
- package/test/run.js +2 -1
- package/test/test_spec.json +16 -1
package/README.md
CHANGED
|
@@ -16,6 +16,57 @@ npm install @peter_marklund/json -g
|
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
18
|
echo '{"foo": "1"}' | json .foo
|
|
19
|
+
|
|
20
|
+
# Colorized pretty printing is the default
|
|
21
|
+
cat test/input/array.json | json
|
|
22
|
+
# [
|
|
23
|
+
# {
|
|
24
|
+
# "id": 1,
|
|
25
|
+
# "name": "Item 1",
|
|
26
|
+
# "value": 100
|
|
27
|
+
# },
|
|
28
|
+
# {
|
|
29
|
+
# "id": 2,
|
|
30
|
+
# "name": "Item 2",
|
|
31
|
+
# "value": 200
|
|
32
|
+
# },
|
|
33
|
+
# {
|
|
34
|
+
# "id": 3,
|
|
35
|
+
# "name": "Item 3",
|
|
36
|
+
# "value": 300
|
|
37
|
+
# }
|
|
38
|
+
# ]
|
|
39
|
+
|
|
40
|
+
# Without pretty printing (single line):
|
|
41
|
+
cat test/input/basic.json | PRETTY=false json
|
|
42
|
+
# {"bar":"Hello world","baz":false,"data":[{"id":1,"name":"Item 1","value":100},{"id":2,"name":"Item 2","value":200},{"id":3,"name":"Item 3","value":300}],"foo":1,"nested":{"foo":{"bar":"nested value"}}}
|
|
43
|
+
|
|
44
|
+
# JSONL output (for an array with one JSON object per line)
|
|
45
|
+
cat test/input/array.json | JSONL=true json
|
|
46
|
+
# {"id":1,"name":"Item 1","value":100}
|
|
47
|
+
# {"id":2,"name":"Item 2","value":200}
|
|
48
|
+
# {"id":3,"name":"Item 3","value":300}
|
|
49
|
+
|
|
50
|
+
# The json command can take JSONL as input as well
|
|
51
|
+
cat test/input/array.jsonl | json
|
|
52
|
+
|
|
53
|
+
# The json command can also parse JSON data at the end of log lines:
|
|
54
|
+
cat test/input/log-with-json.log | json
|
|
55
|
+
# [
|
|
56
|
+
# {
|
|
57
|
+
# "_line": "192.168.1.1 - - [21/Feb/2026:10:00:01 +0000] \"GET /api/users HTTP/1.1\" 200 ",
|
|
58
|
+
# "cache": "hit",
|
|
59
|
+
# "duration_ms": 42,
|
|
60
|
+
# "user_id": 1021
|
|
61
|
+
# },
|
|
62
|
+
# {
|
|
63
|
+
# "_line": "192.168.1.2 - - [21/Feb/2026:10:00:03 +0000] \"POST /api/orders HTTP/1.1\" 201 ",
|
|
64
|
+
# "cache": "miss",
|
|
65
|
+
# "duration_ms": 87,
|
|
66
|
+
# "user_id": 4432
|
|
67
|
+
# },
|
|
68
|
+
# ...
|
|
69
|
+
# ]
|
|
19
70
|
```
|
|
20
71
|
|
|
21
72
|
## Running the Tests
|
package/bin/json.js
CHANGED
|
@@ -61,7 +61,38 @@ function getCodeArg() {
|
|
|
61
61
|
function readStdIn() {
|
|
62
62
|
return fs.readFileSync(0).toString();
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
function parseLine(line, openLines) {
|
|
66
|
+
let result = { openLines: [...openLines] };
|
|
67
|
+
try {
|
|
68
|
+
const openIndex = line.startsWith("[") ? 0 : line.indexOf("{");
|
|
69
|
+
if (
|
|
70
|
+
openLines.length === 0 &&
|
|
71
|
+
((line.indexOf("{") >= 0 && line.endsWith("}")) ||
|
|
72
|
+
(line.startsWith("[") && line.endsWith("]")))
|
|
73
|
+
) {
|
|
74
|
+
const doc = JSON.parse(line.substring(openIndex));
|
|
75
|
+
if (openIndex > 0 && !doc._line) doc._line = line.substring(0, openIndex);
|
|
76
|
+
result.parsedLine = doc;
|
|
77
|
+
} else if (line === "{") {
|
|
78
|
+
result.openLines = [line];
|
|
79
|
+
} else if (openLines.length > 0) {
|
|
80
|
+
result.openLines.push(line);
|
|
81
|
+
if (line === "}") {
|
|
82
|
+
result.parsedLine = JSON.parse(openLines.join("\n"));
|
|
83
|
+
result.openLines = [];
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
result.parsedLine = { _line: line };
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
result.error = `Error thrown parsing line: ${line} - ${err.stack}`;
|
|
90
|
+
result.openLines = [];
|
|
91
|
+
result.parsedLine = { _line: line };
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
|
|
65
96
|
async function jsonIn(filePath) {
|
|
66
97
|
let textInput
|
|
67
98
|
try {
|
package/package.json
CHANGED
package/src/helpers.js
CHANGED
|
@@ -54,10 +54,17 @@ function base64Encode(data) {
|
|
|
54
54
|
return data && Buffer.from(data).toString("base64");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function percentile(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
function percentile(arr, p) {
|
|
58
|
+
if (typeof p !== 'number' || p <= 0 || p >= 1.0) {
|
|
59
|
+
throw new Error('Percentile must be a number between 0 and 1');
|
|
60
|
+
}
|
|
61
|
+
const sorted = [...arr].sort((a, b) => a - b);
|
|
62
|
+
const index = p * (sorted.length - 1);
|
|
63
|
+
const lower = Math.floor(index);
|
|
64
|
+
const upper = Math.ceil(index);
|
|
65
|
+
const weight = index - lower;
|
|
66
|
+
|
|
67
|
+
return sorted[lower] * (1 - weight) + sorted[upper] * weight;
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
function p50(values) {
|
package/test/run.js
CHANGED
|
@@ -25,7 +25,7 @@ async function runTest(test) {
|
|
|
25
25
|
console.log(`output: ${output}`)
|
|
26
26
|
const elapsedTime = Date.now() - startTime
|
|
27
27
|
console.log(`elapsed: ${elapsedTime}`)
|
|
28
|
-
if (isJsonScalarValue(test.expected)) {
|
|
28
|
+
if (isJsonScalarValue(test.expected) || test.command.includes('JSONL=true')) {
|
|
29
29
|
assert.strictEqual(output, test.expected)
|
|
30
30
|
} else {
|
|
31
31
|
assert.strictEqual(stringify(JSON.parse(output)), stringify(JSON.parse(test.expected)))
|
|
@@ -42,6 +42,7 @@ async function run() {
|
|
|
42
42
|
const elapsedTime = Date.now() - startTime
|
|
43
43
|
console.log(`\nTotal elapsed: ${elapsedTime}`)
|
|
44
44
|
console.log(`Total tests run: ${spec.tests.length}`)
|
|
45
|
+
console.log('SUCCESS!')
|
|
45
46
|
process.exit(0)
|
|
46
47
|
} catch (error) {
|
|
47
48
|
console.log(error.stack || error)
|
package/test/test_spec.json
CHANGED
|
@@ -48,7 +48,22 @@
|
|
|
48
48
|
{
|
|
49
49
|
"name": "stats",
|
|
50
50
|
"command": "cat test/input/basic.json | json 'pick(stats(data.data.map(i => i.value)), [\"min\", \"max\", \"avg\", \"p50\", \"p90\"])'",
|
|
51
|
-
"expected": "{\"min\": 100, \"max\": 300, \"avg\": 200, \"p50\": 200, \"p90\":
|
|
51
|
+
"expected": "{\"min\": 100, \"max\": 300, \"avg\": 200, \"p50\": 200, \"p90\": 280}"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "jsonl_input",
|
|
55
|
+
"command": "cat test/input/array.jsonl | json",
|
|
56
|
+
"expected": "[{\"id\":1,\"name\":\"Item 1\",\"value\":100},{\"id\":2,\"name\":\"Item 2\",\"value\":200},{\"id\":3,\"name\":\"Item 3\",\"value\":300}]"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "jsonl_output",
|
|
60
|
+
"command": "cat test/input/array.jsonl | JSONL=true json",
|
|
61
|
+
"expected": "{\"id\":1,\"name\":\"Item 1\",\"value\":100}\n{\"id\":2,\"name\":\"Item 2\",\"value\":200}\n{\"id\":3,\"name\":\"Item 3\",\"value\":300}"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "log_with_json_input",
|
|
65
|
+
"command": "cat test/input/log-with-json.log | json 'sum(data.map(d => d.duration_ms))'",
|
|
66
|
+
"expected": "141"
|
|
52
67
|
}
|
|
53
68
|
]
|
|
54
69
|
}
|