tabnasjsonl

package module
v0.1.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 6 Imported by: 0

README

jsonl (Go)

A JSON Lines (JSONL, also known as NDJSON) grammar plugin for the Tabnas parsing engine (github.com/tabnas/parser/go).

Each line of the source is one complete, standard-JSON value, the newline is the record separator, and a document parses to a slice of the per-line values.

This is the Go port; the TypeScript package (../ts/) is canonical. Both runtimes run the shared fixtures in ../test/spec/ and produce the same values.

Install

go get github.com/tabnas/jsonl/go@latest
import tabnasjsonl "github.com/tabnas/jsonl/go"

The module requires github.com/tabnas/parser/go (the engine) and github.com/tabnas/json/go (the strict-JSON grammar it layers on). Both are ordinary module requirements, resolved by go get.

One example

tabnasjsonl.Parse is the one-call entry point: pass source, get the records and an error:

package main

import (
	"fmt"

	tabnasjsonl "github.com/tabnas/jsonl/go"
	tabnas "github.com/tabnas/parser/go"
)

func main() {
	doc, err := tabnasjsonl.Parse(`{"name":"alice","age":30}
{"name":"bob","age":25}`)
	if err != nil {
		panic(err)
	}

	for _, rec := range doc.([]any) {
		name, _ := rec.(*tabnas.OrderedMap).Get("name")
		fmt.Println(name)
	}
	// alice
	// bob
}

Parse returns any, always a []any on success, one entry per record, in source order. A JSON object parses to a *tabnas.OrderedMap (insertion-ordered; Map.Plain yields a plain map[string]any instead), an array to []any, and scalars to float64 / string / bool / nil.

Parse reuses one lazily built instance, so repeated calls do not rebuild the engine, and it is safe for concurrent use. To configure the parser, build your own instance with tabnasjsonl.Make(extra ...).

One record per line

The format's defining rule is that a record occupies exactly one line, so a value split across lines is not a record:

tabnasjsonl.Parse("{\"a\":1}\n{\"b\":2}") // 2 records
tabnasjsonl.Parse("{\n  \"a\": 1\n}")     // error at 1:2 (pretty-printed JSON is not JSONL)

Nothing in this plugin's grammar states that rule. It follows from the newline being a token the parser can see: see doc/concepts.md.

How it is put together

The plugin adds no lexer matchers and reuses the whole strict-JSON rule set (val / map / list / pair / elem) from github.com/tabnas/json/go untouched. It does two things:

  1. drops #LN from the IGNORE token set, so a newline stops being skipped and becomes a token the grammar can match;
  2. adds two rules: jsonl (the document) and record (one line).

Install it on an engine that already carries the strict-JSON grammar. Order matters; Make does it for you:

import (
	tabnasjson "github.com/tabnas/json/go"
	tabnasjsonl "github.com/tabnas/jsonl/go"
	tabnas "github.com/tabnas/parser/go"
)

j := tabnas.Make()
j.Use(tabnasjson.Json)   // strict JSON first
j.Use(tabnasjsonl.Jsonl) // then JSON Lines

// identical to:
j = tabnasjsonl.Make()

Jsonl on a bare engine returns an error rather than installing the JSON grammar itself, because the two orders are not equivalent: the json plugin narrows the active rule alternates to its own json tag, which would filter this plugin's alternates back out.

Documentation

Full documentation follows the Diátaxis framework:

  • Tutorial. A guided first parse, start to finish.
  • How-to guide. Short recipes for individual tasks.
  • Reference. The public API, the document grammar, and what each record accepts.
  • Concepts. How one lexer change produces the one-record-per-line rule, and how the Go version differs from TypeScript.

For the canonical TypeScript implementation, see ../ts/README.md.

Test

From this directory:

go build ./...
go test ./...

go test runs the in-language suite (jsonl_test.go) plus every shared fixture in ../test/spec/, which parity_test.go discovers by glob. ts/test/parity.test.ts discovers the same files, so adding a .tsv there covers both runtimes.

License

Copyright (c) 2026 tabnas, MIT License. See ../LICENSE.

Documentation

Overview

Package jsonl is a JSON Lines (JSONL, also known as NDJSON) grammar plugin for the tabnas parsing engine (github.com/tabnas/parser/go).

JSON Lines (https://jsonlines.org) is a text format where each line is one complete, standard-JSON value, and the newline is the record separator. A document parses to a slice of the per-line values.

{"name":"alice","age":30}
{"name":"bob","age":25}

=> []any{map[...]{name:alice, age:30}, map[...]{name:bob, age:25}}

This plugin is a deliberately small demonstration of the engine's extensible-grammar model: it adds NO lexer matchers and re-uses the entire strict-JSON rule set (val / map / list / pair / elem) from github.com/tabnas/json/go untouched. All of JSONL is expressed as

  1. one lexer semantic change — the newline token stops being ignorable and becomes a meaningful token the grammar can match;
  2. two new rules — jsonl (the document) and record (one line).

Point 1 does more work than it appears to. Once #LN is no longer in the IGNORE token set, a newline inside a record is no longer invisible to the parser, so a value SPLIT ACROSS LINES stops parsing — which is exactly the JSON Lines requirement that each record occupy one line. That rule is not written down anywhere below; it falls out of making the separator significant.

This is the Go port; the TypeScript package (ts/src/jsonl.ts) is canonical. The two are held together by the shared test/spec/*.tsv fixtures, which both runtimes discover and run.

Index

Constants

View Source
const VERSION = "0.1.12"

VERSION is this module's version. It MUST equal ts/package.json "version": the release orchestrator rewrites both, and TestVersionMatchesPackageJSON fails the build if they drift.

Variables

This section is empty.

Functions

func Jsonl

func Jsonl(j *tabnas.Tabnas, _ map[string]any) error

Jsonl is the standard plugin form. Install it on an engine that ALREADY has the strict-JSON grammar:

j := tabnas.Make()
tabnasjson.Json(j, nil)
tabnasjsonl.Jsonl(j, nil)

Order matters, and not only by convention: the json plugin sets rule.Include "json", which would filter this plugin's alternates straight back out if it were applied afterwards. Applying the json plugin here when it is absent would silently accept the wrong order, so instead the missing-grammar case is reported.

func Make

func Make(extra ...tabnas.Options) *tabnas.Tabnas

Make builds a JSON Lines parser instance: a tabnas engine with the strict-JSON grammar and this plugin installed, in that order. Extra options are applied after the grammar exists, mirroring the TS make().

func Parse

func Parse(src string) (any, error)

Parse parses a JSON Lines source string and returns the slice of per-line values, or a *tabnas.TabnasError on failure. The error's Row is the line of the offending record.

func RegisterJsonlGrammar

func RegisterJsonlGrammar(j *tabnas.Tabnas) error

RegisterJsonlGrammar installs the JSONL document rules on j via the engine's declarative grammar spec — the same shape as the TypeScript registerJsonlGrammar. Exposed separately from the options (the same split github.com/tabnas/json/go makes) so a plugin layering on JSONL can re-use the rules without re-declaring them.

The value tree is built entirely by the engine's native-value $-builtins, so this grammar is function-free and serializable:

@array$ — allocate an empty array into the node (the document).
@push$  — append the just-built child value to that array.

Types

type JsonlError

type JsonlError = tabnas.TabnasError

JsonlError is the error type returned by a failed parse — an alias of the engine's *tabnas.TabnasError (with Code / Row / Col / Hint fields and a formatted Error() report). Mirrors the TS re-export `export { TabnasError as JsonlError }`; reach it with `errors.As(err, &je)` where je is a *tabnasjsonl.JsonlError.

type TranslationPart added in v0.1.11

type TranslationPart struct {
	Entry  string
	Source string
}

TranslationPart is one optional alchemy source and the entry point a host calls.

type TranslationParts added in v0.1.11

type TranslationParts struct {
	Manifest string
	Lift     *TranslationPart
	Render   *TranslationPart
}

TranslationParts is the package-local structural translation interface.

func Translate added in v0.1.11

func Translate() *TranslationParts

Translate returns JSON Lines' immutable translation parts.

Directories

Path Synopsis
core.go — the library's behaviour, in plain Go.
core.go — the library's behaviour, in plain Go.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL