feat: add the -validate mode to interpres-decode
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Command interpres-decode reads a TOML document from standard input and writes
|
||||
// the toml-test "tagged JSON" representation to standard output.
|
||||
// Command interpres-decode is the toml-test harness adapter and a TOML
|
||||
// validator. Without flags it reads a TOML document from standard input and
|
||||
// writes the toml-test "tagged JSON" representation to standard output. With
|
||||
// -validate it checks the named documents, or standard input when none are
|
||||
// named, and exits non-zero on the first invalid one:
|
||||
//
|
||||
// It exits non-zero on a parse error, which is how the toml-test harness checks
|
||||
// that invalid documents are rejected. Run the official suite against it with:
|
||||
// interpres-decode -validate config.toml
|
||||
//
|
||||
// Run the official suite against the adapter with:
|
||||
//
|
||||
// toml-test ./interpres-decode
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -23,13 +29,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(Run(os.Stdin, os.Stdout, os.Stderr))
|
||||
os.Exit(Run(os.Args[1:], os.Stdin, os.Stdout, os.Stderr))
|
||||
}
|
||||
|
||||
// Run reads a TOML document from stdin, emits the toml-test tagged-JSON form
|
||||
// on stdout, and returns the process exit code (0 success, 1 parse error,
|
||||
// 2 I/O, encoding, or unsupported-value error).
|
||||
func Run(stdin io.Reader, stdout, stderr io.Writer) int {
|
||||
// Run runs the command line and returns the process exit code: 0 success,
|
||||
// 1 an invalid document, 2 a usage, reading, encoding, or
|
||||
// unsupported-value error.
|
||||
func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
|
||||
fs := flag.NewFlagSet("interpres-decode", flag.ContinueOnError)
|
||||
fs.SetOutput(stderr)
|
||||
validate := fs.Bool("validate", false, "validate the documents instead of emitting tagged JSON")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
if errors.Is(err, flag.ErrHelp) {
|
||||
return 0
|
||||
}
|
||||
return 2
|
||||
}
|
||||
if *validate {
|
||||
return validatePaths(fs.Args(), stdin, stderr)
|
||||
}
|
||||
if fs.NArg() > 0 {
|
||||
fmt.Fprintln(stderr, "interpres-decode: the adapter mode takes no arguments; name files with -validate")
|
||||
return 2
|
||||
}
|
||||
data, err := io.ReadAll(stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintln(stderr, "read stdin:", err)
|
||||
@@ -54,6 +76,39 @@ func Run(stdin io.Reader, stdout, stderr io.Writer) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// validatePaths parses every named file, or standard input when none are
|
||||
// named, and reports each invalid document on stderr. It returns 0 when all
|
||||
// documents parse, 1 when one does not, and 2 on a usage or read failure.
|
||||
func validatePaths(paths []string, stdin io.Reader, stderr io.Writer) int {
|
||||
if len(paths) == 0 {
|
||||
paths = []string{"-"}
|
||||
}
|
||||
valid := true
|
||||
for _, p := range paths {
|
||||
name := p
|
||||
var data []byte
|
||||
var err error
|
||||
if p == "-" {
|
||||
data, err = io.ReadAll(stdin)
|
||||
name = "<stdin>"
|
||||
} else {
|
||||
data, err = os.ReadFile(p)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "interpres-decode: %s: %v\n", name, err)
|
||||
return 2
|
||||
}
|
||||
if _, err := interpres.Parse(data); err != nil {
|
||||
fmt.Fprintf(stderr, "%s: %v\n", name, err)
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// tag converts an interpres value into its toml-test tagged-JSON form. Tables
|
||||
// become JSON objects and arrays become JSON arrays; scalars are wrapped in a
|
||||
// {"type", "value"} object. An error is returned for value types the encoder
|
||||
|
||||
Reference in New Issue
Block a user