Load a default written out in every position, refuse null outside a column again, read a field once per alternation, refuse an empty segment in the CLI's lone reference, and hold a declared datatype as one value

This commit is contained in:
2026-10-07 23:20:59 +02:00
committed by Lillem4n
parent 49736bd2b6
commit d8acc9f3f3
8 changed files with 104 additions and 71 deletions
+30 -11
View File
@@ -291,12 +291,15 @@ func operandError(arg string) error {
if fi, err := os.Stat(arg); err == nil && fi.Mode().IsRegular() {
return fmt.Errorf("%s; read a file from stdin: fejkdata < %s", unexpected, shellQuoted(arg))
}
example, ref := pipeHint, "{/"+strings.TrimPrefix(arg, "/")+"}"
if _, lone := loneReference(arg); lone {
ref := "{/" + strings.TrimPrefix(arg, "/") + "}"
_, argLone := loneReference(arg)
inline, err := fejkdata.IsTemplate(arg)
_, refLone := loneReference(ref)
example := pipeHint
switch {
case argLone || inline:
example = piped(arg)
} else if inline, err := fejkdata.IsTemplate(arg); inline {
example = piped(arg)
} else if _, lone := loneReference(ref); lone && err == nil {
case err == nil && refLone:
example = piped(ref)
}
return fmt.Errorf("%s; the template is read from stdin: %s", unexpected, example)
@@ -453,11 +456,8 @@ type input struct {
// allowed.
func parseInput(raw string) (input, error) {
trimmed := strings.Trim(raw, jsonSpace)
switch trimmed {
case "":
if trimmed == "" {
return input{}, fmt.Errorf("stdin holds no template: %s", pipeHint)
case "null":
return input{}, fmt.Errorf("stdin holds only null, as jq prints for a missing key: %s", pipeHint)
}
text := raw
if json.Valid([]byte(trimmed)) {
@@ -487,20 +487,39 @@ func loneReference(text string) (string, bool) {
}
// isPath reports whether a reference's body after its / is a path alone: no second /, no
// folder sigil, and none of the |, ( or " as " a token reads outside a selector.
// folder sigil, no empty segment, and none of the |, ( or " as " a token reads outside a selector.
// It copies the grammar, since the CLI reads only the library's public API.
func isPath(body string) bool {
if body == "" || strings.ContainsAny(body[:1], "/.") {
return false
}
names := withoutSelectors(body)
if strings.ContainsAny(names, "|(") || strings.Contains(names, " as ") {
if strings.ContainsAny(names, "|(") || strings.Contains(names, " as ") || hasEmptySegment(names) {
return false
}
inline, err := fejkdata.IsTemplate(body)
return !inline && err == nil
}
// hasEmptySegment reports whether a dotted path holds a segment with no name: two dots are a
// step up, and only a step up may end the path.
func hasEmptySegment(path string) bool {
segments := strings.Split(path, ".")
stepUp := false
for i, seg := range segments[1:] {
last := i == len(segments)-2
switch {
case seg != "":
stepUp = false
case stepUp && !last, !stepUp && last:
return true
default:
stepUp = !stepUp
}
}
return false
}
// spacedReference adds to a record refusal that whitespace around a lone reference made
// the template text.
func spacedReference(template string, err error) error {