Skip to content

Releases: nao1215/jsonize

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 22 Sep 03:53
b553c48

This release adds sixteen definitions (the registry holds 280 commands through 758 definitions, from 270 and 742), makes an option either change the answer or be refused before anything is read, keeps the headings of a csv read as data as written, and fixes readers that returned JSON different from their input: YAML, JSON Lines, LTSV, local timestamps, folded lines and floats too small to hold.

Added

  • rsync --stats (rsync/stats): the transfer counts rsync prints at the end of a run, with the summary lines that follow them, as one object of typed numbers. The counts by kind that rsync prints in parentheses are read as an object of their own, and a kind it leaves out is null rather than zero. -v, -i, --progress and two or more -h options print something else and are refused.
  • 7z l -slt -ba (7z/list-technical-bare): the entry blocks 7-Zip prints with -ba, which leaves out the banner, the scan line, the archive name and the archive's own properties. An entry is the same object 7z/list-technical gives it; what differs is the whole, which is the array of them rather than an object holding the archive beside them.
  • openssl x509 -noout -text (openssl/x509-text): the version, the serial, the signature algorithm, the issuer, the subject, the two dates, the kind of key and its size, and one record per X509v3 extension with its critical mark and its value as printed. The key material and the signature are hexadecimal folded over a dozen lines or more and are not read; input.ignore names those lines, so --explain reports how many were left out.
  • tesseract IMAGE stdout tsv (tesseract/tsv): one row per page, block, paragraph, line and word, with the box each occupies and, for a word, its confidence. A row that is not a word prints -1 for the confidence, which is tesseract's own value and stays the number it printed. hocr, alto, pdf and the plain text tesseract writes when no configuration is named are other formats and are refused.
  • Seven definitions for time zones, the SSH client and the desktop: zdump (zdump/current) and zdump -v / -V (zdump/verbose, which keeps the lines where gmtime or localtime failed, with the seconds they failed on), ssh -G HOST (ssh/config-dump, a list of name and value, so a keyword given more than once such as identityfile or localforward keeps every value), xwininfo (xwininfo/stats), usb-devices (usb-devices/linux, one object per device with its interfaces and their endpoints), glxinfo -B (glxinfo/brief) and eglinfo -B (eglinfo/brief, one record per platform and per device, holding the errors a platform printed).
  • Five definitions: lscpu -p (lscpu/parsable, the columns named by the header comment, so any -p=LIST is read, and a row whose cache IDs lscpu left out is refused rather than shifted), gcc -print-search-dirs (gcc/print-search-dirs, also under g++, with the program and library paths as arrays), apt-cache rdepends (apt-cache/rdepends, marking an alternative and the other packages that satisfy the same dependency), pw-cli ls (pw-cli/list-objects, one record per PipeWire object with its properties), and xprop -root / xprop -id (xprop/default, one record per property, with the lines printed under it kept). The registry holds 280 commands through 758 definitions.
  • A server-side group in the cookbook: inspecting an uploaded PDF with pdfinfo, an archive with 7z l -slt, a certificate with openssl x509, an upload's type with file -i, and recording what a backup run moved with rsync --stats, closing with the jz run exit-status contract and what converting the output does not do. The five commands run for real in the end-to-end suite on Linux, over paths holding a space and shell metacharacters, with their failure cases.
  • group_separator on an int or a float field: the one character a format writes between groups of three digits. It is removed only where the digits are grouped by it, so a value of another shape is an error rather than a number made by dropping characters. It is for a format that decides the character itself; a count printed with the separator of the user's locale still stays the string it was printed as.

Changed

  • An option either changes the answer or is refused with exit 2 before anything is read or run. --raw, --assume-year and --assume-zone are now refused for a data format (--format or a data file's extension), which is read without a definition's field rules and so could change nothing, and --assume-year and --assume-zone are refused when no variant of the named parser, or the --define, prints a timestamp they could complete (jz run --assume-year now df), the way a key to --extract none of them has already was. --assume-year and --assume-zone beside --raw are refused as --type beside it is, since --raw leaves a timestamp as the text it was cut as. When the definition is found from the text, an option it has no use for still passes, since which definition reads the input is not known until it has been read.
  • The header line of a csv or tsv read as data (--format csv, a .csv file, jz new k:=@x.csv, --stream) is now the keys as written: 名前, In Stock and %CPU stay as they are, where they became column, in_stock and cpu_percent. An empty heading is still column and a repeated one a_2. --parser csv, which reads with a definition, normalises the headings as before.
  • jz list df/gnu and jz list --schema df/gnu take the name --explain and jz list print for a definition. A path such as /usr/bin/df is still read as the program it names.
  • An ini section heading with no name ([]) is an error. It merged into the keys written before the first heading, which go under the empty name.

Fixed

  • apt-cache/depends refused the line of a relationship ORed with the next one ( |PreDepends: coreutils-from-uutils), so jz run apt-cache depends coreutils was exit 3. The mark is now read into alternative, which is true for such a relationship and false for the others.
  • apt-cache/depends claimed the output of apt-cache rdepends -o APT::Cache::ShowDependencyType=true, then failed on its Reverse Depends: line with exit 3. It now leaves that output to apt-cache/rdepends.
  • gpg/list-keys refused a user ID whose validity gpg pads on both sides ([ full ]), which is how a key signed into full validity is listed, with exit 3.
  • A time field with location: local moved a wall clock the zone skips to another hour. With TZ=America/New_York, 2025-03-09 02:30 came out as 2025-03-09T01:30:00-05:00, the same answer as for 01:30, because time.ParseInLocation normalises the hour a change to summer time skips. The value is now refused with exit 3.
  • input.fold joined a continuation onto a blank line above it, so a, an empty line and an indented b gave a record " b" with a space the text does not hold. A blank line is now nothing to join onto, in the whole reading and in --stream alike, and the continuation is an error naming its line.
  • A float field, and --type COLUMN=float, wrote 0 for a value too small for a 64-bit float (1e-400), while one too large was refused. Both are now refused with exit 3.
  • The error for a tree line that skips a level gave the wrong levels: a followed by a line indented twice said "indented 1 levels below a line at level 1". It now says the line is at level 2 under a line at level 0, and a first line that is indented says there is no line above it.
  • jz list dff did not suggest df, although jz run dff and --parser dff do. jz list now gives the same suggestion.
  • YAML: the value of an explicit key written on the line of its ":" was read as one string when it opened a collection there. ? a followed by : - x and an indented - y gave {"a":"- x - y"} with exit 0; it is now the list ["x","y"], and : b: 1 is a mapping.
  • YAML: a sequence item written on the line of its key, a: - b, was read as the string "- b". The same happened with - 1 inside a flow sequence and with ? b used where a value belongs. YAML does not allow a plain scalar to start with an indicator and a space, and other readers refuse the line; jz now refuses it with exit 3 and says to start the items on the next line.
  • YAML: a comment did not end a plain scalar written over several lines. a: x # note followed by an indented y gave "x y", keeping the text after the comment; the indented line is now refused as unexpected indentation.
  • YAML: a literal or folded scalar at the end of a text without a final line break gained one. a: | over x with no newline after it gave "x\n"; the break a scalar keeps is the one its last line has, so it is now "x".
  • JSON Lines, LTSV and jz new --each skipped any line of Unicode white space. A line holding only a no-break space, an ideographic space, a form feed or a vertical tab disappeared with exit 0, although none of these is white space in JSON, and --format json refuses the same text. Only a line of JSON's white space, spaces, tabs and carriage returns, is blank in JSON Lines now; LTSV skips only an empty line and, as its reference says, refuses a line of spaces as a field without a label.
  • jz run go test -bench=Parse was exit 4. go/bench required -bench or the literal -bench=., and an argument written with = is matched by its name and the =, so any other value left it without a candidate. go/bench now takes -bench= and the two-dash spellings, and go/test refuses them.
  • FuzzReadJSON reported an escape naming half of a surrogate pair as valid JSON the reader refused, so make fuzz failed on every run that reached that input. json.Valid accepts such a document and json.Unmarshal then hands back U+FFFD, which is a character the input may hold for itself, so refusing it is what keeps a conversion from changing what it was given. The fuzz target now names it among the refu...
Read more

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 05:20
2d00c24

This release adds five Git inspection reports, holds every document built by jz new to the same nesting limit as documents jz reads, and replaces the in-process Go benchmarks with whole-command himorime suites that cover latency, CPU time, peak memory and throughput.

Added

  • Five Git reports: git clean -n (git/clean-dry-run), git diff --summary (git/diff-summary), git ls-files --eol (git/ls-files-eol), git notes list (git/notes-list) and git submodule status (git/submodule-status). The registry holds 270 commands through 742 definitions.

Changed

  • Performance is measured only with himorime. bench/himorime.yaml runs jz as a pipeline does, one process per call: start-up, detection with and without a named parser, text no definition reads, registries of 26 to 1000 extra definitions and --define, 100 000-row ps, df, mount and env output, every data format, csv key selection, --stream, -p and jz new, for latency, CPU time, peak RSS and throughput. A pull request is compared with its base on the same runner and fails on a confident regression. bench/compare/himorime.yaml measures jz against jc and jo, and make bench-docs rewrites the tables of the comparison page from it. The Go benchmark functions, bench/baseline.txt, the benchstat comparison and scripts/compare_bench.sh are gone.

Fixed

  • jz new --path could build a document nested past the 1000-level limit that the same document read as JSON or YAML refused. The completed document, including containers made by a location and values read from files or --each, is now held to that limit with exit 3 and no output.

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 17 Sep 02:52
05bff70

A performance release with no change to what jz reads or writes. jz run COMMAND and --parser NAME read only the definitions that answer to the name, so a short conversion with a named parser takes about a tenth of the time it did, and csv files and tables with many columns are read in about half the time with less memory. The documentation site has a page comparing jz with jc and jo, with the benchmark script that produced its figures.

Added

  • A comparison with jc 1.25.7 and jo 1.9 on the documentation site and in the README: what each reads and builds, where each is the better choice, what jsonize does not do, and timings and peak memory measured on all cores and on one core with scripts/compare_bench.sh, including the cases where jc or jo is faster.

Changed

  • jz run COMMAND and --parser NAME read only the built-in definitions that answer to the name, not all 737. On a short df -h report pinned to one core, jz --parser df takes about 5 ms instead of 46 ms and jz run df -h about 6 ms instead of 47 ms. Detecting the format from the text still reads every definition. With a registry of your own, every definition is read as before.
  • Reading a csv allocates a quarter of what it did and takes about half the time: every record was read through a new 4 KB buffer, and one buffer now serves the whole input.
  • A table whose rows hold more than eight columns, such as ps aux or top, no longer builds a map for each row, and a process time such as 4:50 is added up in whole seconds unless it has a fraction. On 100,000 rows of ps aux jz takes about half the time and a third less memory.

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 00:03
af62247

The registry reads 270 commands through 737 definitions, up from 227
through 600: sar's reports, gpg keys, git's branches and config, file
system and partition tools (dumpe2fs, wipefs, gdisk, partx), CUPS's
lpstat and more. What was read wrong with exit 0 is refused instead: a
csv whose lines end with a carriage return alone, and YAML text after a
flow collection. A csv record read as data is bounded by the input limit
like every other format, an option error names the option the way the
help writes it, and top -b -n N is a list with a record per iteration.

Added

  • Twenty-three commands: dumpe2fs -h and tune2fs -l (the superblock
    of an ext2/3/4 file system), e2freefrag (free space summary and
    histogram), wipefs (the signature table, and the report --all
    prints), partx --show (with rounded sizes and with -b), gdisk -l
    and sgdisk -p (a GPT listing), filefrag -v (the extents of each
    file), fincore (with rounded sizes and with -b), diffstat,
    gocyclo (with -avg and -avg-short), exif (libexif's table),
    isoinfo -d, cmp and cmp -b, cloud-init status --long,
    pro status on a machine with no subscription (also as ua),
    oomctl, pinky and pinky -l, stty and stty -a,
    setxkbmap -query, udisksctl status, lpstat -p, -v and -t,
    and cpupower frequency-info. git diff --stat is no longer read
    from diffstat output, whose count column git never prints at that
    width. The registry holds 270 commands through 737 definitions.
  • net-tools arp, arp -n and arp -i IFACE (arp/net-tools), the
    cache as a table, and ifconfig -s (ifconfig/net-tools-short).
    arp -a reads an entry published for a proxy, which net-tools prints
    with <from_interface> for its hardware address and was refused.
    net-tools route -ee (route/linux-extended) and route -A inet6
    (route/linux-inet6), and route -e through netstat/routing. A
    rejecting route, whose counts net-tools prints as -, was refused by
    route/linux and netstat/routing; the counts are null now, and the
    published schemas are unchanged, since they already allowed it. The
    registry holds 247 commands through 704 definitions.
  • numactl --show (the NUMA policy and the processors and nodes a
    process is bound to) and taskset -p (the affinity mask of a process,
    beside the list taskset -pc already gave), and resolvectl query
    (the answers for each name, with the link, the protocol, how long it
    took and where the data came from). The registry holds 247 commands
    through 707 definitions.
  • gpg -k and gpg -K, each key with its algorithm, dates,
    capabilities and fingerprint, its user IDs with their validity, and its
    subkeys. The registry holds 247 commands through 700 definitions.
  • dpkg-deb -I (a package's size, the members of its control archive
    and its control fields) and dpkg-deb -c, which prints the listing
    tar/gnu reads, and dpkg-divert --list. The registry holds 247
    commands through 699 definitions.
  • readelf -s -W, each symbol table with the value, size, type,
    binding, visibility, section and name of every symbol, and the version
    a symbol is bound to. The registry holds 245 commands through 697
    definitions.
  • Three commands of poppler-utils: pdfinfo (the document information,
    page count, page size and version), pdffonts (each font with its
    type, encoding and whether it is embedded) and pdfimages -list
    (each image with its size, color space and encoding), and trust list from p11-kit (each certificate of the trust store). The registry
    holds 245 commands through 696 definitions.
  • The checksum lines of more tools: cksum -a ALGORITHM (tagged, and
    with --untagged), cksum -a bsd, shasum with no algorithm, -a 1,
    224, 384 and 512 and with --tag, and b2sum -l BITS for 128,
    256 and 384 bits. Each goes to the definition whose line it prints.
  • git config --list --show-origin and --show-scope (the scope, the
    kind of origin and the file of each setting), git diff --shortstat
    and git ls-tree -l (the size of each blob). The registry holds 241
    commands through 692 definitions.
  • go tool cover -func (the coverage of each function and the total),
    git status --porcelain=v2 (the branch headers, and each entry by
    kind with its modes and object names), and git log --numstat,
    --name-status and --name-only (and git show with them), which
    before failed with exit 3. git/log now refuses those forms and -p
    with exit 4. The registry holds 241 commands through 689 definitions.
  • Seventeen definitions. Eight commands jz did not read: apt-config dump, avahi-browse -p (and with -r the resolved host, address,
    port and TXT record; a browse left running is read as a stream),
    fc-match, gio mime TYPE, gpgconf --list-dirs and
    --list-components, gsettings list-recursively (a value kept as the
    GVariant text printed), pwdx (read only when named) and
    systemd-delta --diff=false. More of three it did: git diff --name-status (a quoted path decoded), git reflog, git ls-remote,
    git cherry, systemd-analyze timespan, timestamp and calendar,
    and resolvectl dns and domain.
  • Three more: sum (the BSD checksum, told from cksum by its padding),
    ipcs -l (a record per resource) and df -P with -B, -m or
    --block-size (the unit the heading names in bytes). The registry
    holds 236 commands through 620 definitions.
  • sar -d, the activity of each block device, and for ELF files
    readelf -S -W (the section headers), readelf -d (the dynamic
    section) and size -A (the size and address of each section), and
    rustc -vV and cargo -vV, and BusyBox top -b (a virtual size
    that runs into the percentage beside it is told apart). The registry
    holds 237 commands through 627 definitions.
  • Twenty-five sar reports: -W, -H, -v, -I, -u ALL, -r ALL,
    -m CPU, and with -n the reports EDEV, NFS, NFSD, SOCK,
    IP, EIP, ICMP, EICMP, TCP, ETCP, UDP, SOCK6, IP6,
    EIP6, ICMP6, EICMP6, UDP6 and SOFT, pidstat -U, the
    per-task report with user names, and iostat -x -d, the extended
    device counters without the CPU table, and vmstat -p PARTITION
    (655 definitions).
  • Network settings: ethtool -g (ring sizes) and ethtool -a (pause
    frames), ip route get, nmcli -t device, iw reg get (the
    regulatory rules per frequency range) and hostname -I.
  • pmap -x (a record per process with its mappings and totals),
    pgrep -l and getent ahosts.
  • rpm -qi and rpm -qia (rpm/info), one object per package with
    the description kept whole, read from rpm 4.14, 4.16 and 6.0 output;
    git log --stat and --shortstat (git/log-stat), each commit with
    its diffstat as files and summary; ifconfig from net-tools
    (ifconfig/net-tools) and from macOS and FreeBSD (ifconfig/bsd);
    and macOS arp -a (arp/darwin).
  • /proc/pressure/* (pressure stall averages), /proc/self/io,
    /proc/cgroups, /proc/net/sockstat, /proc/PID/maps and
    /proc/net/if_inet6.
  • apt-cache show (a record per package version, sizes typed), and
    snap refresh --list, snap aliases and snap version.
  • For git, branch (which branch is checked out here or in another
    worktree), status -sb (the branch, its upstream and how far ahead or
    behind, then the changed paths), worktree list --porcelain and
    count-objects -vH; and go version. The registry holds 241 commands
    through 684 definitions.
  • jz run --format NAME reads the command's output as a data format,
    the way COMMAND | jz --format NAME reads it, with --stream,
    --columns and --type as there. jz run --type already told the
    caller to give --format csv, which jz run did not take.

Changed

  • jz run --help lists --format, --columns and --type under
    Input and the parser options under the same heading as jz --help,
    where --columns and --type were among the parser options and
    --format among the options for the command.
  • npm ls -g and npm ls -g --all are read. The first line is the
    global directory with no package name, so the project's name in
    npm/ls and the root's name in npm/ls-all may be null, and both
    schemas are version 2. Before, the output was refused with exit 4.
  • go list -m -u all is read: go/list-modules adds update, the newer
    version shown in brackets, retracted and deprecated, and the same
    three for the replacement. Before, the first line with any of them
    failed with exit 3. Every object now has these keys, so the schema is
    version 2.
  • git branch -r is read, and git branch -a when the current branch
    is past the twentieth line. Both were refused with exit 4, since the
    signature asked for a line marked current.
  • An args entry that ends in = also matches the one-dash spelling
    of Go's flag package: any: ["-func="] takes -func=c.out, which
    before was only split into letters.
  • git log --stat output named as --parser git --variant log is
    refused by the signature (exit 4) instead of failing inside the message
    (exit 3), and detection hands it to git/log-stat. The published
    schema of git/log is unchanged.
  • A file path names more definitions: a dot in the file name is looked
    up as a dash (jz --file /etc/resolv.conf reads with etc/resolv-conf)
    and a file one directory down has that directory joined to its name
    (/proc/net/dev is proc/net-dev, /proc/self/io is proc/self-io).
    Before, both went to automatic detection, which refuses formats that
    are read only when named. A capture saved as fstab.txt still names
    nothing.
  • iostat -s and iostat -xs print short forms whose columns
    (kB_w+d/s, kB/s, rqm/s, await, areq-sz, aqu-sz, %util)
    iostat/linux read as strings; they are numbers now, and the published
    schema of iostat/linux is version 3.
  • top/linux is a l...
Read more

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 08:14
7f4b73d

A stream ends at the first record it cannot read, so the next program in
a pipeline never sees a partial result that looks complete, and
--stop-on-error goes away with the choice it offered. jz new KEY:=JSON
returns the same status as the same text read from a file, and the
registry reads what exiftool, identify and pkg-config print: 227 commands
through 600 definitions.

Added

  • Four definitions for what three tools print: exiftool FILE (the tags
    one per line) and exiftool -G FILE (the group in front of each of
    them), identify FILE... (one record per image, its width and height
    typed), and pkg-config --list-all (the modules it knows, read only
    when named since a name and a phrase is also what a glossary looks
    like). The registry holds 227 commands through 600 definitions.

Fixed

  • jz new KEY:=JSON returns 3 rather than 2 when the argument is JSON
    and jz refuses what it holds: a key given twice in one object, or
    nesting past the depth limit. The same text in a file (KEY:=@f.json)
    and the same text read as data (jz --format json) already returned 3,
    so a script that built the argument with a command substitution got a
    different status from one that passed the file. Text that is not JSON
    at all is still 2, since that is the command line being wrong.

Changed

  • A stream ends at the first record it cannot read, rather than leaving
    the record out and going on. --stream, jz run --stream and jz new --each all do this, for a command's output, a data file and lines or
    nul alike: the records written before the failure stand, it is
    reported once on standard error, nothing after it is read, and the
    status is 3. A stream that goes on past a record it dropped reaches the
    next program in the pipeline looking complete, since the diagnostic
    went to standard error and the status comes only after the records have
    been read and acted on.

Removed

  • --stop-on-error asked for what every stream now does. A command line
    that still names it is refused with exit status 2 and a message saying
    so; drop the option and the behaviour is unchanged.
  • engine.Stream no longer takes an onError func(*ParseError) error
    beside emit: with one answer to a record that cannot be read there is
    nothing to choose. A caller passing nil today drops the argument and
    gets the same reading.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 02:33
f1a1a80

jz holds every reading of an input to the same rules. A stream is
identified under the record limit it is read under and drops a file path
that does not fit, the way a whole document does; a JSON escape that
names no character and a control character standing in YAML text are
refused rather than replaced; YAML nests as deeply as JSON. A table can
ask for its rows to be counted instead of letting the last column take
the rest of the line, jz test --json writes what failed as one object,
and loading the registry costs a tenth less time and a fifth fewer
allocations. The registry is unchanged at 224 commands and 596
definitions.

Added

  • jz test --json writes the result to standard output as one object:
    the counts, and a failure per entry with the definition, the case, the
    fixture path, the registry it came from, what it failed at and the
    message. The kinds are load, select, parse, refuse, stream, unread,
    schema and golden, so a job can tell one failure from another without
    matching the message. The lines on standard error and the exit status
    are the same with the option as without.

Changed

  • max_fields of a table may be one more than the number of columns,
    which is how a definition asks for a row to be counted rather than for
    its last column to take the rest of the line. ps aux keeps the
    default; proc/diskstats now counts every row, where a twenty-first
    field used to be caught only by failing to convert to an integer in
    the last column.
  • Loading the registry costs about a tenth less time, a tenth fewer
    bytes and a fifth fewer allocations. The walk that looks for
    definitions no longer descends into the fixtures beside them (5,614
    files were read through to find 596), a definition file is read into
    one buffer of its own length, and the YAML reader takes its nodes from
    blocks, leaves text with no CRLF in it where it lies and does not
    build a scalar written on one line. Nothing about what is chosen, what
    is reported or which registry wins changes.

Fixed

  • The examples that append to an array are quoted, in the README, the
    usage guide, the cookbook, jz new --help and the demo recording.
    jz new tags[]=web copied into zsh, which is what macOS starts with,
    was refused by the shell with no matches found before jz saw it.
  • --stream holds the lines it identifies the format by to the 1 MiB
    record limit that the reading of a record already applied, so a
    producer that never ends a record is refused at the byte past the
    limit with exit 3 instead of waited for. Two megabytes with no line
    break were refused at once with --define and waited for with
    --parser df --variant gnu.
  • --stream --file drops a file path that named a definition the text
    does not fit, the way the whole-document reading does, and reads the
    text on its own terms. A df report saved as /etc/fstab was exit 4
    with --stream and exit 0 without it.
  • Input that cannot be read at all, such as a gzip file whose checksum
    does not match, ends --stream with the status the whole-document
    reading ends with: exit 3 rather than exit 1.
  • A \u escape naming half of a surrogate pair in JSON or JSON Lines is
    refused with the line it is on, where it was read as U+FFFD and
    written out with exit 0: {"name":"\ud800"} became {"name":"\ufffd"}.
    A pair written in full and a replacement character the text holds for
    itself are unchanged.
  • A control character standing in YAML text is refused, as YAML 1.2.2
    does not allow it there. key: ab<NUL>cd was read as a value holding
    it. One written as an escape ("a\0b") is still a character of the
    value.
  • YAML nests as deeply as JSON: both are held to 1000 levels of arrays
    and objects, where YAML stopped at 100 and counted a scalar as a
    level.
  • JSON, JSON Lines, YAML, LTSV, lines and nul input, read with
    --format, a file's extension or jz new key:=@file, is held to the
    4,194,304 values a csv and a definition's reading were already held to:
    a JSON array of 4,194,305 numbers was read with exit 0. Past the limit
    a whole reading is exit 3 with nothing written. A stream counts each
    record, and a record past the limit is a record that cannot be read,
    with the records before it kept.
  • jz new counts the values of the whole document it makes, so files each
    under the limit cannot make one past it. --each counts each document
    and treats one past the limit as a line that cannot be read.
  • jz new reports a file or standard input past the 64 MiB limit with
    exit 3, as --file does, where it was exit 1.
  • Without --extract or --exclude, output is no longer copied object by
    object, and no option remembers every key it has seen: a stream of JSON
    Lines whose records each have keys of their own grew from 23 MiB to
    162 MiB of memory between 100,000 and 1,000,000 records, and now stays
    at 12 MiB with or without the options. A refusal of an unknown key
    names at most 64 of the keys the input had.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 15:33
6136cd5

jz is the step that makes JSON for the next command. jz new places
strings, file text and JSON values at keys or JSON Pointers, and makes one
document per line of standard input with --each; plain text reads as
strings with --format text, lines and nul; a csv or tsv column
takes a type with --type. --yaml output is removed. The registry is
unchanged at 224 commands and 596 definitions.

Added

  • jz new --each makes one document per line of standard input and
    writes each as a line of JSON when its line has come, holding nothing
    else of the input: vmstat 1 | jz --stream | jz new --each host=a sample:=@-. KEY:=@- is the line read as JSON, KEY=@- the line as a
    string, and the files the other arguments name are read once. A line
    that cannot be read is reported and left out, with the status 3.
  • --stop-on-error ends a stream (--stream, jz run --stream, jz new --each) at the first record it cannot read, keeping the records written
    before it, with the status 3; a command jz run started is stopped.
  • --format text, --format lines and --format nul read input that
    has no format of its own as strings: the whole input as one string, a
    list with one string per line (LF or CRLF), or one per NUL-terminated
    record as find -print0 writes them. Nothing is trimmed, empty records
    stay "", and a separator at the end does not add an empty record.
    --stream writes lines and nul records as they arrive.
  • --type COLUMN=TYPE converts a csv or tsv column to int, float or
    bool with the rules a definition's field of that type follows; an
    empty value is null and the other columns stay text. A value that is
    not the type is exit 3 with the line and the column, and a column the
    input does not have is exit 2.
  • jz new --string KEY=TEXT writes TEXT as a string exactly as it is, so
    a value from a variable is never read as a file name (@...) or JSON,
    whatever it holds: jz new --string "message=$MESSAGE".
  • jz new --text-file KEY=PATH puts a file's text, or standard input's
    with -, into the JSON with every line ending kept. KEY=@PATH still
    drops the last one. Text that is not UTF-8 is exit 3.
  • jz new --path POINTER=VALUE places a value at a JSON Pointer with
    the operators a plain argument has (=, :=, =@, :=@), making the
    objects and arrays on the way; - appends and an index names an
    element already given. --string and --text-file take a pointer in
    place of a key. A location given twice, a pointer into a value given
    whole, a key in an array and an index past the end are exit 2 before
    anything is read. spec.replicas:=3 is still the key spec.replicas.

Changed

  • jz --help groups the options under Input, Output and the parser of
    command output, says what jz is for in one line, and shows examples of
    every source of JSON; jz run --help and jz new --help group theirs
    the same way. --raw is described as what it is, the text a definition
    cut without its field rules, and --extract and --exclude as keeping
    and dropping keys of each object.
  • The README, the landing page and the usage guide describe jz as the
    step that makes JSON for the next command, and every jz command they
    show with its output is run by the end-to-end suite
    (e2e/atago/docs.atago.yaml); a test fails when a page shows one that
    no scenario runs. The --explain=json example said the df capture had
    8 lines read, where 7 are read and one is left out.
  • A data file read with --stream (jsonl, ltsv, and the new lines
    and nul) leaves out a record it cannot read and goes on, as a stream
    of a command's output does, where it ended at the first. The status is
    still 3. Pass --stop-on-error to end at the first as before.

Removed

  • Breaking: --yaml, which wrote the output as YAML, is gone from the
    default mode, jz run and jz new. jz writes JSON only, and a command
    line that still passes --yaml is refused with exit status 2 and a
    message saying so, before anything is read or run. To keep getting
    YAML, pipe the JSON to a YAML tool: df -h | jz | yq -P. With
    --stream, read the JSON Lines one document at a time. Reading YAML is
    unchanged: a .yaml or .yml file, --format yaml, jz new key:=@file.yaml and definitions written in YAML all work as before.

Fixed

  • A csv or tsv read as data (--format csv, a .csv or .tsv file, jz new key:=@file.csv) keeps what it holds: an escape sequence stays in
    its value, where it was taken off as colour, and a line of spaces is a
    row, where it was dropped (printf 'key\n \nx\n' | jz --format csv
    gave one row). A csv definition in the user registry no longer changes
    such a reading, which made 007 a number with --format csv and left
    it "007" with jz new; only --parser csv reads with it. --explain
    now says the file was read as csv rather than naming csv/comma.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 09:52
5e82af5

jz makes JSON from more than command output: from data files (CSV, TSV,
LTSV, JSON Lines, JSON and YAML, also gzip or bzip2 compressed) and from
arguments given to jz new. The registry is unchanged at 224 commands
and 596 definitions.

Added

  • jz new makes a JSON object from its arguments, or an array with
    --array: key=text is a string, key:=json a JSON value,
    key=@path a file's text, key:=@path the value a data file holds and
    key[]= one more element of an array. Nothing is guessed from a value,
    and a key given twice without [] is exit 2.
  • Data files: jz --file reads a file as the format its extension
    names, .csv, .tsv, .ltsv, .jsonl (or .ndjson), .json and
    .yaml (or .yml), each also compressed as .gz or .bz2, and
    --format NAME reads piped data as that format. JSON keeps its key
    order and number literals, YAML is typed by the 1.2 core schema, and a
    key given twice, text that is not UTF-8 or a value JSON cannot hold is
    exit 3 with the line. --stream writes JSON Lines and LTSV records as
    they are read. --explain says which format was read and what named
    it, and --explain=json counts the values in read.values.
  • The site has a Cookbook
    of 20 tasks, each run by the end-to-end suite, and a test fails when a
    documented command, the options block, the exit-code table or a demo
    tape no longer matches the command line.

Changed

  • A file given with --file whose extension names a data format is read
    as that format, where its text was detected as command output. Name
    --parser or --define to read such a file as a command's output;
    a file with any other extension (captured.txt) is detected as before.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 06:07
7ce3083

145 definitions for 55 more commands, 224 commands and 596 definitions
in all, the system commands of Windows and macOS among them. Where one
command's output is followed by another's, more definitions now refuse
the text instead of reading the other command's lines as their own.

Added

  • A tree definition can state what its top-level line looks like with
    parse.root. The node alternatives read every depth, and the one
    that reads the continuation of a wrapped list reads any text, so a
    word printed after lspci -v, or another command's output piped in
    behind it, was read as one more device with no children; with root
    it is refused, naming the line. lspci -v, lsusb -v, lsusb -t,
    iw dev, apt-cache depends, systemctl list-dependencies and
    systemd-analyze critical-chain state theirs.
  • Definitions for 25 more traditional and modern commands. Archive
    listings: gzip -l and -lv, xz -l and --robot -l, zstd -l and -lv, lz4 --list, 7z l and 7z l -slt.
    Checks and keys: md5sum -c and the other digest commands' -c,
    ssh-keyscan, ssh-add -L (and ssh-add -l as ssh-keygen -l),
    openssl x509 -noout with -subject, -issuer, -dates, -serial
    and -fingerprint, passwd -S, screen -ls. System: snap services,
    snap connections and snap changes, lsipc -q, -m and -s,
    nmcli radio, timedatectl show, loginctl show-user, show-session
    and show-seat, apt-cache search, dpkg-query -W, pip freeze and
    pip list --outdated. Developer tooling: go test result lines and
    go test -bench reports, gh pr list, issue list, run list,
    release list, workflow list and repo list, rustup check,
    cargo search, just --list, uv python list, mise outdated.
    Containers and clusters: docker system df and system df -v,
    docker context ls, docker compose ls and compose ps,
    docker ps -s, docker version, kubectl get pods, nodes,
    services, deployments and namespaces in their default, wide and
    all-namespaces forms, kubectl config get-contexts,
    kubectl api-resources, kubectl version, rclone lsl, lsd and
    version, redis-cli info and client list.
  • A top-level input.select.until that states its whole line reads that
    line as the end of the output, the way after reads a heading, and a
    line after it is unread (exit 3). net share closes on its completion
    line with it, so another command's output behind the listing is
    refused rather than read as shares.
  • unescape takes octal: true, which reads a backslash and three
    octal digits as the byte they name, and quote, which decodes only a
    value put between that character. git and getfacl write names that
    way.
  • A definition for systemd-cgls: the control groups under the group,
    unit or directory it starts from, the processes in each with their
    ids, whether a group is delegated, and the group ids and extended
    attributes systemd 252 prints to root. In a tree, a form of
    indentation that ends in a branch character (|-, └─) ends the
    indentation, so the blanks after it that pad a right-aligned number
    belong to the node.
  • Definitions for eza -l (with --header, -a, -B, and in its
    long-iso, full-iso, -g and -H column sets), procs, tokei,
    bat --list-languages and hyperfine --style basic.
  • Definitions for macOS: vm_stat, sw_vers, diskutil list,
    launchctl list, pmset -g, netstat -i and netstat -rn,
    system_profiler SPSoftwareDataType and SPHardwareDataType,
    scutil --dns, networksetup -listallhardwareports,
    brew outdated --verbose, memory_pressure, top -l, otool -L,
    lipo -info, csrutil status, spctl --status, fdesetup status
    and shasum -a 256, from output captured on a macOS 26 runner.
  • Definitions for Windows: tasklist in its table, /v, /svc, /m,
    /fo list and /fo csv forms, netstat -an, -ano and -e,
    route print, arp -a, getmac /v, driverquery and driverquery /v, sc query and sc queryex, schtasks /query as a table and as
    a list, net user, net localgroup, net share and net start,
    whoami /groups and /priv, chcp and ver, from output captured on
    Windows Server 2022 and 2025 runners.
  • Definitions for compiler-style diagnostics: go vet (and go build),
    staticcheck, golangci-lint, actionlint and shellcheck -f gcc;
    and for mc ls (the MinIO client) and task --list.
  • Definitions for cargo tree, uv tree, npm ls --all, busctl tree
    (one service or several), docker buildx ls and xinput list.
  • md5sum --tag, sha1sum --tag, sha256sum --tag, b2sum --tag and
    the rest of the GNU and uutils family are read by the definition of
    the BSD digest line, which they print, together with FreeBSD and macOS
    md5. A name the tools escape is decoded and marked escaped.
  • When jz run has no parser for a command and nothing in its arguments
    names one, the refusal shows how to name one:
    jz run --parser PARSER -- COMMAND ....
  • split: aligned reads a heading of several words, such as
    CONTAINER ID or Soft Limit, as one column when header.columns
    gives it the name those words derive together.
  • Definitions for lshw -short and lshw -businfo.
  • Definitions for FreeBSD md5 and the other BSD digest commands,
    sysctl, vmstat -i, df -hT and arp -a, and for OpenZFS
    zfs list and zpool list.
  • Definitions for FreeBSD kldstat -h, netstat -ib, netstat -r,
    sockstat -s, last -y and iostat -x, and for ldd output that
    names each program above its libraries (glibc given several programs,
    FreeBSD always).
  • With --stream and --explain=json, a record the stream leaves out is
    reported when it is left out, on its own jz: explain: line of
    standard error: {"event":"skipped","definition":...,"line":..., "reason":...,"skipped":N}, where skipped counts the records left out
    so far. --explain writes the same fact as a line of text.
  • Releases sign checksums.txt with cosign, include an SPDX SBOM for
    each archive, and publish a Homebrew cask to nao1215/homebrew-tap.
    A tag is published only after the release smoke checks pass on it.

Fixed

  • chage -l, curl --version, git count-objects -v and ethtool -i
    are read only as the lines they print, readelf -h only as the fields
    of an ELF header, and lscpu --caches holds each row to a cache name
    and type. Lines another command printed after them were read as more
    fields and as more caches. The readelf -h schema names the fields it
    can hold, and is version 2.
  • systemctl list-sockets, list-paths, list-timers,
    list-automounts, list-machines, list-unit-files, list-jobs and
    list-units, networkctl list, loginctl list-sessions,
    list-seats and list-users, systemd-inhibit --list and tree
    read their count line ("29 sockets listed.", "3 directories, 5
    files") as the end of the listing. Another
    command's output after it is refused as unread (exit 3), where rows of
    it that fit the columns were read as more entries.
  • jz run sysctl and jz run lsof on macOS found no definition: both are
    the programs FreeBSD and Linux have, printing the same lines, and their
    definitions now apply there. ls -le and ls -lO on macOS, which add
    access control lists and file flags to a long listing, are refused by
    the argument rather than failing on the first list.
  • Ctrl-C typed at a terminal reached the command jz run started twice:
    once from the terminal, which sends it to the whole foreground group,
    and once passed on by jz. A command that stops at once on a second
    interrupt was stopped by one keypress. jz no longer passes on an
    interrupt when the terminal's foreground group is its own and the
    command is in it.
  • jz run ls -l for a user whose environment sets QUOTING_STYLE
    returned names with the quotes in them. jz runs ls with the literal
    style, and the long listings refuse -Q, --quoting-style, -b and
    -q, which change the names they print.
  • jz run git log --oneline in a repository or for a user whose
    configuration sets log.decorate returned the branch names as part of
    the first subject. jz runs git with decorations and signatures off for
    this format, refuses -c and --config-env among its arguments, and
    on a pipe refuses a line whose parenthesis opens with HEAD, a tag or
    a remote branch. An args entry that ends in = matches the long
    option with any value.
    exec.env now comes from the variants the arguments leave, so the
    setting does not reach git config --list.
  • A duration with a fraction of a unit under a second is the number the
    text names: 1.3 ms is 0.0013 where it was 0.0013000000000000002,
    and systemd-analyze critical-chain reports +87ms as 0.087. The
    parts of a duration are added up exactly and turned into a number
    once.
  • jz run systeminfo /fo csv no longer suggests that systeminfo runs
    csv. A name whose definitions only describe a shape (csv, table)
    is an option's value when it appears among a command's arguments.
  • jz run systemctl list-units --plain failed with exit 3 while a unit
    had a job pending. --plain drops the marker column, and the
    definition for the table with a JOB column expected the header to be
    indented for it. That table now has its own definition,
    systemctl/units-jobs-plain, and systemctl/units-jobs reads only
    the indented header.
  • ip address output whose first inet line is past the first twenty
    lines, as when nine or more interfaces without an address come first,
    was read as ip link with each address and lifetime as a setting.
    iproute2's output is now read as ip address (its header has the
    group and no mode), and BusyBox's, whose header is the same for both,
    is refused.
  • sysctl/freebsd no longer reads the lines of a value printed over
    ...
Read more

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 16:40
319fc31

The first release of jsonize and its jz command.

Added

  • jz converts command output from standard input or --file into
    JSON. It identifies the format from the text, and refuses input it
    cannot identify or read completely instead of guessing.
  • jz run COMMAND [args...] runs a command without a shell, converts its
    standard output and exits with the command's status. The command name
    and its arguments narrow the choice of definition; --env,
    --keep-locale and --timeout control how the command runs.
  • Output options: --pretty, --yaml, --stream for commands that keep
    printing, --extract and --exclude for keys, and --raw for values
    without field conversion.
  • Selection options: --parser and --variant name a definition,
    --define supplies one inline, --columns names csv columns, and
    --explain reports why a definition was chosen.
  • --assume-year and --assume-zone for timestamps printed without a
    year or with a zone abbreviation.
  • An embedded registry of 451 YAML definitions for 169 commands and
    files, covering GNU, BusyBox, macOS, FreeBSD and Windows variants where
    their output differs, with 1,226 captured or documented fixtures.
  • A published JSON Schema for the output of every definition under
    registry/schemas, shown by jz list --schema COMMAND VARIANT.
  • jz list for supported commands and definitions, and jz test for
    checking local definitions against their fixtures and the official
    fixture corpus.
  • Layered registries: JSONIZE_REGISTRY_PATH, the user registry and the
    embedded registry. Definitions are data and are never downloaded.
  • bash and zsh completion from jz completion.
  • Go packages under pkg/ for loading registries, selecting a definition
    and parsing text.
  • Release archives for Linux, macOS and Windows on amd64 and arm64,
    .deb, .rpm and .apk packages, SHA-256 checksums and GitHub build
    provenance.

Known limitations

  • Rounded human-readable sizes such as 1.8T stay strings.
  • Some generic formats, such as du, wc and env, are read only when
    the parser is named.
  • Windows command output is read for ipconfig, ipconfig /all and
    systeminfo in English. Other languages and code pages are not
    checked.
  • FreeBSD is tested by the end-to-end suite but has no release archive.
    Install it with go install.
  • Windows release binaries are built with GOEXPERIMENT=nogreenteagc,
    the garbage collector configuration the Windows CI jobs run.