headson 0.2.3__tar.gz → 0.2.4__tar.gz
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.
Potentially problematic release.
This version of headson might be problematic. Click here for more details.
- {headson-0.2.3 → headson-0.2.4}/Cargo.lock +101 -3
- {headson-0.2.3 → headson-0.2.4}/Cargo.toml +3 -1
- {headson-0.2.3 → headson-0.2.4}/PKG-INFO +2 -1
- {headson-0.2.3 → headson-0.2.4}/README.md +1 -0
- {headson-0.2.3 → headson-0.2.4}/pyproject.toml +1 -1
- {headson-0.2.3 → headson-0.2.4}/python/Cargo.lock +12 -2
- {headson-0.2.3 → headson-0.2.4}/python/Cargo.toml +1 -1
- headson-0.2.4/src/main.rs +245 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/mod.rs +2 -1
- {headson-0.2.3 → headson-0.2.4}/src/serialization/mod.rs +1 -1
- {headson-0.2.3 → headson-0.2.4}/src/serialization/templates/js.rs +2 -2
- {headson-0.2.3 → headson-0.2.4}/src/serialization/templates/json.rs +2 -2
- {headson-0.2.3 → headson-0.2.4}/src/serialization/templates/mod.rs +4 -4
- {headson-0.2.3 → headson-0.2.4}/src/serialization/templates/pseudo.rs +2 -2
- headson-0.2.3/src/main.rs +0 -174
- {headson-0.2.3 → headson-0.2.4}/JSONTestSuite/LICENSE +0 -0
- {headson-0.2.3 → headson-0.2.4}/JSONTestSuite/README.md +0 -0
- {headson-0.2.3 → headson-0.2.4}/LICENSE +0 -0
- {headson-0.2.3 → headson-0.2.4}/python/README.md +0 -0
- {headson-0.2.3 → headson-0.2.4}/python/headson/__init__.py +0 -0
- {headson-0.2.3 → headson-0.2.4}/python/src/lib.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/json_ingest/builder.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/json_ingest/mod.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/lib.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/build.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/scoring.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/snapshots/headson__order__build__tests__order_empty_array_order.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/snapshots/headson__order__build__tests__order_single_string_array_order.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/order/types.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/serialization/snapshots/headson__serialization__tests__arena_render_empty.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/serialization/snapshots/headson__serialization__tests__arena_render_single.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/serialization/templates/core.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/serialization/types.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__order_empty_array_order.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__order_single_string_array_order.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__pq_empty_array_queue.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__pq_single_string_array_queue.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__queue__tests__pq_empty_array_queue.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__queue__tests__pq_single_string_array_queue.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__tree__tests__build_tree_empty.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__tree__tests__build_tree_single.snap +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/graph.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/json.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/mod.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/search.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/text.rs +0 -0
- {headson-0.2.3 → headson-0.2.4}/src/utils/tree_arena.rs +0 -0
|
@@ -98,6 +98,12 @@ version = "1.5.0"
|
|
|
98
98
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
99
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
100
100
|
|
|
101
|
+
[[package]]
|
|
102
|
+
name = "bitflags"
|
|
103
|
+
version = "2.10.0"
|
|
104
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
105
|
+
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
|
106
|
+
|
|
101
107
|
[[package]]
|
|
102
108
|
name = "bstr"
|
|
103
109
|
version = "1.12.0"
|
|
@@ -179,6 +185,15 @@ dependencies = [
|
|
|
179
185
|
"windows-sys 0.59.0",
|
|
180
186
|
]
|
|
181
187
|
|
|
188
|
+
[[package]]
|
|
189
|
+
name = "content_inspector"
|
|
190
|
+
version = "0.2.4"
|
|
191
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
192
|
+
checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
|
|
193
|
+
dependencies = [
|
|
194
|
+
"memchr",
|
|
195
|
+
]
|
|
196
|
+
|
|
182
197
|
[[package]]
|
|
183
198
|
name = "deunicode"
|
|
184
199
|
version = "1.6.2"
|
|
@@ -203,6 +218,16 @@ version = "1.0.0"
|
|
|
203
218
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
204
219
|
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
|
205
220
|
|
|
221
|
+
[[package]]
|
|
222
|
+
name = "errno"
|
|
223
|
+
version = "0.3.14"
|
|
224
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
225
|
+
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
226
|
+
dependencies = [
|
|
227
|
+
"libc",
|
|
228
|
+
"windows-sys 0.60.2",
|
|
229
|
+
]
|
|
230
|
+
|
|
206
231
|
[[package]]
|
|
207
232
|
name = "fake"
|
|
208
233
|
version = "2.10.0"
|
|
@@ -213,6 +238,12 @@ dependencies = [
|
|
|
213
238
|
"rand",
|
|
214
239
|
]
|
|
215
240
|
|
|
241
|
+
[[package]]
|
|
242
|
+
name = "fastrand"
|
|
243
|
+
version = "2.3.0"
|
|
244
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
245
|
+
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
|
246
|
+
|
|
216
247
|
[[package]]
|
|
217
248
|
name = "float-cmp"
|
|
218
249
|
version = "0.9.0"
|
|
@@ -235,6 +266,18 @@ dependencies = [
|
|
|
235
266
|
"wasm-bindgen",
|
|
236
267
|
]
|
|
237
268
|
|
|
269
|
+
[[package]]
|
|
270
|
+
name = "getrandom"
|
|
271
|
+
version = "0.3.4"
|
|
272
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
273
|
+
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
274
|
+
dependencies = [
|
|
275
|
+
"cfg-if",
|
|
276
|
+
"libc",
|
|
277
|
+
"r-efi",
|
|
278
|
+
"wasip2",
|
|
279
|
+
]
|
|
280
|
+
|
|
238
281
|
[[package]]
|
|
239
282
|
name = "halfbrown"
|
|
240
283
|
version = "0.2.5"
|
|
@@ -257,11 +300,12 @@ dependencies = [
|
|
|
257
300
|
|
|
258
301
|
[[package]]
|
|
259
302
|
name = "headson"
|
|
260
|
-
version = "0.2.
|
|
303
|
+
version = "0.2.4"
|
|
261
304
|
dependencies = [
|
|
262
305
|
"anyhow",
|
|
263
306
|
"assert_cmd",
|
|
264
307
|
"clap",
|
|
308
|
+
"content_inspector",
|
|
265
309
|
"fake",
|
|
266
310
|
"insta",
|
|
267
311
|
"rand",
|
|
@@ -269,6 +313,7 @@ dependencies = [
|
|
|
269
313
|
"serde",
|
|
270
314
|
"serde_json",
|
|
271
315
|
"simd-json",
|
|
316
|
+
"tempfile",
|
|
272
317
|
"test_each_file",
|
|
273
318
|
"unicode-segmentation",
|
|
274
319
|
]
|
|
@@ -375,6 +420,12 @@ version = "0.2.177"
|
|
|
375
420
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
376
421
|
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
|
377
422
|
|
|
423
|
+
[[package]]
|
|
424
|
+
name = "linux-raw-sys"
|
|
425
|
+
version = "0.11.0"
|
|
426
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
427
|
+
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
|
428
|
+
|
|
378
429
|
[[package]]
|
|
379
430
|
name = "log"
|
|
380
431
|
version = "0.4.28"
|
|
@@ -462,6 +513,12 @@ dependencies = [
|
|
|
462
513
|
"proc-macro2",
|
|
463
514
|
]
|
|
464
515
|
|
|
516
|
+
[[package]]
|
|
517
|
+
name = "r-efi"
|
|
518
|
+
version = "5.3.0"
|
|
519
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
520
|
+
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
521
|
+
|
|
465
522
|
[[package]]
|
|
466
523
|
name = "rand"
|
|
467
524
|
version = "0.8.5"
|
|
@@ -489,7 +546,7 @@ version = "0.6.4"
|
|
|
489
546
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
490
547
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
491
548
|
dependencies = [
|
|
492
|
-
"getrandom",
|
|
549
|
+
"getrandom 0.2.16",
|
|
493
550
|
]
|
|
494
551
|
|
|
495
552
|
[[package]]
|
|
@@ -518,6 +575,19 @@ version = "0.4.13"
|
|
|
518
575
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
519
576
|
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
|
520
577
|
|
|
578
|
+
[[package]]
|
|
579
|
+
name = "rustix"
|
|
580
|
+
version = "1.1.2"
|
|
581
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
582
|
+
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
|
583
|
+
dependencies = [
|
|
584
|
+
"bitflags",
|
|
585
|
+
"errno",
|
|
586
|
+
"libc",
|
|
587
|
+
"linux-raw-sys",
|
|
588
|
+
"windows-sys 0.60.2",
|
|
589
|
+
]
|
|
590
|
+
|
|
521
591
|
[[package]]
|
|
522
592
|
name = "rustversion"
|
|
523
593
|
version = "1.0.22"
|
|
@@ -579,7 +649,7 @@ version = "0.13.11"
|
|
|
579
649
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
580
650
|
checksum = "a0228a564470f81724e30996bbc2b171713b37b15254a6440c7e2d5449b95691"
|
|
581
651
|
dependencies = [
|
|
582
|
-
"getrandom",
|
|
652
|
+
"getrandom 0.2.16",
|
|
583
653
|
"halfbrown",
|
|
584
654
|
"lexical-core",
|
|
585
655
|
"ref-cast",
|
|
@@ -618,6 +688,19 @@ dependencies = [
|
|
|
618
688
|
"unicode-ident",
|
|
619
689
|
]
|
|
620
690
|
|
|
691
|
+
[[package]]
|
|
692
|
+
name = "tempfile"
|
|
693
|
+
version = "3.23.0"
|
|
694
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
695
|
+
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
|
696
|
+
dependencies = [
|
|
697
|
+
"fastrand",
|
|
698
|
+
"getrandom 0.3.4",
|
|
699
|
+
"once_cell",
|
|
700
|
+
"rustix",
|
|
701
|
+
"windows-sys 0.60.2",
|
|
702
|
+
]
|
|
703
|
+
|
|
621
704
|
[[package]]
|
|
622
705
|
name = "termtree"
|
|
623
706
|
version = "0.5.1"
|
|
@@ -687,6 +770,15 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|
|
687
770
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
688
771
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
689
772
|
|
|
773
|
+
[[package]]
|
|
774
|
+
name = "wasip2"
|
|
775
|
+
version = "1.0.1+wasi-0.2.4"
|
|
776
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
777
|
+
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
|
778
|
+
dependencies = [
|
|
779
|
+
"wit-bindgen",
|
|
780
|
+
]
|
|
781
|
+
|
|
690
782
|
[[package]]
|
|
691
783
|
name = "wasm-bindgen"
|
|
692
784
|
version = "0.2.104"
|
|
@@ -899,6 +991,12 @@ version = "0.53.1"
|
|
|
899
991
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
900
992
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|
901
993
|
|
|
994
|
+
[[package]]
|
|
995
|
+
name = "wit-bindgen"
|
|
996
|
+
version = "0.46.0"
|
|
997
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
998
|
+
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
|
999
|
+
|
|
902
1000
|
[[package]]
|
|
903
1001
|
name = "zerocopy"
|
|
904
1002
|
version = "0.8.27"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "headson"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "Budget‑constrained JSON preview renderer"
|
|
6
6
|
readme = "README.md"
|
|
@@ -25,6 +25,7 @@ serde = { version = "1.0.228", features = ["derive"] }
|
|
|
25
25
|
serde_json = "1.0.145"
|
|
26
26
|
unicode-segmentation = "1.12.0"
|
|
27
27
|
simd-json = { version = "0.13", features = ["serde_impl"] }
|
|
28
|
+
content_inspector = "0.2"
|
|
28
29
|
|
|
29
30
|
[dev-dependencies]
|
|
30
31
|
insta = "1.40.0"
|
|
@@ -33,6 +34,7 @@ test_each_file = "0.3"
|
|
|
33
34
|
fake = "2"
|
|
34
35
|
rand = "0.8"
|
|
35
36
|
rand_chacha = "0.3"
|
|
37
|
+
tempfile = "3"
|
|
36
38
|
|
|
37
39
|
[profile.release]
|
|
38
40
|
# Prioritize runtime speed for large inputs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: headson
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Classifier: Programming Language :: Python
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Rust
|
|
@@ -52,6 +52,7 @@ Notes:
|
|
|
52
52
|
- JSON template outputs a single JSON object keyed by the input file paths.
|
|
53
53
|
- Pseudo and JS templates render file sections with human-readable headers.
|
|
54
54
|
- Using `--global-budget` may truncate or omit entire files to respect the total budget.
|
|
55
|
+
- When passing file paths, directories and binary files are ignored; a notice is printed to stderr for each (e.g., `Ignored binary file: ./path/to/file`). Stdin mode reads the stream as-is.
|
|
55
56
|
|
|
56
57
|
Examples:
|
|
57
58
|
|
|
@@ -37,6 +37,7 @@ Notes:
|
|
|
37
37
|
- JSON template outputs a single JSON object keyed by the input file paths.
|
|
38
38
|
- Pseudo and JS templates render file sections with human-readable headers.
|
|
39
39
|
- Using `--global-budget` may truncate or omit entire files to respect the total budget.
|
|
40
|
+
- When passing file paths, directories and binary files are ignored; a notice is printed to stderr for each (e.g., `Ignored binary file: ./path/to/file`). Stdin mode reads the stream as-is.
|
|
40
41
|
|
|
41
42
|
Examples:
|
|
42
43
|
|
|
@@ -140,6 +140,15 @@ version = "1.0.4"
|
|
|
140
140
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
141
141
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
|
142
142
|
|
|
143
|
+
[[package]]
|
|
144
|
+
name = "content_inspector"
|
|
145
|
+
version = "0.2.4"
|
|
146
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
147
|
+
checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
|
|
148
|
+
dependencies = [
|
|
149
|
+
"memchr",
|
|
150
|
+
]
|
|
151
|
+
|
|
143
152
|
[[package]]
|
|
144
153
|
name = "float-cmp"
|
|
145
154
|
version = "0.9.0"
|
|
@@ -184,10 +193,11 @@ dependencies = [
|
|
|
184
193
|
|
|
185
194
|
[[package]]
|
|
186
195
|
name = "headson"
|
|
187
|
-
version = "0.2.
|
|
196
|
+
version = "0.2.4"
|
|
188
197
|
dependencies = [
|
|
189
198
|
"anyhow",
|
|
190
199
|
"clap",
|
|
200
|
+
"content_inspector",
|
|
191
201
|
"serde",
|
|
192
202
|
"serde_json",
|
|
193
203
|
"simd-json",
|
|
@@ -196,7 +206,7 @@ dependencies = [
|
|
|
196
206
|
|
|
197
207
|
[[package]]
|
|
198
208
|
name = "headson-python"
|
|
199
|
-
version = "0.2.
|
|
209
|
+
version = "0.2.4"
|
|
200
210
|
dependencies = [
|
|
201
211
|
"anyhow",
|
|
202
212
|
"headson",
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
use std::fs::File;
|
|
2
|
+
use std::io::{self, Read};
|
|
3
|
+
use std::path::{Path, PathBuf};
|
|
4
|
+
|
|
5
|
+
use anyhow::{Context, Result};
|
|
6
|
+
use clap::{Parser, ValueEnum};
|
|
7
|
+
use content_inspector::{ContentType, inspect};
|
|
8
|
+
|
|
9
|
+
type InputEntry = (String, Vec<u8>);
|
|
10
|
+
type InputEntries = Vec<InputEntry>;
|
|
11
|
+
type IgnoreNotices = Vec<String>;
|
|
12
|
+
|
|
13
|
+
#[derive(Parser, Debug)]
|
|
14
|
+
#[command(
|
|
15
|
+
name = "headson",
|
|
16
|
+
version,
|
|
17
|
+
about = "Get a small but useful preview of a JSON file"
|
|
18
|
+
)]
|
|
19
|
+
struct Cli {
|
|
20
|
+
#[arg(short = 'n', long = "budget", conflicts_with = "global_budget")]
|
|
21
|
+
budget: Option<usize>,
|
|
22
|
+
#[arg(short = 'f', long = "template", value_enum, default_value_t = Template::Pseudo)]
|
|
23
|
+
template: Template,
|
|
24
|
+
#[arg(long = "indent", default_value = " ")]
|
|
25
|
+
indent: String,
|
|
26
|
+
#[arg(long = "no-space", default_value_t = false)]
|
|
27
|
+
no_space: bool,
|
|
28
|
+
#[arg(
|
|
29
|
+
long = "no-newline",
|
|
30
|
+
default_value_t = false,
|
|
31
|
+
help = "Do not add newlines in the output"
|
|
32
|
+
)]
|
|
33
|
+
no_newline: bool,
|
|
34
|
+
#[arg(
|
|
35
|
+
short = 'm',
|
|
36
|
+
long = "compact",
|
|
37
|
+
default_value_t = false,
|
|
38
|
+
conflicts_with_all = ["no_space", "no_newline", "indent"],
|
|
39
|
+
help = "Compact output with no added whitespace. Not very human-readable."
|
|
40
|
+
)]
|
|
41
|
+
compact: bool,
|
|
42
|
+
#[arg(
|
|
43
|
+
long = "string-cap",
|
|
44
|
+
default_value_t = 500,
|
|
45
|
+
help = "Maximum string length to display"
|
|
46
|
+
)]
|
|
47
|
+
string_cap: usize,
|
|
48
|
+
#[arg(
|
|
49
|
+
short = 'N',
|
|
50
|
+
long = "global-budget",
|
|
51
|
+
value_name = "BYTES",
|
|
52
|
+
conflicts_with = "budget",
|
|
53
|
+
help = "Total output budget across all inputs; useful to keep multiple files within a fixed overall output size (may omit entire files)."
|
|
54
|
+
)]
|
|
55
|
+
global_budget: Option<usize>,
|
|
56
|
+
#[arg(
|
|
57
|
+
value_name = "INPUT",
|
|
58
|
+
value_hint = clap::ValueHint::FilePath,
|
|
59
|
+
num_args = 0..,
|
|
60
|
+
help = "Optional file paths. If omitted, reads JSON from stdin. Multiple input files are supported. Directories and binary files are ignored with a notice on stderr."
|
|
61
|
+
)]
|
|
62
|
+
inputs: Vec<PathBuf>,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[derive(Copy, Clone, Debug, ValueEnum)]
|
|
66
|
+
enum Template {
|
|
67
|
+
Json,
|
|
68
|
+
Pseudo,
|
|
69
|
+
Js,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fn main() -> Result<()> {
|
|
73
|
+
let cli = Cli::parse();
|
|
74
|
+
|
|
75
|
+
let render_cfg = get_render_config_from(&cli);
|
|
76
|
+
let (output, ignore_notices) = if cli.inputs.is_empty() {
|
|
77
|
+
(run_from_stdin(&cli, &render_cfg)?, Vec::new())
|
|
78
|
+
} else {
|
|
79
|
+
run_from_paths(&cli, &render_cfg)?
|
|
80
|
+
};
|
|
81
|
+
println!("{output}");
|
|
82
|
+
|
|
83
|
+
for notice in ignore_notices {
|
|
84
|
+
eprintln!("{notice}");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Ok(())
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn compute_effective_budget(cli: &Cli, input_count: usize) -> usize {
|
|
91
|
+
if let Some(g) = cli.global_budget {
|
|
92
|
+
g
|
|
93
|
+
} else {
|
|
94
|
+
let per_file = cli.budget.unwrap_or(500);
|
|
95
|
+
per_file.saturating_mul(input_count)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn compute_priority(
|
|
100
|
+
cli: &Cli,
|
|
101
|
+
effective_budget: usize,
|
|
102
|
+
input_count: usize,
|
|
103
|
+
) -> headson::PriorityConfig {
|
|
104
|
+
let per_file_for_priority = (effective_budget / input_count.max(1)).max(1);
|
|
105
|
+
get_priority_config(per_file_for_priority, cli)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fn run_from_stdin(
|
|
109
|
+
cli: &Cli,
|
|
110
|
+
render_cfg: &headson::RenderConfig,
|
|
111
|
+
) -> Result<String> {
|
|
112
|
+
let input_bytes = read_stdin()?;
|
|
113
|
+
let input_count = 1usize;
|
|
114
|
+
let eff = compute_effective_budget(cli, input_count);
|
|
115
|
+
let prio = compute_priority(cli, eff, input_count);
|
|
116
|
+
headson::headson(input_bytes, render_cfg, &prio, eff)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fn run_from_paths(
|
|
120
|
+
cli: &Cli,
|
|
121
|
+
render_cfg: &headson::RenderConfig,
|
|
122
|
+
) -> Result<(String, IgnoreNotices)> {
|
|
123
|
+
let (entries, ignored) = ingest_paths(&cli.inputs)?;
|
|
124
|
+
let included = entries.len();
|
|
125
|
+
let input_count = included.max(1);
|
|
126
|
+
let eff = compute_effective_budget(cli, input_count);
|
|
127
|
+
let prio = compute_priority(cli, eff, input_count);
|
|
128
|
+
if cli.inputs.len() > 1 {
|
|
129
|
+
let out = headson::headson_many(entries, render_cfg, &prio, eff)?;
|
|
130
|
+
Ok((out, ignored))
|
|
131
|
+
} else if included == 0 {
|
|
132
|
+
Ok((String::new(), ignored))
|
|
133
|
+
} else {
|
|
134
|
+
let bytes = entries.into_iter().next().unwrap().1;
|
|
135
|
+
let out = headson::headson(bytes, render_cfg, &prio, eff)?;
|
|
136
|
+
Ok((out, ignored))
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn read_stdin() -> Result<Vec<u8>> {
|
|
141
|
+
let mut buf = Vec::new();
|
|
142
|
+
io::stdin()
|
|
143
|
+
.read_to_end(&mut buf)
|
|
144
|
+
.context("failed to read from stdin")?;
|
|
145
|
+
Ok(buf)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fn sniff_then_read_text(path: &Path) -> Result<Option<Vec<u8>>> {
|
|
149
|
+
// Inspect the first chunk with content_inspector; if it looks binary, skip.
|
|
150
|
+
// Otherwise, read the remainder without further inspection for speed.
|
|
151
|
+
const CHUNK: usize = 64 * 1024;
|
|
152
|
+
let file = File::open(path).with_context(|| {
|
|
153
|
+
format!("failed to open input file: {}", path.display())
|
|
154
|
+
})?;
|
|
155
|
+
let meta_len = file.metadata().ok().map(|m| m.len());
|
|
156
|
+
let mut reader = io::BufReader::with_capacity(CHUNK, file);
|
|
157
|
+
|
|
158
|
+
let mut first = [0u8; CHUNK];
|
|
159
|
+
let n = reader.read(&mut first).with_context(|| {
|
|
160
|
+
format!("failed to read input file: {}", path.display())
|
|
161
|
+
})?;
|
|
162
|
+
if n == 0 {
|
|
163
|
+
return Ok(Some(Vec::new()));
|
|
164
|
+
}
|
|
165
|
+
if matches!(inspect(&first[..n]), ContentType::BINARY) {
|
|
166
|
+
return Ok(None);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Preallocate buffer: first chunk + estimated remainder (capped)
|
|
170
|
+
let mut buf = Vec::with_capacity(
|
|
171
|
+
n + meta_len
|
|
172
|
+
.map(|m| m.saturating_sub(n as u64) as usize)
|
|
173
|
+
.unwrap_or(0)
|
|
174
|
+
.min(8 * 1024 * 1024),
|
|
175
|
+
);
|
|
176
|
+
buf.extend_from_slice(&first[..n]);
|
|
177
|
+
reader.read_to_end(&mut buf).with_context(|| {
|
|
178
|
+
format!("failed to read input file: {}", path.display())
|
|
179
|
+
})?;
|
|
180
|
+
Ok(Some(buf))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
fn ingest_paths(paths: &[PathBuf]) -> Result<(InputEntries, IgnoreNotices)> {
|
|
184
|
+
let mut out: InputEntries = Vec::with_capacity(paths.len());
|
|
185
|
+
let mut ignored: IgnoreNotices = Vec::new();
|
|
186
|
+
for path in paths.iter() {
|
|
187
|
+
let display = path.display().to_string();
|
|
188
|
+
if let Ok(meta) = std::fs::metadata(path) {
|
|
189
|
+
if meta.is_dir() {
|
|
190
|
+
ignored.push(format!("Ignored directory: {display}"));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if let Some(bytes) = sniff_then_read_text(path)? {
|
|
195
|
+
out.push((display, bytes))
|
|
196
|
+
} else {
|
|
197
|
+
ignored.push(format!("Ignored binary file: {display}"));
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
Ok((out, ignored))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
fn get_render_config_from(cli: &Cli) -> headson::RenderConfig {
|
|
205
|
+
let template = match cli.template {
|
|
206
|
+
Template::Json => headson::OutputTemplate::Json,
|
|
207
|
+
Template::Pseudo => headson::OutputTemplate::Pseudo,
|
|
208
|
+
Template::Js => headson::OutputTemplate::Js,
|
|
209
|
+
};
|
|
210
|
+
let space = if cli.compact || cli.no_space { "" } else { " " }.to_string();
|
|
211
|
+
let newline = if cli.compact || cli.no_newline {
|
|
212
|
+
""
|
|
213
|
+
} else {
|
|
214
|
+
"\n"
|
|
215
|
+
}
|
|
216
|
+
.to_string();
|
|
217
|
+
let indent_unit = if cli.compact {
|
|
218
|
+
String::new()
|
|
219
|
+
} else {
|
|
220
|
+
cli.indent.clone()
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
headson::RenderConfig {
|
|
224
|
+
template,
|
|
225
|
+
indent_unit,
|
|
226
|
+
space,
|
|
227
|
+
newline,
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
fn get_priority_config(
|
|
232
|
+
per_file_budget: usize,
|
|
233
|
+
cli: &Cli,
|
|
234
|
+
) -> headson::PriorityConfig {
|
|
235
|
+
// Optimization: derive a conservative per‑array expansion cap from the output
|
|
236
|
+
// budget to avoid allocating/walking items that could never appear in the
|
|
237
|
+
// final preview. As a simple lower bound, an array of N items needs ~2*N
|
|
238
|
+
// bytes to render (item plus comma), so we cap per‑array expansion at
|
|
239
|
+
// budget/2. This prunes unnecessary work on large inputs without changing
|
|
240
|
+
// output semantics.
|
|
241
|
+
headson::PriorityConfig {
|
|
242
|
+
max_string_graphemes: cli.string_cap,
|
|
243
|
+
array_max_items: (per_file_budget / 2).max(1),
|
|
244
|
+
}
|
|
245
|
+
}
|
|
@@ -60,10 +60,10 @@ impl Style for Js {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
pub fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
63
|
+
pub(super) fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
64
64
|
render_array_with::<Js>(ctx)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
pub fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
67
|
+
pub(super) fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
68
68
|
render_object_with::<Js>(ctx)
|
|
69
69
|
}
|
|
@@ -13,10 +13,10 @@ impl Style for Json {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
pub fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
16
|
+
pub(super) fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
17
17
|
render_array_with::<Json>(ctx)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
pub fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
20
|
+
pub(super) fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
21
21
|
render_object_with::<Json>(ctx)
|
|
22
22
|
}
|
|
@@ -39,10 +39,10 @@ impl Style for Pseudo {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
pub fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
42
|
+
pub(super) fn render_array(ctx: &ArrayCtx<'_>) -> String {
|
|
43
43
|
render_array_with::<Pseudo>(ctx)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
pub fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
46
|
+
pub(super) fn render_object(ctx: &ObjectCtx<'_>) -> String {
|
|
47
47
|
render_object_with::<Pseudo>(ctx)
|
|
48
48
|
}
|
headson-0.2.3/src/main.rs
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
use std::io::{self, Read};
|
|
2
|
-
use std::path::PathBuf;
|
|
3
|
-
|
|
4
|
-
use anyhow::{Context, Result};
|
|
5
|
-
use clap::{Parser, ValueEnum};
|
|
6
|
-
|
|
7
|
-
#[derive(Parser, Debug)]
|
|
8
|
-
#[command(
|
|
9
|
-
name = "headson",
|
|
10
|
-
version,
|
|
11
|
-
about = "Get a small but useful preview of a JSON file"
|
|
12
|
-
)]
|
|
13
|
-
struct Cli {
|
|
14
|
-
#[arg(short = 'n', long = "budget", conflicts_with = "global_budget")]
|
|
15
|
-
budget: Option<usize>,
|
|
16
|
-
#[arg(short = 'f', long = "template", value_enum, default_value_t = Template::Pseudo)]
|
|
17
|
-
template: Template,
|
|
18
|
-
#[arg(long = "indent", default_value = " ")]
|
|
19
|
-
indent: String,
|
|
20
|
-
#[arg(long = "no-space", default_value_t = false)]
|
|
21
|
-
no_space: bool,
|
|
22
|
-
#[arg(
|
|
23
|
-
long = "no-newline",
|
|
24
|
-
default_value_t = false,
|
|
25
|
-
help = "Do not add newlines in the output"
|
|
26
|
-
)]
|
|
27
|
-
no_newline: bool,
|
|
28
|
-
#[arg(
|
|
29
|
-
short = 'm',
|
|
30
|
-
long = "compact",
|
|
31
|
-
default_value_t = false,
|
|
32
|
-
conflicts_with_all = ["no_space", "no_newline", "indent"],
|
|
33
|
-
help = "Compact output with no added whitespace. Not very human-readable."
|
|
34
|
-
)]
|
|
35
|
-
compact: bool,
|
|
36
|
-
#[arg(
|
|
37
|
-
long = "string-cap",
|
|
38
|
-
default_value_t = 500,
|
|
39
|
-
help = "Maximum string length to display"
|
|
40
|
-
)]
|
|
41
|
-
string_cap: usize,
|
|
42
|
-
#[arg(
|
|
43
|
-
short = 'N',
|
|
44
|
-
long = "global-budget",
|
|
45
|
-
value_name = "BYTES",
|
|
46
|
-
conflicts_with = "budget",
|
|
47
|
-
help = "Total output budget across all inputs; useful to keep multiple files within a fixed overall output size (may omit entire files)."
|
|
48
|
-
)]
|
|
49
|
-
global_budget: Option<usize>,
|
|
50
|
-
#[arg(
|
|
51
|
-
value_name = "INPUT",
|
|
52
|
-
value_hint = clap::ValueHint::FilePath,
|
|
53
|
-
num_args = 0..,
|
|
54
|
-
help = "Optional file paths. If omitted, reads JSON from stdin. Multiple input files are supported."
|
|
55
|
-
)]
|
|
56
|
-
inputs: Vec<PathBuf>,
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
#[derive(Copy, Clone, Debug, ValueEnum)]
|
|
60
|
-
enum Template {
|
|
61
|
-
Json,
|
|
62
|
-
Pseudo,
|
|
63
|
-
Js,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
fn main() -> Result<()> {
|
|
67
|
-
let cli = Cli::parse();
|
|
68
|
-
|
|
69
|
-
let render_cfg = get_render_config_from(&cli);
|
|
70
|
-
let input_count = if cli.inputs.is_empty() {
|
|
71
|
-
1
|
|
72
|
-
} else {
|
|
73
|
-
cli.inputs.len()
|
|
74
|
-
};
|
|
75
|
-
let effective_budget = if let Some(g) = cli.global_budget {
|
|
76
|
-
g
|
|
77
|
-
} else {
|
|
78
|
-
let per_file = cli.budget.unwrap_or(500);
|
|
79
|
-
per_file.saturating_mul(input_count)
|
|
80
|
-
};
|
|
81
|
-
// Derive a per-file baseline for priority heuristics to avoid over-pruning.
|
|
82
|
-
let per_file_for_priority = (effective_budget / input_count).max(1);
|
|
83
|
-
let priority_cfg = get_priority_config(per_file_for_priority, &cli);
|
|
84
|
-
|
|
85
|
-
let output = if cli.inputs.len() <= 1 {
|
|
86
|
-
let input_bytes = get_input_single(&cli.inputs)?;
|
|
87
|
-
headson::headson(
|
|
88
|
-
input_bytes,
|
|
89
|
-
&render_cfg,
|
|
90
|
-
&priority_cfg,
|
|
91
|
-
effective_budget,
|
|
92
|
-
)?
|
|
93
|
-
} else {
|
|
94
|
-
let inputs = get_input_many(&cli.inputs)?;
|
|
95
|
-
headson::headson_many(
|
|
96
|
-
inputs,
|
|
97
|
-
&render_cfg,
|
|
98
|
-
&priority_cfg,
|
|
99
|
-
effective_budget,
|
|
100
|
-
)?
|
|
101
|
-
};
|
|
102
|
-
println!("{output}");
|
|
103
|
-
|
|
104
|
-
Ok(())
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
fn get_input_single(paths: &[PathBuf]) -> Result<Vec<u8>> {
|
|
108
|
-
// Read input from first file path when provided, otherwise from stdin.
|
|
109
|
-
if let Some(path) = paths.first() {
|
|
110
|
-
std::fs::read(path).with_context(|| {
|
|
111
|
-
format!("failed to read input file: {}", path.display())
|
|
112
|
-
})
|
|
113
|
-
} else {
|
|
114
|
-
let mut buf = Vec::new();
|
|
115
|
-
io::stdin()
|
|
116
|
-
.read_to_end(&mut buf)
|
|
117
|
-
.context("failed to read from stdin")?;
|
|
118
|
-
Ok(buf)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
fn get_input_many(paths: &[PathBuf]) -> Result<Vec<(String, Vec<u8>)>> {
|
|
123
|
-
let mut out: Vec<(String, Vec<u8>)> = Vec::with_capacity(paths.len());
|
|
124
|
-
for path in paths.iter() {
|
|
125
|
-
let bytes = std::fs::read(path).with_context(|| {
|
|
126
|
-
format!("failed to read input file: {}", path.display())
|
|
127
|
-
})?;
|
|
128
|
-
out.push((path.display().to_string(), bytes));
|
|
129
|
-
}
|
|
130
|
-
Ok(out)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
fn get_render_config_from(cli: &Cli) -> headson::RenderConfig {
|
|
134
|
-
let template = match cli.template {
|
|
135
|
-
Template::Json => headson::OutputTemplate::Json,
|
|
136
|
-
Template::Pseudo => headson::OutputTemplate::Pseudo,
|
|
137
|
-
Template::Js => headson::OutputTemplate::Js,
|
|
138
|
-
};
|
|
139
|
-
let space = if cli.compact || cli.no_space { "" } else { " " }.to_string();
|
|
140
|
-
let newline = if cli.compact || cli.no_newline {
|
|
141
|
-
""
|
|
142
|
-
} else {
|
|
143
|
-
"\n"
|
|
144
|
-
}
|
|
145
|
-
.to_string();
|
|
146
|
-
let indent_unit = if cli.compact {
|
|
147
|
-
String::new()
|
|
148
|
-
} else {
|
|
149
|
-
cli.indent.clone()
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
headson::RenderConfig {
|
|
153
|
-
template,
|
|
154
|
-
indent_unit,
|
|
155
|
-
space,
|
|
156
|
-
newline,
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
fn get_priority_config(
|
|
161
|
-
per_file_budget: usize,
|
|
162
|
-
cli: &Cli,
|
|
163
|
-
) -> headson::PriorityConfig {
|
|
164
|
-
// Optimization: derive a conservative per‑array expansion cap from the output
|
|
165
|
-
// budget to avoid allocating/walking items that could never appear in the
|
|
166
|
-
// final preview. As a simple lower bound, an array of N items needs ~2*N
|
|
167
|
-
// bytes to render (item plus comma), so we cap per‑array expansion at
|
|
168
|
-
// budget/2. This prunes unnecessary work on large inputs without changing
|
|
169
|
-
// output semantics.
|
|
170
|
-
headson::PriorityConfig {
|
|
171
|
-
max_string_graphemes: cli.string_cap,
|
|
172
|
-
array_max_items: (per_file_budget / 2).max(1),
|
|
173
|
-
}
|
|
174
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__order_empty_array_order.snap
RENAMED
|
File without changes
|
|
File without changes
|
{headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__order__tests__pq_empty_array_queue.snap
RENAMED
|
File without changes
|
|
File without changes
|
{headson-0.2.3 → headson-0.2.4}/src/snapshots/headson__queue__tests__pq_empty_array_queue.snap
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|