Full Code of rjrodger/jsonic for AI

main 38693d01a0a6 cached
296 files
2.7 MB
727.9k tokens
1894 symbols
1 requests
Download .txt
Showing preview only (2,911K chars total). Download the full file or copy to clipboard to get everything.
Repository: rjrodger/jsonic
Branch: main
Commit: 38693d01a0a6
Files: 296
Total size: 2.7 MB

Directory structure:
gitextract_o0u0amii/

├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── CNAME
├── LICENSE
├── Makefile
├── README.md
├── TODO.md
├── bin/
│   ├── jsonic
│   └── jsonic-bnf
├── dist/
│   ├── bnf.d.ts
│   ├── bnf.js
│   ├── debug.d.ts
│   ├── debug.js
│   ├── defaults.d.ts
│   ├── defaults.js
│   ├── error.d.ts
│   ├── error.js
│   ├── grammar.d.ts
│   ├── grammar.js
│   ├── jsonic-bnf-cli.d.ts
│   ├── jsonic-bnf-cli.js
│   ├── jsonic-cli.d.ts
│   ├── jsonic-cli.js
│   ├── jsonic.d.ts
│   ├── jsonic.js
│   ├── lexer.d.ts
│   ├── lexer.js
│   ├── parser.d.ts
│   ├── parser.js
│   ├── rules.d.ts
│   ├── rules.js
│   ├── self.d.ts
│   ├── self.js
│   ├── tsconfig.tsbuildinfo
│   ├── types.d.ts
│   ├── types.js
│   ├── utility.d.ts
│   └── utility.js
├── dist-test/
│   ├── prep.js
│   └── tsconfig.tsbuildinfo
├── doc/
│   ├── api.md
│   ├── bnf-to-jsonic-feasibility.md
│   ├── lsp-feasibility.md
│   ├── options.md
│   ├── plugins.md
│   └── syntax.md
├── docs/
│   ├── 404.html
│   ├── CNAME
│   ├── assets/
│   │   ├── css/
│   │   │   └── 0.styles.610e9dca.css
│   │   └── js/
│   │       ├── 10.88d9a57b.js
│   │       ├── 11.7988a5fa.js
│   │       ├── 12.d9f3d941.js
│   │       ├── 13.775f91ca.js
│   │       ├── 14.f56c2700.js
│   │       ├── 15.00058088.js
│   │       ├── 16.70a6eea0.js
│   │       ├── 17.0d1f36b1.js
│   │       ├── 18.0f184e32.js
│   │       ├── 19.57ad231b.js
│   │       ├── 2.34930047.js
│   │       ├── 20.58c8b075.js
│   │       ├── 21.0c46ffa9.js
│   │       ├── 22.965cbc0d.js
│   │       ├── 23.18c270f0.js
│   │       ├── 24.5895d76a.js
│   │       ├── 25.a347f1d6.js
│   │       ├── 26.c7b8345d.js
│   │       ├── 27.4e6f90b7.js
│   │       ├── 28.6e0fa7bc.js
│   │       ├── 29.77b8e3b6.js
│   │       ├── 3.6ce1235a.js
│   │       ├── 30.69b1b865.js
│   │       ├── 31.c68f976d.js
│   │       ├── 32.0a08a140.js
│   │       ├── 4.064b2ac3.js
│   │       ├── 5.46815478.js
│   │       ├── 6.f03d59ff.js
│   │       ├── 7.6be3acca.js
│   │       ├── 8.0a081a71.js
│   │       ├── 9.9b6e31d5.js
│   │       └── app.0c621e62.js
│   ├── guide/
│   │   ├── alternatives.html
│   │   ├── custom-parsers.html
│   │   ├── getting-started.html
│   │   ├── index.html
│   │   ├── install.html
│   │   ├── syntax-introduction.html
│   │   └── tutorials.html
│   ├── index.html
│   ├── jsonic.js
│   ├── plugin/
│   │   ├── csv.html
│   │   ├── dynamic.html
│   │   ├── hoover.html
│   │   ├── index.html
│   │   ├── json.html
│   │   ├── multifile.html
│   │   └── native.html
│   ├── railroad-diagrams.css
│   ├── ref/
│   │   ├── api.html
│   │   ├── index.html
│   │   ├── options.html
│   │   └── syntax.html
│   └── tutorial/
│       ├── index.html
│       ├── parsing-csv.html
│       ├── write-a-parser.html
│       └── write-a-plugin.html
├── go/
│   ├── README.md
│   ├── alignment_test.go
│   ├── both_ref_test.go
│   ├── color_test.go
│   ├── comment_suffix_test.go
│   ├── coverage.html
│   ├── csv_grammar_test.go
│   ├── debug.go
│   ├── directive_grammar_test.go
│   ├── doc/
│   │   ├── api.md
│   │   ├── differences.md
│   │   ├── options.md
│   │   ├── plugins.md
│   │   └── syntax.md
│   ├── feature_tsv_test.go
│   ├── fnref_identity_test.go
│   ├── fnref_reinstall_test.go
│   ├── go.mod
│   ├── grammar.go
│   ├── grammar_decl_test.go
│   ├── grammar_setting_test.go
│   ├── grammarspec.go
│   ├── jsonic.go
│   ├── jsonic_nontsv_test.go
│   ├── jsonic_test.go
│   ├── lexer.go
│   ├── listchild_test.go
│   ├── listref_test.go
│   ├── mapref_test.go
│   ├── nlookahead_test.go
│   ├── options.go
│   ├── options_parity_test.go
│   ├── parser.go
│   ├── plugin.go
│   ├── plugin_test.go
│   ├── readme_test.go
│   ├── rule.go
│   ├── rule_include_test.go
│   ├── safe_test.go
│   ├── text.go
│   ├── textinfo_test.go
│   ├── token.go
│   ├── token_test.go
│   ├── util.go
│   ├── util_test.go
│   ├── utility.go
│   └── variant_test.go
├── package.json
├── src/
│   ├── bnf.ts
│   ├── debug.ts
│   ├── defaults.ts
│   ├── error.ts
│   ├── grammar.ts
│   ├── jsonic-bnf-cli.ts
│   ├── jsonic-cli.ts
│   ├── jsonic.ts
│   ├── lexer.ts
│   ├── mfix.js
│   ├── parser.ts
│   ├── rules.ts
│   ├── self.ts
│   ├── tsconfig.json
│   ├── types.ts
│   └── utility.ts
└── test/
    ├── aa-wildcard.test.js
    ├── alignment.test.js
    ├── also-bad-plugin.js
    ├── angle.js
    ├── api.test.js
    ├── bad-plugin.js
    ├── bar.jsonic
    ├── bnf.test.js
    ├── cli.test.js
    ├── comma.test.js
    ├── comment.test.js
    ├── csv-grammar.test.js
    ├── custom.test.js
    ├── debug.test.js
    ├── directive-grammar.test.js
    ├── dive.js
    ├── doc.test.js
    ├── error.test.js
    ├── exhaust.js
    ├── feature.test.js
    ├── first-version-perf.js
    ├── first-version.test.js
    ├── foo.jsonic
    ├── grammar/
    │   ├── arith-leftrec.bnf
    │   ├── arith.bnf
    │   ├── greet.bnf
    │   ├── json-subset.bnf
    │   ├── pair.bnf
    │   └── rfc3986-uri.abnf
    ├── grammar.test.js
    ├── happy.js
    ├── json-standard.js
    ├── jsonic.test.js
    ├── justjson.js
    ├── large.js
    ├── lex.test.js
    ├── long.js
    ├── module.mjs
    ├── multifile-remove/
    │   ├── again.jsonic
    │   ├── blue01.js
    │   ├── func.js
    │   ├── green01.json
    │   ├── main01.jsonic
    │   └── trunk/
    │       ├── branch.jsonic
    │       └── twig/
    │           └── leaf1.jsonic
    ├── nlookahead.test.js
    ├── p0.js
    ├── p1.js
    ├── p2.js
    ├── pa-qa.js
    ├── perf.js
    ├── plugin-default.js
    ├── plugin-name.js
    ├── plugin.test.js
    ├── plugins-parity.sh
    ├── prep.ts
    ├── probe.test.js
    ├── quick.js
    ├── readme.test.js
    ├── require.js
    ├── rewind.test.js
    ├── rfc3986.test.js
    ├── safe.test.js
    ├── smoke.js
    ├── spec/
    │   ├── alignment-empty.tsv
    │   ├── alignment-errors.tsv
    │   ├── alignment-map-merge.tsv
    │   ├── alignment-number-text.tsv
    │   ├── alignment-safe-key.tsv
    │   ├── alignment-structure.tsv
    │   ├── alignment-values.tsv
    │   ├── comma-implicit-comma.tsv
    │   ├── comma-optional-comma.tsv
    │   ├── exclude-comma-errors.tsv
    │   ├── exclude-comma.tsv
    │   ├── exclude-strict-json-errors.tsv
    │   ├── exclude-strict-json.tsv
    │   ├── feature-comment-suffix-block.tsv
    │   ├── feature-comment-suffix-line.tsv
    │   ├── feature-debug-cases.tsv
    │   ├── feature-implicit-map.tsv
    │   ├── feature-implicit-object.tsv
    │   ├── feature-list-child-deep.tsv
    │   ├── feature-list-child-pair-deep.tsv
    │   ├── feature-list-child-pair.tsv
    │   ├── feature-list-child.tsv
    │   ├── feature-list-pair.tsv
    │   ├── feature-map-child-deep.tsv
    │   ├── feature-map-child.tsv
    │   ├── feature-nested-space-pairs.tsv
    │   ├── fv-arrays.tsv
    │   ├── fv-comma.tsv
    │   ├── fv-deep.tsv
    │   ├── fv-drop-outs.tsv
    │   ├── fv-numbers.tsv
    │   ├── fv-subobj.tsv
    │   ├── fv-types.tsv
    │   ├── fv-works.tsv
    │   ├── happy.tsv
    │   ├── include-json-errors.tsv
    │   ├── include-json.tsv
    │   ├── jsonic-basic-array-tree.tsv
    │   ├── jsonic-basic-json.tsv
    │   ├── jsonic-basic-mixed-tree.tsv
    │   ├── jsonic-basic-object-tree.tsv
    │   ├── jsonic-funky-keys.tsv
    │   ├── jsonic-process-array.tsv
    │   ├── jsonic-process-implicit-object.tsv
    │   ├── jsonic-process-mixed-nodes.tsv
    │   ├── jsonic-process-object-tree.tsv
    │   ├── jsonic-process-scalars.tsv
    │   ├── jsonic-process-text.tsv
    │   ├── jsonic-process-whitespace.tsv
    │   ├── lex-errors.tsv
    │   ├── utility-deep.tsv
    │   ├── utility-modlist.tsv
    │   ├── utility-str.tsv
    │   └── utility-strinject.tsv
    ├── spec.test.js
    ├── syntax-error.js
    ├── test-plugins.sh
    ├── tsconfig.json
    ├── utility.js
    ├── utility.test.js
    ├── variant.test.js
    └── web-all.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
name: build

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [24.x]

    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@v4
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm i
    - run: npm run build --if-present
    - run: npm test


  build-go:

    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]

    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@v4
    - name: Set up Go
      uses: actions/setup-go@v5
      with:
        go-version: '1.24'
    - name: Build
      run: go build ./...
      working-directory: ./go
    - name: Test
      run: go test ./...
      working-directory: ./go



================================================
FILE: .gitignore
================================================
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz

pids
logs
results

npm-debug.log

*~
node_modules

.idea/


trial

test/coverage.html

coverage

package-lock.json
yarn.lock


================================================
FILE: CNAME
================================================
jsonic.richardrodger.com

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2013-2020 Richard Rodger

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
.PHONY: all build test clean build-ts build-go test-ts test-go clean-ts clean-go publish-go tags-go reset

all: build test

build: build-ts build-go

test: test-ts test-go

clean: clean-ts clean-go

# TypeScript
build-ts:
	npm run build

test-ts:
	npm test

clean-ts:
	rm -rf dist dist-test

# Go
build-go:
	cd go && go build ./...

test-go:
	cd go && go test -v ./...

clean-go:
	cd go && go clean

# Publish Go module: make publish-go V=0.1.7
publish-go: test-go
	@test -n "$(V)" || (echo "Usage: make publish-go V=x.y.z" && exit 1)
	sed -i '' 's/^const Version = ".*"/const Version = "$(V)"/' go/jsonic.go
	sed -i '' 's/^Version: .*/Version: $(V)/' go/README.md
	git add go/jsonic.go go/README.md
	git commit -m "go: v$(V)"
	git tag go/v$(V)
	git push origin main go/v$(V)
	if command -v gh >/dev/null 2>&1; then gh release create go/v$(V) --title "go/v$(V)" --notes "Go module release v$(V)"; fi

tags-go:
	git tag -l 'go/v*' --sort=-version:refname

reset:
	npm run reset
	cd go && go clean -cache
	cd go && go build ./...
	cd go && go test -v ./...


================================================
FILE: README.md
================================================
# jsonic

JSON is great. JSON parsers are not. They punish you for every missing
quote and misplaced comma. You're a professional -- you know what you
meant. jsonic knows too.

```
a:1,foo:bar  →  {"a": 1, "foo": "bar"}
```

It's a JSON parser that isn't strict. And it's very, very extensible.

Available for [TypeScript/JavaScript](#install) and [Go](go/).

## Install

```bash
npm install jsonic
```

## Quick Example

```js
const { Jsonic } = require('jsonic')

// Relaxed syntax, just works
Jsonic('a:1, b:2')           // {"a": 1, "b": 2}
Jsonic('x, y, z')            // ["x", "y", "z"]
Jsonic('{a: {b: 1, c: 2}}') // {"a": {"b": 1, "c": 2}}
```

```ts
import { Jsonic } from 'jsonic'

Jsonic('a:1, b:2') // {"a": 1, "b": 2}
```

## What Syntax Does jsonic Accept?

More than you'd expect. All of the following parse to `{"a": 1, "b": "B"}`:

```
a:1,b:B
```

```
a:1
b:B
```

```
a:1
// a:2
# a:3
/* b wants
 * to B
 */
b:B
```

```
{ "a": 100e-2, '\u0062':`\x42`, }
```

That last one mixes double quotes, single quotes, backticks, unicode
escapes, hex escapes, and scientific notation. It doesn't matter. jsonic
handles it.

Here's the full set of relaxations:

- **Unquoted keys and values**: `a:1` → `{"a": 1}`
- **Implicit top-level object**: `a:1,b:2` → `{"a": 1, "b": 2}`
- **Implicit top-level array**: `a,b` → `["a", "b"]`
- **Trailing commas**: `{a:1,b:2,}` → `{"a": 1, "b": 2}`
- **Single-quoted strings**: `'hello'` works like `"hello"`
- **Backtick strings**: `` `hello` `` works like `"hello"`
- **Multiline strings**: backtick strings preserve newlines
- **Indent-adjusted strings**: `'''...\n'''` trims leading indent
- **Comments**: `//`, `#` (line), `/* */` (block)
- **Object merging**: `a:{b:1},a:{c:2}` → `{"a": {"b": 1, "c": 2}}`
- **Path diving**: `a:b:1,a:c:2` → `{"a": {"b": 1, "c": 2}}`
- **All number formats**: `1e1 === 0xa === 0o12 === 0b1010`, plus `1_000` separators
- **Auto-close at EOF**: unclosed `{` or `[` close automatically

For the full syntax reference, see [doc/syntax.md](doc/syntax.md).

## Customization

You might be tempted to think a lenient parser is a simple thing. It
isn't. jsonic is built around a rule-based parser and a matcher-based
lexer. Both are fully customizable through options and plugins. You can
change almost anything about how parsing works -- and you don't have to
understand the internals to do it.

### Options

Let's start simple. Create a configured instance with `Jsonic.make()`:

```js
const lenient = Jsonic.make({
  comment: { lex: false },         // disable comments
  number: { hex: false },          // disable hex numbers
  value: {
    def: { yes: { val: true }, no: { val: false } }
  }
})

lenient('yes')  // true
```

Options compose. You turn things off, you turn things on, you define new
value tokens. That's it.

See [doc/options.md](doc/options.md) for the full options reference.

### Plugins

When options aren't enough, plugins let you reach deeper. They can
modify the grammar, add matchers, or hook into parse events:

```js
function myPlugin(jsonic, options) {
  // Register a custom fixed token
  jsonic.options({ fixed: { token: { '#TL': '~' } } })
  const T_TILDE = jsonic.token('#TL')

  // Modify grammar rules
  jsonic.rule('val', (rs) => {
    rs.open([{
      s: [T_TILDE],
      a: (rule) => { rule.node = options.tildeValue ?? null }
    }])
  })
}

const j = Jsonic.make()
j.use(myPlugin, { tildeValue: 42 })
j('~')  // 42
```

Consider what just happened: we invented a new syntax element (`~`),
told the parser what to do when it encounters one, and wired it up with
a configurable value. The parser itself doesn't care what symbols you
use. It only cares about rules.

See [doc/plugins.md](doc/plugins.md) for the plugin authoring guide.

## API Reference

See [doc/api.md](doc/api.md) for the full API.

The essentials:

| Function / Property | Description |
|---|---|
| `Jsonic(src)` | Parse a string with default settings |
| `Jsonic.make(options?)` | Create a configured parser instance |
| `instance.use(plugin, opts?)` | Register a plugin |
| `instance.rule(name, definer)` | Modify a grammar rule |
| `instance.token(ref)` | Get or create a token type |
| `instance.sub({lex?, rule?})` | Subscribe to parse events |
| `instance.options` | Current options |

## Go Version

There's a Go port with the same core parsing behavior. Same syntax,
same relaxations, same results. See the [Go documentation](go/) for
installation and usage.

```go
import "github.com/jsonicjs/jsonic/go"

result, err := jsonic.Parse("a:1, b:2")
```

## License

MIT. Copyright (c) Richard Rodger.



================================================
FILE: TODO.md
================================================
# TODO

* P1; exception inside matcher needs own error code - too easy to miss!
* P1; remove console colors in browser? option
* P2; quotes are value enders - x:a"a" is an err! not 'a"a"', option?
* P2: fix type chaining with jsonic.rule
* P3; Consider: option to control comma null insertion
* P3; YAML quoted strings: https://yaml-multiline.info/ - via options 
  * provide in yaml plugin
* P3; cli - less ambiguous merging at top level
* P3; consistent use of clean on options to allow null to mean 'remove property'
* P3; data file to diff exhaust changes
* P3; define explicitly: p in close, r in open, behaviour 
  * r in open means a run of opens with one close - see TOML - needs unit test 
  * p in close means ??? - needs unit test
* P3; docs: nice tree diagram of rules (generate?)
* P3; docs: ref https://wiki.alopex.li/OnParsers
* P3; document standard g names: open, close, step, start, end, imp, top, val, map, etc
* P3; error if fixed tokens clash
* P3; http://seriot.ch/projects/parsing_json.html 
  * implement as tests
* P3; if token recognized, error needs to be about token, not characters
* P3; implicit lists in pair values: "a:1,2 b:3" -> {a:[1,2], b:3} - pair key terminates (A)
* P3; internal errors - e.g. adding a null rulespec
* P3; is s:[] needed? different from s:undefined ?
* P3; line continuation ("\" at end) should be a feature of standard JSONIC text
* P3; option for sparse arrays: https://dmitripavlutin.com/javascript-sparse-dense-arrays/
* P3; perhaps remove the # prefix from token names?
* P3; rename tokens to be user friendly - maybe?
* P3; specific error if rule name not found when parsing
* P3; string format for rule def: s:'ST,NR' -> s:[ST,NR], also "s:ST,NR,p:foo,..." - needs (A) - can only used post standard definition (thus not in grammar.ts)
* P3; support BigInt numbers: 123n
* P3; unit test for custom alt error: eg.  { e: (r: Rule) => r.close[0] } ??? bug: r.close empty!




================================================
FILE: bin/jsonic
================================================
#!/usr/bin/env node
require('../dist/jsonic-cli').run(process.argv, console).catch((e) => console.error(e.message))


================================================
FILE: bin/jsonic-bnf
================================================
#!/usr/bin/env node
require('../dist/jsonic-bnf-cli').run(process.argv, console).catch((e) => console.error(e.message))


================================================
FILE: dist/bnf.d.ts
================================================
import type { BnfConvertOptions, GrammarSpec, Rule } from './types';
type BnfElement = {
    kind: 'term';
    literal: string;
    caseSensitive?: boolean;
} | {
    kind: 'ref';
    name: string;
} | {
    kind: 'regex';
    pattern: string;
    flags: string;
} | {
    kind: 'opt';
    inner: BnfElement;
} | {
    kind: 'star';
    inner: BnfElement;
} | {
    kind: 'plus';
    inner: BnfElement;
} | {
    kind: 'rep';
    min: number;
    max: number;
    inner: BnfElement;
} | {
    kind: 'group';
    alts: BnfSequence[];
};
type BnfSequence = BnfElement[];
type BnfProduction = {
    name: string;
    alts: BnfSequence[];
    incremental?: boolean;
    probeDispatch?: ProbeDispatchSpec;
    probeHelper?: {
        vocabElements: BnfElement[];
    };
    nodeKind?: 'user' | 'core' | 'helper';
};
type ProbeDispatchSpec = {
    probeRule: string;
    disambiguator: BnfElement;
    withBranch: string;
    noBranch: string;
};
type BnfGrammar = {
    productions: BnfProduction[];
    ambiguities?: AmbiguityReport[];
};
type AmbiguityReport = {
    rule: string;
    altIdx: number;
    optIdx: number;
    reason: string;
    resolved: boolean;
};
declare const bnfRules: Record<string, {
    bo?: (r: Rule) => void;
    bc?: (r: Rule) => void;
    open?: any[];
    close?: any[];
}>;
declare function eliminateLeftRecursion(grammar: BnfGrammar): BnfGrammar;
declare class BnfParseError extends Error {
    readonly line?: number;
    readonly column?: number;
    readonly cause?: unknown;
    constructor(message: string, location?: {
        line?: number;
        column?: number;
    }, cause?: unknown);
}
declare function parseBnf(src: string): BnfGrammar;
declare function emitGrammarSpec(grammar: BnfGrammar, opts?: BnfConvertOptions): GrammarSpec;
declare function bnf(src: string, opts?: BnfConvertOptions): GrammarSpec;
export { bnf, parseBnf, emitGrammarSpec, eliminateLeftRecursion, bnfRules, BnfParseError, };


================================================
FILE: dist/bnf.js
================================================
"use strict";
/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.BnfParseError = exports.bnfRules = void 0;
exports.bnf = bnf;
exports.parseBnf = parseBnf;
exports.emitGrammarSpec = emitGrammarSpec;
exports.eliminateLeftRecursion = eliminateLeftRecursion;
// Declarative definition of the BNF grammar itself, expressed as
// jsonic rules. Each rule names its `open`/`close` alt list and, where
// necessary, a `bo`/`bc` state hook for AST assembly.
//
// Stage 8: incremental alternatives via `name =/ alt` now fold
// into the earlier production with the same name. Quoted strings
// default to case-insensitive (ABNF semantics), `%s` / `%i` force
// sensitivity explicitly, numeric values and repetition prefixes
// work as in previous stages.
//
// Token vocabulary:
//   #DEF   `=`  (rule-definition operator)
//   #DEFA  `=/` (incremental-alternatives operator)
//   #ALT   `/`  (alternation)
//   #STAR  `*`  (repetition separator)
//   #NUM   decimal repetition count (matched via match.token)
//   #NV    `%[xdb]NN[(-NN|(.NN)*)]` numeric value (match.token)
//   #SS    `%s` (case-sensitive string prefix)
//   #SI    `%i` (case-insensitive string prefix — same as default)
//   #LP    `(`
//   #RP    `)`
//   #OB    `[` (optional-group open)
//   #CB    `]` (optional-group close)
//   #TX    bare identifier (jsonic default text token)
//   #ST    quoted string literal (jsonic default string token)
//   #ZZ    end-of-source
//
// Grammar:
//   bnf        = production*
//   production = IDENT ('=' / '=/') alts
//   alts       = seq ('/' seq)*
//   seq        = element*
//   element    = repetition? atom
//   repetition = NUM '*' NUM / NUM '*' / '*' NUM / '*' / NUM
//   atom       = IDENT | STRING | ['%s' | '%i'] STRING | NUMVAL
//              | '(' alts ')' | '[' alts ']'
//   numval     = '%' ('x' / 'd' / 'b') DIGITS [ '-' DIGITS | ('.' DIGITS)* ]
const bnfRules = {
    // Top-level: accumulates productions into r.node.
    bnf: {
        bo: (r) => { r.node = []; },
        open: [
            { s: '#ZZ', g: 'empty' },
            { p: 'prod' },
        ],
        close: [{ s: '#ZZ' }],
    },
    // One production per invocation; tail-recurses (r:'prod') for the
    // next. Inherits its parent's node (the productions array) and
    // appends to it in `bc` once its `alts` child has returned.
    // Production header is `IDENT =` — a bareword rule name followed
    // by the `=` definition operator.
    prod: {
        open: [
            // Standalone definition:   name = alts
            {
                s: '#TX #DEF',
                a: (r) => {
                    r.u.name = r.o[0].val;
                    r.u.incremental = false;
                },
                p: 'alts',
            },
            // Incremental alternatives:   name =/ alts
            {
                s: '#TX #DEFA',
                a: (r) => {
                    r.u.name = r.o[0].val;
                    r.u.incremental = true;
                },
                p: 'alts',
            },
        ],
        close: [
            // A TX followed by `=` or `=/` means the next production has
            // begun — back up 2 tokens so a fresh `prod` invocation sees
            // them.
            { s: '#TX #DEF', b: 2, r: 'prod' },
            { s: '#TX #DEFA', b: 2, r: 'prod' },
            { b: 1 },
        ],
        bc: (r) => {
            if (r.child && r.child.node !== undefined) {
                const prod = { name: r.u.name, alts: r.child.node };
                if (r.u.incremental)
                    prod.incremental = true;
                r.node.push(prod);
            }
        },
    },
    // A list of alternative sequences separated by `/` (ABNF
    // alternation). Owns its own array (`bo` resets it) and pushes
    // each seq result in `bc`.
    alts: {
        bo: (r) => { r.node = []; },
        open: [{ p: 'seq' }],
        close: [
            { s: '#ALT', p: 'seq' },
            { b: 1 },
        ],
        bc: (r) => {
            if (r.child && r.child.node !== undefined) {
                r.node.push(r.child.node);
            }
        },
    },
    // A (possibly empty) sequence of elements. The 2-token lookahead
    // `#TX #DEF` detects a following production boundary and bails
    // out without consuming the tokens; a plain `#TX` at the leading
    // position (tried later so the longer alt wins) is a rule
    // reference inside the current sequence.
    seq: {
        bo: (r) => { r.node = []; },
        open: [
            { s: '#TX #DEF', b: 2, g: 'end' },
            { s: '#TX #DEFA', b: 2, g: 'end' },
            { s: '#ALT', b: 1, g: 'end' },
            { s: '#ZZ', b: 1, g: 'end' },
            { s: '#RP', b: 1, g: 'end' },
            { s: '#CB', b: 1, g: 'end' },
            // Listing element-starter tokens in `s:` here ensures the
            // tcol-driven matcher considers each one when lexing.
            { s: '#ST', b: 1, p: 'elem' },
            { s: '#NV', b: 1, p: 'elem' },
            { s: '#SS', b: 1, p: 'elem' },
            { s: '#SI', b: 1, p: 'elem' },
            { s: '#TX', b: 1, p: 'elem' },
            { s: '#LP', b: 1, p: 'elem' },
            { s: '#OB', b: 1, p: 'elem' },
            { s: '#STAR', b: 1, p: 'elem' },
            { s: '#NUM', b: 1, p: 'elem' },
            { p: 'elem' },
        ],
        close: [
            { s: '#TX #DEF', b: 2, g: 'end' },
            { s: '#TX #DEFA', b: 2, g: 'end' },
            { s: '#ALT', b: 1, g: 'end' },
            { s: '#ZZ', b: 1, g: 'end' },
            { s: '#RP', b: 1, g: 'end' },
            { s: '#CB', b: 1, g: 'end' },
            { s: '#ST', b: 1, p: 'elem' },
            { s: '#NV', b: 1, p: 'elem' },
            { s: '#SS', b: 1, p: 'elem' },
            { s: '#SI', b: 1, p: 'elem' },
            { s: '#TX', b: 1, p: 'elem' },
            { s: '#LP', b: 1, p: 'elem' },
            { s: '#OB', b: 1, p: 'elem' },
            { s: '#STAR', b: 1, p: 'elem' },
            { s: '#NUM', b: 1, p: 'elem' },
            { b: 1 },
        ],
    },
    // One element: an optional ABNF repetition prefix (`*A`, `1*A`,
    // `m*nA`, `*nA`, `m*A`, `nA`) followed by an atom. The prefix is
    // matched up front, stored on `r.u.min`/`r.u.max`; then `atom` is
    // pushed to parse the actual element body, whose result is wrapped
    // into an AST node and appended to the parent seq's array in close.
    elem: {
        bo: (r) => { r.u.min = 1; r.u.max = 1; },
        open: [
            // NUM '*' NUM — bounded repetition, followed by the atom
            // itself (listed via the ATOM tokenset so every atom-starter
            // tin — including `#NV` — is in tcol for this position).
            {
                s: '#NUM #STAR #NUM #ATOM',
                b: 1,
                a: (r) => {
                    r.u.min = parseInt(r.o[0].src, 10);
                    r.u.max = parseInt(r.o[2].src, 10);
                },
                p: 'atom',
            },
            // NUM '*' — at-least-NUM repetition followed by an atom.
            {
                s: '#NUM #STAR #ATOM',
                b: 1,
                a: (r) => {
                    r.u.min = parseInt(r.o[0].src, 10);
                    r.u.max = Infinity;
                },
                p: 'atom',
            },
            // '*' NUM — at-most-NUM repetition.
            {
                s: '#STAR #NUM #ATOM',
                b: 1,
                a: (r) => {
                    r.u.min = 0;
                    r.u.max = parseInt(r.o[1].src, 10);
                },
                p: 'atom',
            },
            // '*' — zero-or-more.
            {
                s: '#STAR #ATOM',
                b: 1,
                a: (r) => { r.u.min = 0; r.u.max = Infinity; },
                p: 'atom',
            },
            // NUM — exact repetition count.
            {
                s: '#NUM #ATOM',
                b: 1,
                a: (r) => {
                    const n = parseInt(r.o[0].src, 10);
                    r.u.min = n;
                    r.u.max = n;
                },
                p: 'atom',
            },
            // No prefix — push atom directly (min = max = 1).
            { p: 'atom' },
        ],
        close: [{
                // Wrap the returned atom (r.child.node) based on r.u.min/max
                // and append to the parent seq's array.
                a: (r) => {
                    const item = r.child.node;
                    const { min, max } = r.u;
                    if (min === 1 && max === 1) {
                        r.node.push(item);
                    }
                    else if (min === 0 && max === Infinity) {
                        r.node.push({ kind: 'star', inner: item });
                    }
                    else if (min === 1 && max === Infinity) {
                        r.node.push({ kind: 'plus', inner: item });
                    }
                    else if (min === 0 && max === 1) {
                        r.node.push({ kind: 'opt', inner: item });
                    }
                    else {
                        r.node.push({ kind: 'rep', min, max, inner: item });
                    }
                },
            }],
    },
    // The atom body — a bareword ref, quoted-string terminal,
    // parenthesised group, or bracketed optional. Sets its OWN r.node
    // to the AST element so the enclosing `elem` rule can read it
    // from `r.child.node` in its close state.
    atom: {
        bo: (r) => { r.node = undefined; },
        open: [
            // Case-sensitive string:   %s"foo"
            {
                s: '#SS #ST',
                a: (r) => {
                    r.node = {
                        kind: 'term',
                        literal: r.o[1].val,
                        caseSensitive: true,
                    };
                },
            },
            // Case-insensitive string: %i"foo" (same as bare "foo" below,
            // but spelled explicitly).
            {
                s: '#SI #ST',
                a: (r) => {
                    r.node = { kind: 'term', literal: r.o[1].val };
                },
            },
            // Bare quoted string — case-insensitive per ABNF default.
            {
                s: '#ST',
                a: (r) => {
                    r.node = { kind: 'term', literal: r.o[0].val };
                },
            },
            {
                s: '#NV',
                a: (r) => {
                    r.node = parseNumericValue(r.o[0].src);
                },
            },
            {
                s: '#TX',
                a: (r) => {
                    r.node = { kind: 'ref', name: r.o[0].val };
                },
            },
            {
                s: '#LP',
                a: (r) => { r.u.groupKind = 'group'; },
                p: 'alts',
            },
            {
                s: '#OB',
                a: (r) => { r.u.groupKind = 'opt'; },
                p: 'alts',
            },
        ],
        close: [
            {
                s: '#RP',
                c: (r) => r.u.groupKind === 'group',
                a: (r) => {
                    r.node = { kind: 'group', alts: r.child.node };
                },
            },
            {
                s: '#CB',
                c: (r) => r.u.groupKind === 'opt',
                a: (r) => {
                    r.node = {
                        kind: 'opt',
                        inner: { kind: 'group', alts: r.child.node },
                    };
                },
            },
            // For simple atoms (string/ref), r.node is already set by
            // open; we want to pop without consuming the next token.
            // List every token that can legitimately follow an atom so
            // the lexer's tcol-driven match-matcher emits #NUM, #STAR,
            // and friends as their proper types here — otherwise the
            // default number-matcher would lex `1` as #NR and the
            // enclosing seq.close wouldn't recognise the digit as the
            // start of a repetition prefix.
            { s: '#TX', b: 1 },
            { s: '#ST', b: 1 },
            { s: '#NV', b: 1 },
            { s: '#SS', b: 1 },
            { s: '#SI', b: 1 },
            { s: '#NUM', b: 1 },
            { s: '#STAR', b: 1 },
            { s: '#LP', b: 1 },
            { s: '#OB', b: 1 },
            { s: '#RP', b: 1 },
            { s: '#CB', b: 1 },
            { s: '#ALT', b: 1 },
            { s: '#DEF', b: 1 },
            { s: '#ZZ', b: 1 },
            { b: 1 },
        ],
    },
};
exports.bnfRules = bnfRules;
// Lazily built jsonic instance that parses BNF source. Deferred
// construction avoids a circular-import failure at module load time.
let _bnfParser = null;
function getBnfParser() {
    if (_bnfParser)
        return _bnfParser;
    const { Jsonic } = require('./jsonic');
    const j = Jsonic.make({
        rule: { start: 'bnf' },
        fixed: {
            token: {
                // Clear JSON-oriented defaults we're not using so `:`, `,`
                // and `{` have no special meaning inside BNF source.
                '#OS': null,
                '#CS': null,
                '#CL': null,
                '#CA': null,
                // Re-map `#OB` / `#CB` from JSON's `{` / `}` to ABNF's
                // `[` / `]` optional-group brackets.
                '#OB': '[',
                '#CB': ']',
                '#DEF': '=',
                // `=/` — ABNF's incremental-alternatives operator. Longer
                // than `=`, so jsonic's longest-match-wins fixed matcher
                // tries it first.
                '#DEFA': '=/',
                '#ALT': '/',
                '#STAR': '*',
                '#LP': '(',
                '#RP': ')',
            },
        },
        match: {
            token: {
                // ABNF repetition counts: decimal integers.
                '#NUM': /^[0-9]+/,
                // ABNF numeric value notation:
                //   %xNN        single hex code point
                //   %dNN        single decimal code point
                //   %bNN        single binary code point
                //   %xNN-NN     hex range
                //   %xNN.NN.NN  concatenated hex code points (= string)
                // Digits are permissive (hex covers the decimal / binary
                // subsets); `parseNumericValue` re-validates against the
                // actual base.
                '#NV': /^%[xdbXDB][0-9a-fA-F]+(?:[-.][0-9a-fA-F]+)*/,
                // `%s` / `%i` prefixes on a quoted string. The lookahead
                // requires `"` so they don't steal the `%` of `%xNN`.
                '#SS': /^%[sS](?=")/,
                '#SI': /^%[iI](?=")/,
            },
        },
        tokenSet: {
            // Tokens that can legitimately open an atom. Declaring this
            // as a set lets elem.open use `#ATOM` inside its `s:` patterns
            // — that way the tcol at the atom-starter position includes
            // every matcher tin (notably #NV), so the lexer doesn't fall
            // through to #TX when the actual atom is `%xNN`.
            ATOM: ['#ST', '#NV', '#TX', '#LP', '#OB', '#SS', '#SI'],
        },
        comment: {
            // ABNF uses `;` to start a line comment. Override jsonic's
            // default `hash` definition (which used `#`) and disable the
            // other comment styles so `//` and `/* */` aren't confused
            // with the alternation operator.
            def: {
                hash: { line: true, start: ';', lex: true, eatline: false },
                slash: null,
                multi: null,
            },
        },
    });
    // Drop the default JSON rules — they would otherwise compete with
    // ours for the starting token set.
    const existing = j.rule();
    for (const name of Object.keys(existing)) {
        j.rule(name, null);
    }
    for (const name of Object.keys(bnfRules)) {
        const spec = bnfRules[name];
        j.rule(name, (rs) => {
            if (spec.bo)
                rs.bo(spec.bo);
            if (spec.bc)
                rs.bc(spec.bc);
            if (spec.open)
                rs.open(spec.open);
            if (spec.close)
                rs.close(spec.close);
        });
    }
    _bnfParser = (src) => j(src);
    return _bnfParser;
}
// Rewrite a grammar so that the only element kinds remaining are
// `term` and `ref`. Each `X?`, `X*`, `X+` occurrence is replaced by a
// reference to a newly-generated helper production that expresses the
// same language in plain BNF.
// Eliminate left recursion — both direct (P → P α) and indirect
// (P → Q α, Q → P β) — via Paull's algorithm.
//
// Order the productions, and for each A_i walk back over A_1..A_{i-1}
// inlining any leading reference into A_i's alternatives. Once the
// only remaining leading self-reference on A_i is direct, rewrite to
// the iterative form
//   P → (β_1 | … | β_m) (α_1 | … | α_n)*
// which jsonic's push-down parser can execute without re-entering P
// at the same source position.
//
// The substitution step can duplicate alternatives, so pathological
// grammars will enlarge — caller is expected to keep the grammar
// reasonably small (this is a first-step converter, not a full
// toolchain).
function eliminateLeftRecursion(grammar) {
    const originalOrder = grammar.productions.map((p) => p.name);
    // Order productions so that rules referenced at a leading position
    // are processed before the rules that reference them. Paull's
    // substitution inlines A_j's alts into A_i for j < i, so putting
    // dependencies first is what makes nullable-prefixed hidden left
    // recursion reachable by the substitution step.
    //
    // Note: substitution here always runs, even for cycle-free
    // grammars. The reason is pragmatic rather than theoretical —
    // populating tcol from multi-token altPrefixes (needed so the
    // lexer's regex matchers fire with the right tin in nested
    // contexts) requires the full inlined shape. A future refactor
    // could compute tcol from the un-substituted grammar and only
    // apply Paull's to the cyclic SCCs, which would preserve more
    // named-rule structure in the emitted AST.
    let prods = topoOrderForPaull(grammar.productions.map((p) => ({
        name: p.name,
        alts: p.alts.map((a) => a.slice()),
        nodeKind: p.nodeKind,
    })));
    for (let i = 0; i < prods.length; i++) {
        // For each earlier production A_j, inline any alternative of
        // A_i whose leading element is a reference to A_j.
        for (let j = 0; j < i; j++) {
            prods[i] = substituteLeadingRef(prods[i], prods[j]);
        }
        prods[i] = eliminateDirectLeftRec(prods[i]);
    }
    // Restore the caller's declared order, so the start rule still
    // ends up first (and the user sees their rule names in a
    // recognisable order when inspecting the spec).
    const byName = new Map(prods.map((p) => [p.name, p]));
    const ordered = [];
    for (const name of originalOrder) {
        const p = byName.get(name);
        if (p) {
            ordered.push(p);
            byName.delete(name);
        }
    }
    // Any generated productions created during substitution (none in
    // the current implementation) would fall through here.
    for (const p of byName.values())
        ordered.push(p);
    return { productions: ordered };
}
// Tarjan-flavoured SCC scan over the leading-reference graph:
// returns the names of productions that participate in at least one
// cycle (self-loop or longer). Used to scope Paull's substitution to
// only the rules that actually need it.
function findLeadingRefCycleMembers(prods) {
    const byName = new Map(prods.map((p) => [p.name, p]));
    const leadingRefs = (p) => {
        const out = [];
        for (const alt of p.alts) {
            if (alt.length === 0)
                continue;
            const first = alt[0];
            if (first.kind === 'ref' && byName.has(first.name))
                out.push(first.name);
        }
        return out;
    };
    // Tarjan's SCC algorithm.
    let index = 0;
    const stack = [];
    const onStack = new Set();
    const indices = new Map();
    const lowlinks = new Map();
    const cyclic = new Set();
    function strongConnect(name) {
        indices.set(name, index);
        lowlinks.set(name, index);
        index++;
        stack.push(name);
        onStack.add(name);
        const prod = byName.get(name);
        if (prod) {
            for (const target of leadingRefs(prod)) {
                if (!indices.has(target)) {
                    strongConnect(target);
                    lowlinks.set(name, Math.min(lowlinks.get(name), lowlinks.get(target)));
                }
                else if (onStack.has(target)) {
                    lowlinks.set(name, Math.min(lowlinks.get(name), indices.get(target)));
                }
            }
        }
        if (lowlinks.get(name) === indices.get(name)) {
            // Pop the SCC. If it has more than one member, or it's a
            // single member with a self-loop, mark as cyclic.
            const scc = [];
            let w;
            do {
                w = stack.pop();
                onStack.delete(w);
                scc.push(w);
            } while (w !== name);
            const isCycle = scc.length > 1 ||
                (scc.length === 1 && leadingRefs(byName.get(scc[0])).includes(scc[0]));
            if (isCycle)
                for (const n of scc)
                    cyclic.add(n);
        }
    }
    for (const p of prods) {
        if (!indices.has(p.name))
            strongConnect(p.name);
    }
    return cyclic;
}
// Topological order over the "leading-position reference" graph:
// an edge A → B exists when A has at least one alternative whose
// first element is a reference to B. Cycles are preserved as-is
// (Paull's handles them via the substitution + direct-LR rewrite).
function topoOrderForPaull(prods) {
    const byName = new Map(prods.map((p) => [p.name, p]));
    const colour = new Map(); // 0 unseen, 1 in-progress, 2 done
    const order = [];
    function visit(name) {
        const c = colour.get(name) ?? 0;
        if (c !== 0)
            return; // already seen or on the current path
        colour.set(name, 1);
        const p = byName.get(name);
        if (p) {
            for (const alt of p.alts) {
                if (alt.length > 0 && alt[0].kind === 'ref' && byName.has(alt[0].name)) {
                    visit(alt[0].name);
                }
            }
            colour.set(name, 2);
            order.push(p);
        }
        else {
            colour.set(name, 2);
        }
    }
    for (const p of prods)
        visit(p.name);
    return order;
}
// For every alternative of `target` that begins with a ref to
// `source`, replace that alt with |source.alts| copies — each one
// with the leading source-ref expanded to one of source's alts.
function substituteLeadingRef(target, source) {
    const newAlts = [];
    for (const alt of target.alts) {
        if (alt.length > 0 &&
            alt[0].kind === 'ref' &&
            alt[0].name === source.name) {
            const tail = alt.slice(1);
            for (const srcAlt of source.alts) {
                newAlts.push([...srcAlt, ...tail]);
            }
        }
        else {
            newAlts.push(alt);
        }
    }
    return { name: target.name, alts: newAlts, nodeKind: target.nodeKind };
}
// Rewrite a single production's direct left recursion to its
// iterative equivalent. Equivalent to the previous version of
// `eliminateLeftRecursion` but scoped to one production.
function eliminateDirectLeftRec(prod) {
    const recursive = [];
    const seeds = [];
    for (const alt of prod.alts) {
        if (alt.length > 0 &&
            alt[0].kind === 'ref' &&
            alt[0].name === prod.name) {
            recursive.push(alt.slice(1));
        }
        else {
            seeds.push(alt);
        }
    }
    // A trivial recursive alt `[P]` (P ::= P, nothing else) would
    // derive P from P with no progress — semantically a no-op. Drop
    // them silently, since nullable-prefix expansion in Paull's can
    // legitimately produce them and erroring would hide a legal
    // grammar.
    const nonTrivialRecursive = recursive.filter((t) => t.length > 0);
    if (nonTrivialRecursive.length === 0) {
        // Either no recursion at all, or only trivial self-refs — keep
        // just the seeds.
        return { name: prod.name, alts: seeds, nodeKind: prod.nodeKind };
    }
    if (seeds.length === 0) {
        throw new Error(`bnf: rule '${prod.name}' is purely left-recursive ` +
            `(no seed alternative); cannot eliminate`);
    }
    const seedElement = seeds.length === 1 && seeds[0].length === 1
        ? seeds[0][0]
        : { kind: 'group', alts: seeds };
    const tailInner = nonTrivialRecursive.length === 1 && nonTrivialRecursive[0].length === 1
        ? nonTrivialRecursive[0][0]
        : { kind: 'group', alts: nonTrivialRecursive };
    return {
        name: prod.name,
        alts: [[seedElement, { kind: 'star', inner: tailInner }]],
        nodeKind: prod.nodeKind,
    };
}
function desugar(grammar) {
    const extra = [];
    const used = new Set(grammar.productions.map((p) => p.name));
    function freshName(hint) {
        // Collision-avoiding name like `_gen1`, `_gen2`, …
        let i = extra.length;
        let name;
        do {
            i++;
            name = `_gen${i}_${hint}`;
        } while (used.has(name));
        used.add(name);
        return name;
    }
    function desugarAlt(alt) {
        return alt.map(desugarElement);
    }
    function desugarElement(el) {
        if (el.kind === 'term' || el.kind === 'ref' || el.kind === 'regex') {
            return el;
        }
        if (el.kind === 'group') {
            // Recurse into the group's alts so nested sugar is flattened,
            // then emit a helper production whose body is those alts.
            const innerAlts = el.alts.map((a) => desugarAlt(a));
            const name = freshName('group');
            extra.push({ name, alts: innerAlts, nodeKind: 'helper' });
            return { kind: 'ref', name };
        }
        // `opt`, `star`, `plus` all wrap a single inner element.
        const inner = desugarElement(el.inner);
        const hint = inner.kind === 'ref' ? inner.name :
            inner.kind === 'term' ? 'term' : 'x';
        if (el.kind === 'opt') {
            // H ::= inner | (empty)
            const name = freshName('opt_' + hint);
            extra.push({ name, alts: [[inner], []], nodeKind: 'helper' });
            return { kind: 'ref', name };
        }
        if (el.kind === 'star') {
            // H = inner H / (empty)
            const name = freshName('star_' + hint);
            const selfRef = { kind: 'ref', name };
            extra.push({ name, alts: [[inner, selfRef], []], nodeKind: 'helper' });
            return { kind: 'ref', name };
        }
        if (el.kind === 'plus') {
            // H = inner Tail   where   Tail = inner Tail / (empty)
            const tailName = freshName('star_' + hint);
            const plusName = freshName('plus_' + hint);
            const tailRef = { kind: 'ref', name: tailName };
            extra.push({
                name: tailName,
                alts: [[inner, tailRef], []],
                nodeKind: 'helper',
            });
            extra.push({
                name: plusName,
                alts: [[inner, tailRef]],
                nodeKind: 'helper',
            });
            return { kind: 'ref', name: plusName };
        }
        // ABNF m*n bounded repetition. Desugars to a concatenation of
        // `min` mandatory copies of the inner element followed by a
        // tail that accepts up to `(max - min)` more.
        //   m*n A   =>   A{m}  [A[A[A...[A]]]]   (nested optionals)
        //   m*  A   =>   A{m}  *A                 (mandatory prefix + star)
        //   *n  A   =>   [A [A ... [A]]]          (n nested optionals)
        // The helper's single alt has `min` repetitions of inner, then
        // either a star-helper for (min, ∞) or `max - min` nested
        // optionals for a finite range.
        const { min, max } = el;
        const repName = freshName('rep_' + hint);
        const repAlt = [];
        for (let i = 0; i < min; i++)
            repAlt.push(inner);
        if (max === Infinity) {
            // Tail: unbounded star of inner.
            const tailStarName = freshName('star_' + hint);
            const tailStarRef = { kind: 'ref', name: tailStarName };
            extra.push({
                name: tailStarName,
                alts: [[inner, tailStarRef], []],
                nodeKind: 'helper',
            });
            repAlt.push(tailStarRef);
        }
        else {
            // Nest (max - min) optionals: [A [A [A ...]]].
            let nested = [];
            for (let i = 0; i < max - min; i++) {
                // Wrap current `nested` into an optional and prepend `inner`.
                if (nested.length === 0) {
                    nested = [{ kind: 'opt', inner: { kind: 'group', alts: [[inner]] } }];
                }
                else {
                    nested = [{
                            kind: 'opt',
                            inner: { kind: 'group', alts: [[inner, ...nested]] },
                        }];
                }
            }
            repAlt.push(...nested);
        }
        extra.push({ name: repName, alts: [desugarAlt(repAlt)], nodeKind: 'helper' });
        return { kind: 'ref', name: repName };
    }
    const rewritten = grammar.productions.map((p) => {
        const out = {
            name: p.name,
            alts: p.alts.map(desugarAlt),
            nodeKind: p.nodeKind,
        };
        // Probe-dispatch flags survive desugar unchanged — the emitter
        // routes around the standard alt-compilation path for these.
        if (p.probeDispatch)
            out.probeDispatch = p.probeDispatch;
        if (p.probeHelper)
            out.probeHelper = p.probeHelper;
        return out;
    });
    return { productions: [...rewritten, ...extra] };
}
// Error raised when the BNF source itself can't be parsed.  Surfaces
// line and column from the underlying jsonic error so the caller can
// report them directly. The original error is kept on `.cause`.
class BnfParseError extends Error {
    constructor(message, location, cause) {
        super(message);
        this.name = 'BnfParseError';
        this.line = location?.line;
        this.column = location?.column;
        this.cause = cause;
    }
}
exports.BnfParseError = BnfParseError;
// Parse BNF source into a grammar AST via the jsonic-based parser.
function parseBnf(src) {
    const parser = getBnfParser();
    let productions;
    try {
        productions = parser(src) ?? [];
    }
    catch (e) {
        // JsonicError carries `lineNumber` / `columnNumber`; fall back to
        // ad-hoc extraction from the error message otherwise.
        const line = e?.lineNumber ?? e?.row;
        const column = e?.columnNumber ?? e?.col;
        const loc = (line != null && column != null)
            ? ` at line ${line}, column ${column}`
            : '';
        const raw = e?.message ? String(e.message).split('\n')[0] : String(e);
        throw new BnfParseError(`bnf: parse error${loc}: ${raw}`, { line, column }, e);
    }
    if (!Array.isArray(productions) || productions.length === 0) {
        throw new BnfParseError('bnf: no productions found');
    }
    const merged = mergeIncrementals(productions);
    return { productions: withCoreRules(merged) };
}
// RFC 5234 Appendix B.1 core rules. Parsed lazily on first use
// and spliced into any user grammar that references them but
// doesn't define them locally.
const CORE_RULES_ABNF = `
ALPHA  = %x41-5A / %x61-7A
BIT    = "0" / "1"
CHAR   = %x01-7F
CR     = %x0D
LF     = %x0A
CRLF   = CR LF
CTL    = %x00-1F / %x7F
DIGIT  = %x30-39
DQUOTE = %x22
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
HTAB   = %x09
OCTET  = %x00-FF
SP     = %x20
VCHAR  = %x21-7E
WSP    = SP / HTAB
`;
let _coreRules = null;
function getCoreRules() {
    if (_coreRules)
        return _coreRules;
    const parser = getBnfParser();
    const raw = parser(CORE_RULES_ABNF);
    // Core rules flatten to `src` in the output AST — they're
    // character-class bricks, not structural nodes users want to see
    // one-per-matched-character.
    for (const p of raw)
        p.nodeKind = 'core';
    _coreRules = new Map(raw.map((p) => [p.name, p]));
    return _coreRules;
}
function refsIn(alt, out) {
    for (const el of alt) {
        if (el.kind === 'ref')
            out.add(el.name);
        else if (el.kind === 'opt' || el.kind === 'star' ||
            el.kind === 'plus' || el.kind === 'rep') {
            refsIn([el.inner], out);
        }
        else if (el.kind === 'group') {
            for (const a of el.alts)
                refsIn(a, out);
        }
    }
}
// Add each RFC 5234 core rule that the user's grammar references
// but doesn't define locally. Resolution is transitive: if the
// user mentions HEXDIG, DIGIT is pulled in too. User definitions
// always win — a local `DIGIT = …` is left untouched.
function withCoreRules(user) {
    const core = getCoreRules();
    const defined = new Set(user.map((p) => p.name));
    const needed = new Set();
    const scan = (prods) => {
        for (const p of prods) {
            for (const alt of p.alts)
                refsIn(alt, needed);
        }
    };
    scan(user);
    const out = [];
    // Transitively add core rules, in declaration order.
    let added = true;
    while (added) {
        added = false;
        for (const [name, prod] of core) {
            if (defined.has(name))
                continue;
            if (!needed.has(name))
                continue;
            defined.add(name);
            out.push(prod);
            scan([prod]);
            added = true;
        }
    }
    return [...user, ...out];
}
// Fold every `name =/ alt` production into the earlier production
// with the same name by appending its alternatives. Throws if an
// incremental references a name that hasn't been defined yet — ABNF
// requires the base production to appear first.
function mergeIncrementals(prods) {
    const out = [];
    const byName = new Map();
    for (const p of prods) {
        if (p.incremental) {
            const base = byName.get(p.name);
            if (!base) {
                throw new BnfParseError(`bnf: '${p.name} =/ …' has no earlier '${p.name} = …' to extend`);
            }
            base.alts.push(...p.alts);
            continue;
        }
        // Strip the (absent) flag on a cleanly-written production so
        // downstream code never sees it.
        const clean = { name: p.name, alts: p.alts };
        if (p.nodeKind)
            clean.nodeKind = p.nodeKind;
        out.push(clean);
        byName.set(p.name, clean);
    }
    return out;
}
// -- Probe-dispatch analyser + rewriter -----------------------------
//
// ABNF has a large family of grammars that aren't LL(k) for any
// bounded k. The canonical example is RFC 3986's `authority`:
//
//   authority = [ userinfo "@" ] host [ ":" port ]
//   userinfo  = *( unreserved / pct-encoded / sub-delims / ":" )
//   host      = IP-literal / IPv4address / reg-name
//   reg-name  = *( unreserved / pct-encoded / sub-delims )
//
// `userinfo` and `reg-name` share a character vocabulary, so a
// FIRST-set dispatcher can't decide which branch the optional
// `[ userinfo "@" ]` belongs to — the disambiguating `@` can be
// arbitrarily far from the start.
//
// For the common pattern `[X D] Y` — an optional group whose body
// ends with a terminal D, followed by a sequence Y whose leading
// terminals overlap with X's — we handle the ambiguity by rewriting
// the rule to a probe+phase-retry dispatcher:
//
//   1. On first entry (phase 0), mark the token position and push a
//      failure-proof probe rule that greedily consumes every token
//      in the joint vocabulary of X and Y.
//   2. When the probe returns, peek ctx.t[0]:
//        D seen   → phase = 1 (take the `X D Y` branch)
//        D absent → phase = 2 (take the `Y` branch)
//      Rewind to the mark and `r:` back into the dispatcher.
//   3. The dispatcher's open has a `c:`-guarded alt for each phase
//      that pushes the corresponding committed branch.
//
// The primitives used (`r:`, `k:`, `c:`, `ctx.mark`, `ctx.rewind`,
// `ctx.t`) are the same building blocks rules/parser already exposes
// — no new jsonic machinery is needed.
// Predicate: element is `[ X D ]` where X is one or more elements
// and D is a terminal literal or a regex terminal.
function isProbeableOpt(el) {
    if (el.kind !== 'opt')
        return null;
    const inner = el.inner;
    if (inner.kind !== 'group')
        return null;
    if (inner.alts.length !== 1)
        return null;
    const seq = inner.alts[0];
    if (seq.length < 2)
        return null;
    const last = seq[seq.length - 1];
    if (last.kind !== 'term' && last.kind !== 'regex')
        return null;
    return { xSeq: seq.slice(0, -1), disambiguator: last };
}
// Union of every terminal reachable by walking an element's subtree,
// following refs transitively. Cycles are broken by the visited set.
// Returns terminals as BnfElements so the caller isn't tied to the
// emitter's token-allocation step.
function collectTerminalVocabElements(el, grammar, out, visited) {
    if (el.kind === 'term') {
        const k = termKey(el);
        if (!out.has(k))
            out.set(k, el);
        return;
    }
    if (el.kind === 'regex') {
        const k = regexKey(el);
        if (!out.has(k))
            out.set(k, el);
        return;
    }
    if (el.kind === 'ref') {
        if (visited.has(el.name))
            return;
        visited.add(el.name);
        const prod = grammar.productions.find((p) => p.name === el.name);
        if (!prod)
            return;
        for (const alt of prod.alts)
            for (const sub of alt)
                collectTerminalVocabElements(sub, grammar, out, visited);
        return;
    }
    if (el.kind === 'opt' || el.kind === 'star' || el.kind === 'plus' ||
        el.kind === 'rep') {
        collectTerminalVocabElements(el.inner, grammar, out, visited);
        return;
    }
    if (el.kind === 'group') {
        for (const alt of el.alts)
            for (const sub of alt)
                collectTerminalVocabElements(sub, grammar, out, visited);
        return;
    }
}
function collectSeqVocabElements(seq, grammar) {
    const out = new Map();
    const visited = new Set();
    for (const el of seq)
        collectTerminalVocabElements(el, grammar, out, visited);
    return out;
}
function mapsOverlap(a, b) {
    for (const x of a.keys())
        if (b.has(x))
            return true;
    return false;
}
// Rewrite every ambiguous `[X D] Y` subsequence in `grammar` into a
// probe-dispatch pattern. The grammar at this point still has `opt`,
// `group`, `star`, `plus`, `rep` sugar — intentionally, since that's
// where the pattern is easy to recognise. Runs BEFORE token
// allocation; probe metadata stores BnfElements, and the emitter
// resolves them to token names at emit time.
function rewriteProbeDispatches(grammar) {
    const reports = grammar.ambiguities ?? [];
    const extra = [];
    const used = new Set(grammar.productions.map((p) => p.name));
    function freshName(hint) {
        let name = hint;
        let i = 1;
        while (used.has(name)) {
            name = hint + i;
            i++;
        }
        used.add(name);
        return name;
    }
    const rewritten = [];
    for (const prod of grammar.productions) {
        let newAlts = [];
        let touched = false;
        for (let altIdx = 0; altIdx < prod.alts.length; altIdx++) {
            const alt = prod.alts[altIdx];
            let resultAlt = [];
            for (let i = 0; i < alt.length; i++) {
                const el = alt[i];
                const info = isProbeableOpt(el);
                if (!info) {
                    resultAlt.push(el);
                    continue;
                }
                const ySeq = alt.slice(i + 1);
                if (ySeq.length === 0) {
                    // `[X D]` is the last thing in the alt — nothing follows, so
                    // there's nothing to disambiguate against. Standard emit.
                    resultAlt.push(el);
                    continue;
                }
                const xVocab = collectSeqVocabElements(info.xSeq, grammar);
                const yVocab = collectSeqVocabElements(ySeq, grammar);
                if (!mapsOverlap(xVocab, yVocab)) {
                    // The optional's leading tokens don't overlap with the tail's
                    // leading tokens, so the normal FIRST-based dispatcher can
                    // decide. No rewrite needed.
                    resultAlt.push(el);
                    continue;
                }
                // Joint vocab: union of everything the probe might need to
                // consume. Includes the disambiguator, which we then remove so
                // the probe stops on it and the peek works.
                const vocab = new Map([...xVocab, ...yVocab]);
                const d = info.disambiguator;
                const dKey = d.kind === 'term' ? termKey(d)
                    : d.kind === 'regex' ? regexKey(d)
                        : null;
                if (dKey)
                    vocab.delete(dKey);
                const dispatchName = freshName(`${prod.name}$pd${i}`);
                const probeName = freshName(`${dispatchName}$probe`);
                const withName = freshName(`${dispatchName}$with`);
                const noName = freshName(`${dispatchName}$no`);
                // Synthesise the probe helper.
                extra.push({
                    name: probeName,
                    alts: [],
                    probeHelper: { vocabElements: [...vocab.values()] },
                    nodeKind: 'helper',
                });
                // Synthesise the committed branches. `with` = X D Y, `no` = Y.
                extra.push({
                    name: withName,
                    alts: [[...info.xSeq, info.disambiguator, ...ySeq]],
                    nodeKind: 'helper',
                });
                extra.push({
                    name: noName,
                    alts: [ySeq],
                    nodeKind: 'helper',
                });
                // Synthesise the dispatcher. The `alts` list is a "virtual"
                // spec — two ref-only alts — that exists solely to feed
                // computeFirstSets the right FIRST/nullable answers (FIRST
                // = FIRST(with) ∪ FIRST(no)). The emitter checks
                // `probeDispatch` first and emits the phase-retry body
                // instead of compiling `alts`.
                extra.push({
                    name: dispatchName,
                    alts: [
                        [{ kind: 'ref', name: withName }],
                        [{ kind: 'ref', name: noName }],
                    ],
                    probeDispatch: {
                        probeRule: probeName,
                        disambiguator: info.disambiguator,
                        withBranch: withName,
                        noBranch: noName,
                    },
                    nodeKind: 'helper',
                });
                reports.push({
                    rule: prod.name, altIdx, optIdx: i,
                    reason: `optional prefix shares vocabulary with tail`,
                    resolved: true,
                });
                resultAlt.push({ kind: 'ref', name: dispatchName });
                // Everything that followed the opt is now inside the dispatcher
                // (withBranch / noBranch), so skip the rest of the alt.
                i = alt.length;
                touched = true;
            }
            newAlts.push(resultAlt);
        }
        if (touched) {
            rewritten.push({
                name: prod.name,
                alts: newAlts,
                nodeKind: prod.nodeKind,
            });
        }
        else {
            rewritten.push(prod);
        }
    }
    return {
        productions: [...rewritten, ...extra],
        ambiguities: reports,
    };
}
// Emit a probe helper production. A self-looping rule that matches any
// one of the vocab tokens and restarts; a final empty-alt fallback
// ensures the rule NEVER fails — if the current lookahead isn't in the
// vocab (or we're at #ZZ), the rule pops cleanly. This is the
// failure-proof property the probe pattern relies on.
function emitProbeHelper(prod, tag, ruleSpec, literals, regexTokens) {
    const elems = prod.probeHelper.vocabElements;
    const opens = [];
    for (const el of elems) {
        const tok = el.kind === 'term'
            ? literals.get(termKey(el))
            : el.kind === 'regex' ? regexTokens.get(regexKey(el))
                : undefined;
        if (tok)
            opens.push({ s: tok, r: prod.name, g: tag });
    }
    // Empty fallback — pops without consuming anything. Must be last.
    opens.push({ g: tag });
    ruleSpec[prod.name] = { open: opens };
}
// Emit a probe-dispatch production. Encodes the three-phase retry
// pattern; uses only standard jsonic primitives (r:, p:, c:, k:,
// ctx.mark/rewind/t).
function emitProbeDispatch(prod, tag, ruleSpec, refs, literals, regexTokens) {
    const { probeRule, disambiguator, withBranch, noBranch } = prod.probeDispatch;
    const disambiguatorToken = disambiguator.kind === 'term'
        ? literals.get(termKey(disambiguator))
        : disambiguator.kind === 'regex'
            ? regexTokens.get(regexKey(disambiguator))
            : undefined;
    if (!disambiguatorToken) {
        throw new Error(`bnf: probe-dispatch rule '${prod.name}' has unresolvable ` +
            `disambiguator (kind=${disambiguator.kind})`);
    }
    const initMark = refs.register((r, ctx) => {
        r.k.pd_phase = 0;
        r.k.pd_mark = ctx.mark();
    });
    const decide = refs.register((r, ctx) => {
        // ctx.t[0] is the first token the probe didn't consume. The probe
        // never fails, so this always reflects a real position.
        const peek = ctx.t[0];
        ctx.rewind(r.k.pd_mark);
        const matched = peek && peek.name === disambiguatorToken;
        r.k.pd_phase = matched ? 1 : 2;
    });
    const bubble = refs.register((r) => {
        if (r.child && r.child.node !== undefined)
            r.node = r.child.node;
    });
    ruleSpec[prod.name] = {
        open: [
            // Phase 0 — first pass: mark and probe.
            {
                c: refs.register((r) => !r.k.pd_phase),
                a: initMark,
                p: probeRule,
                g: tag,
            },
            // Phase 1 — disambiguator was seen: commit to X D Y.
            {
                c: refs.register((r) => r.k.pd_phase === 1),
                p: withBranch,
                g: tag,
            },
            // Phase 2 — disambiguator was not seen: commit to Y alone.
            {
                c: refs.register((r) => r.k.pd_phase === 2),
                p: noBranch,
                g: tag,
            },
        ],
        close: [
            // Phase 0 close: decide phase based on peek, rewind, retry self.
            {
                c: refs.register((r) => r.k.pd_phase === 0),
                a: decide,
                r: prod.name,
                g: tag,
            },
            // Phase 1 / 2 close: lift the committed child's node up.
            { a: bubble, g: tag },
        ],
    };
}
// Convert a BNF grammar AST into a jsonic GrammarSpec.
function emitGrammarSpec(grammar, opts) {
    const start = opts?.start ?? grammar.productions[0].name;
    const tag = opts?.tag ?? 'bnf';
    // Eliminate direct left recursion (P → P α | β) by rewriting to
    // the equivalent right-recursive form P → β (α)*, then detect
    // ambiguous `[X D] Y` optional-prefix patterns and rewrite them
    // into probe-dispatch helpers; finally flatten any EBNF sugar
    // (`?`, `*`, `+`, grouping) into plain BNF.
    grammar = eliminateLeftRecursion(grammar);
    grammar = rewriteProbeDispatches(grammar);
    grammar = desugar(grammar);
    // Allocate a fixed token for each unique literal, and a match
    // token for each unique regex terminal. Literals are keyed by
    // (literal, effective-case-sensitivity) so a `%s"foo"` (sensitive)
    // and a bare `"foo"` (insensitive) produce distinct tokens.
    const literals = new Map(); // literal-key -> token name
    const regexTokens = new Map(); // regex key -> token name
    const usedNames = new Set();
    const fixedTokens = {};
    const matchTokens = {};
    for (const prod of grammar.productions) {
        for (const alt of prod.alts) {
            for (const el of alt) {
                if (el.kind === 'term') {
                    const key = termKey(el);
                    if (!literals.has(key)) {
                        const name = allocTokenName(el.literal, usedNames);
                        literals.set(key, name);
                        if (isEffectivelyCaseSensitive(el)) {
                            fixedTokens[name] = el.literal;
                        }
                        else {
                            // Insensitive literal with at least one letter — emit
                            // as an anchored regex with the `i` flag. Mark the
                            // matcher `eager$` so jsonic's lexer fires it even
                            // when the current rule's tcol doesn't list its tin.
                            const re = new RegExp('^' + escapeRegExp(el.literal), 'i');
                            re.eager$ = true;
                            matchTokens[name] = re;
                        }
                    }
                }
                else if (el.kind === 'regex') {
                    const key = regexKey(el);
                    if (!regexTokens.has(key)) {
                        const name = allocTokenName('rx_' + el.pattern, usedNames);
                        regexTokens.set(key, name);
                        matchTokens[name] = new RegExp('^' + el.pattern, el.flags);
                    }
                }
            }
        }
        // Probe-helper productions store their vocab as BnfElements —
        // walk those too so the required tokens get allocated.
        if (prod.probeHelper) {
            for (const el of prod.probeHelper.vocabElements) {
                if (el.kind === 'term') {
                    const key = termKey(el);
                    if (!literals.has(key)) {
                        const name = allocTokenName(el.literal, usedNames);
                        literals.set(key, name);
                        if (isEffectivelyCaseSensitive(el)) {
                            fixedTokens[name] = el.literal;
                        }
                        else {
                            const re = new RegExp('^' + escapeRegExp(el.literal), 'i');
                            re.eager$ = true;
                            matchTokens[name] = re;
                        }
                    }
                }
                else if (el.kind === 'regex') {
                    const key = regexKey(el);
                    if (!regexTokens.has(key)) {
                        const name = allocTokenName('rx_' + el.pattern, usedNames);
                        regexTokens.set(key, name);
                        matchTokens[name] = new RegExp('^' + el.pattern, el.flags);
                    }
                }
            }
        }
    }
    const knownRules = new Set(grammar.productions.map((p) => p.name));
    const { firstSets, nullable } = computeFirstSets(grammar, literals, regexTokens);
    const refs = new RefRegistry();
    const ruleSpec = {};
    for (const prod of grammar.productions) {
        if (prod.probeHelper) {
            emitProbeHelper(prod, tag, ruleSpec, literals, regexTokens);
            continue;
        }
        if (prod.probeDispatch) {
            emitProbeDispatch(prod, tag, ruleSpec, refs, literals, regexTokens);
            continue;
        }
        // Standard path: a (possibly single-segment) set of alternatives
        // compiled to jsonic alts. Simple alts collapse into `open` alts
        // directly; multi-segment alts emit a chain of aux rules.
        emitProduction(prod, grammar, literals, regexTokens, knownRules, tag, ruleSpec, firstSets, nullable, refs);
    }
    // Wrap the user-visible start rule in a synthetic rule that
    // explicitly consumes #ZZ. Without this, a user rule that pops
    // without matching the end-of-source token lets trailing content
    // slip past jsonic's post-loop endtkn check (the lookahead buffer
    // outlives the parse loop).
    const startWrapper = '__start__';
    ruleSpec[startWrapper] = {
        open: [{
                p: start,
                g: tag,
            }],
        close: [{
                s: '#ZZ',
                // Return the start rule's AST node directly — the `__start__`
                // wrapper exists only to ensure end-of-source gets consumed.
                // The caller of `jsonic(src)` receives the tagged user-rule
                // node (e.g. `{rule: 'URI', src, kids: [...]}`) unadorned.
                a: refs.register((r) => {
                    if (r.child && r.child.node !== undefined) {
                        r.node = r.child.node;
                    }
                }),
                g: tag,
            }],
    };
    const options = {
        fixed: { token: fixedTokens },
        rule: { start: startWrapper },
    };
    if (Object.keys(matchTokens).length > 0) {
        options.match = { token: matchTokens };
    }
    const spec = {
        ref: refs.map,
        options,
        rule: ruleSpec,
    };
    return spec;
}
// Break an alternative into segments. Each segment is a (possibly
// empty) run of terminal tokens followed by at most one rule
// reference. A single-segment alt has at most one ref, located at the
// very end; everything else has two or more segments.
function segmentize(alt, literals, regexTokens) {
    const segs = [];
    let current = { terms: [], ref: null };
    for (const el of alt) {
        if (el.kind === 'term') {
            current.terms.push(literals.get(termKey(el)));
        }
        else if (el.kind === 'regex') {
            const key = regexKey(el);
            current.terms.push(regexTokens.get(key));
        }
        else if (el.kind === 'ref') {
            current.ref = el.name;
            segs.push(current);
            current = { terms: [], ref: null };
        }
        else {
            // `opt`, `star`, `plus`, `group` must have been desugared
            // before reaching the emitter.
            throw new Error(`bnf: internal — unexpected element kind '${el.kind}' in emitter`);
        }
    }
    if (current.terms.length > 0 || segs.length === 0) {
        segs.push(current);
    }
    return segs;
}
function regexKey(el) {
    return `/${el.pattern}/${el.flags}`;
}
function isSingleSegment(alt) {
    let sawRef = false;
    for (const el of alt) {
        if (el.kind === 'ref') {
            if (sawRef)
                return false;
            sawRef = true;
        }
        else if (el.kind === 'term' || el.kind === 'regex') {
            if (sawRef)
                return false; // terminal after a ref — multi-segment
        }
        else {
            // Desugar should have eliminated sugar kinds.
            return false;
        }
    }
    return true;
}
function validateRefs(alt, knownRules, ruleName) {
    for (const el of alt) {
        if (el.kind === 'ref' && !knownRules.has(el.name)) {
            throw new Error(`bnf: rule '${ruleName}' references unknown rule '${el.name}'`);
        }
    }
}
// Registry used by the emitter to allocate unique `@`-prefixed
// FuncRef names for inline action functions. The resulting spec is
// still declarative: every function appears once, keyed by name,
// under the spec's `ref` map.
class RefRegistry {
    constructor() {
        this.refs = {};
        this.counter = 0;
    }
    register(fn) {
        const name = `@bnf_a${this.counter++}`;
        this.refs[name] = fn;
        return name;
    }
    get map() {
        return this.refs;
    }
}
function mkAstNode(ruleName, nodeKind) {
    return nodeKind === 'user'
        ? { rule: ruleName, src: '', kids: [] }
        : { src: '', kids: [] };
}
function segmentToAlt(seg, tag, refs, initNode, ruleName, nodeKind) {
    const spec = { g: tag };
    if (seg.terms.length > 0)
        spec.s = seg.terms.join(' ');
    if (seg.ref)
        spec.p = seg.ref;
    // Default tree-building: accumulate each matched terminal's source
    // text into `r.node.src`. Head alts also allocate a fresh AST node
    // so the child doesn't inherit (and then mutate) its parent's.
    const nterms = seg.terms.length;
    if (nterms > 0 || initNode) {
        spec.a = refs.register((r) => {
            if (initNode)
                r.node = mkAstNode(ruleName, nodeKind);
            const n = r.node;
            for (let i = 0; i < nterms; i++)
                n.src += r.o[i].src;
        });
    }
    return spec;
}
// Close-state action: merge the just-returned child rule's AST node
// into the current rule's. Tagged children (user rules) get pushed
// verbatim into `kids`; untagged (helper / core) flatten — their
// `src` appends and their `kids` extend. Either way `src`
// concatenates so every ancestor's `.src` reflects everything it
// matched.
function captureChildRef(refs, ruleName, nodeKind) {
    return refs.register((r) => {
        if (r.node == null)
            r.node = mkAstNode(ruleName, nodeKind);
        const n = r.node;
        const c = r.child && r.child.node;
        if (c == null)
            return;
        if (typeof c !== 'object' || !('src' in c)) {
            // Legacy shape — wrap as a leaf kid.
            n.kids.push(c);
            return;
        }
        // Defensive: if the child somehow shares this rule's node
        // object, skip the merge rather than push a self-reference. (A
        // properly-emitted grammar always allocates fresh child nodes.)
        if (c === n)
            return;
        n.src += c.src;
        if (c.rule)
            n.kids.push(c);
        else if (Array.isArray(c.kids))
            n.kids.push(...c.kids);
    });
}
function emitProduction(prod, grammar, literals, regexTokens, knownRules, tag, ruleSpec, firstSets, nullable, refs) {
    for (const alt of prod.alts) {
        validateRefs(alt, knownRules, prod.name);
    }
    const allSimple = prod.alts.every(isSingleSegment);
    if (allSimple) {
        // Every alternative collapses to one jsonic alt — emit them
        // directly into the production's open state. This is a head
        // rule, so each alt initialises its own node array. Empty alts
        // are sorted to the end so jsonic's first-match-wins doesn't let
        // them short-circuit non-empty alternatives.
        const ordered = [
            ...prod.alts.filter((alt) => alt.length > 0),
            ...prod.alts.filter((alt) => alt.length === 0),
        ];
        // Ref-only alternatives have no terminal to discriminate on, so
        // jsonic's first-match-wins would silently let them shadow any
        // later alternative. Guard them with FIRST-set peeks when the
        // production has more than one alt.
        const needsPeek = ordered.length > 1;
        const opens = [];
        for (const alt of ordered) {
            const segs = segmentize(alt, literals, regexTokens);
            const seg = segs[0];
            const isRefOnly = alt.length >= 1 &&
                alt.every((el) => el.kind === 'ref') &&
                seg.terms.length === 0 &&
                seg.ref != null;
            const prodKind = prod.nodeKind ?? 'user';
            if (needsPeek && isRefOnly) {
                const firstTokens = firstOfAlt(alt, literals, regexTokens, firstSets, nullable);
                if (firstTokens) {
                    for (const tok of firstTokens) {
                        opens.push({
                            s: tok,
                            b: 1,
                            p: seg.ref,
                            a: refs.register((r) => {
                                r.node = mkAstNode(prod.name, prodKind);
                            }),
                            g: tag,
                        });
                    }
                    continue;
                }
            }
            opens.push(segmentToAlt(seg, tag, refs, true, prod.name, prodKind));
        }
        const rs = { open: opens };
        // If any alt has a push, the close state must capture the
        // returned child. Add a universal fallback close alt whose
        // action is a no-op when there was no push.
        if (prod.alts.some((alt) => alt.some((el) => el.kind === 'ref'))) {
            rs.close = [{
                    a: captureChildRef(refs, prod.name, prod.nodeKind ?? 'user'),
                    g: tag,
                }];
        }
        ruleSpec[prod.name] = rs;
        return;
    }
    if (prod.alts.length === 1) {
        // Single-alt, multi-segment: chain rules directly on the
        // production.
        emitChain(prod.name, prod.alts[0], literals, regexTokens, tag, ruleSpec, refs, prod.nodeKind ?? 'user');
        return;
    }
    // Multi-alt with at least one multi-segment alternative: emit a
    // dispatcher. Each alt becomes its own chained impl rule
    // (`<prodname>$alt<i>`); the main rule's open peeks the first token
    // and pushes the matching impl rule. Using `p:` (not `r:`) keeps
    // the parent's `child` pointer valid so the parent can read the
    // impl's node in its close-state action.
    const dispatchOpen = [];
    let emptyAltSeen = false;
    for (let i = 0; i < prod.alts.length; i++) {
        const alt = prod.alts[i];
        const implName = `${prod.name}$alt${i}`;
        if (alt.length === 0) {
            // Empty alt acts as fallback — handled after the loop.
            emptyAltSeen = true;
            continue;
        }
        emitChain(implName, alt, literals, regexTokens, tag, ruleSpec, refs, 'helper');
        // Fan out this alt into one dispatch entry per concrete token
        // sequence it can start with. Up to LOOKAHEAD_K tokens per
        // prefix is enough for the grammars this converter targets; a
        // ref with multiple alts produces one prefix per sub-alt so
        // overlapping FIRST sets between competing alts can still be
        // separated by their second (or later) token.
        // The dispatcher itself is a user (or helper) rule — it must
        // allocate its own AST node on every dispatch alt, otherwise the
        // node inherited from the parent via makeRule(ctx, rule.node)
        // would be shared and the dispatcher's captureChildRef would
        // mutate the parent's tree.
        const dispatchKind = prod.nodeKind ?? 'user';
        const initDispatchNode = refs.register((r) => {
            r.node = mkAstNode(prod.name, dispatchKind);
        });
        const LOOKAHEAD_K = 4;
        const prefixes = altPrefixes(alt, grammar, literals, regexTokens, LOOKAHEAD_K);
        const usable = prefixes.filter((p) => p.length > 0);
        if (usable.length > 0) {
            for (const p of usable) {
                dispatchOpen.push({
                    s: p.join(' '),
                    b: p.length,
                    p: implName,
                    a: initDispatchNode,
                    g: tag,
                });
            }
        }
        else {
            const firstTokens = firstOfAlt(alt, literals, regexTokens, firstSets, nullable);
            if (firstTokens === null) {
                throw new Error(`bnf: rule '${prod.name}' alternative ${i} is nullable ` +
                    `but is not the only empty alt; FIRST set is ambiguous`);
            }
            for (const tok of firstTokens) {
                dispatchOpen.push({
                    s: tok, b: 1, p: implName, a: initDispatchNode, g: tag,
                });
            }
        }
    }
    if (emptyAltSeen) {
        // Fallback: matches any token (or none), pops immediately with
        // an empty tree. Tagged with the user rule name so a consumer
        // walking the tree still gets a placeholder node for the empty
        // alternative.
        const fallbackKind = prod.nodeKind ?? 'user';
        dispatchOpen.push({
            a: refs.register((r) => {
                r.node = mkAstNode(prod.name, fallbackKind);
            }),
            g: tag,
        });
    }
    ruleSpec[prod.name] = {
        open: dispatchOpen,
        close: [{
                // Merge the chosen impl's result up into the dispatcher's node,
                // tagged with the user rule name (so the enclosing rule sees a
                // `{rule, src, kids}` child, not the impl chain's transparent
                // `{src, kids}`).
                a: captureChildRef(refs, prod.name, prod.nodeKind ?? 'user'),
                g: tag,
            }],
    };
}
// Emit a (possibly single-step) chain of rules for one alt under the
// given head rule name. Segment 0 goes into `headName`; later
// segments get synthetic `<headName>$stepN` continuations.
//
// `headKind` controls the head rule's AST node shape: 'user' tags
// the head's node with the rule name; 'helper' leaves it untagged
// (transparent to the enclosing user rule). Step rules are always
// helpers — they inherit and accumulate into the head's node via
// `r:` replacement.
function emitChain(headName, alt, literals, regexTokens, tag, ruleSpec, refs, headKind = 'helper') {
    const segs = segmentize(alt, literals, regexTokens);
    const chainName = (i) => i === 0 ? headName : `${headName}$step${i}`;
    for (let i = 0; i < segs.length; i++) {
        const name = chainName(i);
        const seg = segs[i];
        const kind = i === 0 ? headKind : 'helper';
        // Only the head of the chain initialises the node object; later
        // steps inherit and continue to accumulate into it via `r:`.
        const open = [segmentToAlt(seg, tag, refs, i === 0, name, kind)];
        const rs = { open };
        const isLast = i === segs.length - 1;
        if (!isLast) {
            // Non-last step: after the push returns, capture the child's
            // node and replace with the next step rule.
            rs.close = [{
                    r: chainName(i + 1),
                    a: captureChildRef(refs, name, kind),
                    g: tag,
                }];
        }
        else if (seg.ref) {
            // Last step, but it had a push — we still need to capture the
            // final child before popping.
            rs.close = [{ a: captureChildRef(refs, name, kind), g: tag }];
        }
        ruleSpec[name] = rs;
    }
}
// Compute FIRST(ref) for every production, plus which productions
// are nullable (can derive the empty string). Iterates to a fixed
// point. Terminals in FIRST sets are represented by their allocated
// token names (e.g. `#X`).
function computeFirstSets(grammar, literals, regexTokens) {
    const firstSets = new Map();
    const nullable = new Set();
    for (const p of grammar.productions)
        firstSets.set(p.name, new Set());
    let changed = true;
    while (changed) {
        changed = false;
        for (const prod of grammar.productions) {
            const first = firstSets.get(prod.name);
            for (const alt of prod.alts) {
                // Walk the alt, accumulating FIRST until a non-nullable
                // position is hit.
                let altNullable = true;
                for (const el of alt) {
                    if (el.kind === 'term' || el.kind === 'regex') {
                        const tok = el.kind === 'term'
                            ? literals.get(termKey(el))
                            : regexTokens.get(regexKey(el));
                        if (!first.has(tok)) {
                            first.add(tok);
                            changed = true;
                        }
                        altNullable = false;
                        break;
                    }
                    if (el.kind === 'ref') {
                        const refFirst = firstSets.get(el.name) ?? new Set();
                        for (const tok of refFirst) {
                            if (!first.has(tok)) {
                                first.add(tok);
                                changed = true;
                            }
                        }
                        if (!nullable.has(el.name)) {
                            altNullable = false;
                            break;
                        }
                        continue;
                    }
                    // Desugar should have eliminated other kinds.
                    throw new Error(`bnf: internal — unexpected kind in FIRST: ${el.kind}`);
                }
                if (altNullable && !nullable.has(prod.name)) {
                    nullable.add(prod.name);
                    changed = true;
                }
            }
        }
    }
    return { firstSets, nullable };
}
// FIRST set for a specific alternative (not the whole production).
// Returns null if the alt is nullable — the caller must treat that
// case separately (typically as a fallback empty alt).
function firstOfAlt(alt, literals, regexTokens, firstSets, nullable) {
    const out = new Set();
    for (const el of alt) {
        if (el.kind === 'term' || el.kind === 'regex') {
            const tok = el.kind === 'term'
                ? literals.get(termKey(el))
                : regexTokens.get(regexKey(el));
            out.add(tok);
            return out;
        }
        if (el.kind === 'ref') {
            const rf = firstSets.get(el.name) ?? new Set();
            for (const tok of rf)
                out.add(tok);
            if (!nullable.has(el.name))
                return out;
            // else keep walking into the next element
            continue;
        }
        throw new Error(`bnf: internal — unexpected kind in firstOfAlt: ${el.kind}`);
    }
    // Alt is nullable — no non-empty prefix.
    return null;
}
// Longest deterministic terminal prefix of a rule — the longest
// sequence of tokens that every alternative of the rule starts
// with. Refs are followed into their target rule, with a `visited`
// set guarding cycles. An empty array means there's no confident
// prefix (the rule either has divergent alts, starts with a multi-
// alt ref, or hits a cycle), so the caller should fall back to a
// single-token FIRST-set lookahead instead.
function ruleLiteralPrefix(name, grammar, literals, regexTokens, visited) {
    if (visited.has(name))
        return [];
    const next = new Set(visited);
    next.add(name);
    const prod = grammar.productions.find((p) => p.name === name);
    if (!prod || prod.alts.length === 0)
        return [];
    const prefixes = prod.alts.map((alt) => altLiteralPrefix(alt, grammar, literals, regexTokens, next));
    if (prefixes.some((p) => p.length === 0))
        return [];
    const minLen = Math.min(...prefixes.map((p) => p.length));
    const common = [];
    for (let i = 0; i < minLen; i++) {
        const tok = prefixes[0][i];
        if (prefixes.every((p) => p[i] === tok))
            common.push(tok);
        else
            break;
    }
    return common;
}
function altLiteralPrefix(alt, grammar, literals, regexTokens, visited) {
    const out = [];
    for (const el of alt) {
        if (el.kind === 'term') {
            out.push(literals.get(termKey(el)));
        }
        else if (el.kind === 'regex') {
            out.push(regexTokens.get(regexKey(el)));
        }
        else if (el.kind === 'ref') {
            const sub = ruleLiteralPrefix(el.name, grammar, literals, regexTokens, visited);
            // Take the ref's literal prefix and stop — we can't see past
            // the ref without more expensive analysis.
            out.push(...sub);
            return out;
        }
        else {
            return out;
        }
    }
    return out;
}
// Enumerate concrete token-sequence prefixes an alternative can
// start with, each at most `maxK` tokens long. Refs with multiple
// alternatives fan out into one prefix per sub-alternative so the
// caller can emit a dedicated dispatch alt for each path. When a
// ref cycles back or exhausts depth, the path is *terminated* at
// the tokens accumulated so far — the `done` flag is propagated
// out of nested calls so a truncated sub-prefix is never extended
// with tokens from elements the outer alt happens to list after the
// cycled ref.
function altPrefixesRaw(alt, grammar, literals, regexTokens, maxK, visited = new Set()) {
    let paths = [{ tokens: [], done: false }];
    for (const el of alt) {
        const next = [];
        for (const p of paths) {
            if (p.done || p.tokens.length >= maxK) {
                next.push(p);
                continue;
            }
            if (el.kind === 'term') {
                next.push({
                    tokens: [...p.tokens, literals.get(termKey(el))],
                    done: false,
                });
            }
            else if (el.kind === 'regex') {
                next.push({
                    tokens: [...p.tokens, regexTokens.get(regexKey(el))],
                    done: false,
                });
            }
            else if (el.kind === 'ref') {
                if (visited.has(el.name)) {
                    next.push({ tokens: p.tokens, done: true });
                    continue;
                }
                const childVisited = new Set(visited);
                childVisited.add(el.name);
                const target = grammar.productions.find((pr) => pr.name === el.name);
                if (!target || target.alts.length === 0) {
                    next.push({ tokens: p.tokens, done: true });
                    continue;
                }
                for (const sub of target.alts) {
                    const subPaths = altPrefixesRaw(sub, grammar, literals, regexTokens, maxK - p.tokens.length, childVisited);
                    for (const sp of subPaths) {
                        next.push({
                            tokens: [...p.tokens, ...sp.tokens],
                            // Propagate `done` so the outer loop won't extend a
                            // cycle-truncated sub-prefix.
                            done: sp.done,
                        });
                    }
                }
            }
            else {
                // Desugar should have eliminated group/star/etc. at this point.
                next.push({ tokens: p.tokens, done: true });
            }
        }
        paths = next;
        if (paths.every((p) => p.done || p.tokens.length >= maxK))
            break;
    }
    return paths;
}
function altPrefixes(alt, grammar, literals, regexTokens, maxK) {
    const raw = altPrefixesRaw(alt, grammar, literals, regexTokens, maxK);
    const seen = new Set();
    const out = [];
    for (const p of raw) {
        const key = p.tokens.join(' ');
        if (!seen.has(key)) {
            seen.add(key);
            out.push(p.tokens);
        }
    }
    return out;
}
// A quoted-string literal is effectively case-sensitive either
// when the user explicitly wrote `%s"…"` or when it contains no
// ASCII letters (there's nothing to fold — `"+"` matches `+` in
// any "case").
function isEffectivelyCaseSensitive(el) {
    if (el.caseSensitive === true)
        return true;
    return !/[A-Za-z]/.test(el.literal);
}
// Map a term element to the key used to look up (or allocate) its
// emitted token. The key folds together the literal and its
// effective case-sensitivity so a sensitive and an insensitive
// occurrence of the same string are distinct tokens.
function termKey(el) {
    return (isEffectivelyCaseSensitive(el) ? 'cs:' : 'ci:') + el.literal;
}
function escapeRegExp(s) {
    return s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
}
// Decode an ABNF numeric value (`%xNN`, `%dNN`, `%bNN`, or one of
// the range/concatenation forms) into a `BnfElement`.
//
//   %x61            => single-char term "a"
//   %x66.6f.6f      => concatenated term "foo"
//   %x30-39         => regex character class [\u0030-\u0039]
//
// Hex is case-insensitive; decimal and binary accept only digits
// in their respective ranges. Range endpoints must be the same
// base as the prefix (RFC 5234 doesn't allow mixing).
function parseNumericValue(src) {
    const base = src[1].toLowerCase();
    const radix = base === 'x' ? 16 : base === 'd' ? 10 : 2;
    const body = src.slice(2);
    if (body.includes('-')) {
        const [loStr, hiStr] = body.split('-');
        const lo = parseInt(loStr, radix);
        const hi = parseInt(hiStr, radix);
        if (lo === hi) {
            return { kind: 'term', literal: String.fromCharCode(lo) };
        }
        const toEsc = (n) => '\\u' + n.toString(16).padStart(4, '0');
        return {
            kind: 'regex',
            pattern: '[' + toEsc(lo) + '-' + toEsc(hi) + ']',
            flags: '',
        };
    }
    const parts = body.split('.');
    const chars = parts.map((n) => String.fromCharCode(parseInt(n, radix)));
    return { kind: 'term', literal: chars.join('') };
}
function allocTokenName(literal, used) {
    const base = literal
        .replace(/[^A-Za-z0-9]/g, '_')
        .toUpperCase()
        .replace(/^_+|_+$/g, '');
    const candidate = base.length > 0 ? '#' + base : '#T';
    if (!used.has(candidate)) {
        used.add(candidate);
        return candidate;
    }
    let i = 1;
    while (used.has(candidate + i))
        i++;
    const chosen = candidate + i;
    used.add(chosen);
    return chosen;
}
// Public entry point: take BNF source and return a jsonic GrammarSpec.
function bnf(src, opts) {
    const grammar = parseBnf(src);
    return emitGrammarSpec(grammar, opts);
}
//# sourceMappingURL=bnf.js.map

================================================
FILE: dist/debug.d.ts
================================================
import type { Plugin } from './jsonic';
declare const Debug: Plugin;
export { Debug };


================================================
FILE: dist/debug.js
================================================
"use strict";
/* Copyright (c) 2021-2023 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Debug = void 0;
const jsonic_1 = require("./jsonic");
const DEFAULTS = {
    print: true,
    trace: {
        step: true,
        rule: true,
        lex: true,
        parse: true,
        node: true,
        stack: true,
    },
};
const { entries, tokenize } = jsonic_1.util;
const Debug = (jsonic, options) => {
    options.trace =
        true === options.trace ? { ...DEFAULTS.trace } : options.trace;
    const { keys, values, entries } = jsonic.util;
    jsonic.debug = {
        describe: function () {
            let cfg = jsonic.internal().config;
            let match = cfg.lex.match;
            let rules = jsonic.rule();
            return [
                '========= TOKENS ========',
                Object.entries(cfg.t)
                    .filter((te) => 'string' === typeof te[1])
                    .map((te) => {
                    return ('  ' +
                        te[0] +
                        '\t' +
                        te[1] +
                        '\t' +
                        ((s) => (s ? '"' + s + '"' : ''))(cfg.fixed.ref[te[0]] || ''));
                })
                    .join('\n'),
                '\n',
                Object.entries(cfg.tokenSet)
                    .map((te) => {
                    return ('    ' +
                        te[0] +
                        '\t' +
                        Object.keys(cfg.tokenSetTins[te[0]] ?? []));
                })
                    .join('\n'),
                '\n',
                ,
                '========= RULES =========',
                ruleTree(jsonic, keys(rules), rules),
                '\n',
                '========= ALTS =========',
                values(rules)
                    .map((rs) => '  ' +
                    rs.name +
                    ':\n' +
                    descAlt(jsonic, rs, 'open') +
                    descAlt(jsonic, rs, 'close'))
                    .join('\n\n'),
                '\n',
                '========= LEXER =========',
                '  ' +
                    ((match &&
                        match.map((m) => m.order + ': ' + m.matcher + ' (' + m.make.name + ')')) ||
                        []).join('\n  '),
                '\n',
                '\n',
                '========= PLUGIN =========',
                '  ' +
                    jsonic
                        .internal()
                        .plugins.map((p) => p.name +
                        (p.options
                            ? entries(p.options).reduce((s, e) => (s += '\n    ' + e[0] + ': ' + JSON.stringify(e[1])), '')
                            : ''))
                        .join('\n  '),
                '\n',
            ].join('\n');
        },
    };
    const origUse = jsonic.use.bind(jsonic);
    jsonic.use = (...args) => {
        let self = origUse(...args);
        if (options.print) {
            self
                .internal()
                .config.debug.get_console()
                .log('USE:', args[0].name, '\n\n', self.debug.describe());
        }
        return self;
    };
    if (options.trace) {
        jsonic.options({
            parse: {
                prepare: {
                    debug: (_jsonic, ctx, _meta) => {
                        const console_log = ctx.cfg.debug.get_console().log;
                        console_log('\n========= TRACE ==========');
                        ctx.log =
                            ctx.log ||
                                ((kind, ...rest) => {
                                    if (LOGKIND[kind] && options.trace[kind]) {
                                        console_log(LOGKIND[kind](...rest)
                                            .filter((item) => 'object' != typeof item)
                                            .map((item) => 'function' == typeof item ? item.name : item)
                                            .join('  '));
                                    }
                                });
                    },
                },
            },
        });
    }
};
exports.Debug = Debug;
function descAlt(jsonic, rs, kind) {
    const { entries } = jsonic.util;
    return 0 === rs.def[kind].length
        ? ''
        : '    ' +
            kind.toUpperCase() +
            ':\n' +
            rs.def[kind]
                .map((a, i) => '      ' +
                ('' + i).padStart(5, ' ') +
                ' ' +
                ('[' +
                    (a.s || [])
                        .map((tin) => null == tin
                        ? '***INVALID***'
                        : 'number' === typeof tin
                            ? jsonic.token[tin]
                            : Array.isArray(tin) ? '[' + tin.map((t) => jsonic.token[t]) + ']'
                                : ('' + tin))
                        .join(' ') +
                    '] ').padEnd(32, ' ') +
                (a.r ? ' r=' + ('string' === typeof a.r ? a.r : '<F>') : '') +
                (a.p ? ' p=' + ('string' === typeof a.p ? a.p : '<F>') : '') +
                (!a.r && !a.p ? '\t' : '') +
                '\t' +
                (null == a.b ? '' : 'b=' + a.b) +
                '\t' +
                (null == a.n
                    ? ''
                    : 'n=' +
                        entries(a.n).map(([k, v]) => k + ':' + v)) +
                '\t' +
                (null == a.a ? '' : 'A') +
                (null == a.c ? '' : 'C') +
                (null == a.h ? '' : 'H') +
                '\t' +
                (null == a.c?.n
                    ? '\t'
                    : ' CN=' +
                        entries(a.c.n).map(([k, v]) => k + ':' + v)) +
                (null == a.c?.d ? '' : ' CD=' + a.c.d) +
                (a.g ? '\tg=' + a.g : ''))
                .join('\n') +
            '\n';
}
function ruleTree(jsonic, rn, rsm) {
    const { values, omap } = jsonic.util;
    return rn.reduce((a, n) => ((a +=
        '  ' +
            n +
            ':\n    ' +
            values(omap({
                op: ruleTreeStep(rsm, n, 'open', 'p'),
                or: ruleTreeStep(rsm, n, 'open', 'r'),
                cp: ruleTreeStep(rsm, n, 'close', 'p'),
                cr: ruleTreeStep(rsm, n, 'close', 'r'),
            }, ([n, d]) => [
                1 < d.length ? n : undefined,
                n + ': ' + d,
            ])).join('\n    ') +
            '\n'),
        a), '');
}
function ruleTreeStep(rsm, name, state, step) {
    return [
        ...new Set(rsm[name].def[state]
            .filter((alt) => alt[step])
            .map((alt) => alt[step])
            .map((step) => ('string' === typeof step ? step : '<F>'))),
    ].join(' ');
}
function descTokenState(ctx) {
    return ('[' +
        (ctx.NOTOKEN === ctx.t0 ? '' : ctx.F(ctx.t0.src)) +
        (ctx.NOTOKEN === ctx.t1 ? '' : ' ' + ctx.F(ctx.t1.src)) +
        ']~[' +
        (ctx.NOTOKEN === ctx.t0 ? '' : tokenize(ctx.t0.tin, ctx.cfg)) +
        (ctx.NOTOKEN === ctx.t1 ? '' : ' ' + tokenize(ctx.t1.tin, ctx.cfg)) +
        ']');
}
function descParseState(ctx, rule, lex) {
    return (ctx.F(ctx.src().substring(lex.pnt.sI, lex.pnt.sI + 16)).padEnd(18, ' ') +
        ' ' +
        descTokenState(ctx).padEnd(34, ' ') +
        ' ' +
        ('' + rule.d).padStart(4, ' '));
}
function descRuleState(ctx, rule) {
    let en = entries(rule.n);
    let eu = entries(rule.u);
    let ek = entries(rule.k);
    return ('' +
        (0 === en.length
            ? ''
            : ' N<' +
                en
                    .filter((n) => n[1])
                    .map((n) => n[0] + '=' + n[1])
                    .join(';') +
                '>') +
        (0 === eu.length
            ? ''
            : ' U<' + eu.map((u) => u[0] + '=' + ctx.F(u[1])).join(';') + '>') +
        (0 === ek.length
            ? ''
            : ' K<' + ek.map((k) => k[0] + '=' + ctx.F(k[1])).join(';') + '>'));
}
function descAltSeq(alt, cfg) {
    return ('[' +
        (alt.s || [])
            .map((tin) => 'number' === typeof tin
            ? tokenize(tin, cfg)
            : Array.isArray(tin)
                ? '[' + tin.map((t) => tokenize(t, cfg)) + ']'
                : '')
            .join(' ') +
        '] ');
}
const LOG = {
    RuleState: {
        o: jsonic_1.S.open.toUpperCase(),
        c: jsonic_1.S.close.toUpperCase(),
    },
};
const LOGKIND = {
    step: (...rest) => rest,
    stack: (ctx, rule, lex) => [
        jsonic_1.S.logindent + jsonic_1.S.stack,
        descParseState(ctx, rule, lex),
        // S.indent.repeat(Math.max(rule.d + ('o' === rule.state ? -1 : 1), 0)) +
        jsonic_1.S.indent.repeat(rule.d) +
            '/' +
            ctx.rs
                // .slice(0, ctx.rsI)
                .slice(0, rule.d)
                .map((r) => r.name + '~' + r.i)
                .join('/'),
        '~',
        '/' +
            ctx.rs
                // .slice(0, ctx.rsI)
                .slice(0, rule.d)
                .map((r) => ctx.F(r.node))
                .join('/'),
        // 'd=' + rule.d,
        //'rsI=' + ctx.rsI,
        ctx,
        rule,
        lex,
    ],
    rule: (ctx, rule, lex) => [
        rule,
        ctx,
        lex,
        jsonic_1.S.logindent + jsonic_1.S.rule + jsonic_1.S.space,
        descParseState(ctx, rule, lex),
        jsonic_1.S.indent.repeat(rule.d) +
            (rule.name + '~' + rule.i + jsonic_1.S.colon + LOG.RuleState[rule.state]).padEnd(16),
        ('prev=' +
            rule.prev.i +
            ' parent=' +
            rule.parent.i +
            ' child=' +
            rule.child.i).padEnd(28),
        descRuleState(ctx, rule),
    ],
    node: (ctx, rule, lex, next) => [
        rule,
        ctx,
        lex,
        next,
        jsonic_1.S.logindent + jsonic_1.S.node + jsonic_1.S.space,
        descParseState(ctx, rule, lex),
        jsonic_1.S.indent.repeat(rule.d) +
            ('why=' + next.why + jsonic_1.S.space + '<' + ctx.F(rule.node) + '>').padEnd(46),
        descRuleState(ctx, rule),
    ],
    parse: (ctx, rule, lex, match, cond, altI, alt, out) => {
        let ns = match && out.n ? entries(out.n) : null;
        let us = match && out.u ? entries(out.u) : null;
        let ks = match && out.k ? entries(out.k) : null;
        return [
            ctx,
            rule,
            lex,
            jsonic_1.S.logindent + jsonic_1.S.parse,
            descParseState(ctx, rule, lex),
            jsonic_1.S.indent.repeat(rule.d) + (match ? 'alt=' + altI : 'no-alt'),
            match && alt ? descAltSeq(alt, ctx.cfg) : '',
            match && out.g ? 'g:' + out.g + ' ' : '',
            (match && out.p ? 'p:' + out.p + ' ' : '') +
                (match && out.r ? 'r:' + out.r + ' ' : '') +
                (match && out.b ? 'b:' + out.b + ' ' : ''),
            alt && alt.c ? 'c:' + cond : jsonic_1.EMPTY,
            null == ns ? '' : 'n:' + ns.map((p) => p[0] + '=' + p[1]).join(';'),
            null == us ? '' : 'u:' + us.map((p) => p[0] + '=' + p[1]).join(';'),
            null == ks ? '' : 'k:' + ks.map((p) => p[0] + '=' + p[1]).join(';'),
        ];
    },
    lex: (ctx, rule, lex, pnt, sI, match, tkn, alt, altI, tI) => [
        jsonic_1.S.logindent + jsonic_1.S.lex + jsonic_1.S.space + jsonic_1.S.space,
        descParseState(ctx, rule, lex),
        jsonic_1.S.indent.repeat(rule.d) +
            // S.indent.repeat(rule.d) + S.lex, // Log entry prefix.
            // Name of token from tin (token identification numer).
            tokenize(tkn.tin, ctx.cfg),
        ctx.F(tkn.src), // Format token src for log.
        pnt.sI, // Current source index.
        pnt.rI + ':' + pnt.cI, // Row and column.
        match?.name || '',
        alt
            ? 'on:alt=' +
                altI +
                ';' +
                alt.g +
                ';t=' +
                tI +
                ';' +
                descAltSeq(alt, ctx.cfg)
            : '',
        ctx.F(lex.src.substring(sI, sI + 16)),
        ctx,
        rule,
        lex,
    ],
};
Debug.defaults = DEFAULTS;
//# sourceMappingURL=debug.js.map

================================================
FILE: dist/defaults.d.ts
================================================
import { Options } from './jsonic';
declare const defaults: Options;
export { defaults };


================================================
FILE: dist/defaults.js
================================================
"use strict";
/* Copyright (c) 2013-2023 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaults = void 0;
// Functions that create token matching lexers.
// The `make*Matcher` functions may optionally initialise
// and validate Config properties specific to their lexing.
const lexer_1 = require("./lexer");
const defaults = {
    // Prevent prototype pollution
    safe: {
        key: true,
    },
    // Default tag - set your own!
    tag: '-',
    // Fixed token lexing.
    fixed: {
        // Recognize fixed tokens in the Lexer.
        lex: true,
        // Token names.
        token: {
            '#OB': '{',
            '#CB': '}',
            '#OS': '[',
            '#CS': ']',
            '#CL': ':',
            '#CA': ',',
        },
    },
    match: {
        lex: true,
        token: {},
    },
    // Token sets.
    tokenSet: {
        IGNORE: ['#SP', '#LN', '#CM'],
        VAL: ['#TX', '#NR', '#ST', '#VL'],
        KEY: ['#TX', '#NR', '#ST', '#VL'],
    },
    // Recognize space characters in the lexer.
    space: {
        // Recognize space in the Lexer.
        lex: true,
        // Space characters are kept to a minimal set.
        // Add more from https://en.wikipedia.org/wiki/Whitespace_character as needed.
        chars: ' \t',
    },
    // Line lexing.
    line: {
        // Recognize lines in the Lexer.
        lex: true,
        // Line characters.
        chars: '\r\n',
        // Increments row (aka line) counter.
        rowChars: '\n',
        // Generate separate lexer tokens for each newline.
        // Note: '\r\n' counts as one newline.
        single: false,
    },
    // Text formats.
    text: {
        // Recognize text (non-quoted strings) in the Lexer.
        lex: true,
    },
    // Control number formats.
    number: {
        // Recognize numbers in the Lexer.
        lex: true,
        // Recognize hex numbers (eg. 10 === 0x0a).
        hex: true,
        // Recognize octal numbers (eg. 10 === 0o12).
        oct: true,
        // Recognize ninary numbers (eg. 10 === 0b1010).
        bin: true,
        // All possible number chars. |+-|0|xob|0-9a-fA-F|.e|+-|0-9a-fA-F|
        // digital: '-1023456789._xoeEaAbBcCdDfF+',
        // Allow embedded separator. `null` to disable.
        sep: '_',
        // Exclude number strings matching this RegExp
        exclude: undefined,
    },
    // Comment markers.
    // <mark-char>: true -> single line comments
    // <mark-start>: <mark-end> -> multiline comments
    comment: {
        // Recognize comments in the Lexer.
        lex: true,
        // TODO: plugin
        // Balance multiline comments.
        // balance: true,
        // Comment markers.
        def: {
            hash: { line: true, start: '#', lex: true, eatline: false },
            slash: { line: true, start: '//', lex: true, eatline: false },
            multi: {
                line: false,
                start: '/' + '*',
                end: '*' + '/',
                lex: true,
                eatline: false,
            },
        },
    },
    // String formats.
    string: {
        // Recognize strings in the Lexer.
        lex: true,
        // Quote characters
        chars: '\'"`',
        // Multiline quote chars.
        multiChars: '`',
        // Escape character.
        escapeChar: '\\',
        // String escape chars.
        // Denoting char (follows escape char) => actual char.
        escape: {
            b: '\b',
            f: '\f',
            n: '\n',
            r: '\r',
            t: '\t',
            v: '\v',
            // These preserve standard escapes when allowUnknown=false.
            '"': '"',
            "'": "'",
            '`': '`',
            '\\': '\\',
            '/': '/',
        },
        // Allow unknown escape characters - they are copied to output: '\w' -> 'w'.
        allowUnknown: true,
        // If string lexing fails, instead of error, allow other matchers to try.
        abandon: false,
    },
    // Object formats.
    map: {
        // TODO: or trigger error?
        // Later duplicates extend earlier ones, rather than replacing them.
        extend: true,
        // Custom merge function for duplicates (optional).
        // TODO: needs function signature
        merge: undefined,
        // Allow bare colon `:value` in maps, stored as `child$` property.
        child: false,
    },
    // Array formats.
    list: {
        // Allow arrays to have properties: `[a:9,0,1]`
        property: true,
        // Parse pairs as object elements: `[a:1]` -> `[{"a":1}]`
        // Takes precedence over list.property when true.
        pair: false,
        // Parse bare colon as child$ property: `[:1]` -> [] with child$=1
        // Multiple child values merge.
        child: false,
    },
    // Metadata info markers. When enabled, a non-enumerable marker property
    // is attached to parsed nodes with metadata (implicit flag, meta bag, etc.).
    info: {
        // Attach marker to map nodes.
        map: false,
        // Attach marker to list nodes.
        list: false,
        // Wrap string values as String objects with marker (quote info).
        text: false,
        // Property name for the marker.
        marker: '__info__',
    },
    // Keyword values.
    value: {
        lex: true,
        def: {
            true: { val: true },
            false: { val: false },
            null: { val: null },
        },
    },
    // Additional text ending characters
    ender: [],
    // Plugin custom options, (namespace by plugin name).
    plugin: {},
    // Debug settings
    debug: {
        // Default console for logging.
        get_console: () => console,
        // Max length of parse value to print.
        maxlen: 99,
        // Print internal structures
        print: {
            // Print config built from options.
            config: false,
            // Custom string formatter for src and node values.
            src: undefined,
        },
    },
    // Error messages.
    error: {
        unknown: 'unknown error: {code}',
        unexpected: 'unexpected character(s): {src}',
        invalid_unicode: 'invalid unicode escape: {src}',
        invalid_ascii: 'invalid ascii escape: {src}',
        unprintable: 'unprintable character: {src}',
        unterminated_string: 'unterminated string: {src}',
        unterminated_comment: 'unterminated comment: {src}',
        unknown_rule: 'unknown rule: {rulename}',
        end_of_source: 'unexpected end of source',
    },
    errmsg: {
        name: 'jsonic',
        suffix: true
    },
    // Error hints: {error-code: hint-text}.
    hint: {
        unknown: `
Since the error is unknown, this is probably a bug inside jsonic
itself, or a plugin. Please consider posting a github issue - thanks!

Code: {code}, Details: 
{details}`,
        unexpected: `
The character(s) {src} were not expected at this point as they do not
match the expected syntax, even under the relaxed jsonic rules. If it
is not obviously wrong, the actual syntax error may be elsewhere. Try
commenting out larger areas around this point until you get no errors,
then remove the comments in small sections until you find the
offending syntax. NOTE: Also check if any plugins you are using
expect different syntax in this case.`,
        invalid_unicode: `
The escape sequence {src} does not encode a valid unicode code point
number. You may need to validate your string data manually using test
code to see how JavaScript will interpret it. Also consider that your
data may have become corrupted, or the escape sequence has not been
generated correctly.`,
        invalid_ascii: `
The escape sequence {src} does not encode a valid ASCII character. You
may need to validate your string data manually using test code to see
how JavaScript will interpret it. Also consider that your data may
have become corrupted, or the escape sequence has not been generated
correctly.`,
        unprintable: `
String values cannot contain unprintable characters (character codes
below 32). The character {src} is unprintable. You may need to remove
these characters from your source data. Also check that it has not
become corrupted.`,
        unterminated_string: `
This string has no end quote.`,
        unterminated_comment: `
This comment is never closed.`,
        unknown_rule: `
No rule named $rulename is defined. This is probably an error in the
grammar of a plugin.`,
        end_of_source: `
Unexpected end of source.`,
    },
    // Lexer
    lex: {
        match: {
            match: { order: 1e6, make: lexer_1.makeMatchMatcher },
            fixed: { order: 2e6, make: lexer_1.makeFixedMatcher },
            space: { order: 3e6, make: lexer_1.makeSpaceMatcher },
            line: { order: 4e6, make: lexer_1.makeLineMatcher },
            string: { order: 5e6, make: lexer_1.makeStringMatcher },
            comment: { order: 6e6, make: lexer_1.makeCommentMatcher },
            number: { order: 7e6, make: lexer_1.makeNumberMatcher },
            text: { order: 8e6, make: lexer_1.makeTextMatcher },
        },
        // Empty string is allowed and returns undefined
        empty: true,
        emptyResult: undefined,
    },
    // Parser
    parse: {
        // Plugin custom functions to prepare parser context.
        prepare: {},
    },
    // Parser rule options.
    rule: {
        // Name of the starting rule.
        start: 'val',
        // Automatically close remaining structures at EOF.
        finish: true,
        // Multiplier to increase the maximum number of rule occurences.
        maxmul: 3,
        // Include only those alts with matching group tags (comma sep).
        // NOTE: applies universally, thus also for subsequent rules.
        include: '',
        // Exclude alts with matching group tags (comma sep).
        // NOTE: applies universally, thus also for subsequent rules.
        exclude: '',
    },
    // Result value options.
    result: {
        // Fail if result matches any of these.
        fail: [],
    },
    // Token-rewind options. `history` bounds how many consumed tokens
    // are retained on ctx.v for ctx.rewind(). The default of 64 keeps
    // parse-time memory bounded for large inputs; raise it if a
    // grammar needs to rewind further, or set to Infinity to retain
    // every consumed token. ctx.rewind(mark) throws if `mark` falls
    // outside the retained window.
    rewind: {
        history: 64,
    },
    // Configuration options.
    config: {
        // Configuration modifiers.
        modify: {},
    },
    // Provide a custom parser.
    parser: {
        start: undefined,
    },
};
exports.defaults = defaults;
//# sourceMappingURL=defaults.js.map

================================================
FILE: dist/error.d.ts
================================================
import type { Bag, Context, Rule, Token } from './types';
declare class JsonicError extends SyntaxError {
    constructor(code: string, details: Bag, token: Token, rule: Rule, ctx: Context);
}
declare function errinject<T extends string | string[] | {
    [key: string]: string;
}>(s: T, code: string, details: Bag, token: Token, rule: Rule, ctx: Context): T;
declare function trimstk(err: Error): void;
declare function errsite(spec: {
    src: string;
    sub?: string;
    msg?: string;
    row?: number;
    col?: number;
    pos?: number;
    cline?: string;
}): string;
declare function errmsg(spec: {
    code?: string;
    name?: string;
    txts?: {
        msg?: string;
        hint?: string;
        site?: string;
    };
    smsg?: string;
    src?: string;
    file?: string;
    row?: number;
    col?: number;
    pos?: number;
    site?: string;
    sub?: string;
    prefix?: string | Function;
    suffix?: string | Function;
    color?: {
        active?: boolean;
        reset?: string;
        hi?: string;
        lo?: string;
        line?: string;
    };
}): string;
declare function errdesc(code: string, details: Bag, token: Token, rule: Rule, ctx: Context): Bag;
declare function strinject<T extends string | string[] | {
    [key: string]: string;
}>(s: T, m: Bag, f?: {
    indent?: string;
}): T;
declare function prop(obj: any, path: string, val?: any): any;
export { JsonicError, errdesc, errinject, errsite, errmsg, trimstk, strinject, prop, };


================================================
FILE: dist/error.js
================================================
"use strict";
/* Copyright (c) 2013-2024 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonicError = void 0;
exports.errdesc = errdesc;
exports.errinject = errinject;
exports.errsite = errsite;
exports.errmsg = errmsg;
exports.trimstk = trimstk;
exports.strinject = strinject;
exports.prop = prop;
const types_1 = require("./types");
const utility_1 = require("./utility");
const S = {
    function: 'function',
    object: 'object',
    string: 'string',
    unexpected: 'unexpected',
    Object: 'Object',
    Array: 'Array',
    gap: '  ',
    no_re_flags: types_1.EMPTY,
};
// Jsonic errors with nice formatting.
class JsonicError extends SyntaxError {
    constructor(code, details, token, rule, ctx) {
        details = (0, utility_1.deep)({}, details);
        let desc = errdesc(code, details, token, rule, ctx);
        super(desc.message);
        (0, utility_1.assign)(this, desc);
    }
}
exports.JsonicError = JsonicError;
// Inject value text into an error message. The value is taken from
// the `details` parameter to JsonicError. If not defined, the value is
// determined heuristically from the Token and Context.
function errinject(s, code, details, token, rule, ctx) {
    let ref = {
        ...(ctx || {}),
        ...(ctx.cfg || {}),
        ...(ctx.opts || {}),
        ...(token || {}),
        ...(rule || {}),
        ...(ctx.meta || {}),
        ...(details || {}),
        ...{ code, details, token, rule, ctx },
    };
    return strinject(s, ref, { indent: '  ' });
}
// Remove Jsonic internal lines as spurious for caller.
function trimstk(err) {
    if (err.stack) {
        err.stack = err.stack
            .split('\n')
            .filter((s) => !s.includes('jsonic/jsonic'))
            .map((s) => s.replace(/    at /, 'at '))
            .join('\n');
    }
}
// Extract error site in source text and mark error point. */
function errsite(spec) {
    let { src, sub, msg, cline, row, col, pos } = spec;
    row = null != row && 0 < row ? row : 1;
    col = null != col && 0 < col ? col : 1;
    pos =
        null != pos && 0 < pos
            ? pos
            : null == src
                ? 0
                : src
                    .split('\n')
                    .reduce((pos, line, i) => ((pos +=
                    i < row - 1 ? line.length + 1 : i === row - 1 ? col : 0),
                    pos), 0);
    let tsrc = null == sub ? types_1.EMPTY : sub;
    let behind = src.substring(Math.max(0, pos - 333), pos).split('\n');
    let ahead = src.substring(pos, pos + 333).split('\n');
    let pad = 2 + (types_1.EMPTY + (row + 2)).length;
    let rc = row < 3 ? 1 : row - 2;
    let ln = (s) => (null == cline ? '' : cline) +
        (types_1.EMPTY + rc++).padStart(pad, ' ') +
        ' | ' +
        (null == cline ? '' : '\x1b[0m') +
        (null == s ? types_1.EMPTY : s);
    let blen = behind.length;
    let lines = [
        2 < blen ? ln(behind[blen - 3]) : null,
        1 < blen ? ln(behind[blen - 2]) : null,
        ln(behind[blen - 1] + ahead[0]),
        ' '.repeat(pad) +
            '   ' +
            ' '.repeat(col - 1) +
            (null == cline ? '' : cline) +
            '^'.repeat(tsrc.length || 1) +
            ' ' +
            msg +
            (null == cline ? '' : '\x1b[0m'),
        ln(ahead[1]),
        ln(ahead[2]),
    ]
        .filter((line) => null != line)
        .join('\n');
    return lines;
}
function errmsg(spec) {
    const color = {
        active: false,
        reset: '',
        hi: '',
        lo: '',
        line: '',
    };
    if (spec.color && spec.color.active) {
        Object.assign(color, spec.color);
    }
    const txts = {
        msg: null,
        hint: null,
        site: null,
        ...(spec.txts || {})
    };
    let message = [
        null == spec.prefix
            ? null
            : 'function' === typeof spec.prefix
                ? spec.prefix(color, spec)
                : '' + spec.prefix,
        (null == spec.code
            ? ''
            : color.hi +
                '[' +
                (null == spec.name ? '' : spec.name + '/') +
                spec.code +
                ']:') +
            color.reset +
            ' ' +
            // (null == spec.msg ? '' : spec.msg),
            (null == txts.msg ? '' : txts.msg),
        (null != spec.row && null != spec.col) || null != spec.file
            ? '  ' +
                color.line +
                '-->' +
                color.reset +
                ' ' +
                (null == spec.file ? '<no-file>' : spec.file) +
                (null == spec.row || null == spec.col
                    ? ''
                    : ':' + spec.row + ':' + spec.col)
            : null,
        null == spec.src
            ? ''
            : (null == txts.site ? '' : errsite({
                src: spec.src,
                sub: spec.sub,
                msg: spec.smsg || spec.txts?.msg,
                cline: color.line,
                row: spec.row,
                col: spec.col,
                pos: spec.pos,
            })),
        '',
        // null == spec.hint ? null : spec.hint,
        // txts.hint,
        (null == txts.hint ? '' : txts.hint),
        null == spec.suffix
            ? null
            : 'function' === typeof spec.suffix
                ? spec.suffix(color, spec)
                : '' + spec.suffix,
    ]
        .filter((n) => null != n)
        .join('\n');
    return message;
}
function errdesc(code, details, token, rule, ctx) {
    try {
        const src = ctx.src();
        const cfg = ctx.cfg;
        const meta = ctx.meta;
        const txts = errinject({
            msg: cfg.error[code] ||
                (details?.use?.err &&
                    (details.use.err.code || details.use.err.message)) ||
                cfg.error.unknown,
            hint: (cfg.hint[code] ||
                details.use?.err?.message ||
                cfg.hint.unknown ||
                '')
                .trim()
                .split('\n')
                .map((s) => '  ' + s)
                .join('\n'),
            site: '',
        }, code, details, token, rule, ctx);
        txts.site = errsite({
            src,
            msg: txts.msg,
            cline: cfg.color.active ? cfg.color.line : '',
            row: token.rI,
            col: token.cI,
            pos: token.sI,
            sub: token.src,
        });
        const suffix = true === cfg.errmsg.suffix ? (color) => [
            '',
            '  ' + color.lo + 'https://jsonic.senecajs.org' + color.reset + '',
            '  ' +
                color.lo +
                '--internal: tag=' +
                (ctx.opts.tag || '') +
                '; rule=' +
                rule.name +
                '~' +
                rule.state +
                '; token=' +
                (0, utility_1.tokenize)(token.tin, ctx.cfg) +
                (null == token.why ? '' : '~' + token.why) +
                '; plugins=' +
                ctx
                    .plgn()
                    .map((p) => p.name)
                    .join(',') +
                '--' +
                color.reset,
        ].join('\n') :
            ('string' === typeof cfg.errmsg.suffix || 'function' === typeof cfg.errmsg.suffix) ?
                cfg.errmsg.suffix :
                undefined;
        let message = errmsg({
            code,
            // name: 'jsonic',
            name: cfg.errmsg.name,
            txts,
            src,
            file: meta ? meta.fileName : undefined,
            row: token.rI,
            col: token.cI,
            pos: token.sI,
            sub: token.src,
            color: cfg.color,
            suffix,
        });
        let desc = {
            internal: {
                token,
                ctx,
            },
        };
        desc = {
            ...Object.create(desc),
            message,
            code,
            details,
            meta,
            fileName: meta ? meta.fileName : undefined,
            lineNumber: token.rI,
            columnNumber: token.cI,
            txts: () => txts
        };
        return desc;
    }
    catch (e) {
        // TODO: fix
        console.log(e);
        return {};
    }
}
// Inject value into text by key using "{key}" syntax.
function strinject(s, m, f) {
    let st = typeof s;
    let t = Array.isArray(s)
        ? 'array'
        : null == s
            ? 'string'
            : 'object' === st
                ? st
                : 'string';
    let so = 'object' === t
        ? s
        : 'array' === t
            ? s.reduce((a, n, i) => ((a[i] = n), a), {})
            : { _: s };
    let mo = null == m ? {} : m;
    Object.entries(so).map((n) => (so[n[0]] =
        null == n[1]
            ? ''
            : ('' + n[1]).replace(/\{([\w_0-9.]+)}/g, (match, keypath) => {
                let inject = prop(mo, keypath);
                inject = undefined === inject ? match : inject;
                if ('object' === typeof inject) {
                    let cn = inject?.constructor?.name;
                    if ('Object' === cn || 'Array' === cn) {
                        inject = JSON.stringify(inject).replace(/([^"])"/g, '$1');
                    }
                    else {
                        inject = inject.toString();
                    }
                }
                else {
                    inject = '' + inject;
                }
                if (f) {
                    if ('string' === typeof f.indent) {
                        inject = inject.replace(/\n/g, '\n' + f.indent);
                    }
                }
                return inject;
            })));
    return ('string' === t ? so._ : 'array' === t ? Object.values(so) : so);
}
function prop(obj, path, val) {
    let root = obj;
    try {
        let parts = path.split('.');
        let pn;
        for (let pI = 0; pI < parts.length; pI++) {
            pn = parts[pI];
            if ('__proto__' === pn) {
                throw new Error(pn);
            }
            if (pI < parts.length - 1) {
                obj = obj[pn] = obj[pn] || {};
            }
        }
        if (undefined !== val) {
            if ('__proto__' === pn) {
                throw new Error(pn);
            }
            obj[pn] = val;
        }
        return obj[pn];
    }
    catch (e) {
        throw new Error('Cannot ' +
            (undefined === val ? 'get' : 'set') +
            ' path ' +
            path +
            ' on object: ' +
            str(root) +
            (undefined === val ? '' : ' to value: ' + str(val, 22)));
    }
}
function str(o, len = 44) {
    let s;
    try {
        s = 'object' === typeof o ? JSON.stringify(o) : '' + o;
    }
    catch (e) {
        s = '' + o;
    }
    return snip(len < s.length ? s.substring(0, len - 3) + '...' : s, len);
}
function snip(s, len = 5) {
    return undefined === s
        ? ''
        : ('' + s).substring(0, len).replace(/[\r\n\t]/g, '.');
}
//# sourceMappingURL=error.js.map

================================================
FILE: dist/grammar.d.ts
================================================
import { Jsonic } from './jsonic';
declare function grammar(jsonic: Jsonic): void;
declare function makeJSON(jsonic: any): any;
export { grammar, makeJSON };


================================================
FILE: dist/grammar.js
================================================
"use strict";
/* Copyright (c) 2013-2024 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.grammar = grammar;
exports.makeJSON = makeJSON;
const defprop = Object.defineProperty;
function mark(node, marker, data) {
    if (node != null && typeof node === 'object') {
        defprop(node, marker, { value: data, writable: true });
    }
}
function grammar(jsonic) {
    const { deep } = jsonic.util;
    const { 
    // Fixed tokens
    // OB, // Open Brace `{`
    // CB, // Close Brace `}`
    // OS, // Open Square `[`
    // CS, // Close Square `]`
    // CL, // Colon `:`
    CA, // Comma `,`
    // Complex tokens
    TX, // Text (unquoted character sequence)
    ST, // String (quoted character sequence)
    // Control tokens
    ZZ, // End-of-source
     } = jsonic.token;
    const { VAL, // All tokens that make up values
    // KEY, // All tokens that make up keys
     } = jsonic.tokenSet;
    const fnm = {
        '@finish': (_rule, ctx) => {
            if (!ctx.cfg.rule.finish) {
                // TODO: pass missing end char for replacement in error message
                ctx.t0.err = 'end_of_source';
                return ctx.t0;
            }
        },
        // TODO: define a way to "export" rule actions or other functions so that
        // other plugins can use them.
        '@pairkey': (r) => {
            // Get key string value from first matching token of `Open` state.
            const key_token = r.o0;
            const key = ST === key_token.tin || TX === key_token.tin
                ? key_token.val // Was text
                : key_token.src; // Was number, use original text
            r.u.key = key;
        },
    };
    // Plain JSON
    // ----------
    jsonic.grammar({
        ref: {
            '@finish': (_rule, ctx) => {
                if (!ctx.cfg.rule.finish) {
                    // TODO: pass missing end char for replacement in error message
                    ctx.t0.err = 'end_of_source';
                    return ctx.t0;
                }
            },
            // TODO: define a way to "export" rule actions or other functions so that
            // other plugins can use them.
            '@pairkey': (r) => {
                // Get key string value from first matching token of `Open` state.
                const key_token = r.o0;
                const key = ST === key_token.tin || TX === key_token.tin
                    ? key_token.val // Was text
                    : key_token.src; // Was number, use original text
                r.u.key = key;
            },
            '@val-bo': (rule) => (rule.node = undefined),
            '@val-bc': (r, ctx) => {
                // NOTE: val can be undefined when there is no value at all
                // (eg. empty string, thus no matched opening token)
                r.node =
                    // If there's no node,
                    undefined === r.node
                        ? // ... or no child node (child map or list),
                            undefined === r.child.node
                                ? // ... or no matched tokens,
                                    0 === r.os
                                        ? // ... then the node has no value
                                            undefined
                                        : // .. otherwise use the token value
                                            (() => {
                                                let val = r.o0.resolveVal(r, ctx);
                                                if (ctx.cfg.info.text &&
                                                    typeof val === 'string' &&
                                                    (r.o0.tin === ctx.cfg.t.ST || r.o0.tin === ctx.cfg.t.TX)) {
                                                    let quote = r.o0.tin === ctx.cfg.t.ST && r.o0.src.length > 0
                                                        ? r.o0.src[0] : '';
                                                    let sv = new String(val);
                                                    mark(sv, ctx.cfg.info.marker, { quote });
                                                    val = sv;
                                                }
                                                return val;
                                            })()
                                : r.child.node
                        : r.node;
            },
            '@map-bo': (r, ctx) => {
                // Create a new empty map.
                r.node = Object.create(null);
                if (ctx.cfg.info.map) {
                    mark(r.node, ctx.cfg.info.marker, { implicit: false, meta: {} });
                }
            },
            '@list-bo': (r, ctx) => {
                // Create a new empty list.
                r.node = [];
                if (ctx.cfg.info.list) {
                    mark(r.node, ctx.cfg.info.marker, { implicit: false, meta: {} });
                }
            },
            '@pair-bc': (r, ctx) => {
                if (r.u.pair) {
                    // Drop keys that match the info marker to preserve metadata.
                    if (ctx.cfg.info.map && r.u.key === ctx.cfg.info.marker) {
                        return;
                    }
                    // Store previous value (if any, for extensions).
                    r.u.prev = r.node[r.u.key];
                    r.node[r.u.key] = r.child.node;
                }
            },
            '@elem-bc': (r) => {
                if (true !== r.u.done && undefined !== r.child.node) {
                    r.node.push(r.child.node);
                }
            },
        },
        rule: {
            val: {
                // Opening token alternates.
                open: [
                    // A map: `{ ...`
                    { s: '#OB', p: 'map', b: 1, g: 'map,json' },
                    // A list: `[ ...`
                    { s: '#OS', p: 'list', b: 1, g: 'list,json' },
                    // A plain value: `x` `"x"` `1` `true` ....
                    { s: '#VAL', g: 'val,json' },
                ],
                // Closing token alternates.
                close: [
                    // End of input.
                    { s: '#ZZ', g: 'end,json' },
                    // There's more JSON.
                    { b: 1, g: 'more,json' },
                ]
            },
            map: {
                open: [
                    // An empty map: {}.
                    { s: '#OB #CB', b: 1, n: { pk: 0 }, g: 'map,json' },
                    // Start matching map key-value pairs: a:1.
                    // Reset counter n.pk as new map (for extensions).
                    { s: '#OB', p: 'pair', n: { pk: 0 }, g: 'map,json,pair' },
                ],
                close: [
                    // End of map.
                    { s: '#CB', g: 'end,json' },
                ],
            },
            list: {
                open: [
                    // An empty list: [].
                    { s: '#OS #CS', b: 1, g: 'list,json' },
                    // Start matching list elements: 1,2.
                    { s: '#OS', p: 'elem', g: 'list,elem,json' },
                ],
                close: [
                    // End of map.
                    { s: '#CS', g: 'end,json' },
                ]
            },
            // sets key:val on node
            pair: {
                open: [
                    // Match key-colon start of pair. Marker `pair=true` allows flexibility.
                    {
                        s: '#KEY #CL',
                        p: 'val',
                        u: { pair: true },
                        a: '@pairkey',
                        g: 'map,pair,key,json',
                    },
                ],
                close: [
                    // Comma means a new pair at same pair-key level.
                    { s: '#CA', r: 'pair', g: 'map,pair,json' },
                    // End of map.
                    { s: '#CB', b: 1, g: 'map,pair,json' },
                ]
            },
            // push onto node
            elem: {
                open: [
                    // List elements are values.
                    { p: 'val', g: 'list,elem,val,json' },
                ],
                close: [
                    // Next element.
                    { s: '#CA', r: 'elem', g: 'list,elem,json' },
                    // End of list.
                    { s: '#CS', b: 1, g: 'list,elem,json' },
                ],
            },
        },
    });
    /*
    jsonic.rule('val', (rs: RuleSpec) => {
    rs
     
    .fnref({
      '@val-bo': (rule: Rule) => (rule.node = undefined),
      '@val-bc': (r: Rule, ctx: Context) => {
        // NOTE: val can be undefined when there is no value at all
        // (eg. empty string, thus no matched opening token)
        r.node =
          // If there's no node,
          undefined === r.node
            ? // ... or no child node (child map or list),
            undefined === r.child.node
              ? // ... or no matched tokens,
              0 === r.os
                ? // ... then the node has no value
                undefined
                : // .. otherwise use the token value
                r.o0.resolveVal(r, ctx)
              : r.child.node
            : r.node
      }
    })
     
    // Clear the current node as this a new value.
    // .bo((rule: Rule) => (rule.node = undefined))
    // .bo('@val-bo')
     
    // Opening token alternates.
    .open([
    // A map: `{ ...`
    { s: '#OB', p: 'map', b: 1, g: 'map,json' },
     
    // A list: `[ ...`
    { s: '#OS', p: 'list', b: 1, g: 'list,json' },
     
    // A plain value: `x` `"x"` `1` `true` ....
    { s: '#VAL', g: 'val,json' },
    ])
     
    // Closing token alternates.
    .close([
    // End of input.
    { s: '#ZZ', g: 'end,json' },
     
    // There's more JSON.
    { b: 1, g: 'more,json' },
    ])
     
    // .bc('@val-bc')
     
    })
     
     
     
    jsonic.rule('map', (rs: RuleSpec) => {
      rs
        .fnref({
          '@map-bo': (r: Rule) => {
            // Create a new empty map.
            r.node = Object.create(null)
          }
        })
        // .bo('@bo')
        .open([
          // An empty map: {}.
          { s: '#OB #CB', b: 1, n: { pk: 0 }, g: 'map,json' },
     
          // Start matching map key-value pairs: a:1.
          // Reset counter n.pk as new map (for extensions).
          { s: '#OB', p: 'pair', n: { pk: 0 }, g: 'map,json,pair' },
        ])
        .close([
          // End of map.
          { s: '#CB', g: 'end,json' },
        ])
    })
     
    jsonic.rule('list', (rs: RuleSpec) => {
      rs
        .fnref({
          '@list-bo': (r: Rule) => {
            // Create a new empty list.
            r.node = []
          }
        })
        // .bo('@bo')
        .open([
          // An empty list: [].
          { s: '#OS #CS', b: 1, g: 'list,json' },
    
          // Start matching list elements: 1,2.
          { s: '#OS', p: 'elem', g: 'list,elem,json' },
        ])
        .close([
          // End of map.
          { s: '#CS', g: 'end,json' },
        ])
    })
  
  
  
  
    // sets key:val on node
    jsonic.rule('pair', (rs: RuleSpec) => {
      rs
        .fnref({
          ...fnm,
          '@pair-bc': (r: Rule, _ctx: Context) => {
            if (r.u.pair) {
              // Store previous value (if any, for extensions).
              r.u.prev = r.node[r.u.key]
              r.node[r.u.key] = r.child.node
            }
          }
        })
  
        .open([
          // Match key-colon start of pair. Marker `pair=true` allows flexibility.
          {
            s: '#KEY #CL',
            p: 'val',
            u: { pair: true },
            a: '@pairkey',
            g: 'map,pair,key,json',
          },
        ])
        // .bc('@bc')
        .close([
          // Comma means a new pair at same pair-key level.
          { s: '#CA', r: 'pair', g: 'map,pair,json' },
  
          // End of map.
          { s: '#CB', b: 1, g: 'map,pair,json' },
        ])
    })
  
    // push onto node
    jsonic.rule('elem', (rs: RuleSpec) => {
      rs
        .fnref({
          ...fnm,
          '@elem-bc': (r: Rule) => {
            if (true !== r.u.done && undefined !== r.child.node) {
              r.node.push(r.child.node)
            }
          }
        })
        .open([
          // List elements are values.
          { p: 'val', g: 'list,elem,val,json' },
        ])
        // .bc('@bc')
        .close([
          // Next element.
          { s: '#CA', r: 'elem', g: 'list,elem,json' },
  
          // End of list.
          { s: '#CS', b: 1, g: 'list,elem,json' },
        ])
    })
  
    */
    // Jsonic syntax extensions.
    // NOTE: undefined values are still removed, as JSON does not have "undefined", only null.
    // Counters.
    // * pk: depth of the pair-key path
    // * dmap: depth of maps
    function pairval(r, ctx) {
        let key = r.u.key;
        let val = r.child.node;
        const prev = r.u.prev;
        // Convert undefined to null when there was no pair value
        val = undefined === val ? null : val;
        // Do not set unsafe keys on Arrays (Objects are created without a prototype)
        if (r.u.list && ctx.cfg.safe.key) {
            if ('__proto__' === key || 'constructor' === key) {
                return;
            }
        }
        // Drop keys that match the info marker to preserve metadata.
        if (ctx.cfg.info.map && key === ctx.cfg.info.marker) {
            return;
        }
        val = null == prev
            ? val
            : ctx.cfg.map.merge
                ? ctx.cfg.map.merge(prev, val, r, ctx)
                : ctx.cfg.map.extend
                    ? deep(prev, val)
                    : val;
        r.node[key] = val;
    }
    jsonic.grammar({
        ref: {
            '@val-close-error': (r, c) => (0 === r.d ? c.t0 : undefined),
        },
        rule: {
            val: {
                open: {
                    alts: [
                        // A pair key: `a: ...`
                        // Implicit map at top level.
                        {
                            s: '#KEY #CL',
                            c: { d: 0 },
                            p: 'map',
                            b: 2,
                            g: 'pair,jsonic,top',
                        },
                        // A pair dive: `a:b: ...`
                        // Increment counter n.pk to indicate pair-key depth (for extensions).
                        // a:9 -> pk=undef, a:b:9 -> pk=1, a:b:c:9 -> pk=2, etc
                        {
                            s: '#KEY #CL',
                            p: 'map',
                            b: 2,
                            n: { pk: 1 },
                            g: 'pair,jsonic',
                        },
                        // A plain value: `x` `"x"` `1` `true` ....
                        { s: '#VAL', g: 'val,json' },
                        // Implicit ends `{a:}` -> {"a":null}, `[a:]` -> [{"a":null}]
                        {
                            s: ['#CB #CS'],
                            b: 1,
                            c: { d: { $gt: 0 } },
                            g: 'val,imp,null,jsonic',
                        },
                        // Implicit list at top level: a,b.
                        {
                            s: '#CA',
                            c: { d: 0 },
                            p: 'list',
                            b: 1,
                            g: 'list,imp,jsonic',
                        },
                        // Value is implicitly null when empty before commas.
                        { s: '#CA', b: 1, g: 'list,val,imp,null,jsonic' },
                        { s: '#ZZ', g: 'jsonic' },
                    ],
                    inject: { append: true, delete: [2] },
                },
                close: {
                    alts: [
                        // Explicitly close map or list: `}`, `]`
                        {
                            s: ['#CB #CS'],
                            b: 1,
                            g: 'val,json,close',
                            e: '@val-close-error', // (r, c) => (0 === r.d ? c.t0 : undefined),
                        },
                        // Implicit list (comma sep) only allowed at top level: `1,2`.
                        {
                            s: '#CA',
                            c: { 'n.dlist': { $lte: 0 }, 'n.dmap': { $lte: 0 } },
                            r: 'list',
                            u: { implist: true },
                            g: 'list,val,imp,comma,jsonic',
                        },
                        // Implicit list (space sep) only allowed at top level: `1 2`.
                        {
                            c: { 'n.dlist': { $lte: 0 }, 'n.dmap': { $lte: 0 } },
                            r: 'list',
                            u: { implist: true },
                            g: 'list,val,imp,space,jsonic',
                            b: 1,
                        },
                        { s: '#ZZ', g: 'jsonic' },
                    ],
                    inject: {
                        append: true,
                        // Move "There's more JSON" to end.
                        move: [1, -1],
                    }
                }
            }
        }
    });
    /*
      jsonic.rule('val', (rs: RuleSpec) => {
        rs
          .open(
            [
              // A pair key: `a: ...`
              // Implicit map at top level.
              {
                s: '#KEY #CL',
                c: { d: 0 },
                p: 'map',
                b: 2,
                g: 'pair,jsonic,top',
              },
     
              // A pair dive: `a:b: ...`
              // Increment counter n.pk to indicate pair-key depth (for extensions).
              // a:9 -> pk=undef, a:b:9 -> pk=1, a:b:c:9 -> pk=2, etc
              {
                s: '#KEY #CL',
                p: 'map',
                b: 2,
                n: { pk: 1 },
                g: 'pair,jsonic',
              },
     
              // A plain value: `x` `"x"` `1` `true` ....
              { s: [VAL], g: 'val,json' },
     
              // Implicit ends `{a:}` -> {"a":null}, `[a:]` -> [{"a":null}]
              {
                s: ['#CB #CS'],
                b: 1,
                c: { d: { $gt: 0 } },
                g: 'val,imp,null,jsonic',
              },
     
              // Implicit list at top level: a,b.
              {
                s: '#CA',
                c: { d: 0 },
                p: 'list',
                b: 1,
                g: 'list,imp,jsonic',
              },
     
              // Value is implicitly null when empty before commas.
              { s: '#CA', b: 1, g: 'list,val,imp,null,jsonic' },
     
              { s: '#ZZ', g: 'jsonic' },
            ],
            { append: true, delete: [2] },
          )
          .close(
            [
              // Explicitly close map or list: `}`, `]`
              {
                s: ['#CB #CS'],
                b: 1,
                g: 'val,json,close',
                e: (r, c) => (0 === r.d ? c.t0 : undefined),
              },
     
              // Implicit list (comma sep) only allowed at top level: `1,2`.
              {
                s: '#CA',
                c: { 'n.dlist': { $lte: 0 }, 'n.dmap': { $lte: 0 } },
                r: 'list',
                u: { implist: true },
                g: 'list,val,imp,comma,jsonic',
              },
     
              // Implicit list (space sep) only allowed at top level: `1 2`.
              {
                c: { 'n.dlist': { $lte: 0 }, 'n.dmap': { $lte: 0 } },
                r: 'list',
                u: { implist: true },
                g: 'list,val,imp,space,jsonic',
                b: 1,
              },
     
              { s: '#ZZ', g: 'jsonic' },
            ],
            {
              append: true,
     
              // Move "There's more JSON" to end.
              move: [1, -1],
            },
          )
      })
    */
    jsonic.rule('map', (rs) => {
        rs
            .fnref({
            ...fnm
        })
            .bo((r) => {
            // Increment depth of maps.
            r.n.dmap = 1 + (r.n.dmap ? r.n.dmap : 0);
        })
            .open([
            // Auto-close; fail if rule.finish option is false.
            { s: '#OB #ZZ', b: 1, e: '@finish', g: 'end,jsonic' },
        ])
            .open([
            // Pair from implicit map.
            { s: '#KEY #CL', p: 'pair', b: 2, g: 'pair,list,val,imp,jsonic' },
        ], { append: true })
            .close([
            // Normal end of map, no path dive.
            {
                s: '#CB',
                c: { 'n.pk': { $lte: 0 } },
                g: 'end,json',
            },
            // Not yet at end of path dive, keep ascending.
            { s: '#CB', b: 1, g: 'path,jsonic' },
            // End of implicit path
            { s: ['#CA #CS #VAL'], b: 1, g: 'end,path,jsonic' },
            // Auto-close; fail if rule.finish option is false.
            { s: '#ZZ', e: '@finish', g: 'end,jsonic' },
        ], { append: true, delete: [0] })
            .bc((r, ctx) => {
            let m = ctx.cfg.info.marker;
            if (ctx.cfg.info.map && r.node?.[m]) {
                r.node[m].implicit = !(r.o0 && r.o0.tin === ctx.cfg.t.OB);
            }
        });
    });
    jsonic.rule('list', (rs) => {
        rs
            .fnref({
            ...fnm,
            '@list-bo': (r) => {
                // Increment depth of lists.
                r.n.dlist = 1 + (r.n.dlist ? r.n.dlist : 0);
                if (r.prev.u.implist) {
                    r.node.push(r.prev.node);
                    r.prev.node = r.node;
                }
            }
        })
            // .bo('@bo')
            .open({
            c: { 'prev.u.implist': { $eq: true } },
            p: 'elem',
        })
            .open([
            // Initial comma [, will insert null as [null,
            { s: '#CA', p: 'elem', b: 1, g: 'list,elem,val,imp,jsonic' },
            // Another element.
            { p: 'elem', g: 'list,elem,jsonic' },
        ], { append: true })
            .close([
            // Fail if rule.finish option is false.
            { s: '#ZZ', e: '@finish', g: 'end,jsonic' },
        ], { append: true })
            .bc((r, ctx) => {
            let m = ctx.cfg.info.marker;
            if (ctx.cfg.info.list && r.node?.[m]) {
                r.node[m].implicit = !(r.o0 && r.o0.tin === ctx.cfg.t.OS);
            }
        });
    });
    // sets key:val on node
    jsonic.rule('pair', (rs, p) => {
        rs
            .fnref({
            ...fnm,
            '@pair-bc': (r, ctx) => {
                if (r.u.pair) {
                    pairval(r, ctx);
                }
                if (true === r.u.child) {
                    let val = r.child.node;
                    val = undefined === val ? null : val;
                    let prev = r.node['child$'];
                    if (undefined === prev) {
                        r.node['child$'] = val;
                    }
                    else {
                        r.node['child$'] =
                            ctx.cfg.map.merge
                                ? ctx.cfg.map.merge(prev, val, r, ctx)
                                : ctx.cfg.map.extend
                                    ? deep(prev, val)
                                    : val;
                    }
                }
            }
        })
            .open([
            // Ignore initial comma: {,a:1.
            { s: '#CA', g: 'map,pair,comma,jsonic' },
            // map.child: bare colon `:value` stores value on child$ property.
            p.cfg.map.child && {
                s: '#CL',
                p: 'val',
                u: { done: true, child: true },
                g: 'map,pair,child,jsonic',
            },
        ], { append: true })
            // NOTE: JSON pair.bc runs first, then this bc may override value.
            // .bc('@bc')
            .close([
            // End of map, reset implicit depth counter so that
            // a:b:c:1,d:2 -> {a:{b:{c:1}},d:2}
            {
                s: '#CB',
                c: { 'n.pk': { $lte: 0 } },
                b: 1,
                g: 'map,pair,json',
            },
            // Ignore trailing comma at end of map.
            {
                s: '#CA #CB',
                c: { 'n.pk': { $lte: 0 } },
                b: 1,
                g: 'map,pair,comma,jsonic',
            },
            { s: [CA, ZZ], g: 'end,jsonic' },
            // Comma means a new pair at same pair-key level.
            {
                s: '#CA',
                c: { 'n.pk': { $lte: 0 } },
                r: 'pair',
                g: 'map,pair,json',
            },
            // TODO: try CA VAL ? works anywhere?
            // Comma means a new pair if implicit top level map.
            {
                s: '#CA',
                c: { 'n.dmap': { $lte: 1 } },
                r: 'pair',
                g: 'map,pair,jsonic',
            },
            // TODO: try VAL CL ? works anywhere?
            // Value means a new pair if implicit top level map.
            {
                s: '#KEY',
                c: { 'n.dmap': { $lte: 1 } },
                r: 'pair',
                b: 1,
                g: 'map,pair,imp,jsonic',
            },
            // End of implicit path (eg. a:b:1), keep closing until pk=0.
            {
                s: ['#CB #CA #CS #KEY'],
                c: { 'n.pk': { $gt: 0 } },
                b: 1,
                g: 'map,pair,imp,path,jsonic',
            },
            // Can't close a map with `]`
            { s: '#CS', e: (r) => r.c0, g: 'end,jsonic' },
            // Fail if auto-close option is false.
            { s: '#ZZ', e: '@finish', g: 'map,pair,json' },
            // Who needs commas anyway?
            {
                r: 'pair',
                b: 1,
                g: 'map,pair,imp,jsonic',
            },
        ], { append: true, delete: [0, 1] });
    });
    // push onto node
    jsonic.rule('elem', (rs, p) => {
        rs
            .fnref({
            ...fnm,
            '@elem-bc': (r, ctx) => {
                if (true === r.u.pair) {
                    if (ctx.cfg.list.pair) {
                        // list.pair: push pair as object element into the list
                        let key = r.u.key;
                        let val = r.child.node;
                        val = undefined === val ? null : val;
                        let pairObj = Object.create(null);
                        pairObj[key] = val;
                        r.node.push(pairObj);
                    }
                    else {
                        r.u.prev = r.node[r.u.key];
                        pairval(r, ctx);
                    }
                }
                if (true === r.u.child) {
                    let val = r.child.node;
                    val = undefined === val ? null : val;
                    let prev = r.node['child$'];
                    if (undefined === prev) {
                        r.node['child$'] = val;
                    }
                    else {
                        r.node['child$'] =
                            ctx.cfg.map.merge
                                ? ctx.cfg.map.merge(prev, val, r, ctx)
                                : ctx.cfg.map.extend
                                    ? deep(prev, val)
                                    : val;
                    }
                }
            }
        })
            .open([
            // Empty commas insert null elements.
            // Note that close consumes a comma, so b:2 works.
            {
                s: '#CA #CA',
                b: 2,
                u: { done: true },
                a: (r) => r.node.push(null),
                g: 'list,elem,imp,null,jsonic',
            },
            {
                s: '#CA',
                u: { done: true },
                a: (r) => r.node.push(null),
                g: 'list,elem,imp,null,jsonic',
            },
            {
                s: '#KEY #CL',
                e: (p.cfg.list.property || p.cfg.list.pair) ? undefined :
                    (_r, ctx) => ctx.t0,
                p: 'val',
                n: { pk: 1, dmap: 1 },
                u: { done: true, pair: true, list: true },
                a: '@pairkey',
                g: 'elem,pair,jsonic',
            },
            // list.child: bare colon `:value` stores value on child$ property.
            p.cfg.list.child && {
                s: '#CL',
                p: 'val',
                u: { done: true, child: true, list: true },
                g: 'elem,child,jsonic',
            },
        ])
            // .bc('@bc')
            .close([
            // Ignore trailing comma.
            { s: ['#CA', '#CS #ZZ'], b: 1, g: 'list,elem,comma,jsonic' },
            // Next element.
            { s: '#CA', r: 'elem', g: 'list,elem,json' },
            // End of list.
            { s: '#CS', b: 1, g: 'list,elem,json' },
            // Fail if auto-close option is false.
            { s: '#ZZ', e: '@finish', g: 'list,elem,json' },
            // Can't close a list with `}`
            { s: '#CB', e: (r) => r.c0, g: 'end,jsonic' },
            // Who needs commas anyway?
            { r: 'elem', b: 1, g: 'list,elem,imp,jsonic' },
        ], { delete: [-1, -2] });
    });
}
function makeJSON(jsonic) {
    let justJSON = jsonic.make({
        grammar$: false,
        text: { lex: false },
        number: {
            hex: false,
            oct: false,
            bin: false,
            sep: null,
            exclude: /^00+/,
        },
        string: {
            chars: '"',
            multiChars: '',
            allowUnknown: false,
            escape: { v: null },
        },
        comment: { lex: false },
        map: { extend: false },
        lex: { empty: false },
        rule: { finish: false, include: 'json' },
        result: { fail: [undefined, NaN] },
        tokenSet: {
            KEY: ['#ST', null, null, null],
        },
    });
    grammar(justJSON);
    return justJSON;
}
//# sourceMappingURL=grammar.js.map

================================================
FILE: dist/jsonic-bnf-cli.d.ts
================================================
export declare function run(argv: string[], console: Console): Promise<void>;


================================================
FILE: dist/jsonic-bnf-cli.js
================================================
"use strict";
/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = run;
/*  jsonic-bnf-cli.ts
 *  CLI wrapper for the BNF -> jsonic grammar spec converter.
 */
const node_fs_1 = __importDefault(require("node:fs"));
const bnf_1 = require("./bnf");
const jsonic_1 = require("./jsonic");
async function run(argv, console) {
    const args = {
        help: false,
        stdin: false,
        files: [],
        inline: [],
        start: undefined,
        tag: undefined,
        space: 2,
        // When set, convert and install the grammar, parse each sample,
        // and report the tree (or an error) instead of the spec.
        parse: [],
        parseFiles: [],
    };
    for (let aI = 2; aI < argv.length; aI++) {
        const arg = argv[aI];
        if ('-' === arg) {
            args.stdin = true;
        }
        else if ('--help' === arg || '-h' === arg) {
            args.help = true;
        }
        else if ('--file' === arg || '-f' === arg) {
            args.files.push(argv[++aI]);
        }
        else if ('--start' === arg || '-s' === arg) {
            args.start = argv[++aI];
        }
        else if ('--tag' === arg || '-t' === arg) {
            args.tag = argv[++aI];
        }
        else if ('--compact' === arg || '-c' === arg) {
            args.space = 0;
        }
        else if ('--parse' === arg || '-P' === arg) {
            args.parse.push(argv[++aI]);
        }
        else if ('--parse-file' === arg) {
            args.parseFiles.push(argv[++aI]);
        }
        else if (arg && !arg.startsWith('-')) {
            args.inline.push(arg);
        }
    }
    if (args.help) {
        return help(console);
    }
    let src = '';
    for (const fp of args.files) {
        if ('string' === typeof fp && '' !== fp) {
            src += node_fs_1.default.readFileSync(fp).toString() + '\n';
        }
    }
    for (const inline of args.inline) {
        src += inline + '\n';
    }
    if ('' === src.trim() || args.stdin) {
        src += await readStdin(console);
    }
    const spec = (0, bnf_1.bnf)(src, { start: args.start, tag: args.tag });
    // Parse-mode: validate the grammar against one or more sample
    // inputs and print their parse trees. Exits 1 if any sample fails.
    if (args.parse.length > 0 || args.parseFiles.length > 0) {
        const samples = [];
        for (const fp of args.parseFiles) {
            samples.push({
                label: fp,
                input: node_fs_1.default.readFileSync(fp).toString(),
            });
        }
        for (const inp of args.parse) {
            samples.push({ label: inp, input: inp });
        }
        const j = jsonic_1.Jsonic.make();
        j.grammar(spec);
        let failed = 0;
        for (const { label, input } of samples) {
            try {
                const tree = j(input);
                console.log(`ok: ${JSON.stringify(label)} -> ` +
                    JSON.stringify(tree, null, args.space || undefined));
            }
            catch (e) {
                failed++;
                const msg = (e?.message || String(e)).split('\n')[0];
                console.error(`fail: ${JSON.stringify(label)}: ${msg}`);
            }
        }
        if (failed > 0) {
            process.exitCode = 1;
        }
        return;
    }
    console.log(JSON.stringify(spec, null, args.space || undefined));
}
async function readStdin(console) {
    if ('string' === typeof console.test$) {
        return console.test$;
    }
    if (process.stdin.isTTY)
        return '';
    let s = '';
    process.stdin.setEncoding('utf8');
    for await (const p of process.stdin)
        s += p;
    return s;
}
function help(console) {
    console.log(`
jsonic-bnf: convert a BNF grammar into a jsonic grammar spec.

Usage: jsonic-bnf <args> [<bnf-source>]*

Arguments:
  -                      Read BNF source from stdin.
  --file <path>          Read BNF source from <path> (repeatable).
  -f <path>

  --start <name>         Set the start rule (defaults to the first
  -s <name>                production).

  --tag <name>           Group tag applied to every emitted alt.
  -t <name>                Defaults to \`bnf\`.

  --compact              Emit single-line JSON (default indent is 2).
  -c

  --parse <input>        Parse <input> against the generated grammar
  -P <input>               and print its parse tree. Repeatable.
                           Exits non-zero if any sample fails.

  --parse-file <path>    Parse the contents of <path> against the
                           generated grammar (repeatable).

  --help                 Print this help message.
  -h

Examples:
  > jsonic-bnf '<greet> ::= "hi" | "hello"'
  > jsonic-bnf -f grammar.bnf
  > echo '<g> ::= "a"' | jsonic-bnf -
  > jsonic-bnf -f grammar.bnf --parse 'hi'
`);
}
//# sourceMappingURL=jsonic-bnf-cli.js.map

================================================
FILE: dist/jsonic-cli.d.ts
================================================
export declare function run(argv: string[], console: Console): Promise<void>;


================================================
FILE: dist/jsonic-cli.js
================================================
"use strict";
/* Copyright (c) 2020-2024 Richard Rodger, Oliver Sturm, and other contributors, MIT License */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = run;
const node_fs_1 = __importDefault(require("node:fs"));
const jsonic_1 = require("./jsonic");
const debug_1 = require("./debug");
async function run(argv, console) {
    const args = {
        help: false,
        stdin: false,
        sources: [],
        files: [],
        options: [],
        meta: [],
        plugins: [],
    };
    let plugins = {};
    let accept_args = true;
    for (let aI = 2; aI < argv.length; aI++) {
        let arg = argv[aI];
        if (accept_args && arg.startsWith('-')) {
            if ('-' === arg) {
                args.stdin = true;
            } //
            else if ('--' === arg) {
                accept_args = false;
            } //
            else if ('--file' === arg || '-f' === arg) {
                args.files.push(argv[++aI]);
            } //
            else if ('--option' === arg || '-o' === arg) {
                args.options.push(argv[++aI]);
            } //
            else if ('--meta' === arg || '-m' === arg) {
                args.meta.push(argv[++aI]);
            } //
            else if ('--debug' === arg || '-d' === arg) {
                plugins.debug = debug_1.Debug;
                args.meta.push('log=-1');
            } //
            else if ('--help' === arg || '-h' === arg) {
                args.help = true;
            } //
            else if ('--plugin' === arg || '-p' === arg) {
                args.plugins.push(argv[++aI]);
            } //
            else if ('--nice' === arg || '-n' === arg) {
                args.options.push('JSON.space=2');
            } //
            else {
                args.sources.push(arg);
            }
        } //
        else {
            args.sources.push(arg);
        }
    }
    if (args.help) {
        return help(console);
    }
    let options = handle_props(args.options);
    let meta = handle_props(args.meta);
    plugins = { ...plugins, ...handle_plugins(args.plugins) };
    options.debug = options.debug || {};
    options.debug.get_console = () => console;
    let jsonic = jsonic_1.Jsonic.make(options);
    for (let pn in plugins) {
        jsonic.use(plugins[pn], options.plugin?.[pn] || {});
    }
    if (null != plugins.debug) {
        console.log(jsonic.debug.describe() + '\n=== PARSE ===');
    }
    let data = { val: null };
    for (let fp of args.files) {
        if ('string' === typeof fp && '' !== fp) {
            jsonic_1.util.deep(data, { val: jsonic(node_fs_1.default.readFileSync(fp).toString(), meta) });
        }
    }
    if (0 === args.sources.length || args.stdin) {
        let stdin = await read_stdin(console);
        jsonic_1.util.deep(data, { val: jsonic(stdin, meta) });
    }
    for (let src of args.sources) {
        jsonic_1.util.deep(data, { val: jsonic(src, meta) });
    }
    options.JSON =
        null == options.JSON || 'object' !== typeof options.JSON ? {} : options.JSON;
    let replacer = (0, jsonic_1.Jsonic)(options.JSON.replacer);
    let space = (0, jsonic_1.Jsonic)(options.JSON.space);
    replacer = Array.isArray(replacer)
        ? replacer
        : null == replacer
            ? null
            : [replacer];
    let json = JSON.stringify(data.val, replacer, space);
    console.log(json);
}
async function read_stdin(console) {
    if ('string' === typeof console.test$) {
        return console.test$;
    }
    if (process.stdin.isTTY)
        return '';
    let s = '';
    process.stdin.setEncoding('utf8');
    for await (const p of process.stdin)
        s += p;
    return s;
}
// NOTE: uses vanilla Jsonic to parse arg vals, so you can set complex
// properties.  This will break if core Jsonic is broken.
function handle_props(propvals) {
    let out = {};
    for (let propval of propvals) {
        let pv = propval.split(/=/);
        if ('' !== pv[0] && '' !== pv[1]) {
            let val = (0, jsonic_1.Jsonic)(pv[1]);
            jsonic_1.util.prop(out, pv[0], val);
        }
    }
    return out;
}
function handle_plugins(plugins) {
    let out = {};
    for (let name of plugins) {
        try {
            out[name] = require(name);
        }
        catch (e) {
            let err = e;
            // Might be @jsonic plugin
            if (!name.startsWith('@')) {
                try {
                    out[name] = require('@jsonic/' + name);
                }
                catch (e) {
                    throw err; // NOTE: throws original error
                }
            }
            else {
                throw err;
            }
        }
        // Handle some variations in the way the plugin function is exported.
        if ('function' !== typeof out[name]) {
            let refname = (name.match(/([^.\\\/]+)($|\.[^.]+$)/) || [])[1];
            refname = null != refname ? refname.toLowerCase() : refname;
            // See test plugin test/p1.js
            if ('function' == typeof out[name].default) {
                out[name] = out[name].default;
            } //
            else if (null != refname &&
                'function' == typeof out[name][camel(refname)]) {
                out[name] = out[name][camel(refname)];
            }
            // See test plugin test/p2.js
            else if (null != refname &&
                'function' == typeof out[name][refname]) {
                out[refname] = out[name][refname];
                delete out[name];
            } //
            else {
                throw new Error('Plugin is not a function: ' + name);
            }
        }
    }
    return out;
}
function camel(s) {
    return (s[0].toUpperCase() +
        s
            .substring(1)
            .replace(/-(\w)/g, (m) => m[1][0].toUpperCase() + m[1].substring(1)));
}
function help(console) {
    let s = `
A JSON parser that isn't strict.

Usage: jsonic <args> [<source-text>]*

where 
  <source-text> is the source text to be parsed into JSON.
    If omitted, the source text is read from STDIN. If multiple source texts
    are provided, they will be merged in precedence (from highest) 
    right to left, STDIN, <file>.

  <args> are the command arguments:

    -                      Alias for STDIN.

    --file <file>          Load and parse <file>.
    -f <file>

    --option <name=value>  Set option <name> to <value>, where <name> 
    -o <name=value>          can be a dotted path (see example below).

    --nice                 Print JSON indented over multiple lines.
    -n

    --meta <meta=value>    Set parse meta data <name> to <value>, where <name> 
    -m <meta=value>          can be a dotted path (see option example).

    --plugin <require>     Load a plugin, where <require> is the plugin module
    -p <require>             reference (name or path).

    --debug                Print abbreviated lex and parse logs for debugging,
    -d                       alias of \`--meta log = -1\`.

    --help                 Print this help message.
    -h

Output:
  Output is generated by the built-in JSON.stringify method. The \`replacer\`
    and \`space\` arguments can be specified using \`-o JSON.replacer=...\` and
    \`-o JSON.space=...\` respectively.


Plugins 
  The built-in plugins (found in the ./plugin folder of the distribution) can be 
  specified using the abbreviated references:
    directive, multisource, csv, toml, ...

  Plugin options can be specified using: \`-o plugin.<name>.<option>=<value>\`.
  See the example below.


Examples:

# Basic usage
> jsonic a:1
{"a":1} 

> jsonic -n a:1
{
  "a": 1
}


# Merging arguments
> jsonic a:b:1 a:c:2
{"a":{"b":1,"c":2}}


# Output options
> jsonic a:b:1 a:c:2 --option JSON.space=2
{
  "a": {
    "b": 1,
    "c": 2
  }
}


# Piping
> echo a:1 | jsonic
{"a":1} 


# Using plugins (e.g. npm install @jsonic/csv)
> jsonic -p csv  -o plugin.csv.record.separators=^ "a,b^1,2"
[{"a":"1","b":"2"}]


# Full debug tracing
> jsonic -d -o plugin.debug.trace=true a:1
... lots of debug info, including token-by-token trace ...
{"a":1}


See also: http://jsonic.senecajs.org
`;
    console.log(s);
}
//# sourceMappingURL=jsonic-cli.js.map

================================================
FILE: dist/jsonic.d.ts
================================================
import type { AltAction, AltCond, AltError, AltMatch, AltModifier, AltSpec, Bag, Config, Context, Counters, FuncRef, JsonicAPI, JsonicParse, Lex, LexCheck, LexMatcher, MakeLexMatcher, NormAltSpec, Options, Parser, Plugin, Point, Rule, RuleDefiner, RuleSpec, RuleSpecMap, RuleState, StateAction, Tin, Token } from './types';
import { OPEN, CLOSE, BEFORE, AFTER, EMPTY, SKIP } from './types';
import { S, badlex, deep, makelog, mesc, regexp, tokenize, srcfmt, clone, charset, configure, escre, parserwrap, str, clean } from './utility';
import { JsonicError, errdesc, errinject, errsite, errmsg, trimstk, strinject, prop } from './error';
import { makePoint, makeToken, makeLex, makeFixedMatcher, makeSpaceMatcher, makeLineMatcher, makeStringMatcher, makeCommentMatcher, makeNumberMatcher, makeTextMatcher } from './lexer';
import { makeRule, makeRuleSpec, makeParser } from './parser';
declare const util: {
    tokenize: typeof tokenize;
    srcfmt: typeof srcfmt;
    clone: typeof clone;
    charset: typeof charset;
    trimstk: typeof trimstk;
    makelog: typeof makelog;
    badlex: typeof badlex;
    errsite: typeof errsite;
    errinject: typeof errinject;
    errdesc: typeof errdesc;
    configure: typeof configure;
    parserwrap: typeof parserwrap;
    mesc: typeof mesc;
    escre: typeof escre;
    regexp: typeof regexp;
    prop: typeof prop;
    str: typeof str;
    clean: typeof clean;
    errmsg: typeof errmsg;
    strinject: typeof strinject;
    deep: typeof deep;
    omap: (o: any, f?: (e: any) => any) => any;
    keys: (x: any) => string[];
    values: <T>(x: {
        [key: string]: T;
    } | undefined | null) => T[];
    entries: <T>(x: {
        [key: string]: T;
    } | undefined | null) => [string, T][];
};
type Jsonic = JsonicParse & // A function that parses.
JsonicAPI & {
    [prop: string]: any;
};
declare function make(param_options?: Bag | string, parent?: Jsonic): Jsonic;
declare let root: any;
declare let Jsonic: Jsonic;
export type { AltAction, AltCond, AltError, AltMatch, AltModifier, AltSpec, Bag, Config, Context, Counters, FuncRef, Lex, LexCheck, LexMatcher, MakeLexMatcher, NormAltSpec, Options, Plugin, Point, Rule, RuleDefiner, RuleSpec, RuleSpecMap, RuleState, StateAction, Tin, Token, };
export { Jsonic as Jsonic, JsonicError, Parser, util, make, makeToken, makePoint, makeRule, makeRuleSpec, makeLex, makeParser, makeFixedMatcher, makeSpaceMatcher, makeLineMatcher, makeStringMatcher, makeCommentMatcher, makeNumberMatcher, makeTextMatcher, OPEN, CLOSE, BEFORE, AFTER, EMPTY, SKIP, S, root, };
export default Jsonic;


================================================
FILE: dist/jsonic.js
================================================
"use strict";
/* Copyright (c) 2013-2023 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.root = exports.S = exports.SKIP = exports.EMPTY = exports.AFTER = exports.BEFORE = exports.CLOSE = exports.OPEN = exports.makeTextMatcher = exports.makeNumberMatcher = exports.makeCommentMatcher = exports.makeStringMatcher = exports.makeLineMatcher = exports.makeSpaceMatcher = exports.makeFixedMatcher = exports.makeParser = exports.makeLex = exports.makeRuleSpec = exports.makeRule = exports.makePoint = exports.makeToken = exports.util = exports.JsonicError = exports.Jsonic = void 0;
exports.make = make;
const types_1 = require("./types");
Object.defineProperty(exports, "OPEN", { enumerable: true, get: function () { return types_1.OPEN; } });
Object.defineProperty(exports, "CLOSE", { enumerable: true, get: function () { return types_1.CLOSE; } });
Object.defineProperty(exports, "BEFORE", { enumerable: true, get: function () { return types_1.BEFORE; } });
Object.defineProperty(exports, "AFTER", { enumerable: true, get: function () { return types_1.AFTER; } });
Object.defineProperty(exports, "EMPTY", { enumerable: true, get: function () { return types_1.EMPTY; } });
Object.defineProperty(exports, "SKIP", { enumerable: true, get: function () { return types_1.SKIP; } });
const utility_1 = require("./utility");
Object.defineProperty(exports, "S", { enumerable: true, get: function () { return utility_1.S; } });
const error_1 = require("./error");
Object.defineProperty(exports, "JsonicError", { enumerable: true, get: function () { return error_1.JsonicError; } });
const defaults_1 = require("./defaults");
const lexer_1 = require("./lexer");
Object.defineProperty(exports, "makePoint", { enumerable: true, get: function () { return lexer_1.makePoint; } });
Object.defineProperty(exports, "makeToken", { enumerable: true, get: function () { return lexer_1.makeToken; } });
Object.defineProperty(exports, "makeLex", { enumerable: true, get: function () { return lexer_1.makeLex; } });
Object.defineProperty(exports, "makeFixedMatcher", { enumerable: true, get: function () { return lexer_1.makeFixedMatcher; } });
Object.defineProperty(exports, "makeSpaceMatcher", { enumerable: true, get: function () { return lexer_1.makeSpaceMatcher; } });
Object.defineProperty(exports, "makeLineMatcher", { enumerable: true, get: function () { return lexer_1.makeLineMatcher; } });
Object.defineProperty(exports, "makeStringMatcher", { enumerable: true, get: function () { return lexer_1.makeStringMatcher; } });
Object.defineProperty(exports, "makeCommentMatcher", { enumerable: true, get: function () { return lexer_1.makeCommentMatcher; } });
Object.defineProperty(exports, "makeNumberMatcher", { enumerable: true, get: function () { return lexer_1.makeNumberMatcher; } });
Object.defineProperty(exports, "makeTextMatcher", { enumerable: true, get: function () { return lexer_1.makeTextMatcher; } });
const parser_1 = require("./parser");
Object.defineProperty(exports, "makeRule", { enumerable: true, get: function () { return parser_1.makeRule; } });
Object.defineProperty(exports, "makeRuleSpec", { enumerable: true, get: function () { return parser_1.makeRuleSpec; } });
Object.defineProperty(exports, "makeParser", { enumerable: true, get: function () { return parser_1.makeParser; } });
const grammar_1 = require("./grammar");
const bnf_1 = require("./bnf");
// TODO: remove - too much for an API!
const util = {
    tokenize: utility_1.tokenize,
    srcfmt: utility_1.srcfmt,
    clone: utility_1.clone,
    charset: utility_1.charset,
    trimstk: error_1.trimstk,
    makelog: utility_1.makelog,
    badlex: utility_1.badlex,
    errsite: error_1.errsite,
    errinject: error_1.errinject,
    errdesc: error_1.errdesc,
    configure: utility_1.configure,
    parserwrap: utility_1.parserwrap,
    mesc: utility_1.mesc,
    escre: utility_1.escre,
    regexp: utility_1.regexp,
    prop: error_1.prop,
    str: utility_1.str,
    clean: utility_1.clean,
    errmsg: error_1.errmsg,
    strinject: error_1.strinject,
    // TODO: validated to include in util API:
    deep: utility_1.deep,
    omap: utility_1.omap,
    keys: utility_1.keys,
    values: utility_1.values,
    entries: utility_1.entries,
};
exports.util = util;
function make(param_options, parent) {
    let injectFullAPI = true;
    if ('jsonic' === param_options) {
        injectFullAPI = false;
    }
    else if ('json' === param_options) {
        return (0, grammar_1.makeJSON)(root);
    }
    param_options = 'string' === typeof param_options ? {} : param_options;
    let internal = {
        parser: null,
        config: null,
        plugins: [],
        sub: {
            lex: undefined,
            rule: undefined,
        },
        mark: Math.random(),
    };
    // Merge options.
    let merged_options = (0, utility_1.deep)({}, parent
        ? { ...parent.options }
        : false === param_options?.defaults$
            ? {}
            : defaults_1.defaults, param_options ? param_options : {});
    // Create primary parsing function
    let jsonic = function Jsonic(src, meta, parent_ctx) {
        if (utility_1.S.string === typeof src) {
            let internal = jsonic.internal();
            let parser = optionsMethod.parser?.start
                ? (0, utility_1.parserwrap)(optionsMethod.parser)
                : internal.parser;
            return parser.start(src, jsonic, meta, parent_ctx);
        }
        return src;
    };
    // This lets you access options as direct properties,
    // and set them as a function call.
    // `change_options` can be a Bag object or a jsonic-format string that
    // is parsed into a Bag before applying.
    let optionsMethod = (change_options) => {
        if (null != change_options) {
            if (utility_1.S.string === typeof change_options) {
                const parsed = make()(change_options);
                change_options =
                    null != parsed && utility_1.S.object === typeof parsed
                        ? parsed
                        : undefined;
            }
            if (null != change_options && utility_1.S.object === typeof change_options) {
                (0, utility_1.deep)(merged_options, change_options);
                (0, utility_1.configure)(jsonic, internal.config, merged_options);
                let parser = jsonic.internal().parser;
                internal.parser = parser.clone(merged_options, internal.config, jsonic);
            }
        }
        return { ...jsonic.options };
    };
    // Define the API
    let api = {
        token: ((ref) => internal.config.fixed.token[ref] ??
            (0, utility_1.tokenize)(ref, internal.config, jsonic)),
        tokenSet: ((ref) => (0, utility_1.findTokenSet)(ref, internal.config)),
        fixed: ((ref) => internal.config.fixed.ref[ref]),
        options: (0, utility_1.deep)(optionsMethod, merged_options),
        config: () => (0, utility_1.deep)(internal.config),
        parse: jsonic,
        // TODO: how to handle null plugin?
        use: function use(plugin, plugin_options) {
            if (utility_1.S.function !== typeof plugin) {
                throw new Error('Jsonic.use: the first argument must be a function ' +
                    'defining a plugin. See https://jsonic.senecajs.org/plugin');
            }
            // Plugin name keys in options.plugin are the lower-cased plugin function name.
            const plugin_name = plugin.name.toLowerCase();
            const full_plugin_options = (0, utility_1.deep)({}, plugin.defaults || {}, plugin_options || {});
            jsonic.options({
                plugin: {
                    [plugin_name]: full_plugin_options,
                },
            });
            let merged_plugin_options = jsonic.options.plugin[plugin_name];
            jsonic.internal().plugins.push(plugin);
            plugin.options = merged_plugin_options;
            return plugin(jsonic, merged_plugin_options) || jsonic;
        },
        rule: (name, define) => {
            return jsonic.internal().parser.rule(name, define) || jsonic;
        },
        make: (options) => {
            return make(options, jsonic);
        },
        empty: (options) => make({
            defaults$: false,
            standard$: false,
            grammar$: false,
            ...(options || {}),
        }),
        id: 'Jsonic/' +
            Date.now() +
            '/' +
            ('' + Math.random()).substring(2, 8).padEnd(6, '0') +
            (null == optionsMethod.tag ? '' : '/' + optionsMethod.tag),
        toString: () => {
            return api.id;
        },
        sub: (spec) => {
            if (spec.lex) {
                internal.sub.lex = internal.sub.lex || [];
                internal.sub.lex.push(spec.lex);
            }
            if (spec.rule) {
                internal.sub.rule = internal.sub.rule || [];
                internal.sub.rule.push(spec.rule);
            }
            return jsonic;
        },
        util,
        grammar: (gs, setting) => {
            if ('string' === typeof gs) {
                const parsed = make()(gs);
                if (null == parsed || 'object' !== typeof parsed) {
                    return;
                }
                gs = parsed;
            }
            // Normalize the optional setting's rule.alt.g value to a string[] once.
            const altG = setting?.rule?.alt?.g;
            const altGArr = null == altG
                ? null
                : Array.isArray(altG)
                    ? [...altG]
                    : String(altG).split(/\s*,\s*/).filter((s) => s.length > 0);
            // Append altGArr tags to each alt's g field without mutating the input alt.
            const applyG = (alts) => {
                if (null == altGArr || 0 === altGArr.length || !Array.isArray(alts)) {
                    return alts;
                }
                return alts.map((a) => {
                    if (null == a || 'object' !== typeof a)
                        return a;
                    const existing = null == a.g
                        ? []
                        : Array.isArray(a.g)
                            ? [...a.g]
                            : String(a.g).split(/\s*,\s*/).filter((s) => s.length > 0);
                    return { ...a, g: [...existing, ...altGArr] };
                });
            };
            if (gs.options) {
                const resolved = (0, utility_1.resolveFuncRefs)(gs.options, gs.ref);
                ji.options(resolved);
            }
            if (gs.rule) {
                for (const rulename of Object.keys(gs.rule)) {
                    const rulespec = gs.rule[rulename];
                    ji.rule(rulename, (rs) => {
                        if (gs.ref) {
                            rs.fnref(gs.ref);
                        }
                        if (rulespec.open) {
                            const isarr = Array.isArray(rulespec.open);
                            const alts = isarr ? rulespec.open : rulespec.open.alts;
                            const inject = isarr ? {} : rulespec.open.inject;
                            rs.open(applyG(alts), inject);
                        }
                        if (rulespec.close) {
                            const isarr = Array.isArray(rulespec.close);
                            const alts = isarr ? rulespec.close : rulespec.close.alts;
                            const inject = isarr ? {} : rulespec.close.inject;
                            rs.close(applyG(alts), inject);
                        }
                    });
                }
            }
        },
        // Convert a BNF grammar string into a jsonic GrammarSpec and install
        // it on this instance. Returns the generated spec so callers can
        // inspect, serialise or diff it. Use `bnf.toSpec(src, opts)` to
        // build the spec without installing it.
        bnf: (() => {
            const impl = (src, opts) => {
                const spec = (0, bnf_1.bnf)(src, opts);
                ji.grammar(spec);
                return spec;
            };
            impl.toSpec = (src, opts) => (0, bnf_1.bnf)(src, opts);
            return impl;
        })(),
    };
    // Has to be done indirectly as we are in a fuction named `make`.
    (0, utility_1.defprop)(api.make, utility_1.S.name, { value: utility_1.S.make });
    let ji = jsonic;
    if (injectFullAPI) {
        // Add API methods to the core utility function.
        (0, utility_1.assign)(jsonic, api);
    }
    else {
        (0, utility_1.assign)(jsonic, {
            empty: api.empty,
            parse: api.parse,
            sub: api.sub,
            id: api.id,
            toString: api.toString,
        });
        ji = (0, utility_1.assign)(Object.create(jsonic), api);
    }
    // Hide internals where you can still find them.
    (0, utility_1.defprop)(jsonic, 'internal', { value: () => internal });
    if (parent) {
        // Transfer extra parent properties (preserves plugin decorations, etc).
        for (let k in parent) {
            if (undefined === jsonic[k]) {
                jsonic[k] = parent[k];
            }
        }
        jsonic.parent = parent;
        let parent_internal = parent.internal();
        internal.config = (0, utility_1.deep)({}, parent_internal.config);
        (0, utility_1.configure)(jsonic, internal.config, merged_options);
        (0, utility_1.assign)(jsonic.token, internal.config.t);
        internal.plugins = [...parent_internal.plugins];
        internal.parser = parent_internal.parser.clone(merged_options, internal.config, ji);
    }
    else {
        let rootWithAPI = { ...jsonic, ...api };
        internal.config = (0, utility_1.configure)(rootWithAPI, undefined, merged_options);
        internal.plugins = [];
        internal.parser = (0, parser_1.makeParser)(merged_options, internal.config, ji);
        if (false !== merged_options.grammar$) {
            (0, grammar_1.grammar)(rootWithAPI);
        }
    }
    return jsonic;
}
let root = undefined;
exports.root = root;
// The global root Jsonic instance parsing rules cannot be modified.
// use Jsonic.make() to create a modifiable instance.
let Jsonic = (exports.root = root = make('jsonic'));
exports.Jsonic = Jsonic;
// Provide deconstruction export names
root.Jsonic = root;
root.JsonicError = error_1.JsonicError;
root.makeLex = lexer_1.makeLex;
root.makeParser = parser_1.makeParser;
root.makeToken = lexer_1.makeToken;
root.makePoint = lexer_1.makePoint;
root.makeRule = parser_1.makeRule;
root.makeRuleSpec = parser_1.makeRuleSpec;
root.makeFixedMatcher = lexer_1.makeFixedMatcher;
root.makeSpaceMatcher = lexer_1.makeSpaceMatcher;
root.makeLineMatcher = lexer_1.makeLineMatcher;
root.makeStringMatcher = lexer_1.makeStringMatcher;
root.makeCommentMatcher = lexer_1.makeCommentMatcher;
root.makeNumberMatcher = lexer_1.makeNumberMatcher;
root.makeTextMatcher = lexer_1.makeTextMatcher;
root.OPEN = types_1.OPEN;
root.CLOSE = types_1.CLOSE;
root.BEFORE = types_1.BEFORE;
root.AFTER = types_1.AFTER;
root.EMPTY = types_1.EMPTY;
root.SKIP = types_1.SKIP;
root.util = util;
root.make = make;
root.S = utility_1.S;
exports.default = Jsonic;
if ('undefined' !== typeof module) {
    module.exports = Jsonic;
}
//# sourceMappingURL=jsonic.js.map

================================================
FILE: dist/lexer.d.ts
================================================
import type { Tin, Token, Point, Lex, Rule, Config, Context, MakeLexMatcher, Bag, NormAltSpec } from './types';
import { INSPECT } from './types';
declare class PointImpl implements Point {
    len: number;
    sI: number;
    rI: number;
    cI: number;
    token: Token[];
    end?: Token;
    constructor(len: number, sI?: number, rI?: number, cI?: number);
    toString(): string;
    [INSPECT](): string;
}
declare const makePoint: (...params: ConstructorParameters<typeof PointImpl>) => PointImpl;
declare class TokenImpl implements Token {
    isToken: boolean;
    name: string;
    tin: number;
    val: undefined;
    src: string;
    sI: number;
    rI: number;
    cI: number;
    len: number;
    use?: Bag;
    err?: string;
    why?: string;
    constructor(name: string, tin: Tin, val: any, src: string, pnt: Point, use?: any, why?: string);
    resolveVal(rule: Rule, ctx: Context): any;
    bad(err: string, details?: any): Token;
    toString(): string;
    [INSPECT](): string;
}
declare const makeToken: (...params: ConstructorParameters<typeof TokenImpl>) => TokenImpl;
declare const makeNoToken: () => TokenImpl;
declare let makeFixedMatcher: MakeLexMatcher;
declare let makeMatchMatcher: MakeLexMatcher;
declare let makeCommentMatcher: MakeLexMatcher;
declare let makeTextMatcher: MakeLexMatcher;
declare let makeNumberMatcher: MakeLexMatcher;
declare let makeStringMatcher: MakeLexMatcher;
declare let makeLineMatcher: MakeLexMatcher;
declare let makeSpaceMatcher: MakeLexMatcher;
declare class LexImpl implements Lex {
    src: string;
    ctx: Context;
    cfg: Config;
    pnt: PointImpl;
    fwd: string;
    refwd(): string;
    constructor(ctx: Context);
    token(ref: Tin | string, val: any, src: string, pnt?: Point, use?: any, why?: string): Token;
    next(rule: Rule, alt?: NormAltSpec, altI?: number, tI?: number): Token;
    tokenize<R extends string | Tin, T extends R extends Tin ? string : Tin>(ref: R): T;
    bad(why: string, pstart: number, pend: number): Token;
}
declare const makeLex: (...params: ConstructorParameters<typeof LexImpl>) => LexImpl;
export { makeNoToken, makeLex, makePoint, makeToken, makeMatchMatcher, makeFixedMatcher, makeSpaceMatcher, makeLineMatcher, makeStringMatcher, makeCommentMatcher, makeNumberMatcher, makeTextMatcher, };


================================================
FILE: dist/lexer.js
================================================
"use strict";
/* Copyright (c) 2013-2022 Richard Rodger, MIT License */
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeTextMatcher = exports.makeNumberMatcher = exports.makeCommentMatcher = exports.makeStringMatcher = exports.makeLineMatcher = exports.makeSpaceMatcher = exports.makeFixedMatcher = exports.makeMatchMatcher = exports.makeToken = exports.makePoint = exports.makeLex = exports.makeNoToken = void 0;
const types_1 = require("./types");
const utility_1 = require("./utility");
class PointImpl {
    constructor(len, sI, rI, cI) {
        this.len = -1;
        this.sI = 0;
        this.rI = 1;
        this.cI = 1;
        this.token = [];
        this.len = len;
        if (null != sI) {
            this.sI = sI;
        }
        if (null != rI) {
            this.rI = rI;
        }
        if (null != cI) {
            this.cI = cI;
        }
    }
    toString() {
        return ('Point[' +
            [this.sI + '/' + this.len, this.rI, this.cI] +
            (0 < this.token.length ? ' ' + this.token : '') +
            ']');
    }
    [types_1.INSPECT]() {
        return this.toString();
    }
}
const makePoint = (...params) => new PointImpl(...params);
exports.makePoint = makePoint;
// Tokens from the lexer.
class TokenImpl {
    constructor(name, tin, val, src, pnt, use, why) {
        this.isToken = true;
        this.name = types_1.EMPTY;
        this.tin = -1;
        this.val = undefined;
        this.src = types_1.EMPTY;
        this.sI = -1;
        this.rI = -1;
        this.cI = -1;
        this.len = -1;
        this.name = name;
        this.tin = tin;
        this.src = src;
        this.val = val;
        this.sI = pnt.sI;
        this.rI = pnt.rI;
        this.cI = pnt.cI;
        this.use = use;
        this.why = why;
        this.len = null == src ? 0 : src.length;
    }
    resolveVal(rule, ctx) {
        let out = 'function' === typeof this.val ? this.val(rule, ctx) : this.val;
        return out;
    }
    bad(err, details) {
        this.err = err;
        if (null != details) {
            this.use = (0, utility_1.deep)(this.use || {}, details);
        }
        return this;
    }
    toString() {
        return ('Token[' +
            this.name +
            '=' +
            this.tin +
            ' ' +
            (0, utility_1.snip)(this.src) +
            (undefined === this.val || '#ST' === this.name || '#TX' === this.name
                ? ''
                : '=' + (0, utility_1.snip)(this.val)) +
            ' ' +
            [this.sI, this.rI, this.cI] +
            (null == this.use
                ? ''
                : ' ' + (0, utility_1.snip)('' + JSON.stringify(this.use).replace(/"/g, ''), 22)) +
            (null == this.err ? '' : ' ' + this.err) +
            (null == this.why ? '' : ' ' + (0, utility_1.snip)('' + this.why, 22)) +
            ']');
    }
    [types_1.INSPECT]() {
        return this.toString();
    }
}
const makeToken = (...params) => new TokenImpl(...params);
exports.makeToken = makeToken;
const makeNoToken = () => makeToken('', -1, undefined, types_1.EMPTY, makePoint(-1));
exports.makeNoToken = makeNoToken;
let makeFixedMatcher = (cfg, _opts) => {
    let fixed = (0, utility_1.regexp)(null, '^(', cfg.rePart.fixed, ')');
    return function fixedMatcher(lex) {
        let mcfg = cfg.fixed;
        if (!mcfg.lex)
            return undefined;
        if (cfg.fixed.check) {
            let check = cfg.fixed.check(lex);
            if (check && check.done) {
                return check.token;
            }
        }
        let pnt = lex.pnt;
        let fwd = lex.fwd;
        let m = fwd.match(fixed);
        if (m) {
            let msrc = m[1];
            let mlen = msrc.length;
            if (0 < mlen) {
                let tkn = undefined;
                let tin = mcfg.token[msrc];
                if (null != tin) {
                    tkn = lex.token(tin, undefined, msrc, pnt);
                    pnt.sI += mlen;
                    pnt.cI += mlen;
                }
                return tkn;
            }
        }
    };
};
exports.makeFixedMatcher = makeFixedMatcher;
let makeMatchMatcher = (cfg, _opts) => {
    // Pre-sort both matcher lists at configure time so lexing iterates in
    // a deterministic order regardless of how the config object was built.
    // Value matchers: sort by user-supplied name (ascending).
    // Token matchers: sort by attached tin$ (ascending), set in utility.ts.
    let valueMatchers = (0, utility_1.entries)(cfg.match.value)
        .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
        .map(([, spec]) => spec);
    let tokenMatchers = (0, utility_1.values)(cfg.match.token).sort((a, b) => (a.tin$ || 0) - (b.tin$ || 0));
    // Don't add a matcher if there's nothing to do.
    if (0 === valueMatchers.length && 0 === tokenMatchers.length) {
        return null;
    }
    return function matchMatcher(lex, rule, tI = 0) {
        let mcfg = cfg.match;
        if (!mcfg.lex)
            return undefined;
        if (cfg.match.check) {
            let check = cfg.match.check(lex);
            if (check && check.done) {
                return check.token;
            }
        }
        let pnt = lex.pnt;
        let fwd = lex.fwd;
        let oc = 'o' === rule.state ? 0 : 1;
        for (let valueMatcher of valueMatchers) {
            if (valueMatcher.match instanceof RegExp) {
                // TODO: only match VL if present in rule
                let m = fwd.match(valueMatcher.match);
                if (m) {
                    let msrc = m[0];
                    let mlen = msrc.length;
                    if (0 < mlen) {
                        let tkn = undefined;
Download .txt
gitextract_o0u0amii/

├── .github/
│   └── workflows/
│       └── build.yml
├── .gitignore
├── CNAME
├── LICENSE
├── Makefile
├── README.md
├── TODO.md
├── bin/
│   ├── jsonic
│   └── jsonic-bnf
├── dist/
│   ├── bnf.d.ts
│   ├── bnf.js
│   ├── debug.d.ts
│   ├── debug.js
│   ├── defaults.d.ts
│   ├── defaults.js
│   ├── error.d.ts
│   ├── error.js
│   ├── grammar.d.ts
│   ├── grammar.js
│   ├── jsonic-bnf-cli.d.ts
│   ├── jsonic-bnf-cli.js
│   ├── jsonic-cli.d.ts
│   ├── jsonic-cli.js
│   ├── jsonic.d.ts
│   ├── jsonic.js
│   ├── lexer.d.ts
│   ├── lexer.js
│   ├── parser.d.ts
│   ├── parser.js
│   ├── rules.d.ts
│   ├── rules.js
│   ├── self.d.ts
│   ├── self.js
│   ├── tsconfig.tsbuildinfo
│   ├── types.d.ts
│   ├── types.js
│   ├── utility.d.ts
│   └── utility.js
├── dist-test/
│   ├── prep.js
│   └── tsconfig.tsbuildinfo
├── doc/
│   ├── api.md
│   ├── bnf-to-jsonic-feasibility.md
│   ├── lsp-feasibility.md
│   ├── options.md
│   ├── plugins.md
│   └── syntax.md
├── docs/
│   ├── 404.html
│   ├── CNAME
│   ├── assets/
│   │   ├── css/
│   │   │   └── 0.styles.610e9dca.css
│   │   └── js/
│   │       ├── 10.88d9a57b.js
│   │       ├── 11.7988a5fa.js
│   │       ├── 12.d9f3d941.js
│   │       ├── 13.775f91ca.js
│   │       ├── 14.f56c2700.js
│   │       ├── 15.00058088.js
│   │       ├── 16.70a6eea0.js
│   │       ├── 17.0d1f36b1.js
│   │       ├── 18.0f184e32.js
│   │       ├── 19.57ad231b.js
│   │       ├── 2.34930047.js
│   │       ├── 20.58c8b075.js
│   │       ├── 21.0c46ffa9.js
│   │       ├── 22.965cbc0d.js
│   │       ├── 23.18c270f0.js
│   │       ├── 24.5895d76a.js
│   │       ├── 25.a347f1d6.js
│   │       ├── 26.c7b8345d.js
│   │       ├── 27.4e6f90b7.js
│   │       ├── 28.6e0fa7bc.js
│   │       ├── 29.77b8e3b6.js
│   │       ├── 3.6ce1235a.js
│   │       ├── 30.69b1b865.js
│   │       ├── 31.c68f976d.js
│   │       ├── 32.0a08a140.js
│   │       ├── 4.064b2ac3.js
│   │       ├── 5.46815478.js
│   │       ├── 6.f03d59ff.js
│   │       ├── 7.6be3acca.js
│   │       ├── 8.0a081a71.js
│   │       ├── 9.9b6e31d5.js
│   │       └── app.0c621e62.js
│   ├── guide/
│   │   ├── alternatives.html
│   │   ├── custom-parsers.html
│   │   ├── getting-started.html
│   │   ├── index.html
│   │   ├── install.html
│   │   ├── syntax-introduction.html
│   │   └── tutorials.html
│   ├── index.html
│   ├── jsonic.js
│   ├── plugin/
│   │   ├── csv.html
│   │   ├── dynamic.html
│   │   ├── hoover.html
│   │   ├── index.html
│   │   ├── json.html
│   │   ├── multifile.html
│   │   └── native.html
│   ├── railroad-diagrams.css
│   ├── ref/
│   │   ├── api.html
│   │   ├── index.html
│   │   ├── options.html
│   │   └── syntax.html
│   └── tutorial/
│       ├── index.html
│       ├── parsing-csv.html
│       ├── write-a-parser.html
│       └── write-a-plugin.html
├── go/
│   ├── README.md
│   ├── alignment_test.go
│   ├── both_ref_test.go
│   ├── color_test.go
│   ├── comment_suffix_test.go
│   ├── coverage.html
│   ├── csv_grammar_test.go
│   ├── debug.go
│   ├── directive_grammar_test.go
│   ├── doc/
│   │   ├── api.md
│   │   ├── differences.md
│   │   ├── options.md
│   │   ├── plugins.md
│   │   └── syntax.md
│   ├── feature_tsv_test.go
│   ├── fnref_identity_test.go
│   ├── fnref_reinstall_test.go
│   ├── go.mod
│   ├── grammar.go
│   ├── grammar_decl_test.go
│   ├── grammar_setting_test.go
│   ├── grammarspec.go
│   ├── jsonic.go
│   ├── jsonic_nontsv_test.go
│   ├── jsonic_test.go
│   ├── lexer.go
│   ├── listchild_test.go
│   ├── listref_test.go
│   ├── mapref_test.go
│   ├── nlookahead_test.go
│   ├── options.go
│   ├── options_parity_test.go
│   ├── parser.go
│   ├── plugin.go
│   ├── plugin_test.go
│   ├── readme_test.go
│   ├── rule.go
│   ├── rule_include_test.go
│   ├── safe_test.go
│   ├── text.go
│   ├── textinfo_test.go
│   ├── token.go
│   ├── token_test.go
│   ├── util.go
│   ├── util_test.go
│   ├── utility.go
│   └── variant_test.go
├── package.json
├── src/
│   ├── bnf.ts
│   ├── debug.ts
│   ├── defaults.ts
│   ├── error.ts
│   ├── grammar.ts
│   ├── jsonic-bnf-cli.ts
│   ├── jsonic-cli.ts
│   ├── jsonic.ts
│   ├── lexer.ts
│   ├── mfix.js
│   ├── parser.ts
│   ├── rules.ts
│   ├── self.ts
│   ├── tsconfig.json
│   ├── types.ts
│   └── utility.ts
└── test/
    ├── aa-wildcard.test.js
    ├── alignment.test.js
    ├── also-bad-plugin.js
    ├── angle.js
    ├── api.test.js
    ├── bad-plugin.js
    ├── bar.jsonic
    ├── bnf.test.js
    ├── cli.test.js
    ├── comma.test.js
    ├── comment.test.js
    ├── csv-grammar.test.js
    ├── custom.test.js
    ├── debug.test.js
    ├── directive-grammar.test.js
    ├── dive.js
    ├── doc.test.js
    ├── error.test.js
    ├── exhaust.js
    ├── feature.test.js
    ├── first-version-perf.js
    ├── first-version.test.js
    ├── foo.jsonic
    ├── grammar/
    │   ├── arith-leftrec.bnf
    │   ├── arith.bnf
    │   ├── greet.bnf
    │   ├── json-subset.bnf
    │   ├── pair.bnf
    │   └── rfc3986-uri.abnf
    ├── grammar.test.js
    ├── happy.js
    ├── json-standard.js
    ├── jsonic.test.js
    ├── justjson.js
    ├── large.js
    ├── lex.test.js
    ├── long.js
    ├── module.mjs
    ├── multifile-remove/
    │   ├── again.jsonic
    │   ├── blue01.js
    │   ├── func.js
    │   ├── green01.json
    │   ├── main01.jsonic
    │   └── trunk/
    │       ├── branch.jsonic
    │       └── twig/
    │           └── leaf1.jsonic
    ├── nlookahead.test.js
    ├── p0.js
    ├── p1.js
    ├── p2.js
    ├── pa-qa.js
    ├── perf.js
    ├── plugin-default.js
    ├── plugin-name.js
    ├── plugin.test.js
    ├── plugins-parity.sh
    ├── prep.ts
    ├── probe.test.js
    ├── quick.js
    ├── readme.test.js
    ├── require.js
    ├── rewind.test.js
    ├── rfc3986.test.js
    ├── safe.test.js
    ├── smoke.js
    ├── spec/
    │   ├── alignment-empty.tsv
    │   ├── alignment-errors.tsv
    │   ├── alignment-map-merge.tsv
    │   ├── alignment-number-text.tsv
    │   ├── alignment-safe-key.tsv
    │   ├── alignment-structure.tsv
    │   ├── alignment-values.tsv
    │   ├── comma-implicit-comma.tsv
    │   ├── comma-optional-comma.tsv
    │   ├── exclude-comma-errors.tsv
    │   ├── exclude-comma.tsv
    │   ├── exclude-strict-json-errors.tsv
    │   ├── exclude-strict-json.tsv
    │   ├── feature-comment-suffix-block.tsv
    │   ├── feature-comment-suffix-line.tsv
    │   ├── feature-debug-cases.tsv
    │   ├── feature-implicit-map.tsv
    │   ├── feature-implicit-object.tsv
    │   ├── feature-list-child-deep.tsv
    │   ├── feature-list-child-pair-deep.tsv
    │   ├── feature-list-child-pair.tsv
    │   ├── feature-list-child.tsv
    │   ├── feature-list-pair.tsv
    │   ├── feature-map-child-deep.tsv
    │   ├── feature-map-child.tsv
    │   ├── feature-nested-space-pairs.tsv
    │   ├── fv-arrays.tsv
    │   ├── fv-comma.tsv
    │   ├── fv-deep.tsv
    │   ├── fv-drop-outs.tsv
    │   ├── fv-numbers.tsv
    │   ├── fv-subobj.tsv
    │   ├── fv-types.tsv
    │   ├── fv-works.tsv
    │   ├── happy.tsv
    │   ├── include-json-errors.tsv
    │   ├── include-json.tsv
    │   ├── jsonic-basic-array-tree.tsv
    │   ├── jsonic-basic-json.tsv
    │   ├── jsonic-basic-mixed-tree.tsv
    │   ├── jsonic-basic-object-tree.tsv
    │   ├── jsonic-funky-keys.tsv
    │   ├── jsonic-process-array.tsv
    │   ├── jsonic-process-implicit-object.tsv
    │   ├── jsonic-process-mixed-nodes.tsv
    │   ├── jsonic-process-object-tree.tsv
    │   ├── jsonic-process-scalars.tsv
    │   ├── jsonic-process-text.tsv
    │   ├── jsonic-process-whitespace.tsv
    │   ├── lex-errors.tsv
    │   ├── utility-deep.tsv
    │   ├── utility-modlist.tsv
    │   ├── utility-str.tsv
    │   └── utility-strinject.tsv
    ├── spec.test.js
    ├── syntax-error.js
    ├── test-plugins.sh
    ├── tsconfig.json
    ├── utility.js
    ├── utility.test.js
    ├── variant.test.js
    └── web-all.js
Download .txt
SYMBOL INDEX (1894 symbols across 101 files)

FILE: dist-test/prep.js
  function prep (line 5) | function prep() { return null; }

FILE: dist/bnf.d.ts
  type BnfElement (line 2) | type BnfElement = {
  type BnfSequence (line 31) | type BnfSequence = BnfElement[];
  type BnfProduction (line 32) | type BnfProduction = {
  type ProbeDispatchSpec (line 42) | type ProbeDispatchSpec = {
  type BnfGrammar (line 48) | type BnfGrammar = {
  type AmbiguityReport (line 52) | type AmbiguityReport = {
  class BnfParseError (line 66) | class BnfParseError extends Error {

FILE: dist/bnf.js
  function getBnfParser (line 350) | function getBnfParser() {
  function eliminateLeftRecursion (line 460) | function eliminateLeftRecursion(grammar) {
  function findLeadingRefCycleMembers (line 511) | function findLeadingRefCycleMembers(prods) {
  function topoOrderForPaull (line 576) | function topoOrderForPaull(prods) {
  function substituteLeadingRef (line 606) | function substituteLeadingRef(target, source) {
  function eliminateDirectLeftRec (line 626) | function eliminateDirectLeftRec(prod) {
  function desugar (line 666) | function desugar(grammar) {
  class BnfParseError (line 793) | class BnfParseError extends Error {
    method constructor (line 794) | constructor(message, location, cause) {
  function parseBnf (line 804) | function parseBnf(src) {
  constant CORE_RULES_ABNF (line 830) | const CORE_RULES_ABNF = `
  function getCoreRules (line 848) | function getCoreRules() {
  function refsIn (line 861) | function refsIn(alt, out) {
  function withCoreRules (line 879) | function withCoreRules(user) {
  function mergeIncrementals (line 912) | function mergeIncrementals(prods) {
  function isProbeableOpt (line 969) | function isProbeableOpt(el) {
  function collectTerminalVocabElements (line 989) | function collectTerminalVocabElements(el, grammar, out, visited) {
  function collectSeqVocabElements (line 1026) | function collectSeqVocabElements(seq, grammar) {
  function mapsOverlap (line 1033) | function mapsOverlap(a, b) {
  function rewriteProbeDispatches (line 1045) | function rewriteProbeDispatches(grammar) {
  function emitProbeHelper (line 1175) | function emitProbeHelper(prod, tag, ruleSpec, literals, regexTokens) {
  function emitProbeDispatch (line 1193) | function emitProbeDispatch(prod, tag, ruleSpec, refs, literals, regexTok...
  function emitGrammarSpec (line 1256) | function emitGrammarSpec(grammar, opts) {
  function segmentize (line 1399) | function segmentize(alt, literals, regexTokens) {
  function regexKey (line 1426) | function regexKey(el) {
  function isSingleSegment (line 1429) | function isSingleSegment(alt) {
  function validateRefs (line 1448) | function validateRefs(alt, knownRules, ruleName) {
  class RefRegistry (line 1459) | class RefRegistry {
    method constructor (line 1460) | constructor() {
    method register (line 1464) | register(fn) {
    method map (line 1469) | get map() {
  function mkAstNode (line 1473) | function mkAstNode(ruleName, nodeKind) {
  function segmentToAlt (line 1478) | function segmentToAlt(seg, tag, refs, initNode, ruleName, nodeKind) {
  function captureChildRef (line 1505) | function captureChildRef(refs, ruleName, nodeKind) {
  function emitProduction (line 1530) | function emitProduction(prod, grammar, literals, regexTokens, knownRules...
  function emitChain (line 1690) | function emitChain(headName, alt, literals, regexTokens, tag, ruleSpec, ...
  function computeFirstSets (line 1723) | function computeFirstSets(grammar, literals, regexTokens) {
  function firstOfAlt (line 1778) | function firstOfAlt(alt, literals, regexTokens, firstSets, nullable) {
  function ruleLiteralPrefix (line 1809) | function ruleLiteralPrefix(name, grammar, literals, regexTokens, visited) {
  function altLiteralPrefix (line 1831) | function altLiteralPrefix(alt, grammar, literals, regexTokens, visited) {
  function altPrefixesRaw (line 1862) | function altPrefixesRaw(alt, grammar, literals, regexTokens, maxK, visit...
  function altPrefixes (line 1918) | function altPrefixes(alt, grammar, literals, regexTokens, maxK) {
  function isEffectivelyCaseSensitive (line 1935) | function isEffectivelyCaseSensitive(el) {
  function termKey (line 1944) | function termKey(el) {
  function escapeRegExp (line 1947) | function escapeRegExp(s) {
  function parseNumericValue (line 1960) | function parseNumericValue(src) {
  function allocTokenName (line 1982) | function allocTokenName(literal, used) {
  function bnf (line 2000) | function bnf(src, opts) {

FILE: dist/debug.js
  constant DEFAULTS (line 6) | const DEFAULTS = {
  function descAlt (line 118) | function descAlt(jsonic, rs, kind) {
  function ruleTree (line 163) | function ruleTree(jsonic, rn, rsm) {
  function ruleTreeStep (line 181) | function ruleTreeStep(rsm, name, state, step) {
  function descTokenState (line 189) | function descTokenState(ctx) {
  function descParseState (line 198) | function descParseState(ctx, rule, lex) {
  function descRuleState (line 205) | function descRuleState(ctx, rule) {
  function descAltSeq (line 225) | function descAltSeq(alt, cfg) {
  constant LOG (line 236) | const LOG = {
  constant LOGKIND (line 242) | const LOGKIND = {

FILE: dist/error.d.ts
  class JsonicError (line 2) | class JsonicError extends SyntaxError {

FILE: dist/error.js
  class JsonicError (line 25) | class JsonicError extends SyntaxError {
    method constructor (line 26) | constructor(code, details, token, rule, ctx) {
  function errinject (line 37) | function errinject(s, code, details, token, rule, ctx) {
  function trimstk (line 51) | function trimstk(err) {
  function errsite (line 61) | function errsite(spec) {
  function errmsg (line 105) | function errmsg(spec) {
  function errdesc (line 175) | function errdesc(code, details, token, rule, ctx) {
  function strinject (line 269) | function strinject(s, m, f) {
  function prop (line 311) | function prop(obj, path, val) {
  function str (line 343) | function str(o, len = 44) {
  function snip (line 353) | function snip(s, len = 5) {

FILE: dist/grammar.js
  function mark (line 7) | function mark(node, marker, data) {
  function grammar (line 12) | function grammar(jsonic) {
  function makeJSON (line 845) | function makeJSON(jsonic) {

FILE: dist/jsonic-bnf-cli.js
  function run (line 14) | async function run(argv, console) {
  function readStdin (line 109) | async function readStdin(console) {
  function help (line 121) | function help(console) {

FILE: dist/jsonic-cli.js
  function run (line 11) | async function run(argv, console) {
  function read_stdin (line 102) | async function read_stdin(console) {
  function handle_props (line 116) | function handle_props(propvals) {
  function handle_plugins (line 127) | function handle_plugins(plugins) {
  function camel (line 173) | function camel(s) {
  function help (line 179) | function help(console) {

FILE: dist/jsonic.d.ts
  type Jsonic (line 38) | type Jsonic = JsonicParse & // A function that parses.

FILE: dist/jsonic.js
  function make (line 65) | function make(param_options, parent) {

FILE: dist/lexer.d.ts
  class PointImpl (line 3) | class PointImpl implements Point {
  class TokenImpl (line 15) | class TokenImpl implements Token {
  class LexImpl (line 44) | class LexImpl implements Lex {

FILE: dist/lexer.js
  class PointImpl (line 7) | class PointImpl {
    method constructor (line 8) | constructor(len, sI, rI, cI) {
    method toString (line 25) | toString() {
  method [types_1.INSPECT] (line 31) | [types_1.INSPECT]() {
  class TokenImpl (line 38) | class TokenImpl {
    method constructor (line 39) | constructor(name, tin, val, src, pnt, use, why) {
    method resolveVal (line 60) | resolveVal(rule, ctx) {
    method bad (line 64) | bad(err, details) {
    method toString (line 71) | toString() {
  method [types_1.INSPECT] (line 90) | [types_1.INSPECT]() {
  function normalizeCommentSuffix (line 384) | function normalizeCommentSuffix(raw) {
  function commentSuffixMatch (line 413) | function commentSuffixMatch(fwd, fI, suffixes) {
  function commentSuffixFnMatch (line 426) | function commentSuffixFnMatch(lex, fI, fn) {
  function subMatchFixed (line 849) | function subMatchFixed(lex, first, tsrc) {
  class LexImpl (line 874) | class LexImpl {
    method refwd (line 875) | refwd() {
    method constructor (line 879) | constructor(ctx) {
    method token (line 890) | token(ref, val, src, pnt, use, why) {
    method next (line 904) | next(rule, alt, altI, tI) {
    method tokenize (line 947) | tokenize(ref) {
    method bad (line 950) | bad(why, pstart, pend) {

FILE: dist/parser.d.ts
  class ParserImpl (line 3) | class ParserImpl implements Parser {

FILE: dist/parser.js
  function defineLookaheadAliases (line 15) | function defineLookaheadAliases(ctx, notoken) {
  function attachRewind (line 76) | function attachRewind(ctx) {
  class ParserImpl (line 128) | class ParserImpl {
    method constructor (line 129) | constructor(options, cfg, j) {
    method rule (line 137) | rule(name, define) {
    method start (line 158) | start(src, jsonic, meta, parent_ctx) {
    method clone (line 258) | clone(options, config, j) {
    method norm (line 265) | norm() {

FILE: dist/rules.d.ts
  class RuleImpl (line 2) | class RuleImpl implements Rule {
  class RuleSpecImpl (line 49) | class RuleSpecImpl implements RuleSpec {

FILE: dist/rules.js
  class RuleImpl (line 8) | class RuleImpl {
    method constructor (line 9) | constructor(spec, ctx, node) {
    method o0 (line 45) | get o0() { return this.o[0] ?? this._NOTOKEN; }
    method o0 (line 46) | set o0(v) { this.o[0] = v; }
    method o1 (line 47) | get o1() { return this.o[1] ?? this._NOTOKEN; }
    method o1 (line 48) | set o1(v) { this.o[1] = v; }
    method c0 (line 49) | get c0() { return this.c[0] ?? this._NOTOKEN; }
    method c0 (line 50) | set c0(v) { this.c[0] = v; }
    method c1 (line 51) | get c1() { return this.c[1] ?? this._NOTOKEN; }
    method c1 (line 52) | set c1(v) { this.c[1] = v; }
    method os (line 53) | get os() { return this.oN; }
    method os (line 54) | set os(v) { this.oN = v; }
    method cs (line 55) | get cs() { return this.cN; }
    method cs (line 56) | set cs(v) { this.cN = v; }
    method process (line 57) | process(ctx, lex) {
    method eq (line 61) | eq(counter, limit = 0) {
    method lt (line 65) | lt(counter, limit = 0) {
    method gt (line 69) | gt(counter, limit = 0) {
    method lte (line 73) | lte(counter, limit = 0) {
    method gte (line 77) | gte(counter, limit = 0) {
    method toString (line 81) | toString() {
  class AltMatchImpl (line 90) | class AltMatchImpl {
    method constructor (line 91) | constructor() {
  constant PALT (line 98) | const PALT = makeAltMatch();
  constant EMPTY_ALT (line 99) | const EMPTY_ALT = makeAltMatch();
  class RuleSpecImpl (line 100) | class RuleSpecImpl {
    method constructor (line 101) | constructor(j, cfg, def) {
    method tin (line 136) | tin(ref) {
    method fnref (line 139) | fnref(frm) {
    method add (line 173) | add(rs, a, mods) {
    method open (line 186) | open(a, mods) {
    method close (line 189) | close(a, mods) {
    method action (line 192) | action(append, step, state, action) {
    method bo (line 202) | bo(append, action) {
    method ao (line 206) | ao(append, action) {
    method bc (line 210) | bc(append, action) {
    method ac (line 214) | ac(append, action) {
    method clear (line 218) | clear() {
    method norm (line 227) | norm() {
    method process (line 271) | process(rule, ctx, lex, state) {
    method bad (line 439) | bad(tkn, rule, ctx, parse) {
    method unknownRule (line 445) | unknownRule(tkn, name) {
  function parse_alts (line 456) | function parse_alts(is_open, alts, lex, rule, ctx) {
  constant GROUP_TAG_RE (line 589) | const GROUP_TAG_RE = /^[a-z][a-z0-9-]+$/;
  function normalt (line 591) | function normalt(a, rs, r) {
  function isfnref (line 754) | function isfnref(v) {
  function resolveFunctionRef (line 757) | function resolveFunctionRef(fkind, rs, r, a, k) {
  constant COND_OPS (line 768) | const COND_OPS = {
  function makeRuleCond (line 776) | function makeRuleCond(co, prop, val) {

FILE: dist/types.d.ts
  type JsonicParse (line 9) | type JsonicParse = (src: any, meta?: any, parent_ctx?: any) => any;
  type JsonicAPI (line 10) | interface JsonicAPI {
  type BnfConvertOptions (line 33) | type BnfConvertOptions = {
  type GrammarSetting (line 37) | type GrammarSetting = {
  type Jsonic (line 44) | type Jsonic = JsonicParse & // A function that parses.
  type Plugin (line 48) | type Plugin = ((jsonic: Jsonic, plugin_options?: any) => void | Jsonic) & {
  type Options (line 52) | type Options = {
  type RuleSpec (line 224) | interface RuleSpec {
  type Rule (line 254) | interface Rule {
  type Context (line 291) | type Context = {
  type Lex (line 328) | interface Lex {
  type NextToken (line 340) | type NextToken = (rule: Rule) => Token;
  type Config (line 341) | type Config = {
  type Point (line 505) | interface Point {
  type Token (line 513) | interface Token {
  type AltSpec (line 530) | interface AltSpec {
  type AltSpecish (line 544) | type AltSpecish = AltSpec | undefined | null | false | 0 | typeof NaN;
  type ListMods (line 545) | type ListMods = {
  type AltMatch (line 551) | interface AltMatch {
  type Bag (line 564) | type Bag = {
  type FuncRef (line 567) | type FuncRef = `@${string}`;
  type FuncRefMap (line 568) | type FuncRefMap<FT> = Record<FuncRef, FT>;
  type Counters (line 569) | type Counters = {
  type Tin (line 572) | type Tin = number;
  type TokenMap (line 573) | type TokenMap = {
  type TokenSetMap (line 576) | type TokenSetMap = {
  type TinMap (line 579) | type TinMap = {
  type TinSetMap (line 582) | type TinSetMap = {
  type MatchMap (line 585) | type MatchMap = {
  type Chars (line 588) | type Chars = {
  type StrMap (line 591) | type StrMap = {
  type RuleState (line 594) | type RuleState = 'o' | 'c';
  type RuleStep (line 595) | type RuleStep = 'b' | 'a';
  type LexMatcher (line 596) | type LexMatcher = (lex: Lex, rule: Rule, tI?: number) => Token | undefined;
  type MakeLexMatcher (line 597) | type MakeLexMatcher = (cfg: Config, opts: Options) => LexMatcher | null ...
  type LexCheck (line 598) | type LexCheck = (lex: Lex) => void | undefined | {
  type ParsePrepare (line 602) | type ParsePrepare = (jsonic: Jsonic, ctx: Context, meta?: any) => void;
  type RuleSpecMap (line 603) | type RuleSpecMap = {
  type RuleDefiner (line 606) | type RuleDefiner = (rs: RuleSpec, p: Parser) => void | RuleSpec;
  type NormAltSpec (line 607) | interface NormAltSpec extends AltSpec {
  type AltCond (line 620) | type AltCond = ((rule: Rule, ctx: Context, alt: AltMatch) => boolean) | ...
  type NormAltCond (line 621) | type NormAltCond = ((rule: Rule, ctx: Context, alt: AltMatch) => boolean);
  type AltModifier (line 622) | type AltModifier = (rule: Rule, ctx: Context, alt: AltMatch, next: Rule)...
  type AltAction (line 623) | type AltAction = (rule: Rule, ctx: Context, alt: AltMatch) => any;
  type AltNext (line 624) | type AltNext = (rule: Rule, ctx: Context, alt: AltMatch) => string | nul...
  type AltBack (line 625) | type AltBack = (rule: Rule, ctx: Context, alt: AltMatch) => number | nul...
  type StateAction (line 626) | type StateAction = (rule: Rule, ctx: Context, next: Rule, out?: Token | ...
  type AltError (line 627) | type AltError = (rule: Rule, ctx: Context, alt: AltMatch) => Token | und...
  type ValModifier (line 628) | type ValModifier = (val: any, lex: Lex, cfg: Config, opts: Options) => s...
  type LexSub (line 629) | type LexSub = (tkn: Token, rule: Rule, ctx: Context) => void;
  type RuleSub (line 630) | type RuleSub = (rule: Rule, ctx: Context) => void;
  type Parser (line 631) | interface Parser {
  type GrammarSpec (line 640) | type GrammarSpec = {
  type GrammarAltSpec (line 662) | type GrammarAltSpec = {

FILE: dist/utility.js
  function configure (line 111) | function configure(jsonic, incfg, opts) {
  function tokenize (line 381) | function tokenize(ref, cfg, jsonic) {
  function findTokenSet (line 396) | function findTokenSet(ref, cfg) {
  function mesc (line 403) | function mesc(s, _) {
  function regexp (line 408) | function regexp(flags, ...parts) {
  function escre (line 416) | function escre(s) {
  function deep (line 429) | function deep(base, ...rest) {
  function badlex (line 463) | function badlex(lex, BD, ctx) {
  function makelog (line 481) | function makelog(ctx, meta) {
  function srcfmt (line 511) | function srcfmt(config) {
  function str (line 532) | function str(o, len = 44) {
  function snip (line 542) | function snip(s, len = 5) {
  function clone (line 547) | function clone(class_instance) {
  function charset (line 551) | function charset(...parts) {
  function clean (line 562) | function clean(o) {
  function filterRules (line 571) | function filterRules(rs, cfg) {
  function prop (line 589) | function prop(obj, path, val) {
  function modlist (line 622) | function modlist(list, mods) {
  function parserwrap (line 663) | function parserwrap(parser) {
  function getpath (line 730) | function getpath(root, path) {
  function resolveFuncRefs (line 740) | function resolveFuncRefs(obj, ref) {

FILE: docs/assets/js/2.34930047.js
  function o (line 1) | function o(t){return decodeURI(t).replace(s,"").replace(i,"")}
  function l (line 1) | function l(t){return r.test(t)}
  function u (line 1) | function u(t){return/^mailto:/.test(t)}
  function c (line 1) | function c(t){return/^tel:/.test(t)}
  function h (line 1) | function h(t){if(l(t))return t;const e=t.match(s),n=e?e[0]:"",i=o(t);ret...
  function p (line 1) | function p(t,e){const n=decodeURIComponent(t.hash),i=function(t){const e...
  function d (line 1) | function d(t,e,n){if(l(e))return{type:"external",path:e};n&&(e=function(...
  function f (line 1) | function f(t,e,n,s){const{pages:i,themeConfig:a}=n,r=s&&a.locales&&a.loc...
  function g (line 1) | function g(t){const e=m(t.headers||[]);return[{type:"group",collapsable:...
  function m (line 1) | function m(t){let e;return(t=t.map(t=>Object.assign({},t))).forEach(t=>{...
  function b (line 1) | function b(t){return Object.assign(t,{type:t.items&&t.items.length?"link...
  method beforeCreate (line 1) | beforeCreate(){this.$options.components.SidebarLinks=n(168).default}
  function o (line 1) | function o(t,e,n,s,i){const a={props:{to:e,activeClass:"",exactActiveCla...
  function l (line 1) | function l(t,e,n,i,a,r=1){return!e||r>a?null:t("ul",{class:"sidebar-sub-...
  method render (line 1) | render(t,{parent:{$page:e,$site:n,$route:i,$themeConfig:a,$themeLocaleCo...
  function c (line 1) | function c(t,e){if("group"===e.type){const n=e.path&&Object(s.e)(t,e.pat...
  method data (line 1) | data(){return{openGroupIndex:this.initialOpenGroupIndex||0}}
  method $route (line 1) | $route(){this.refreshIndex()}
  method created (line 1) | created(){this.refreshIndex()}
  method refreshIndex (line 1) | refreshIndex(){const t=function(t,e){for(let n=0;n<e.length;n++){const s...
  method toggleGroup (line 1) | toggleGroup(t){this.openGroupIndex=t===this.openGroupIndex?-1:t}
  method isActive (line 1) | isActive(t){return Object(s.e)(this.$route,t.regularPath)}
  method setHeight (line 1) | setHeight(t){t.style.height=t.scrollHeight+"px"}
  method unsetHeight (line 1) | unsetHeight(t){t.style.height=""}
  method link (line 1) | link(){return Object(s.b)(this.item.link)}
  method exact (line 1) | exact(){return this.$site.locales?Object.keys(this.$site.locales).some(t...
  method isNonHttpURI (line 1) | isNonHttpURI(){return Object(s.g)(this.link)||Object(s.h)(this.link)}
  method isBlankTarget (line 1) | isBlankTarget(){return"_blank"===this.target}
  method isInternal (line 1) | isInternal(){return!Object(s.f)(this.link)&&!this.isBlankTarget}
  method target (line 1) | target(){return this.isNonHttpURI?null:this.item.target?this.item.target...
  method rel (line 1) | rel(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?th...
  method focusoutAction (line 1) | focusoutAction(){this.$emit("focusout")}
  method data (line 1) | data(){return this.$page.frontmatter}
  method actionLink (line 1) | actionLink(){return{link:this.data.actionLink,text:this.data.actionText}}
  method showSuggestions (line 1) | showSuggestions(){return this.focused&&this.suggestions&&this.suggestion...
  method suggestions (line 1) | suggestions(){const t=this.query.trim().toLowerCase();if(!t)return;const...
  method alignRight (line 1) | alignRight(){return(this.$site.themeConfig.nav||[]).length+(this.$site.r...
  method mounted (line 1) | mounted(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",...
  method beforeDestroy (line 1) | beforeDestroy(){document.removeEventListener("keydown",this.onHotkey)}
  method getPageLocalePath (line 1) | getPageLocalePath(t){for(const e in this.$site.locales||{})if("/"!==e&&0...
  method isSearchable (line 1) | isSearchable(t){let e=null;return null===e||(e=Array.isArray(e)?e:new Ar...
  method onHotkey (line 1) | onHotkey(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(th...
  method onUp (line 1) | onUp(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.f...
  method onDown (line 1) | onDown(){this.showSuggestions&&(this.focusIndex<this.suggestions.length-...
  method go (line 1) | go(t){this.showSuggestions&&(this.$router.push(this.suggestions[t].path)...
  method focus (line 1) | focus(t){this.focusIndex=t}
  method unfocus (line 1) | unfocus(){this.focusIndex=-1}
  method dropdownAriaLabel (line 1) | dropdownAriaLabel(){return this.item.ariaLabel||this.item.text}
  method $route (line 1) | $route(){this.open=!1}
  method setOpen (line 1) | setOpen(t){this.open=t}
  method handleDropdown (line 1) | handleDropdown(){0===event.detail&&this.setOpen(!this.open)}
  method userNav (line 1) | userNav(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav...
  method nav (line 1) | nav(){const{locales:t}=this.$site;if(t&&Object.keys(t).length>1){const e...
  method userLinks (line 1) | userLinks(){return(this.nav||[]).map(t=>Object.assign(Object(s.j)(t),{it...
  method repoLink (line 1) | repoLink(){const{repo:t}=this.$site.themeConfig;return t?/^https?:/.test...
  method repoLabel (line 1) | repoLabel(){if(!this.repoLink)return;if(this.$site.themeConfig.repoLabel...
  function C (line 1) | function C(t,e){return t.ownerDocument.defaultView.getComputedStyle(t,nu...
  method algolia (line 1) | algolia(){return this.$themeLocaleConfig.algolia||this.$site.themeConfig...
  method isAlgoliaSearch (line 1) | isAlgoliaSearch(){return this.algolia&&this.algolia.apiKey&&this.algolia...
  method mounted (line 1) | mounted(){const t=parseInt(C(this.$el,"paddingLeft"))+parseInt(C(this.$e...
  method lastUpdated (line 1) | lastUpdated(){return this.$page.lastUpdated}
  method lastUpdatedText (line 1) | lastUpdatedText(){return"string"==typeof this.$themeLocaleConfig.lastUpd...
  method editLink (line 1) | editLink(){const t=w()(this.$page.frontmatter.editLink)?this.$site.theme...
  method editLinkText (line 1) | editLinkText(){return this.$themeLocaleConfig.editLinkText||this.$site.t...
  method createEditLink (line 1) | createEditLink(t,e,n,i,a){if(/bitbucket.org/.test(e)){return e.replace(s...
  method prev (line 1) | prev(){return P(T.PREV,this)}
  method next (line 1) | next(){return P(T.NEXT,this)}
  function P (line 1) | function P(t,{$themeConfig:e,$page:n,$route:i,$site:a,sidebarItems:r}){c...
  function A (line 1) | function A(t,e,n){const s=[];!function t(e,n){for(let s=0,i=e.length;s<i...
  method shouldShowNavbar (line 1) | shouldShowNavbar(){const{themeConfig:t}=this.$site,{frontmatter:e}=this....
  method shouldShowSidebar (line 1) | shouldShowSidebar(){const{frontmatter:t}=this.$page;return!t.home&&!1!==...
  method sidebarItems (line 1) | sidebarItems(){return Object(s.l)(this.$page,this.$page.regularPath,this...
  method pageClasses (line 1) | pageClasses(){const t=this.$page.frontmatter.pageClass;return[{"no-navba...
  method mounted (line 1) | mounted(){this.$router.afterEach(()=>{this.isSidebarOpen=!1})}
  method toggleSidebar (line 1) | toggleSidebar(t){this.isSidebarOpen="boolean"==typeof t?t:!this.isSideba...
  method onTouchStart (line 1) | onTouchStart(t){this.touchStart={x:t.changedTouches[0].clientX,y:t.chang...
  method onTouchEnd (line 1) | onTouchEnd(t){const e=t.changedTouches[0].clientX-this.touchStart.x,n=t....

FILE: docs/assets/js/5.46815478.js
  method mounted (line 1) | mounted(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}

FILE: docs/assets/js/6.f03d59ff.js
  method activeCodeTabIndex (line 1) | activeCodeTabIndex(e){this.activateCodeTab(e)}
  method mounted (line 1) | mounted(){this.loadTabs()}
  method changeCodeTab (line 1) | changeCodeTab(e){this.activeCodeTabIndex=e}
  method loadTabs (line 1) | loadTabs(){this.codeTabs=(this.$slots.default||[]).filter(e=>Boolean(e.c...
  method activateCodeTab (line 1) | activateCodeTab(e){this.codeTabs.forEach(e=>{e.elm&&e.elm.classList.remo...

FILE: docs/assets/js/app.0c621e62.js
  function e (line 1) | function e(e){for(var r,a,s=e[0],u=e[1],l=e[2],f=0,p=[];f<s.length;f++)a...
  function n (line 1) | function n(){for(var t,e=0;e<i.length;e++){for(var n=i[e],r=!0,s=1;s<n.l...
  function a (line 1) | function a(e){if(r[e])return r[e].exports;var n=r[e]={i:e,l:!1,exports:{...
  function r (line 1) | function r(t,e,n,r,o,i,a,s){var u,l="function"==typeof t?t.options:t;if(...
  function u (line 1) | function u(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var...
  function o (line 3) | function o(t,e,n){return t<e?e:t>n?n:t}
  function i (line 3) | function i(t){return 100*(-1+t)}
  function e (line 3) | function e(){var n=t.shift();n&&n(e)}
  function n (line 3) | function n(n){return n=n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(...
  function r (line 3) | function r(t,e,r){e=n(e),t.style[e]=r}
  function u (line 3) | function u(t,e){return("string"==typeof t?t:f(t)).indexOf(" "+e+" ")>=0}
  function l (line 3) | function l(t,e){var n=f(t),r=n+e;u(n,e)||(t.className=r.substring(1))}
  function c (line 3) | function c(t,e){var n,r=f(t);u(t,e)&&(n=r.replace(" "+e+" "," "),t.class...
  function f (line 3) | function f(t){return(" "+(t.className||"")+" ").replace(/\s+/gi," ")}
  function p (line 3) | function p(t){t&&t.parentNode&&t.parentNode.removeChild(t)}
  function u (line 3) | function u(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var...
  function l (line 3) | function l(t){var e=this.__data__=new r(t);this.size=e.size}
  function a (line 3) | function a(t){var e=-1,n=null==t?0:t.length;for(this.__data__=new r;++e<...
  function h (line 10) | function h(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}
  function v (line 10) | function v(t){if("number"==typeof t)return t;if(function(t){return"symbo...
  function y (line 10) | function y(e){var n=r,i=o;return r=o=void 0,l=e,a=t.apply(i,n)}
  function b (line 10) | function b(t){return l=t,s=setTimeout(x,e),c?y(t):a}
  function _ (line 10) | function _(t){var n=t-u;return void 0===u||n>=e||n<0||m&&t-l>=i}
  function x (line 10) | function x(){var t=d();if(_(t))return w(t);s=setTimeout(x,function(t){va...
  function w (line 10) | function w(t){return s=void 0,g&&r?y(t):(r=o=void 0,a)}
  function k (line 10) | function k(){var t=d(),n=_(t);if(r=arguments,o=this,u=t,n){if(void 0===s...
  function u (line 10) | function u(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var...
  function o (line 10) | function o(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)t...
  function i (line 16) | function i(t){return null==t}
  function a (line 16) | function a(t){return null!=t}
  function s (line 16) | function s(t){return!0===t}
  function u (line 16) | function u(t){return"string"==typeof t||"number"==typeof t||"symbol"==ty...
  function l (line 16) | function l(t){return"function"==typeof t}
  function c (line 16) | function c(t){return null!==t&&"object"==typeof t}
  function p (line 16) | function p(t){return"[object Object]"===f.call(t)}
  function d (line 16) | function d(t){return"[object RegExp]"===f.call(t)}
  function h (line 16) | function h(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e...
  function v (line 16) | function v(t){return a(t)&&"function"==typeof t.then&&"function"==typeof...
  function m (line 16) | function m(t){return null==t?"":Array.isArray(t)||p(t)&&t.toString===f?J...
  function g (line 16) | function g(t){var e=parseFloat(t);return isNaN(e)?t:e}
  function y (line 16) | function y(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o<r.len...
  function _ (line 16) | function _(t,e){var n=t.length;if(n){if(e===t[n-1])return void(t.length=...
  function w (line 16) | function w(t,e){return x.call(t,e)}
  function k (line 16) | function k(t){var e=Object.create(null);return function(n){return e[n]||...
  function n (line 16) | function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t...
  function P (line 16) | function P(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n...
  function A (line 16) | function A(t,e){for(var n in e)t[n]=e[n];return t}
  function T (line 16) | function T(t){for(var e={},n=0;n<t.length;n++)t[n]&&A(e,t[n]);return e}
  function L (line 16) | function L(t,e,n){}
  function M (line 16) | function M(t,e){if(t===e)return!0;var n=c(t),r=c(e);if(!n||!r)return!n&&...
  function D (line 16) | function D(t,e){for(var n=0;n<t.length;n++)if(M(t[n],e))return n;return-1}
  function N (line 16) | function N(t){var e=!1;return function(){e||(e=!0,t.apply(this,arguments...
  function U (line 16) | function U(t,e){return t===e?0===t&&1/t!=1/e:t==t||e==e}
  function V (line 16) | function V(t){var e=(t+"").charCodeAt(0);return 36===e||95===e}
  function H (line 16) | function H(t,e,n,r){Object.defineProperty(t,e,{value:n,enumerable:!!r,wr...
  function st (line 16) | function st(t){return"function"==typeof t&&/native code/.test(t.toString...
  function t (line 16) | function t(){this.set=Object.create(null)}
  function ft (line 16) | function ft(t){void 0===t&&(t=null),t||ct&&ct._scope.off(),ct=t,t&&t._sc...
  function t (line 16) | function t(t,e,n,r,o,i,a,s){this.tag=t,this.data=e,this.children=n,this....
  function ht (line 16) | function ht(t){return new pt(void 0,void 0,void 0,String(t))}
  function vt (line 16) | function vt(t){var e=new pt(t.tag,t.data,t.children&&t.children.slice(),...
  function t (line 16) | function t(){this._pending=!1,this.id=mt++,this.subs=[]}
  function _t (line 16) | function _t(t){bt.push(t),yt.target=t}
  function xt (line 16) | function xt(){bt.pop(),yt.target=bt[bt.length-1]}
  function jt (line 16) | function jt(t){Ot=t}
  function t (line 16) | function t(t,e,n){if(void 0===e&&(e=!1),void 0===n&&(n=!1),this.value=t,...
  function Pt (line 16) | function Pt(t,e,n){return t&&w(t,"__ob__")&&t.__ob__ instanceof Et?t.__o...
  function At (line 16) | function At(t,e,n,r,i,a){var s=new yt,u=Object.getOwnPropertyDescriptor(...
  function Tt (line 16) | function Tt(t,e,n){if(!Dt(t)){var r=t.__ob__;return o(t)&&h(e)?(t.length...
  function Lt (line 16) | function Lt(t,e){if(o(t)&&h(e))t.splice(e,1);else{var n=t.__ob__;t._isVu...
  function Rt (line 16) | function Rt(t){for(var e=void 0,n=0,r=t.length;n<r;n++)(e=t[n])&&e.__ob_...
  function It (line 16) | function It(t){return Mt(t,!0),H(t,"__v_isShallow",!0),t}
  function Mt (line 16) | function Mt(t,e){if(!Dt(t)){Pt(t,e,it());0}}
  function Dt (line 16) | function Dt(t){return!(!t||!t.__v_isReadonly)}
  function Nt (line 16) | function Nt(t){return!(!t||!0!==t.__v_isRef)}
  function Ut (line 16) | function Ut(t,e,n){Object.defineProperty(t,n,{enumerable:!0,configurable...
  function t (line 16) | function t(t){void 0===t&&(t=!1),this.detached=t,this.active=!0,this.eff...
  function Bt (line 16) | function Bt(t){var e=t._provided,n=t.$parent&&t.$parent._provided;return...
  function Vt (line 16) | function Vt(t,e){function n(){var t=n.fns;if(!o(t))return Oe(t,null,argu...
  function Ht (line 16) | function Ht(t,e,n,r,o,a){var u,l,c,f;for(u in t)l=t[u],c=e[u],f=qt(u),i(...
  function Wt (line 16) | function Wt(t,e,n){var r;t instanceof pt&&(t=t.data.hook||(t.data.hook={...
  function Kt (line 16) | function Kt(t,e,n,r,o){if(a(e)){if(w(e,n))return t[n]=e[n],o||delete e[n...
  function Jt (line 16) | function Jt(t){return u(t)?[ht(t)]:o(t)?function t(e,n){var r,l,c,f,p=[]...
  function Gt (line 16) | function Gt(t){return a(t)&&a(t.text)&&!1===t.isComment}
  function Qt (line 16) | function Qt(t,e){var n,r,i,s,u=null;if(o(t)||"string"==typeof t)for(u=ne...
  function Xt (line 16) | function Xt(t,e,n,r){var o,i=this.$scopedSlots[t];i?(n=n||{},r&&(n=A(A({...
  function Yt (line 16) | function Yt(t){return Pn(this.$options,"filters",t,!0)||I}
  function Zt (line 16) | function Zt(t,e){return o(t)?-1===t.indexOf(e):t!==e}
  function te (line 16) | function te(t,e,n,r,o){var i=B.keyCodes[e]||n;return o&&r&&!B.keyCodes[e...
  function ee (line 16) | function ee(t,e,n,r,i){if(n)if(c(n)){o(n)&&(n=T(n));var a=void 0,s=funct...
  function ne (line 16) | function ne(t,e){var n=this._staticTrees||(this._staticTrees=[]),r=n[t];...
  function re (line 16) | function re(t,e,n){return oe(t,"__once__".concat(e).concat(n?"_".concat(...
  function oe (line 16) | function oe(t,e,n){if(o(t))for(var r=0;r<t.length;r++)t[r]&&"string"!=ty...
  function ie (line 16) | function ie(t,e,n){t.isStatic=!0,t.key=e,t.isOnce=n}
  function ae (line 16) | function ae(t,e){if(e)if(p(e)){var n=t.on=t.on?A({},t.on):{};for(var r i...
  function se (line 16) | function se(t,e,n,r){e=e||{$stable:!n};for(var i=0;i<t.length;i++){var a...
  function ue (line 16) | function ue(t,e){for(var n=0;n<e.length;n+=2){var r=e[n];"string"==typeo...
  function le (line 16) | function le(t,e){return"string"==typeof t?e+t:t}
  function ce (line 16) | function ce(t){t._o=re,t._n=g,t._s=m,t._l=Qt,t._t=Xt,t._q=M,t._i=D,t._m=...
  function fe (line 16) | function fe(t,e){if(!t||!t.length)return{};for(var n={},r=0,o=t.length;r...
  function pe (line 16) | function pe(t){return t.isComment&&!t.asyncFactory||" "===t.text}
  function de (line 16) | function de(t){return t.isComment&&t.asyncFactory}
  function he (line 16) | function he(t,e,n,o){var i,a=Object.keys(n).length>0,s=e?!!e.$stable:!a,...
  function ve (line 16) | function ve(t,e,n,r){var i=function(){var e=ct;ft(t);var n=arguments.len...
  function me (line 16) | function me(t,e){return function(){return t[e]}}
  function ge (line 16) | function ge(t){return{get attrs(){if(!t._attrsProxy){var e=t._attrsProxy...
  function ye (line 16) | function ye(t,e,n,r,o){var i=!1;for(var a in e)a in t?e[a]!==n[a]&&(i=!0...
  function be (line 16) | function be(t,e,n,r){Object.defineProperty(t,e,{enumerable:!0,configurab...
  function _e (line 16) | function _e(t,e){for(var n in e)t[n]=e[n];for(var n in t)n in e||delete ...
  function we (line 16) | function we(t,e){return(t.__esModule||lt&&"Module"===t[Symbol.toStringTa...
  function ke (line 16) | function ke(t){if(o(t))for(var e=0;e<t.length;e++){var n=t[e];if(a(n)&&(...
  function $e (line 16) | function $e(t,e,n,r,f,p){return(o(n)||u(n))&&(f=r,r=n,n=void 0),s(p)&&(f...
  function Ce (line 16) | function Ce(t,e,n){_t();try{if(e)for(var r=e;r=r.$parent;){var o=r.$opti...
  function Oe (line 16) | function Oe(t,e,n,r,o){var i;try{(i=n?t.apply(e,n):t.call(e))&&!i._isVue...
  function je (line 16) | function je(t,e,n){if(B.errorHandler)try{return B.errorHandler.call(null...
  function Se (line 16) | function Se(t,e,n){if(!J||"undefined"==typeof console)throw t;console.er...
  function Le (line 16) | function Le(){Te=!1;var t=Ae.slice(0);Ae.length=0;for(var e=0;e<t.length...
  function Ne (line 16) | function Ne(t,e){var n;if(Ae.push((function(){if(t)try{t.call(e)}catch(t...
  function Ue (line 16) | function Ue(t){return function(e,n){if(void 0===n&&(n=ct),n)return funct...
  function ze (line 16) | function ze(t){return function t(e,n){var r,i,a=o(e);if(!a&&!c(e)||e.__v...
  function t (line 16) | function t(t,e,n,r,o){var i,a;i=this,void 0===(a=Ft&&!Ft._vm?Ft:t?t._sco...
  function He (line 16) | function He(t,e){Be.$on(t,e)}
  function We (line 16) | function We(t,e){Be.$off(t,e)}
  function Ke (line 16) | function Ke(t,e){var n=Be;return function r(){var o=e.apply(null,argumen...
  function Je (line 16) | function Je(t,e,n){Be=t,Ht(e,n||{},He,We,Ke,t),Be=void 0}
  function Qe (line 16) | function Qe(t){var e=Ge;return Ge=t,function(){Ge=e}}
  function Xe (line 16) | function Xe(t){for(;t&&(t=t.$parent);)if(t._inactive)return!0;return!1}
  function Ye (line 16) | function Ye(t,e){if(e){if(t._directInactive=!1,Xe(t))return}else if(t._d...
  function Ze (line 16) | function Ze(t,e,n,r){void 0===r&&(r=!0),_t();var o=ct;r&&ft(t);var i=t.$...
  function fn (line 16) | function fn(){var t,e;for(sn=un(),on=!0,tn.sort(cn),an=0;an<tn.length;an...
  function pn (line 16) | function pn(t){var e=t.id;if(null==nn[e]&&(t!==yt.target||!t.noRecurse))...
  function dn (line 16) | function dn(t,e){if(t){for(var n=Object.create(null),r=lt?Reflect.ownKey...
  function hn (line 16) | function hn(t,e,n,i,a){var u,l=this,c=a.options;w(i,"_uid")?(u=Object.cr...
  function vn (line 16) | function vn(t,e,n,r,o){var i=vt(t);return i.fnContext=n,i.fnOptions=r,e....
  function mn (line 16) | function mn(t,e){for(var n in e)t[C(n)]=e[n]}
  function gn (line 16) | function gn(t){return t.name||t.__name||t._componentTag}
  function _n (line 16) | function _n(t,e,n,u,l){if(!i(t)){var f=n.$options._base;if(c(t)&&(t=f.ex...
  function xn (line 16) | function xn(t,e){var n=function(n,r){t(n,r),e(n,r)};return n._merged=!0,n}
  function $n (line 16) | function $n(t,e,n){if(void 0===n&&(n=!0),!e)return t;for(var r,o,i,a=lt?...
  function Cn (line 16) | function Cn(t,e,n){return n?function(){var r=l(e)?e.call(n,n):e,o=l(t)?t...
  function On (line 16) | function On(t,e){var n=e?t?t.concat(e):o(e)?e:[e]:t;return n?function(t)...
  function jn (line 16) | function jn(t,e,n,r){var o=Object.create(t||null);return e?A(o,e):o}
  function En (line 16) | function En(t,e,n){if(l(e)&&(e=e.options),function(t,e){var n=t.props;if...
  function Pn (line 16) | function Pn(t,e,n,r){if("string"==typeof n){var o=t[e];if(w(o,n))return ...
  function An (line 16) | function An(t,e,n,r){var o=e[t],i=!w(n,t),a=n[t],s=In(Boolean,o.type);if...
  function Ln (line 16) | function Ln(t){var e=t&&t.toString().match(Tn);return e?e[1]:""}
  function Rn (line 16) | function Rn(t,e){return Ln(t)===Ln(e)}
  function In (line 16) | function In(t,e){if(!o(e))return Rn(e,t)?0:-1;for(var n=0,r=e.length;n<r...
  function Dn (line 16) | function Dn(t,e,n){Mn.get=function(){return this[e][n]},Mn.set=function(...
  function Nn (line 16) | function Nn(t){var e=t.$options;if(e.props&&function(t,e){var n=t.$optio...
  function Fn (line 16) | function Fn(t,e,n){var r=!it();l(n)?(Mn.get=r?zn(e):Bn(n),Mn.set=L):(Mn....
  function zn (line 16) | function zn(t){return function(){var e=this._computedWatchers&&this._com...
  function Bn (line 16) | function Bn(t){return function(){return t.call(this,this)}}
  function qn (line 16) | function qn(t,e,n,r){return p(n)&&(r=n,n=n.handler),"string"==typeof n&&...
  function Hn (line 16) | function Hn(t){var e=t.options;if(t.super){var n=Hn(t.super);if(n!==t.su...
  function Wn (line 16) | function Wn(t){this._init(t)}
  function Kn (line 16) | function Kn(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r...
  function Jn (line 16) | function Jn(t){return t&&(gn(t.Ctor.options)||t.tag)}
  function Gn (line 16) | function Gn(t,e){return o(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(...
  function Qn (line 16) | function Qn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a...
  function Xn (line 16) | function Xn(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstanc...
  function r (line 16) | function r(){n.$off(t,r),e.apply(n,arguments)}
  function lr (line 16) | function lr(t){for(var e=t.data,n=t,r=t;a(r.componentInstance);)(r=r.com...
  function cr (line 16) | function cr(t,e){return{staticClass:fr(t.staticClass,e.staticClass),clas...
  function fr (line 16) | function fr(t,e){return t?e?t+" "+e:t:e||""}
  function pr (line 16) | function pr(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=...
  function xr (line 16) | function xr(t,e){var n=t.data.ref;if(a(n)){var r=t.context,i=t.component...
  function wr (line 16) | function wr(t,e,n){var r=t._setupState;r&&w(r,e)&&(Nt(r[e])?r[e].value=n...
  function Cr (line 16) | function Cr(t,e){return t.key===e.key&&t.asyncFactory===e.asyncFactory&&...
  function Or (line 16) | function Or(t,e,n){var r,o,i={};for(r=e;r<=n;++r)a(o=t[r].key)&&(i[o]=r)...
  function Sr (line 16) | function Sr(t,e){(t.data.directives||e.data.directives)&&function(t,e){v...
  function Pr (line 16) | function Pr(t,e){var n,r,o=Object.create(null);if(!t)return o;for(n=0;n<...
  function Ar (line 16) | function Ar(t){return t.rawName||"".concat(t.name,".").concat(Object.key...
  function Tr (line 16) | function Tr(t,e,n,r,o){var i=t.def&&t.def[e];if(i)try{i(n.elm,t,n,r,o)}c...
  function Rr (line 16) | function Rr(t,e){var n=e.componentOptions;if(!(a(n)&&!1===n.Ctor.options...
  function Ir (line 16) | function Ir(t,e,n,r){r||t.tagName.indexOf("-")>-1?Mr(t,e,n):or(e)?ur(n)?...
  function Mr (line 16) | function Mr(t,e,n){if(ur(n))t.removeAttribute(e);else{if(Q&&!X&&"TEXTARE...
  function Nr (line 16) | function Nr(t,e){var n=e.elm,r=e.data,o=t.data;if(!(i(r.staticClass)&&i(...
  function zr (line 16) | function zr(t,e,n){var r=Ur;return function o(){var i=e.apply(null,argum...
  function qr (line 16) | function qr(t,e,n,r){if(Br){var o=sn,i=e;e=i._wrapper=function(t){if(t.t...
  function Vr (line 16) | function Vr(t,e,n,r){(r||Ur).removeEventListener(t,e._wrapper||e,n)}
  function Hr (line 16) | function Hr(t,e){if(!i(t.data.on)||!i(e.data.on)){var n=e.data.on||{},r=...
  function Jr (line 16) | function Jr(t,e){if(!i(t.data.domProps)||!i(e.data.domProps)){var n,r,o=...
  function Gr (line 16) | function Gr(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e...
  function Yr (line 16) | function Yr(t){var e=Zr(t.style);return t.staticStyle?A(t.staticStyle,e):e}
  function Zr (line 16) | function Zr(t){return Array.isArray(t)?T(t):"string"==typeof t?Xr(t):t}
  function ao (line 16) | function ao(t,e){var n=e.data,r=t.data;if(!(i(n.staticStyle)&&i(n.style)...
  function lo (line 16) | function lo(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.s...
  function co (line 16) | function co(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.s...
  function fo (line 16) | function fo(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&A...
  function _o (line 16) | function _o(t){bo((function(){bo(t)}))}
  function xo (line 16) | function xo(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n...
  function wo (line 16) | function wo(t,e){t._transitionClasses&&_(t._transitionClasses,e),co(t,e)}
  function ko (line 16) | function ko(t,e,n){var r=Co(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!...
  function Co (line 16) | function Co(t,e){var n,r=window.getComputedStyle(t),o=(r[vo+"Delay"]||""...
  function Oo (line 16) | function Oo(t,e){for(;t.length<e.length;)t=t.concat(t);return Math.max.a...
  function jo (line 16) | function jo(t){return 1e3*Number(t.slice(0,-1).replace(",","."))}
  function So (line 16) | function So(t,e){var n=t.elm;a(n._leaveCb)&&(n._leaveCb.cancelled=!0,n._...
  function Eo (line 16) | function Eo(t,e){var n=t.elm;a(n._enterCb)&&(n._enterCb.cancelled=!0,n._...
  function Po (line 16) | function Po(t){return"number"==typeof t&&!isNaN(t)}
  function Ao (line 16) | function Ao(t){if(i(t))return!1;var e=t.fns;return a(e)?Ao(Array.isArray...
  function To (line 16) | function To(t,e){!0!==e.data.show&&So(e)}
  function f (line 16) | function f(t){var e=c.parentNode(t);a(e)&&c.removeChild(e,t)}
  function p (line 16) | function p(t,e,n,o,i,u,l){if(a(t.elm)&&a(u)&&(t=u[l]=vt(t)),t.isRootInse...
  function d (line 16) | function d(t,e){a(t.data.pendingInsert)&&(e.push.apply(e,t.data.pendingI...
  function h (line 16) | function h(t,e,n){a(t)&&(a(n)?c.parentNode(n)===t&&c.insertBefore(t,e,n)...
  function v (line 16) | function v(t,e,n){if(o(e)){0;for(var r=0;r<e.length;++r)p(e[r],n,t.elm,n...
  function m (line 16) | function m(t){for(;t.componentInstance;)t=t.componentInstance._vnode;ret...
  function g (line 16) | function g(t,n){for(var o=0;o<r.create.length;++o)r.create[o](kr,t);a(e=...
  function b (line 16) | function b(t){var e;if(a(e=t.fnScopeId))c.setStyleScope(t.elm,e);else fo...
  function _ (line 16) | function _(t,e,n,r,o,i){for(;r<=o;++r)p(n[r],i,t,e,!1,n,r)}
  function x (line 16) | function x(t){var e,n,o=t.data;if(a(o))for(a(e=o.hook)&&a(e=e.destroy)&&...
  function w (line 16) | function w(t,e,n){for(;e<=n;++e){var r=t[e];a(r)&&(a(r.tag)?(k(r),x(r)):...
  function k (line 16) | function k(t,e){if(a(e)||a(t.data)){var n,o=r.remove.length+1;for(a(e)?e...
  function $ (line 16) | function $(t,e,n,r){for(var o=n;o<r;o++){var i=e[o];if(a(i)&&Cr(t,i))ret...
  function C (line 16) | function C(t,e,n,o,u,l){if(t!==e){a(e.elm)&&a(o)&&(e=o[u]=vt(e));var f=e...
  function O (line 16) | function O(t,e,n){if(s(n)&&a(t.parent))t.parent.data.pendingInsert=e;els...
  function S (line 16) | function S(t,e,n,r){var o,i=e.tag,u=e.data,l=e.children;if(r=r||u&&u.pre...
  function Io (line 16) | function Io(t,e,n){Mo(t,e,n),(Q||Y)&&setTimeout((function(){Mo(t,e,n)}),0)}
  function Mo (line 16) | function Mo(t,e,n){var r=e.value,o=t.multiple;if(!o||Array.isArray(r)){f...
  function Do (line 16) | function Do(t,e){return e.every((function(e){return!M(e,t)}))}
  function No (line 16) | function No(t){return"_value"in t?t._value:t.value}
  function Uo (line 16) | function Uo(t){t.target.composing=!0}
  function Fo (line 16) | function Fo(t){t.target.composing&&(t.target.composing=!1,zo(t.target,"i...
  function zo (line 16) | function zo(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,...
  function Bo (line 16) | function Bo(t){return!t.componentInstance||t.data&&t.data.transition?t:B...
  function Ho (line 16) | function Ho(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abst...
  function Wo (line 16) | function Wo(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];...
  function Ko (line 16) | function Ko(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{...
  function Yo (line 16) | function Yo(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._ent...
  function Zo (line 16) | function Zo(t){t.data.newPos=t.elm.getBoundingClientRect()}
  function ti (line 16) | function ti(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-...
  function ni (line 16) | function ni(t,e){for(var n in e)t[n]=e[n];return t}
  function si (line 16) | function si(t){try{return decodeURIComponent(t)}catch(t){0}return t}
  function li (line 16) | function li(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.sp...
  function ci (line 16) | function ci(t){var e=t?Object.keys(t).map((function(e){var n=t[e];if(voi...
  function pi (line 16) | function pi(t,e,n,r){var o=r&&r.options.stringifyQuery,i=e.query||{};try...
  function di (line 16) | function di(t){if(Array.isArray(t))return t.map(di);if(t&&"object"==type...
  function vi (line 16) | function vi(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}
  function mi (line 16) | function mi(t,e){var n=t.path,r=t.query;void 0===r&&(r={});var o=t.hash;...
  function gi (line 16) | function gi(t,e,n){return e===hi?t===e:!!e&&(t.path&&e.path?t.path.repla...
  function yi (line 16) | function yi(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return ...
  function bi (line 16) | function bi(t){for(var e=0;e<t.matched.length;e++){var n=t.matched[e];fo...
  function xi (line 16) | function xi(t,e,n,r){var o=e.props=function(t,e){switch(typeof e){case"u...
  function wi (line 16) | function wi(t,e,n){var r=t.charAt(0);if("/"===r)return t;if("?"===r||"#"...
  function ki (line 16) | function ki(t){return t.replace(/\/(?:\s*\/)+/g,"/")}
  function Ai (line 16) | function Ai(t,e){for(var n,r=[],o=0,i=0,a="",s=e&&e.delimiter||"/";null!...
  function Ti (line 16) | function Ti(t){return encodeURI(t).replace(/[\/?#]/g,(function(t){return...
  function Li (line 16) | function Li(t,e){for(var n=new Array(t.length),r=0;r<t.length;r++)"objec...
  function Ri (line 16) | function Ri(t){return t.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}
  function Ii (line 16) | function Ii(t){return t.replace(/([=!:$\/()])/g,"\\$1")}
  function Mi (line 16) | function Mi(t,e){return t.keys=e,t}
  function Di (line 16) | function Di(t){return t&&t.sensitive?"":"i"}
  function Ni (line 16) | function Ni(t,e,n){$i(e)||(n=e||n,e=[]);for(var r=(n=n||{}).strict,o=!1!...
  function Ui (line 16) | function Ui(t,e,n){return $i(e)||(n=e||n,e=[]),n=n||{},t instanceof RegE...
  function zi (line 16) | function zi(t,e,n){e=e||{};try{var r=Fi[t]||(Fi[t]=Ci.compile(t));return...
  function Bi (line 16) | function Bi(t,e,n,r){var o="string"==typeof t?{path:t}:t;if(o._normalize...
  function Wi (line 16) | function Wi(t){if(!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey||t.defaul...
  function Ji (line 16) | function Ji(t,e,n,r,o){var i=e||[],a=n||Object.create(null),s=r||Object....
  function Gi (line 16) | function Gi(t,e){return Ci(t,[],e)}
  function Qi (line 16) | function Qi(t,e){var n=Ji(t),r=n.pathList,o=n.pathMap,i=n.nameMap;functi...
  function Xi (line 16) | function Xi(t,e,n){var r=e.match(t);if(!r)return!1;if(!n)return!0;for(va...
  function Zi (line 16) | function Zi(){return Yi.now().toFixed(3)}
  function ea (line 16) | function ea(){return ta}
  function na (line 16) | function na(t){return ta=t}
  function oa (line 16) | function oa(){"scrollRestoration"in window.history&&(window.history.scro...
  function ia (line 16) | function ia(t,e,n,r){if(t.app){var o=t.options.scrollBehavior;o&&t.app.$...
  function aa (line 16) | function aa(){var t=ea();t&&(ra[t]={x:window.pageXOffset,y:window.pageYO...
  function sa (line 16) | function sa(t){aa(),t.state&&t.state.key&&na(t.state.key)}
  function ua (line 16) | function ua(t){return ca(t.x)||ca(t.y)}
  function la (line 16) | function la(t){return{x:ca(t.x)?t.x:window.pageXOffset,y:ca(t.y)?t.y:win...
  function ca (line 16) | function ca(t){return"number"==typeof t}
  function pa (line 16) | function pa(t,e){var n,r="object"==typeof t;if(r&&"string"==typeof t.sel...
  function va (line 16) | function va(t,e){aa();var n=window.history;try{if(e){var r=ni({},n.state...
  function ma (line 16) | function ma(t){va(t,!0)}
  function ya (line 16) | function ya(t,e){return _a(t,e,ga.redirected,'Redirected when going from...
  function ba (line 16) | function ba(t,e){return _a(t,e,ga.cancelled,'Navigation cancelled from "...
  function _a (line 16) | function _a(t,e,n,r){var o=new Error(r);return o._isRouter=!0,o.from=t,o...
  function wa (line 16) | function wa(t){return Object.prototype.toString.call(t).indexOf("Error")...
  function ka (line 16) | function ka(t,e){return wa(t)&&t._isRouter&&(null==e||t.type===e)}
  function $a (line 16) | function $a(t,e,n){var r=function(o){o>=t.length?n():t[o]?e(t[o],(functi...
  function Ca (line 16) | function Ca(t){return function(e,n,r){var o=!1,i=0,a=null;Oa(t,(function...
  function Oa (line 16) | function Oa(t,e){return ja(t.map((function(t){return Object.keys(t.compo...
  function ja (line 16) | function ja(t){return Array.prototype.concat.apply([],t)}
  function Ea (line 16) | function Ea(t){var e=!1;return function(){for(var n=[],r=arguments.lengt...
  function Aa (line 16) | function Aa(t,e,n,r){var o=Oa(t,(function(t,r,o,i){var a=function(t,e){"...
  function Ta (line 16) | function Ta(t,e){if(e)return function(){return t.apply(e,arguments)}}
  function e (line 16) | function e(e,n){t.call(this,e,n),this._startLocation=Ra(this.base)}
  function Ra (line 16) | function Ra(t){var e=window.location.pathname,n=e.toLowerCase(),r=t.toLo...
  function e (line 16) | function e(e,n,r){t.call(this,e,n),r&&function(t){var e=Ra(t);if(!/^\/#/...
  function Ma (line 16) | function Ma(){var t=Da();return"/"===t.charAt(0)||(Fa("/"+t),!1)}
  function Da (line 16) | function Da(){var t=window.location.href,e=t.indexOf("#");return e<0?"":...
  function Na (line 16) | function Na(t){var e=window.location.href,n=e.indexOf("#");return(n>=0?e...
  function Ua (line 16) | function Ua(t){ha?va(Na(t)):window.location.hash=t}
  function Fa (line 16) | function Fa(t){ha?ma(Na(t)):window.location.replace(Na(t))}
  function e (line 16) | function e(e,n){t.call(this,e,n),this.stack=[],this.index=-1}
  function Ha (line 16) | function Ha(t,e){return t.push(e),function(){var n=t.indexOf(e);n>-1&&t....
  function Ja (line 16) | function Ja(t){const e=Object.create(null);return function(n){return e[n...
  function ts (line 16) | function ts(t,e){if(!e)return;if(t(e))return t(e);return e.includes("-")...
  function as (line 16) | function as(t){return ts(rs,t)}
  function ss (line 16) | function ss(t){return ts(os,t)}
  function us (line 16) | function us(t){return ts(ns,t)}
  function ls (line 16) | function ls(t){return ts(is,t)}
  function cs (line 16) | function cs(...t){return Promise.all(t.filter(t=>t).map(async t=>{if(!ls...
  function fs (line 16) | function fs(t,e){"undefined"!=typeof window&&window.__VUEPRESS__&&(windo...
  method created (line 16) | created(){if(this.siteMeta=this.$site.headTags.filter(([t])=>"meta"===t)...
  method mounted (line 16) | mounted(){this.currentMetaTags=[...document.querySelectorAll("meta")],th...
  method updateMeta (line 16) | updateMeta(){document.title=this.$title,document.documentElement.lang=th...
  method getMergedMetaTags (line 16) | getMergedMetaTags(){const t=this.$page.frontmatter.meta||[];return ds()(...
  method updateCanonicalLink (line 16) | updateCanonicalLink(){gs(),this.$canonicalUrl&&document.head.insertAdjac...
  method $page (line 16) | $page(){this.updateMeta(),this.updateCanonicalLink()}
  method beforeDestroy (line 16) | beforeDestroy(){bs(null,this.currentMetaTags),gs()}
  function gs (line 16) | function gs(){const t=document.querySelector("link[rel='canonical']");t&...
  function ys (line 16) | function ys(t=""){return t?`<link href="${t}" rel="canonical" />`:""}
  function bs (line 16) | function bs(t,e){if(e&&[...e].filter(t=>t.parentNode===document.head).fo...
  function _s (line 16) | function _s(t){for(const e of["name","property","itemprop"])if(t.hasOwnP...
  method mounted (line 16) | mounted(){window.addEventListener("scroll",this.onScroll)}
  method setActiveHash (line 16) | setActiveHash(){const t=[].slice.call(document.querySelectorAll(".sideba...
  method beforeDestroy (line 16) | beforeDestroy(){window.removeEventListener("scroll",this.onScroll)}
  method mounted (line 16) | mounted(){$s.a.configure({showSpinner:!1}),this.$router.beforeEach((t,e,...
  method layout (line 16) | layout(){const t=this.getLayout();return fs("layout",t),Wn.component(t)}
  method getLayout (line 16) | getLayout(){if(this.$page.path){const t=this.$page.frontmatter.layout;re...
  method $dataBlock (line 16) | $dataBlock(){return this.$options.__data__block__}
  class Ls (line 16) | class Ls extends class{constructor(){this.store=new Wn({data:{state:{}}}...
    method constructor (line 16) | constructor(){this.store=new Wn({data:{state:{}}})}
    method $get (line 16) | $get(t){return this.store.state[t]}
    method $set (line 16) | $set(t,e){Wn.set(this.store.state,t,e)}
    method $emit (line 16) | $emit(...t){this.store.$emit(...t)}
    method $on (line 16) | $on(...t){this.store.$on(...t)}
  method install (line 16) | install(t){const e=new Ls;t.$vuepress=e,t.prototype.$vuepress=e}
  function Is (line 16) | function Is(t,e){const n=e.toLowerCase();return t.options.routes.some(t=...
  method render (line 16) | render(t){const e=this.pageKey||this.$parent.$page.key;return fs("pageKe...
  method openInNewWindowTitle (line 16) | openInNewWindowTitle(){return this.$themeLocaleConfig.openNewWindowText|...
  method render (line 16) | render(t,{parent:e,children:n}){if(e._isMounted)return n;e.$once("hook:m...
  method setPage (line 16) | setPage(t){this.__page=t}
  method $site (line 16) | get $site(){return t}
  method $themeConfig (line 16) | get $themeConfig(){return this.$site.themeConfig}
  method $frontmatter (line 16) | get $frontmatter(){return this.$page.frontmatter}
  method $localeConfig (line 16) | get $localeConfig(){const{locales:t={}}=this.$site;let e,n;for(const r i...
  method $siteTitle (line 16) | get $siteTitle(){return this.$localeConfig.title||this.$site.title||""}
  method $canonicalUrl (line 16) | get $canonicalUrl(){const{canonicalUrl:t}=this.$page.frontmatter;return"...
  method $title (line 16) | get $title(){const t=this.$page,{metaTitle:e}=this.$page.frontmatter;if(...
  method $description (line 16) | get $description(){const t=function(t){if(t){const e=t.filter(t=>"descri...
  method $lang (line 16) | get $lang(){return this.$page.frontmatter.lang||this.$localeConfig.lang|...
  method $localePath (line 16) | get $localePath(){return this.$localeConfig.path||"/"}
  method $themeLocaleConfig (line 16) | get $themeLocaleConfig(){return(this.$site.themeConfig.locales||{})[this...
  method $page (line 16) | get $page(){return this.__page?this.__page:function(t,e){for(let n=0;n<t...

FILE: docs/jsonic.js
  function make_standard_options (line 17) | function make_standard_options() {
  class JsonicError (line 156) | class JsonicError extends SyntaxError {
    method constructor (line 157) | constructor(code, details, token, rule, ctx) {
    method make_desc (line 188) | static make_desc(code, details, token, rule, ctx) {
    method toJSON (line 228) | toJSON() {
  class Lexer (line 239) | class Lexer {
    method constructor (line 240) | constructor(config) {
    method start (line 257) | start(ctx) {
    method bad (line 734) | bad(ctx, log, why, token, sI, pI, rI, cI, val, src, use) {
    method lex (line 749) | lex(state, matcher) {
    method clone (line 762) | clone(config) {
  class Rule (line 774) | class Rule {
    method constructor (line 777) | constructor(spec, ctx, node) {
    method process (line 788) | process(ctx) {
  class RuleSpec (line 801) | class RuleSpec {
    method constructor (line 802) | constructor(name, def) {
    method open (line 833) | open(rule, ctx) {
    method close (line 882) | close(rule, ctx) {
    method parse_alts (line 930) | parse_alts(alts, rule, ctx) {
  class Parser (line 1002) | class Parser {
    method constructor (line 1003) | constructor(opts, config) {
    method init (line 1008) | init() {
    method rule (line 1167) | rule(name, define) {
    method start (line 1171) | start(lexer, src, jsonic, meta, partial_ctx) {
    method clone (line 1243) | clone(opts, config) {
  function make (line 1547) | function make(first, parent) {
  function make_hint (line 1642) | function make_hint(d = (t, r = 'replace') => t[r](/[A-Z]/g, (m) => ' ' +...

FILE: go/alignment_test.go
  function TestAlignmentValues (line 24) | func TestAlignmentValues(t *testing.T) {
  function TestAlignmentSafeKey (line 30) | func TestAlignmentSafeKey(t *testing.T) {
  function TestAlignmentMapMerge (line 36) | func TestAlignmentMapMerge(t *testing.T) {
  function TestAlignmentNumberText (line 42) | func TestAlignmentNumberText(t *testing.T) {
  function TestAlignmentStructure (line 47) | func TestAlignmentStructure(t *testing.T) {
  function TestAlignmentEmpty (line 52) | func TestAlignmentEmpty(t *testing.T) {
  function TestAlignmentErrors (line 88) | func TestAlignmentErrors(t *testing.T) {
  function runErrorTSV (line 130) | func runErrorTSV(t *testing.T, file string, j *Jsonic) {
  function TestLexErrorsDefault (line 171) | func TestLexErrorsDefault(t *testing.T) {
  function TestLexErrorsExcludeJsonicImp (line 175) | func TestLexErrorsExcludeJsonicImp(t *testing.T) {
  function TestLexErrorsExcludeJsonicImpComma (line 180) | func TestLexErrorsExcludeJsonicImpComma(t *testing.T) {
  function TestExcludeStrictJSON (line 187) | func TestExcludeStrictJSON(t *testing.T) {
  function TestExcludeStrictJSONErrors (line 192) | func TestExcludeStrictJSONErrors(t *testing.T) {
  function TestExcludeComma (line 197) | func TestExcludeComma(t *testing.T) {
  function TestExcludeCommaErrors (line 202) | func TestExcludeCommaErrors(t *testing.T) {
  function TestIncludeJSON (line 212) | func TestIncludeJSON(t *testing.T) {
  function TestIncludeJSONErrors (line 217) | func TestIncludeJSONErrors(t *testing.T) {
  function TestFeatureCommentSuffixLine (line 226) | func TestFeatureCommentSuffixLine(t *testing.T) {
  function TestFeatureCommentSuffixBlock (line 241) | func TestFeatureCommentSuffixBlock(t *testing.T) {
  function TestAlignmentMapExtendFalse (line 259) | func TestAlignmentMapExtendFalse(t *testing.T) {
  function TestAlignmentMapMergeFunc (line 275) | func TestAlignmentMapMergeFunc(t *testing.T) {
  function TestAlignmentSafeKeyArray (line 295) | func TestAlignmentSafeKeyArray(t *testing.T) {
  function TestAlignmentSafeKeyFalse (line 324) | func TestAlignmentSafeKeyFalse(t *testing.T) {
  function TestAlignmentStringEscapeErrors (line 339) | func TestAlignmentStringEscapeErrors(t *testing.T) {
  function TestAlignmentStringAbandon (line 351) | func TestAlignmentStringAbandon(t *testing.T) {
  function TestAlignmentStringReplace (line 376) | func TestAlignmentStringReplace(t *testing.T) {
  function TestAlignmentNumberExclude (line 403) | func TestAlignmentNumberExclude(t *testing.T) {
  function TestAlignmentLineSingle (line 432) | func TestAlignmentLineSingle(t *testing.T) {
  function TestAlignmentCommentEatLine (line 449) | func TestAlignmentCommentEatLine(t *testing.T) {
  function TestAlignmentTextModify (line 472) | func TestAlignmentTextModify(t *testing.T) {
  function TestAlignmentListPropertyGuard (line 504) | func TestAlignmentListPropertyGuard(t *testing.T) {
  function TestAlignmentGrammarGTags (line 524) | func TestAlignmentGrammarGTags(t *testing.T) {
  function TestAlignmentExclude (line 657) | func TestAlignmentExclude(t *testing.T) {
  function TestAlignmentResultFail (line 701) | func TestAlignmentResultFail(t *testing.T) {
  function TestAlignmentParsePrepare (line 728) | func TestAlignmentParsePrepare(t *testing.T) {
  function TestAlignmentEmptyDisabled (line 751) | func TestAlignmentEmptyDisabled(t *testing.T) {
  function TestAlignmentCustomValues (line 762) | func TestAlignmentCustomValues(t *testing.T) {
  function TestAlignmentDeepOptions (line 792) | func TestAlignmentDeepOptions(t *testing.T) {
  function TestAlignmentDeepOptionsPointer (line 833) | func TestAlignmentDeepOptionsPointer(t *testing.T) {
  function TestAlignmentDeepUndefined (line 872) | func TestAlignmentDeepUndefined(t *testing.T) {
  function TestAlignmentModListOrder (line 895) | func TestAlignmentModListOrder(t *testing.T) {
  function TestAlignmentNumberFixedToken (line 919) | func TestAlignmentNumberFixedToken(t *testing.T) {
  function TestAlignmentLexSubscriber (line 947) | func TestAlignmentLexSubscriber(t *testing.T) {
  function TestAlignmentRuleSubscriberTiming (line 965) | func TestAlignmentRuleSubscriberTiming(t *testing.T) {
  function TestAlignmentErrorPropagation (line 989) | func TestAlignmentErrorPropagation(t *testing.T) {
  function TestAlignmentTrailingContent (line 1020) | func TestAlignmentTrailingContent(t *testing.T) {
  function TestAlignmentFinishRuleFalse (line 1033) | func TestAlignmentFinishRuleFalse(t *testing.T) {
  function TestAlignmentSnip (line 1045) | func TestAlignmentSnip(t *testing.T) {
  function TestAlignmentStrNil (line 1070) | func TestAlignmentStrNil(t *testing.T) {
  function TestAlignmentStrWhitespace (line 1078) | func TestAlignmentStrWhitespace(t *testing.T) {
  function TestAlignmentStrTruncateWhitespace (line 1086) | func TestAlignmentStrTruncateWhitespace(t *testing.T) {
  function TestAlignmentModListCustom (line 1096) | func TestAlignmentModListCustom(t *testing.T) {
  function TestAlignmentModListCustomNil (line 1116) | func TestAlignmentModListCustomNil(t *testing.T) {
  function TestAlignmentModListDeleteThenCustom (line 1130) | func TestAlignmentModListDeleteThenCustom(t *testing.T) {

FILE: go/both_ref_test.go
  function expectBothRef (line 8) | func expectBothRef(t *testing.T, input string, expected any) {
  function bothRefEqual (line 23) | func bothRefEqual(a, b any) bool {
  function blr (line 130) | func blr(implicit bool, vals ...any) ListRef {
  function bmr (line 138) | func bmr(implicit bool, pairs ...any) MapRef {
  function TestBothRefExplicitMapExplicitList (line 149) | func TestBothRefExplicitMapExplicitList(t *testing.T) {
  function TestBothRefImplicitMapExplicitList (line 154) | func TestBothRefImplicitMapExplicitList(t *testing.T) {
  function TestBothRefExplicitListExplicitMaps (line 159) | func TestBothRefExplicitListExplicitMaps(t *testing.T) {
  function TestBothRefImplicitListExplicitMaps (line 167) | func TestBothRefImplicitListExplicitMaps(t *testing.T) {
  function TestBothRefSpaceSeparatedMaps (line 175) | func TestBothRefSpaceSeparatedMaps(t *testing.T) {
  function TestBothRefEmptyMapInList (line 185) | func TestBothRefEmptyMapInList(t *testing.T) {
  function TestBothRefEmptyListInMap (line 190) | func TestBothRefEmptyListInMap(t *testing.T) {
  function TestBothRefEmptyMapAndListValues (line 195) | func TestBothRefEmptyMapAndListValues(t *testing.T) {
  function TestBothRefTripleNestingMapListMap (line 202) | func TestBothRefTripleNestingMapListMap(t *testing.T) {
  function TestBothRefTripleNestingListMapList (line 209) | func TestBothRefTripleNestingListMapList(t *testing.T) {
  function TestBothRefQuadNesting (line 216) | func TestBothRefQuadNesting(t *testing.T) {
  function TestBothRefPathDive (line 227) | func TestBothRefPathDive(t *testing.T) {
  function TestBothRefPathDiveWithList (line 232) | func TestBothRefPathDiveWithList(t *testing.T) {
  function TestBothRefExplicitPathDive (line 237) | func TestBothRefExplicitPathDive(t *testing.T) {
  function TestBothRefDeepMergeNestedMapLists (line 244) | func TestBothRefDeepMergeNestedMapLists(t *testing.T) {
  function TestBothRefDeepMergeNestedMaps (line 251) | func TestBothRefDeepMergeNestedMaps(t *testing.T) {
  function TestBothRefDeepMergeMapsWithListValues (line 258) | func TestBothRefDeepMergeMapsWithListValues(t *testing.T) {
  function TestBothRefMapWithMixedValues (line 267) | func TestBothRefMapWithMixedValues(t *testing.T) {
  function TestBothRefListWithMixedValues (line 276) | func TestBothRefListWithMixedValues(t *testing.T) {
  function TestBothRefImplicitListOfImplicitListsInMaps (line 287) | func TestBothRefImplicitListOfImplicitListsInMaps(t *testing.T) {
  function TestBothRefScalarNumber (line 322) | func TestBothRefScalarNumber(t *testing.T) {
  function TestBothRefScalarString (line 333) | func TestBothRefScalarString(t *testing.T) {
  function TestBothRefScalarBool (line 344) | func TestBothRefScalarBool(t *testing.T) {
  function TestBothRefScalarNull (line 355) | func TestBothRefScalarNull(t *testing.T) {
  function TestBothRefPairInList (line 368) | func TestBothRefPairInList(t *testing.T) {
  function TestBothRefStrictJSON (line 386) | func TestBothRefStrictJSON(t *testing.T) {
  function TestBothRefNestedJSONArrays (line 394) | func TestBothRefNestedJSONArrays(t *testing.T) {
  function TestBothRefImplicitListMapsWithLists (line 403) | func TestBothRefImplicitListMapsWithLists(t *testing.T) {
  function TestBothRefDeepMergePreservesMapRef (line 413) | func TestBothRefDeepMergePreservesMapRef(t *testing.T) {
  function TestBothRefDeepMergePreservesListRef (line 422) | func TestBothRefDeepMergePreservesListRef(t *testing.T) {
  function TestBothRefWithTextInfo (line 431) | func TestBothRefWithTextInfo(t *testing.T) {
  function TestBothRefCommaSeparatedLists (line 470) | func TestBothRefCommaSeparatedLists(t *testing.T) {
  function TestBothRefNullMapValue (line 480) | func TestBothRefNullMapValue(t *testing.T) {
  function TestBothRefNullListElements (line 485) | func TestBothRefNullListElements(t *testing.T) {
  function TestBothRefMapWithNullAndList (line 490) | func TestBothRefMapWithNullAndList(t *testing.T) {
  function TestMapRefMetaInitialized (line 497) | func TestMapRefMetaInitialized(t *testing.T) {
  function TestListRefMetaInitialized (line 516) | func TestListRefMetaInitialized(t *testing.T) {
  function TestMapRefMetaAvailableInBOPhase (line 535) | func TestMapRefMetaAvailableInBOPhase(t *testing.T) {
  function TestListRefMetaAvailableInBOPhase (line 562) | func TestListRefMetaAvailableInBOPhase(t *testing.T) {

FILE: go/color_test.go
  function TestColorDefaultsActive (line 10) | func TestColorDefaultsActive(t *testing.T) {
  function TestColorActiveWrapsHeader (line 33) | func TestColorActiveWrapsHeader(t *testing.T) {
  function TestColorActiveWrapsArrow (line 48) | func TestColorActiveWrapsArrow(t *testing.T) {
  function TestColorActiveWrapsCaret (line 62) | func TestColorActiveWrapsCaret(t *testing.T) {
  function TestColorDisabledSuppressesAll (line 80) | func TestColorDisabledSuppressesAll(t *testing.T) {
  function TestColorCustomOverrides (line 102) | func TestColorCustomOverrides(t *testing.T) {
  function TestColorToggleViaSetOptions (line 131) | func TestColorToggleViaSetOptions(t *testing.T) {
  function TestColorFromTextDisable (line 148) | func TestColorFromTextDisable(t *testing.T) {
  function TestColorFromTextCustomCodes (line 162) | func TestColorFromTextCustomCodes(t *testing.T) {
  function TestColorAppliesToLexerError (line 189) | func TestColorAppliesToLexerError(t *testing.T) {

FILE: go/comment_suffix_test.go
  function TestCommentLineSuffixSingleString (line 10) | func TestCommentLineSuffixSingleString(t *testing.T) {
  function TestCommentLineSuffixMultiple (line 33) | func TestCommentLineSuffixMultiple(t *testing.T) {
  function TestCommentLineSuffixPreferredLongestFirst (line 53) | func TestCommentLineSuffixPreferredLongestFirst(t *testing.T) {
  function TestCommentLineSuffixIsConsumed (line 77) | func TestCommentLineSuffixIsConsumed(t *testing.T) {
  function TestCommentLineSuffixFallsBackToNewline (line 98) | func TestCommentLineSuffixFallsBackToNewline(t *testing.T) {
  function TestCommentLineSuffixBeatsEatLine (line 119) | func TestCommentLineSuffixBeatsEatLine(t *testing.T) {
  function TestCommentBlockSuffixEarlyTermination (line 149) | func TestCommentBlockSuffixEarlyTermination(t *testing.T) {
  function TestCommentBlockSuffixStillHonoursEnd (line 176) | func TestCommentBlockSuffixStillHonoursEnd(t *testing.T) {
  function TestCommentBlockSuffixLosesToEndWhenCloser (line 198) | func TestCommentBlockSuffixLosesToEndWhenCloser(t *testing.T) {
  function TestCommentSuffixLexMatcherTerminates (line 226) | func TestCommentSuffixLexMatcherTerminates(t *testing.T) {
  function TestCommentSuffixLexMatcherCannotAdvance (line 252) | func TestCommentSuffixLexMatcherCannotAdvance(t *testing.T) {
  function TestCommentSuffixFromTextString (line 282) | func TestCommentSuffixFromTextString(t *testing.T) {
  function TestCommentSuffixFromTextArray (line 304) | func TestCommentSuffixFromTextArray(t *testing.T) {
  function TestNormalizeCommentSuffixStringForms (line 327) | func TestNormalizeCommentSuffixStringForms(t *testing.T) {
  function TestNormalizeCommentSuffixNilAndEmpty (line 343) | func TestNormalizeCommentSuffixNilAndEmpty(t *testing.T) {

FILE: go/csv_grammar_test.go
  function makeCSV (line 13) | func makeCSV() *Jsonic {
  function runCSV (line 137) | func runCSV(t *testing.T, name, src string, want []any) {
  function TestCSVEmptyInput (line 150) | func TestCSVEmptyInput(t *testing.T) {
  function TestCSVSingleRow (line 154) | func TestCSVSingleRow(t *testing.T) {
  function TestCSVMultipleRows (line 159) | func TestCSVMultipleRows(t *testing.T) {
  function TestCSVTrailingNewline (line 164) | func TestCSVTrailingNewline(t *testing.T) {
  function TestCSVBlankLinesSkipped (line 169) | func TestCSVBlankLinesSkipped(t *testing.T) {
  function TestCSVNumbersParsed (line 174) | func TestCSVNumbersParsed(t *testing.T) {
  function TestCSVQuotedStrings (line 179) | func TestCSVQuotedStrings(t *testing.T) {
  function TestCSVMixedTypes (line 184) | func TestCSVMixedTypes(t *testing.T) {
  function TestCSVEmptyLeadingField (line 189) | func TestCSVEmptyLeadingField(t *testing.T) {
  function TestCSVEmptyMiddleField (line 194) | func TestCSVEmptyMiddleField(t *testing.T) {
  function TestCSVEmptyTrailingField (line 199) | func TestCSVEmptyTrailingField(t *testing.T) {
  function TestCSVSingleCellRow (line 204) | func TestCSVSingleCellRow(t *testing.T) {
  function TestCSVKeywords (line 209) | func TestCSVKeywords(t *testing.T) {

FILE: go/debug.go
  function addTrace (line 29) | func addTrace(j *Jsonic) {
  function Describe (line 44) | func Describe(j *Jsonic) string {

FILE: go/directive_grammar_test.go
  function defineDirective (line 16) | func defineDirective(j *Jsonic, name, open string, action func(any) any) {
  function makeDirectiveJ (line 43) | func makeDirectiveJ() *Jsonic {
  function runDirective (line 54) | func runDirective(t *testing.T, name, src string, want any) {
  function TestDirectiveUpperString (line 67) | func TestDirectiveUpperString(t *testing.T) {
  function TestDirectiveUpperBare (line 71) | func TestDirectiveUpperBare(t *testing.T) {
  function TestDirectiveUpperNumber (line 75) | func TestDirectiveUpperNumber(t *testing.T) {
  function TestDirectiveWrapNumber (line 79) | func TestDirectiveWrapNumber(t *testing.T) {
  function TestDirectiveWrapKeyword (line 84) | func TestDirectiveWrapKeyword(t *testing.T) {
  function TestDirectiveInList (line 89) | func TestDirectiveInList(t *testing.T) {
  function TestDirectiveInMap (line 94) | func TestDirectiveInMap(t *testing.T) {
  function TestDirectiveNested (line 102) | func TestDirectiveNested(t *testing.T) {
  function TestDirectiveWrappingList (line 107) | func TestDirectiveWrappingList(t *testing.T) {
  function TestDirectiveWrappingMap (line 112) | func TestDirectiveWrappingMap(t *testing.T) {

FILE: go/feature_tsv_test.go
  function stripRefs (line 13) | func stripRefs(v any) any {
  function runParserTSV (line 52) | func runParserTSV(t *testing.T, file string, j *Jsonic) {
  function runListChildTSV (line 91) | func runListChildTSV(t *testing.T, file string, j *Jsonic) {
  function TestTSVFeatureListChild (line 156) | func TestTSVFeatureListChild(t *testing.T) {
  function TestTSVFeatureListChildDeep (line 163) | func TestTSVFeatureListChildDeep(t *testing.T) {
  function TestTSVFeatureListChildPair (line 170) | func TestTSVFeatureListChildPair(t *testing.T) {
  function TestTSVFeatureListChildPairDeep (line 180) | func TestTSVFeatureListChildPairDeep(t *testing.T) {
  function TestTSVFeatureListPair (line 190) | func TestTSVFeatureListPair(t *testing.T) {
  function TestTSVFeatureMapChild (line 197) | func TestTSVFeatureMapChild(t *testing.T) {
  function TestTSVFeatureMapChildDeep (line 204) | func TestTSVFeatureMapChildDeep(t *testing.T) {
  function TestStripRefsBasic (line 215) | func TestStripRefsBasic(t *testing.T) {

FILE: go/fnref_identity_test.go
  function TestFnrefDedupeByFunctionIdentity (line 8) | func TestFnrefDedupeByFunctionIdentity(t *testing.T) {

FILE: go/fnref_reinstall_test.go
  function TestFnrefNoReinstallOnSubsequentCall (line 10) | func TestFnrefNoReinstallOnSubsequentCall(t *testing.T) {

FILE: go/grammar.go
  function buildGrammar (line 6) | func buildGrammar(rsm map[string]*RuleSpec, cfg *LexConfig) {
  function nodeListAppend (line 556) | func nodeListAppend(node any, val any) any {
  function nodeListVal (line 568) | func nodeListVal(node any) ([]any, bool) {
  function nodeListSetVal (line 579) | func nodeListSetVal(node any, arr []any) any {
  function nodeMapSet (line 588) | func nodeMapSet(node any, key any, val any) {
  function nodeMapGet (line 598) | func nodeMapGet(node any, key any) (any, bool) {
  function nodeMapGetVal (line 612) | func nodeMapGetVal(node any, key any) any {

FILE: go/grammar_decl_test.go
  function mustGrammar (line 11) | func mustGrammar(t *testing.T, j *Jsonic, gs *GrammarSpec) {
  function TestSkipSentinel (line 20) | func TestSkipSentinel(t *testing.T) {
  function TestSkipInDeepMerge (line 32) | func TestSkipInDeepMerge(t *testing.T) {
  function TestSkipInDeepMergeArray (line 45) | func TestSkipInDeepMergeArray(t *testing.T) {
  function TestResolveFuncRefsAtEscape (line 57) | func TestResolveFuncRefsAtEscape(t *testing.T) {
  function TestResolveFuncRefsAtSkip (line 64) | func TestResolveFuncRefsAtSkip(t *testing.T) {
  function TestResolveFuncRefsRegex (line 71) | func TestResolveFuncRefsRegex(t *testing.T) {
  function TestResolveFuncRefsRegexNoFlags (line 85) | func TestResolveFuncRefsRegexNoFlags(t *testing.T) {
  function TestResolveFuncRefsFuncLookup (line 99) | func TestResolveFuncRefsFuncLookup(t *testing.T) {
  function TestResolveFuncRefsNestedMap (line 109) | func TestResolveFuncRefsNestedMap(t *testing.T) {
  function TestResolveFuncRefsArray (line 136) | func TestResolveFuncRefsArray(t *testing.T) {
  function TestGrammarOptionsValueDef (line 154) | func TestGrammarOptionsValueDef(t *testing.T) {
  function TestGrammarOptionsNumberHex (line 179) | func TestGrammarOptionsNumberHex(t *testing.T) {
  function TestGrammarOptionsNumberSep (line 198) | func TestGrammarOptionsNumberSep(t *testing.T) {
  function TestGrammarRuleConditionFuncRef (line 218) | func TestGrammarRuleConditionFuncRef(t *testing.T) {
  function TestGrammarRuleConditionFalseSkips (line 258) | func TestGrammarRuleConditionFalseSkips(t *testing.T) {
  function TestGrammarOptionsAndRulesCombined (line 290) | func TestGrammarOptionsAndRulesCombined(t *testing.T) {
  function TestGrammarMultipleCalls (line 330) | func TestGrammarMultipleCalls(t *testing.T) {
  function TestGrammarOptionsOnly (line 366) | func TestGrammarOptionsOnly(t *testing.T) {
  function TestGrammarRulesOnly (line 384) | func TestGrammarRulesOnly(t *testing.T) {
  function TestResolveTokenSpecStatic (line 416) | func TestResolveTokenSpecStatic(t *testing.T) {
  function TestResolveTokenFieldStaticSlice (line 436) | func TestResolveTokenFieldStaticSlice(t *testing.T) {
  function TestGrammarStateActionWiring (line 462) | func TestGrammarStateActionWiring(t *testing.T) {
  function TestGrammarDeclarativeCondition (line 488) | func TestGrammarDeclarativeCondition(t *testing.T) {
  function TestGrammarFixedToken (line 518) | func TestGrammarFixedToken(t *testing.T) {
  function TestGrammarMissingFuncRefReturnsError (line 553) | func TestGrammarMissingFuncRefReturnsError(t *testing.T) {
  function TestGrammarInjectAppend (line 575) | func TestGrammarInjectAppend(t *testing.T) {
  function TestGrammarInjectPrepend (line 607) | func TestGrammarInjectPrepend(t *testing.T) {
  function TestGrammarOptionsMapMerge (line 649) | func TestGrammarOptionsMapMerge(t *testing.T) {
  function TestGrammarOptionsMapValueDef (line 680) | func TestGrammarOptionsMapValueDef(t *testing.T) {
  function TestGrammarOptionsMapSkip (line 705) | func TestGrammarOptionsMapSkip(t *testing.T) {
  function TestGrammarOptionsMapAtEscape (line 729) | func TestGrammarOptionsMapAtEscape(t *testing.T) {
  function TestSetOptionsPreservesRuleModifications (line 744) | func TestSetOptionsPreservesRuleModifications(t *testing.T) {
  function TestSetOptionsPreservesGrammarModifications (line 787) | func TestSetOptionsPreservesGrammarModifications(t *testing.T) {
  function TestRuleThenOptionsThenParse (line 822) | func TestRuleThenOptionsThenParse(t *testing.T) {
  function TestGrammarRegexNumberExclude (line 867) | func TestGrammarRegexNumberExclude(t *testing.T) {
  function TestGrammarRegexNumberExcludeTyped (line 907) | func TestGrammarRegexNumberExcludeTyped(t *testing.T) {
  function TestGrammarRegexValueMatch (line 932) | func TestGrammarRegexValueMatch(t *testing.T) {
  function TestGrammarRegexValueMatchTyped (line 978) | func TestGrammarRegexValueMatchTyped(t *testing.T) {
  function TestGrammarRegexWithFlags (line 1013) | func TestGrammarRegexWithFlags(t *testing.T) {
  function TestGrammarRegexNoFlags (line 1058) | func TestGrammarRegexNoFlags(t *testing.T) {
  function TestGrammarRegexMixedWithFuncref (line 1097) | func TestGrammarRegexMixedWithFuncref(t *testing.T) {
  function TestGrammarRegexInArray (line 1152) | func TestGrammarRegexInArray(t *testing.T) {
  function TestGrammarRegexEscapeAtPrefix (line 1190) | func TestGrammarRegexEscapeAtPrefix(t *testing.T) {
  function TestGrammarRegexMatchToken (line 1205) | func TestGrammarRegexMatchToken(t *testing.T) {
  function TestGrammarRegexMatchTokenTyped (line 1242) | func TestGrammarRegexMatchTokenTyped(t *testing.T) {
  function TestGrammarRegexMatchValue (line 1271) | func TestGrammarRegexMatchValue(t *testing.T) {
  function TestGrammarRegexMatchValueTyped (line 1303) | func TestGrammarRegexMatchValueTyped(t *testing.T) {
  function TestResolveFuncRefsRegexInNestedMap (line 1336) | func TestResolveFuncRefsRegexInNestedMap(t *testing.T) {
  function TestResolveFuncRefsRegexInSlice (line 1365) | func TestResolveFuncRefsRegexInSlice(t *testing.T) {
  function TestMatchTokenNilRegexpNoPanic (line 1386) | func TestMatchTokenNilRegexpNoPanic(t *testing.T) {
  function TestGrammarTextNumberSep (line 1414) | func TestGrammarTextNumberSep(t *testing.T) {
  function TestGrammarTextNumberExclude (line 1430) | func TestGrammarTextNumberExclude(t *testing.T) {
  function TestGrammarTextFlatOptions (line 1446) | func TestGrammarTextFlatOptions(t *testing.T) {
  function TestGrammarTextOptionsAndRules (line 1463) | func TestGrammarTextOptionsAndRules(t *testing.T) {
  function TestGrammarTextRulesWithFuncRef (line 1490) | func TestGrammarTextRulesWithFuncRef(t *testing.T) {
  function TestGrammarTextWithInjectAndExclude (line 1522) | func TestGrammarTextWithInjectAndExclude(t *testing.T) {
  function TestExcludeCommaTrailingComma (line 1567) | func TestExcludeCommaTrailingComma(t *testing.T) {
  function TestGrammarTextThenSetOptionsPreserved (line 1598) | func TestGrammarTextThenSetOptionsPreserved(t *testing.T) {
  function TestGrammarTextInvalidSource (line 1645) | func TestGrammarTextInvalidSource(t *testing.T) {
  function TestGrammarTextRuleExclude (line 1656) | func TestGrammarTextRuleExclude(t *testing.T) {
  function TestGrammarTextTextLex (line 1678) | func TestGrammarTextTextLex(t *testing.T) {
  function TestGrammarTextLexEmpty (line 1695) | func TestGrammarTextLexEmpty(t *testing.T) {
  function TestMapToOptionsListChild (line 1707) | func TestMapToOptionsListChild(t *testing.T) {
  function TestMapToOptionsMapChild (line 1723) | func TestMapToOptionsMapChild(t *testing.T) {
  function TestMapToOptionsEnder (line 1737) | func TestMapToOptionsEnder(t *testing.T) {
  function TestSetOptionsLexEmpty (line 1747) | func TestSetOptionsLexEmpty(t *testing.T) {
  function TestTextLexFalseValueKeywordsStillWork (line 1784) | func TestTextLexFalseValueKeywordsStillWork(t *testing.T) {
  function TestTextLexFalseCustomValueDef (line 1813) | func TestTextLexFalseCustomValueDef(t *testing.T) {
  function TestGroupTagsValidFormat (line 1841) | func TestGroupTagsValidFormat(t *testing.T) {
  function TestSetOptionsRuleExclude (line 1873) | func TestSetOptionsRuleExclude(t *testing.T) {
  function TestGrammarLexEmpty (line 1907) | func TestGrammarLexEmpty(t *testing.T) {
  function TestInfoMarkerKeyDropped (line 1923) | func TestInfoMarkerKeyDropped(t *testing.T) {
  function TestInfoMarkerKeyDroppedJSON (line 1942) | func TestInfoMarkerKeyDroppedJSON(t *testing.T) {
  function TestInfoMarkerKeyNotDroppedWhenOff (line 1955) | func TestInfoMarkerKeyNotDroppedWhenOff(t *testing.T) {
  function TestValueDefReUsesValWhenValFuncNil (line 1970) | func TestValueDefReUsesValWhenValFuncNil(t *testing.T) {
  function TestMatchValueNilSpecNoPanic (line 2006) | func TestMatchValueNilSpecNoPanic(t *testing.T) {

FILE: go/grammar_setting_test.go
  function altGTags (line 14) | func altGTags(t *testing.T, j *Jsonic, rulename, state string) [][]string {
  function containsTagSet (line 43) | func containsTagSet(tagSets [][]string, want []string) bool {
  function TestGrammarSettingAltGStringAppended (line 65) | func TestGrammarSettingAltGStringAppended(t *testing.T) {
  function TestGrammarSettingAltGArrayAppended (line 94) | func TestGrammarSettingAltGArrayAppended(t *testing.T) {
  function TestGrammarSettingNilIsNoop (line 120) | func TestGrammarSettingNilIsNoop(t *testing.T) {
  function TestGrammarSettingEmptyGIsNoop (line 139) | func TestGrammarSettingEmptyGIsNoop(t *testing.T) {
  function TestGrammarSettingPreservesInput (line 157) | func TestGrammarSettingPreservesInput(t *testing.T) {
  function TestGrammarSettingInjectFormApplied (line 181) | func TestGrammarSettingInjectFormApplied(t *testing.T) {
  function TestGrammarTextSettingAppendsTags (line 207) | func TestGrammarTextSettingAppendsTags(t *testing.T) {
  function TestValidateGroupTagsRejects (line 236) | func TestValidateGroupTagsRejects(t *testing.T) {
  function TestValidateGroupTagsAccepts (line 246) | func TestValidateGroupTagsAccepts(t *testing.T) {
  function TestNormAltReturnsErrorOnInvalidTag (line 259) | func TestNormAltReturnsErrorOnInvalidTag(t *testing.T) {
  function TestGrammarInvalidGTagReturnsError (line 269) | func TestGrammarInvalidGTagReturnsError(t *testing.T) {
  function TestGrammarSettingInvalidTagReturnsError (line 285) | func TestGrammarSettingInvalidTagReturnsError(t *testing.T) {
  function TestSetOptionsTextBasic (line 305) | func TestSetOptionsTextBasic(t *testing.T) {
  function TestSetOptionsTextEmptyIsNoop (line 319) | func TestSetOptionsTextEmptyIsNoop(t *testing.T) {
  function TestSetOptionsTextMergesWithSetOptions (line 333) | func TestSetOptionsTextMergesWithSetOptions(t *testing.T) {
  function TestSetOptionsTextInvalidSource (line 360) | func TestSetOptionsTextInvalidSource(t *testing.T) {
  function TestSetOptionsTextReturnsInstance (line 369) | func TestSetOptionsTextReturnsInstance(t *testing.T) {

FILE: go/grammarspec.go
  type GrammarSpec (line 14) | type GrammarSpec struct
  type GrammarRuleSpec (line 34) | type GrammarRuleSpec struct
  type GrammarAltListSpec (line 40) | type GrammarAltListSpec struct
  type GrammarInjectSpec (line 46) | type GrammarInjectSpec struct
  type GrammarSetting (line 58) | type GrammarSetting struct
  type GrammarSettingRule (line 63) | type GrammarSettingRule struct
  type GrammarSettingAlt (line 69) | type GrammarSettingAlt struct
  type GrammarAltSpec (line 76) | type GrammarAltSpec struct
  method Grammar (line 100) | func (j *Jsonic) Grammar(gs *GrammarSpec, setting ...*GrammarSetting) er...
  function extractSettingAltG (line 156) | func extractSettingAltG(setting []*GrammarSetting) []string {
  function splitGroupTags (line 180) | func splitGroupTags(s string) []string {
  function mergeG (line 197) | func mergeG(existing string, extra []string) string {
  method GrammarText (line 216) | func (j *Jsonic) GrammarText(text string, setting ...*GrammarSetting) er...
  function mapToGrammarRules (line 242) | func mapToGrammarRules(ruleMap map[string]any) map[string]*GrammarRuleSp...
  function parseGrammarAltsOrSpec (line 264) | func parseGrammarAltsOrSpec(v any) any {
  function parseGrammarAlts (line 307) | func parseGrammarAlts(arr []any) []*GrammarAltSpec {
  function mapToGrammarAltSpec (line 321) | func mapToGrammarAltSpec(m map[string]any) *GrammarAltSpec {
  function applyGrammarAlts (line 370) | func applyGrammarAlts(j *Jsonic, rs *RuleSpec, spec any, ref map[FuncRef...
  method resolveGrammarAlts (line 428) | func (j *Jsonic) resolveGrammarAlts(gas []*GrammarAltSpec, ref map[FuncR...
  method resolveGrammarAlt (line 441) | func (j *Jsonic) resolveGrammarAlt(ga *GrammarAltSpec, ref map[FuncRef]a...
  method resolveTokenField (line 591) | func (j *Jsonic) resolveTokenField(s any) [][]Tin {
  method resolveTokenSpec (line 614) | func (j *Jsonic) resolveTokenSpec(s string) [][]Tin {
  method resolveTokenName (line 627) | func (j *Jsonic) resolveTokenName(name string) []Tin {
  function wireStateActions (line 646) | func wireStateActions(rs *RuleSpec, ref map[FuncRef]any) {
  function resolveTokenFieldStatic (line 718) | func resolveTokenFieldStatic(s any) [][]Tin {
  function resolveTokenSpecStatic (line 740) | func resolveTokenSpecStatic(s string) [][]Tin {
  function resolveTokenNameStatic (line 752) | func resolveTokenNameStatic(name string) []Tin {
  function resolveGrammarAltStatic (line 770) | func resolveGrammarAltStatic(ga *GrammarAltSpec, ref map[FuncRef]any) *A...

FILE: go/jsonic.go
  constant Version (line 15) | Version = "0.1.22"
  type JsonicError (line 27) | type JsonicError struct
    method Error (line 54) | func (e *JsonicError) Error() string {
  function errsite (line 108) | func errsite(src, sub, msg string, row, col int, color ColorConfig) stri...
  function makeJsonicError (line 174) | func makeJsonicError(code, src, fullSource string, pos, row, col int) *J...
  function Parse (line 202) | func Parse(src string) (any, error) {
  function preprocessEscapes (line 209) | func preprocessEscapes(s string) string {

FILE: go/jsonic_nontsv_test.go
  function expectParse (line 16) | func expectParse(t *testing.T, input string, expected any) {
  function expectParseNil (line 30) | func expectParseNil(t *testing.T, input string) {
  function expectParseError (line 44) | func expectParseError(t *testing.T, input string) {
  function m (line 57) | func m(args ...any) map[string]any {
  function a (line 67) | func a(args ...any) []any {
  function TestCommentSingleLine (line 73) | func TestCommentSingleLine(t *testing.T) {
  function TestCommentMultiLine (line 89) | func TestCommentMultiLine(t *testing.T) {
  function TestNumberParsing (line 105) | func TestNumberParsing(t *testing.T) {
  function TestValueStandard (line 218) | func TestValueStandard(t *testing.T) {
  function TestValueStandardNullInMap (line 270) | func TestValueStandardNullInMap(t *testing.T) {
  function TestNullOrUndefined (line 277) | func TestNullOrUndefined(t *testing.T) {
  function TestValueText (line 306) | func TestValueText(t *testing.T) {
  function TestValueString (line 336) | func TestValueString(t *testing.T) {
  function TestMultilineString (line 402) | func TestMultilineString(t *testing.T) {
  function TestSingleChar (line 418) | func TestSingleChar(t *testing.T) {
  function TestImplicitList (line 441) | func TestImplicitList(t *testing.T) {
  function TestExtension (line 512) | func TestExtension(t *testing.T) {
  function TestFinishAutoClose (line 527) | func TestFinishAutoClose(t *testing.T) {
  function TestPropertyDive (line 536) | func TestPropertyDive(t *testing.T) {
  function TestSyntaxErrors (line 582) | func TestSyntaxErrors(t *testing.T) {
  function TestProcessComment (line 596) | func TestProcessComment(t *testing.T) {
  function TestNaN (line 605) | func TestNaN(t *testing.T) {
  function TestPlatformMismatch_ArrayProperties (line 619) | func TestPlatformMismatch_ArrayProperties(t *testing.T) {
  function TestPlatformMismatch_UndefinedVsNull (line 648) | func TestPlatformMismatch_UndefinedVsNull(t *testing.T) {
  function TestPlatformMismatch_NonStringInput (line 680) | func TestPlatformMismatch_NonStringInput(t *testing.T) {
  function TestErrorFormat (line 695) | func TestErrorFormat(t *testing.T) {
  function TestLexFlagCommentOff (line 836) | func TestLexFlagCommentOff(t *testing.T) {
  function TestLexFlagNumberOff (line 859) | func TestLexFlagNumberOff(t *testing.T) {
  function TestLexFlagStringOff (line 882) | func TestLexFlagStringOff(t *testing.T) {
  function TestLexFlagValueOff (line 905) | func TestLexFlagValueOff(t *testing.T) {
  function TestLexFlagSpaceOff (line 928) | func TestLexFlagSpaceOff(t *testing.T) {
  function TestLexFlagLineOff (line 951) | func TestLexFlagLineOff(t *testing.T) {
  function TestLexFlagCommentDefOff (line 974) | func TestLexFlagCommentDefOff(t *testing.T) {
  function TestLexFlagNumberHexOff (line 1013) | func TestLexFlagNumberHexOff(t *testing.T) {
  function TestDeepNesting (line 1050) | func TestDeepNesting(t *testing.T) {

FILE: go/jsonic_test.go
  type tsvRow (line 17) | type tsvRow struct
  function loadTSV (line 23) | func loadTSV(path string) ([]tsvRow, error) {
  function parseExpected (line 49) | func parseExpected(s string) (any, error) {
  function normalizeValue (line 63) | func normalizeValue(v any) any {
  function valuesEqual (line 89) | func valuesEqual(got, expected any) bool {
  function deepCompare (line 95) | func deepCompare(a, b any) bool {
  function formatValue (line 151) | func formatValue(v any) string {
  function specDir (line 163) | func specDir() string {
  function TestParserTSVFiles (line 198) | func TestParserTSVFiles(t *testing.T) {
  function TestUtilityDeep (line 237) | func TestUtilityDeep(t *testing.T) {
  function TestUtilityStr (line 285) | func TestUtilityStr(t *testing.T) {
  function TestUtilityStrInject (line 331) | func TestUtilityStrInject(t *testing.T) {
  function TestUtilityModList (line 366) | func TestUtilityModList(t *testing.T) {
  function formatArgs (line 435) | func formatArgs(args []any) string {

FILE: go/lexer.go
  type MatchValueEntry (line 13) | type MatchValueEntry struct
  type ValueDefEntry (line 22) | type ValueDefEntry struct
  type MatchTokenEntry (line 29) | type MatchTokenEntry struct
  type Lex (line 35) | type Lex struct
    method Cursor (line 313) | func (l *Lex) Cursor() *Point {
    method Token (line 318) | func (l *Lex) Token(name string, tin Tin, val any, src string) *Token {
    method Fwd (line 325) | func (l *Lex) Fwd(maxlen int) string {
    method Bad (line 339) | func (l *Lex) Bad(why string) *Token {
    method Next (line 351) | func (l *Lex) Next(rule ...*Rule) *Token {
    method nextRaw (line 397) | func (l *Lex) nextRaw(rule *Rule) *Token {
    method matchMatch (line 571) | func (l *Lex) matchMatch(rule *Rule) *Token {
    method bad (line 640) | func (l *Lex) bad(why string, pstart, pend int) *Token {
    method matchFixed (line 654) | func (l *Lex) matchFixed() *Token {
    method matchSpace (line 688) | func (l *Lex) matchSpace() *Token {
    method matchLine (line 707) | func (l *Lex) matchLine() *Token {
    method matchComment (line 753) | func (l *Lex) matchComment() *Token {
    method matchString (line 921) | func (l *Lex) matchString() *Token {
    method matchNumber (line 1147) | func (l *Lex) matchNumber() *Token {
    method matchText (line 1377) | func (l *Lex) matchText() *Token {
    method tinNameFor (line 1563) | func (l *Lex) tinNameFor(tin Tin) string {
    method isTextChar (line 1601) | func (l *Lex) isTextChar(pos int) bool {
    method isFollowingText (line 1641) | func (l *Lex) isFollowingText(pos int) bool {
  type LexConfig (line 46) | type LexConfig struct
    method SortFixedTokens (line 273) | func (cfg *LexConfig) SortFixedTokens() {
    method RebuildMatchTokensSorted (line 291) | func (cfg *LexConfig) RebuildMatchTokensSorted() {
  type ColorConfig (line 197) | type ColorConfig struct
    method Codes (line 208) | func (c ColorConfig) Codes() (hi, lo, line, reset string) {
  type LexCheck (line 217) | type LexCheck
  type LexCheckResult (line 220) | type LexCheckResult struct
  function DefaultLexConfig (line 226) | func DefaultLexConfig() *LexConfig {
  function NewLex (line 303) | func NewLex(src string, cfg *LexConfig) *Lex {
  function commentSuffixMatch (line 886) | func commentSuffixMatch(fwd string, fI int, suffixes []string) int {
  function commentSuffixFnMatch (line 904) | func commentSuffixFnMatch(lex *Lex, fI int, fn LexMatcher) int {
  function tinName (line 1572) | func tinName(tin Tin) string {
  function isDigit (line 1591) | func isDigit(ch byte) bool {
  function isHexDigitByte (line 1595) | func isHexDigitByte(ch byte) bool {
  function parseHexInt (line 1662) | func parseHexInt(s string) int {

FILE: go/listchild_test.go
  function makeChildParser (line 9) | func makeChildParser() *Jsonic {
  function expectChild (line 14) | func expectChild(t *testing.T, input string, expectedVal []any, expected...
  function TestListChildNumber (line 37) | func TestListChildNumber(t *testing.T) {
  function TestListChildString (line 42) | func TestListChildString(t *testing.T) {
  function TestListChildQuotedString (line 47) | func TestListChildQuotedString(t *testing.T) {
  function TestListChildTrue (line 52) | func TestListChildTrue(t *testing.T) {
  function TestListChildFalse (line 56) | func TestListChildFalse(t *testing.T) {
  function TestListChildNull (line 60) | func TestListChildNull(t *testing.T) {
  function TestListChildBareColon (line 64) | func TestListChildBareColon(t *testing.T) {
  function TestListChildMap (line 69) | func TestListChildMap(t *testing.T) {
  function TestListChildMapMultiKey (line 74) | func TestListChildMapMultiKey(t *testing.T) {
  function TestListChildEmptyMap (line 79) | func TestListChildEmptyMap(t *testing.T) {
  function TestListChildNestedMap (line 83) | func TestListChildNestedMap(t *testing.T) {
  function TestListChildList (line 87) | func TestListChildList(t *testing.T) {
  function TestListChildEmptyList (line 93) | func TestListChildEmptyList(t *testing.T) {
  function TestListChildNestedList (line 97) | func TestListChildNestedList(t *testing.T) {
  function TestListChildAfterElement (line 107) | func TestListChildAfterElement(t *testing.T) {
  function TestListChildBeforeElement (line 112) | func TestListChildBeforeElement(t *testing.T) {
  function TestListChildMiddle (line 117) | func TestListChildMiddle(t *testing.T) {
  function TestListChildAtEnd (line 122) | func TestListChildAtEnd(t *testing.T) {
  function TestListChildAtStartMultiple (line 127) | func TestListChildAtStartMultiple(t *testing.T) {
  function TestListChildMultipleScalars (line 134) | func TestListChildMultipleScalars(t *testing.T) {
  function TestListChildTripleScalars (line 139) | func TestListChildTripleScalars(t *testing.T) {
  function TestListChildMergeMaps (line 144) | func TestListChildMergeMaps(t *testing.T) {
  function TestListChildMergeThreeMaps (line 149) | func TestListChildMergeThreeMaps(t *testing.T) {
  function TestListChildDeepMergeMaps (line 154) | func TestListChildDeepMergeMaps(t *testing.T) {
  function TestListChildMergeDupKey (line 161) | func TestListChildMergeDupKey(t *testing.T) {
  function TestListChildWithPairProperty (line 168) | func TestListChildWithPairProperty(t *testing.T) {
  function TestListChildPathDive (line 186) | func TestListChildPathDive(t *testing.T) {
  function TestListChildDeepPathDive (line 191) | func TestListChildDeepPathDive(t *testing.T) {
  function TestListChildTrailingComma (line 198) | func TestListChildTrailingComma(t *testing.T) {
  function TestListChildElementThenChildTrailing (line 203) | func TestListChildElementThenChildTrailing(t *testing.T) {
  function TestListChildMultipleTrailing (line 208) | func TestListChildMultipleTrailing(t *testing.T) {
  function TestListChildLeadingCommaNull (line 215) | func TestListChildLeadingCommaNull(t *testing.T) {
  function TestListChildDoubleLeadingComma (line 220) | func TestListChildDoubleLeadingComma(t *testing.T) {
  function TestListChildNone (line 227) | func TestListChildNone(t *testing.T) {
  function TestListChildEmptyBrackets (line 232) | func TestListChildEmptyBrackets(t *testing.T) {
  function TestListChildMapElementThenChild (line 239) | func TestListChildMapElementThenChild(t *testing.T) {
  function TestListChildBeforeMapElement (line 244) | func TestListChildBeforeMapElement(t *testing.T) {
  function TestListChildListElement (line 249) | func TestListChildListElement(t *testing.T) {
  function TestListChildBeforeListElement (line 254) | func TestListChildBeforeListElement(t *testing.T) {
  function TestListChildMapAroundChild (line 259) | func TestListChildMapAroundChild(t *testing.T) {
  function TestListChildBareColonThenElement (line 266) | func TestListChildBareColonThenElement(t *testing.T) {
  function TestListChildElementThenBareColon (line 271) | func TestListChildElementThenBareColon(t *testing.T) {
  function TestListChildInterleaved (line 278) | func TestListChildInterleaved(t *testing.T) {
  function TestListChildMultiInterleaved (line 283) | func TestListChildMultiInterleaved(t *testing.T) {
  function TestListChildAutoEnablesListRef (line 290) | func TestListChildAutoEnablesListRef(t *testing.T) {
  function TestListChildDisabledDefault (line 304) | func TestListChildDisabledDefault(t *testing.T) {
  function TestListChildWithMapRef (line 318) | func TestListChildWithMapRef(t *testing.T) {
  function TestListChildWithTextInfo (line 343) | func TestListChildWithTextInfo(t *testing.T) {
  function TestListChildExplicitBrackets (line 368) | func TestListChildExplicitBrackets(t *testing.T) {
  function TestListChildNoExtend (line 382) | func TestListChildNoExtend(t *testing.T) {

FILE: go/listref_test.go
  function expectListRef (line 8) | func expectListRef(t *testing.T, input string, expected any) {
  function listRefEqual (line 23) | func listRefEqual(a, b any) bool {
  function lr (line 99) | func lr(implicit bool, vals ...any) ListRef {
  function TestListRefOff (line 106) | func TestListRefOff(t *testing.T) {
  function TestListRefExplicitOff (line 118) | func TestListRefExplicitOff(t *testing.T) {
  function TestListRefExplicitList (line 130) | func TestListRefExplicitList(t *testing.T) {
  function TestListRefExplicitEmpty (line 135) | func TestListRefExplicitEmpty(t *testing.T) {
  function TestListRefImplicitComma (line 140) | func TestListRefImplicitComma(t *testing.T) {
  function TestListRefImplicitTrailingComma (line 145) | func TestListRefImplicitTrailingComma(t *testing.T) {
  function TestListRefImplicitSpace (line 150) | func TestListRefImplicitSpace(t *testing.T) {
  function TestListRefImplicitLeadingComma (line 155) | func TestListRefImplicitLeadingComma(t *testing.T) {
  function TestListRefImplicitCommaOnly (line 160) | func TestListRefImplicitCommaOnly(t *testing.T) {
  function TestListRefNestedExplicit (line 165) | func TestListRefNestedExplicit(t *testing.T) {
  function TestListRefExplicitInMap (line 173) | func TestListRefExplicitInMap(t *testing.T) {
  function TestListRefMixedImplicitExplicit (line 180) | func TestListRefMixedImplicitExplicit(t *testing.T) {
  function TestListRefSpaceSeparatedLists (line 188) | func TestListRefSpaceSeparatedLists(t *testing.T) {
  function TestListRefMapsUnaffected (line 196) | func TestListRefMapsUnaffected(t *testing.T) {
  function TestListRefScalarsUnaffected (line 208) | func TestListRefScalarsUnaffected(t *testing.T) {
  function TestListRefDeepMerge (line 229) | func TestListRefDeepMerge(t *testing.T) {
  function TestListRefSpaceSeparatedMaps (line 237) | func TestListRefSpaceSeparatedMaps(t *testing.T) {
  function TestListRefWithNumbers (line 245) | func TestListRefWithNumbers(t *testing.T) {
  function TestListRefImplicitNullCommas (line 250) | func TestListRefImplicitNullCommas(t *testing.T) {
  function TestListRefSingleElement (line 256) | func TestListRefSingleElement(t *testing.T) {
  function TestListRefCombinedWithTextInfo (line 261) | func TestListRefCombinedWithTextInfo(t *testing.T) {

FILE: go/mapref_test.go
  function expectMapRef (line 8) | func expectMapRef(t *testing.T, input string, expected any) {
  function mapRefEqual (line 23) | func mapRefEqual(a, b any) bool {
  function mr (line 100) | func mr(implicit bool, pairs ...any) MapRef {
  function TestMapRefOff (line 109) | func TestMapRefOff(t *testing.T) {
  function TestMapRefExplicitOff (line 121) | func TestMapRefExplicitOff(t *testing.T) {
  function TestMapRefExplicitMap (line 133) | func TestMapRefExplicitMap(t *testing.T) {
  function TestMapRefExplicitEmpty (line 138) | func TestMapRefExplicitEmpty(t *testing.T) {
  function TestMapRefImplicitMap (line 143) | func TestMapRefImplicitMap(t *testing.T) {
  function TestMapRefImplicitMultipleKeys (line 148) | func TestMapRefImplicitMultipleKeys(t *testing.T) {
  function TestMapRefImplicitSpaceSeparated (line 153) | func TestMapRefImplicitSpaceSeparated(t *testing.T) {
  function TestMapRefNestedExplicit (line 158) | func TestMapRefNestedExplicit(t *testing.T) {
  function TestMapRefNestedImplicitInExplicit (line 163) | func TestMapRefNestedImplicitInExplicit(t *testing.T) {
  function TestMapRefListsUnaffected (line 168) | func TestMapRefListsUnaffected(t *testing.T) {
  function TestMapRefScalarsUnaffected (line 180) | func TestMapRefScalarsUnaffected(t *testing.T) {
  function TestMapRefDeepMerge (line 201) | func TestMapRefDeepMerge(t *testing.T) {
  function TestMapRefMapInList (line 206) | func TestMapRefMapInList(t *testing.T) {
  function TestMapRefWithStringValues (line 234) | func TestMapRefWithStringValues(t *testing.T) {
  function TestMapRefCombinedWithListRef (line 238) | func TestMapRefCombinedWithListRef(t *testing.T) {
  function TestMapRefCombinedWithTextInfo (line 264) | func TestMapRefCombinedWithTextInfo(t *testing.T) {
  function TestMapRefSingleKey (line 280) | func TestMapRefSingleKey(t *testing.T) {

FILE: go/nlookahead_test.go
  function TestNLookaheadThreeTokens (line 14) | func TestNLookaheadThreeTokens(t *testing.T) {
  function TestNLookaheadFiveTokensNoCap (line 53) | func TestNLookaheadFiveTokensNoCap(t *testing.T) {
  function TestNLookaheadFirstMatchWins (line 88) | func TestNLookaheadFirstMatchWins(t *testing.T) {
  function TestNLookaheadCtxTSlice (line 139) | func TestNLookaheadCtxTSlice(t *testing.T) {
  function TestNLookaheadNullMiddleSlotIsWildcard (line 187) | func TestNLookaheadNullMiddleSlotIsWildcard(t *testing.T) {
  function TestNLookaheadBacktrackN3 (line 234) | func TestNLookaheadBacktrackN3(t *testing.T) {

FILE: go/options.go
  type Options (line 12) | type Options struct
  type ColorOptions (line 103) | type ColorOptions struct
  type ErrMsgOptions (line 124) | type ErrMsgOptions struct
  type InfoOptions (line 141) | type InfoOptions struct
  type PropertyOptions (line 163) | type PropertyOptions struct
  type MatchOptions (line 171) | type MatchOptions struct
  type MatchValueSpec (line 183) | type MatchValueSpec struct
  type SafeOptions (line 189) | type SafeOptions struct
  type FixedOptions (line 194) | type FixedOptions struct
  type SpaceOptions (line 213) | type SpaceOptions struct
  type LineOptions (line 223) | type LineOptions struct
  type ValModifier (line 235) | type ValModifier
  type TextOptions (line 238) | type TextOptions struct
  type NumberOptions (line 248) | type NumberOptions struct
  type CommentDef (line 262) | type CommentDef struct
  type CommentOptions (line 289) | type CommentOptions struct
  type StringOptions (line 299) | type StringOptions struct
  type MapMergeFunc (line 316) | type MapMergeFunc
  type MapOptions (line 319) | type MapOptions struct
  type ListOptions (line 326) | type ListOptions struct
  type ValueDef (line 333) | type ValueDef struct
  type ValueOptions (line 352) | type ValueOptions struct
  type RuleOptions (line 358) | type RuleOptions struct
  type LexOptions (line 376) | type LexOptions struct
  type ParserOptions (line 386) | type ParserOptions struct
  type ParseOptions (line 391) | type ParseOptions struct
  type ResultOptions (line 400) | type ResultOptions struct
  type ConfigModifier (line 408) | type ConfigModifier
  type Jsonic (line 414) | type Jsonic struct
    method Decorate (line 437) | func (j *Jsonic) Decorate(name string, value any) *Jsonic {
    method Decoration (line 447) | func (j *Jsonic) Decoration(name string) any {
    method Id (line 456) | func (j *Jsonic) Id() string {
    method PluginOptions (line 462) | func (j *Jsonic) PluginOptions(name string) map[string]any {
    method SetPluginOptions (line 471) | func (j *Jsonic) SetPluginOptions(name string, opts map[string]any) {
    method Parse (line 642) | func (j *Jsonic) Parse(src string) (any, error) {
    method parseInternal (line 647) | func (j *Jsonic) parseInternal(src string, meta map[string]any) (any, ...
    method attachHint (line 667) | func (j *Jsonic) attachHint(err error) error {
    method Options (line 680) | func (j *Jsonic) Options() Options {
  function Make (line 487) | func Make(opts ...Options) *Jsonic {
  function Empty (line 601) | func Empty(opts ...Options) *Jsonic {
  function MakeJSON (line 615) | func MakeJSON() *Jsonic {
  function boolPtr (line 688) | func boolPtr(b bool) *bool {
  function intPtr (line 693) | func intPtr(i int) *int {
  function boolVal (line 698) | func boolVal(p *bool, def bool) bool {
  function buildConfig (line 706) | func buildConfig(o *Options) *LexConfig {
  function optBool (line 1041) | func optBool[T any](outer *T, getter func(*T) *bool) *bool {
  function runeSet (line 1049) | func runeSet(s string) map[rune]bool {
  function normalizeCommentSuffix (line 1063) | func normalizeCommentSuffix(raw any) ([]string, LexMatcher) {

FILE: go/options_parity_test.go
  function TestFixedCheckHookFires (line 9) | func TestFixedCheckHookFires(t *testing.T) {
  function TestSpaceCheckHookFires (line 25) | func TestSpaceCheckHookFires(t *testing.T) {
  function TestLineCheckHookFires (line 39) | func TestLineCheckHookFires(t *testing.T) {
  function TestTextCheckHookFires (line 53) | func TestTextCheckHookFires(t *testing.T) {
  function TestNumberCheckHookFires (line 67) | func TestNumberCheckHookFires(t *testing.T) {
  function TestStringCheckHookFires (line 81) | func TestStringCheckHookFires(t *testing.T) {
  function TestCommentCheckHookFires (line 95) | func TestCommentCheckHookFires(t *testing.T) {
  function TestLexCheckCanOverrideResult (line 109) | func TestLexCheckCanOverrideResult(t *testing.T) {
  function TestInfoMarkerDefault (line 123) | func TestInfoMarkerDefault(t *testing.T) {
  function TestInfoMarkerOverride (line 131) | func TestInfoMarkerOverride(t *testing.T) {
  function TestInfoMarkerFromText (line 139) | func TestInfoMarkerFromText(t *testing.T) {
  function TestParsePrepareHooksRunInOrder (line 152) | func TestParsePrepareHooksRunInOrder(t *testing.T) {
  function TestParsePrepareSkipsNil (line 167) | func TestParsePrepareSkipsNil(t *testing.T) {
  function TestMatchCheckHookFires (line 184) | func TestMatchCheckHookFires(t *testing.T) {
  function TestErrMsgSuffixRoundTripString (line 202) | func TestErrMsgSuffixRoundTripString(t *testing.T) {
  function TestErrMsgSuffixRoundTripBool (line 213) | func TestErrMsgSuffixRoundTripBool(t *testing.T) {

FILE: go/parser.go
  type Context (line 10) | type Context struct
  type Parser (line 49) | type Parser struct
    method Start (line 73) | func (p *Parser) Start(src string) (any, error) {
    method StartMeta (line 79) | func (p *Parser) StartMeta(src string, meta map[string]any, lexSubs []...
    method startParse (line 84) | func (p *Parser) startParse(src string, meta map[string]any, lexSubs [...
    method makeError (line 233) | func (p *Parser) makeError(code, src, fullSource string, pos, row, col...
  function NewParser (line 59) | func NewParser() *Parser {
  function parseNumericString (line 271) | func parseNumericString(s string) float64 {

FILE: go/plugin.go
  type Plugin (line 12) | type Plugin
  type LexMatcher (line 20) | type LexMatcher
  type MakeLexMatcher (line 25) | type MakeLexMatcher
  type MatchSpec (line 29) | type MatchSpec struct
  type MatcherEntry (line 38) | type MatcherEntry struct
  type RuleDefiner (line 48) | type RuleDefiner
  type LexSub (line 51) | type LexSub
  type RuleSub (line 54) | type RuleSub
  type pluginEntry (line 57) | type pluginEntry struct
  method Use (line 70) | func (j *Jsonic) Use(plugin Plugin, opts ...map[string]any) error {
  method UseDefaults (line 90) | func (j *Jsonic) UseDefaults(plugin Plugin, defaults map[string]any, opt...
  method Rule (line 115) | func (j *Jsonic) Rule(name string, definer RuleDefiner) *Jsonic {
  method Token (line 138) | func (j *Jsonic) Token(name string, src ...string) Tin {
  method FixedSrc (line 180) | func (j *Jsonic) FixedSrc(src string) Tin {
  method FixedTin (line 190) | func (j *Jsonic) FixedTin(tin Tin) string {
  method registerMatchSpecs (line 207) | func (j *Jsonic) registerMatchSpecs(opts *Options) {
  method applyFixedTokens (line 243) | func (j *Jsonic) applyFixedTokens(opts *Options) {
  method Plugins (line 277) | func (j *Jsonic) Plugins() []Plugin {
  method Config (line 287) | func (j *Jsonic) Config() *LexConfig {
  method RSM (line 292) | func (j *Jsonic) RSM() map[string]*RuleSpec {
  method TinName (line 297) | func (j *Jsonic) TinName(tin Tin) string {
  method TokenSet (line 309) | func (j *Jsonic) TokenSet(name string) []Tin {
  method SetTokenSet (line 345) | func (j *Jsonic) SetTokenSet(name string, tins []Tin) {
  method Sub (line 374) | func (j *Jsonic) Sub(lexSub LexSub, ruleSub RuleSub) *Jsonic {
  method Derive (line 387) | func (j *Jsonic) Derive(opts ...Options) *Jsonic {
  method SetOptions (line 519) | func (j *Jsonic) SetOptions(opts Options) *Jsonic {
  method SetOptionsText (line 674) | func (j *Jsonic) SetOptionsText(text string) (*Jsonic, error) {
  method include (line 699) | func (j *Jsonic) include(groups ...string) *Jsonic {
  method exclude (line 714) | func (j *Jsonic) exclude(groups ...string) *Jsonic {
  function buildTagSet (line 725) | func buildTagSet(groups []string) map[string]bool {
  function filterAlts (line 739) | func filterAlts(alts []*AltSpec, excludeSet map[string]bool) []*AltSpec {
  function filterAltsInclude (line 764) | func filterAltsInclude(alts []*AltSpec, includeSet map[string]bool) []*A...
  method ParseMeta (line 787) | func (j *Jsonic) ParseMeta(src string, meta map[string]any) (any, error) {

FILE: go/plugin_test.go
  function hasExactTag (line 9) | func hasExactTag(tagStr, tag string) bool {
  function TestUseInvokesPlugin (line 20) | func TestUseInvokesPlugin(t *testing.T) {
  function TestUsePassesOptions (line 32) | func TestUsePassesOptions(t *testing.T) {
  function TestUseChaining (line 44) | func TestUseChaining(t *testing.T) {
  function TestPlugins (line 60) | func TestPlugins(t *testing.T) {
  function TestTokenRegisterNew (line 71) | func TestTokenRegisterNew(t *testing.T) {
  function TestTokenLookupBuiltin (line 84) | func TestTokenLookupBuiltin(t *testing.T) {
  function TestTokenFixedRegistration (line 92) | func TestTokenFixedRegistration(t *testing.T) {
  function TestTokenMultipleRegistrations (line 101) | func TestTokenMultipleRegistrations(t *testing.T) {
  function TestTinName (line 113) | func TestTinName(t *testing.T) {
  function TestPluginCustomFixedToken (line 129) | func TestPluginCustomFixedToken(t *testing.T) {
  function TestPluginRuleModification (line 159) | func TestPluginRuleModification(t *testing.T) {
  function TestPluginRuleAddAlternate (line 185) | func TestPluginRuleAddAlternate(t *testing.T) {
  function TestPluginRuleNewRule (line 220) | func TestPluginRuleNewRule(t *testing.T) {
  function TestPluginCustomMatcher (line 235) | func TestPluginCustomMatcher(t *testing.T) {
  function TestPluginCustomMatcherInObject (line 267) | func TestPluginCustomMatcherInObject(t *testing.T) {
  function TestPluginMatcherPriority (line 303) | func TestPluginMatcherPriority(t *testing.T) {
  function TestPluginMatcherLowPriorityCaptures (line 328) | func TestPluginMatcherLowPriorityCaptures(t *testing.T) {
  function TestPluginConfigAccess (line 357) | func TestPluginConfigAccess(t *testing.T) {
  function TestPluginRSMAccess (line 368) | func TestPluginRSMAccess(t *testing.T) {
  function TestPluginInstanceIsolation (line 381) | func TestPluginInstanceIsolation(t *testing.T) {
  function TestPluginComposite (line 395) | func TestPluginComposite(t *testing.T) {
  function TestUseNilOptions (line 437) | func TestUseNilOptions(t *testing.T) {
  function TestPluginDisableComments (line 454) | func TestPluginDisableComments(t *testing.T) {
  function TestPluginDisableNumbers (line 477) | func TestPluginDisableNumbers(t *testing.T) {
  function TestMultiCharFixedToken (line 494) | func TestMultiCharFixedToken(t *testing.T) {
  function TestMultiCharFixedTokenLongestMatch (line 516) | func TestMultiCharFixedTokenLongestMatch(t *testing.T) {
  function TestMultiCharFixedTokenBreaksText (line 559) | func TestMultiCharFixedTokenBreaksText(t *testing.T) {
  function TestEnderCharsBreakText (line 583) | func TestEnderCharsBreakText(t *testing.T) {
  function TestEnderCharsInMap (line 599) | func TestEnderCharsInMap(t *testing.T) {
  function TestCustomEscapeMappings (line 614) | func TestCustomEscapeMappings(t *testing.T) {
  function TestSubLex (line 652) | func TestSubLex(t *testing.T) {
  function TestSubRule (line 678) | func TestSubRule(t *testing.T) {
  function TestDerive (line 706) | func TestDerive(t *testing.T) {
  function TestDeriveIsolation (line 718) | func TestDeriveIsolation(t *testing.T) {
  function TestDeriveInheritsPlugins (line 730) | func TestDeriveInheritsPlugins(t *testing.T) {
  function TestSetOptions (line 756) | func TestSetOptions(t *testing.T) {
  function TestSetOptionsDeepMerge (line 783) | func TestSetOptionsDeepMerge(t *testing.T) {
  function TestSetOptionsDeepMergeMaps (line 816) | func TestSetOptionsDeepMergeMaps(t *testing.T) {
  function TestSetOptionsChaining (line 835) | func TestSetOptionsChaining(t *testing.T) {
  function TestExclude (line 857) | func TestExclude(t *testing.T) {
  function TestExcludeCustomGroup (line 898) | func TestExcludeCustomGroup(t *testing.T) {
  function TestParseMeta (line 928) | func TestParseMeta(t *testing.T) {
  function TestParseMetaNil (line 953) | func TestParseMetaNil(t *testing.T) {
  function TestCustomFixedTokenBreaksText (line 968) | func TestCustomFixedTokenBreaksText(t *testing.T) {
  function TestEmptySourceDefault (line 984) | func TestEmptySourceDefault(t *testing.T) {
  function TestEmptySourceDisabled (line 995) | func TestEmptySourceDisabled(t *testing.T) {
  function TestEmptySourceCustomResult (line 1005) | func TestEmptySourceCustomResult(t *testing.T) {
  function TestCustomParserStart (line 1020) | func TestCustomParserStart(t *testing.T) {
  function TestCustomParserStartWithMeta (line 1037) | func TestCustomParserStartWithMeta(t *testing.T) {
  function TestErrorHints (line 1062) | func TestErrorHints(t *testing.T) {
  function TestErrorHintsInOutput (line 1088) | func TestErrorHintsInOutput(t *testing.T) {
  function TestConfigModify (line 1109) | func TestConfigModify(t *testing.T) {
  function TestTokenSetVAL (line 1133) | func TestTokenSetVAL(t *testing.T) {
  function TestTokenSetIGNORE (line 1154) | func TestTokenSetIGNORE(t *testing.T) {
  function TestTokenSetKEY (line 1165) | func TestTokenSetKEY(t *testing.T) {
  function TestTokenSetUnknown (line 1176) | func TestTokenSetUnknown(t *testing.T) {
  function TestSetTokenSetIGNORE (line 1184) | func TestSetTokenSetIGNORE(t *testing.T) {
  function TestSetTokenSetIGNOREPerInstance (line 1215) | func TestSetTokenSetIGNOREPerInstance(t *testing.T) {
  function TestDeriveInheritsIgnoreSet (line 1233) | func TestDeriveInheritsIgnoreSet(t *testing.T) {
  function TestSetOptionsPreservesIgnoreSet (line 1255) | func TestSetOptionsPreservesIgnoreSet(t *testing.T) {
  function TestSetTokenSetVAL (line 1291) | func TestSetTokenSetVAL(t *testing.T) {
  function TestSetTokenSetKEY (line 1315) | func TestSetTokenSetKEY(t *testing.T) {
  function TestSetTokenSetVALPerInstance (line 1335) | func TestSetTokenSetVALPerInstance(t *testing.T) {
  function TestDeriveInheritsValKeySet (line 1349) | func TestDeriveInheritsValKeySet(t *testing.T) {
  function TestLexCheckFixed (line 1374) | func TestLexCheckFixed(t *testing.T) {
  function TestLexCheckSkipMatcher (line 1402) | func TestLexCheckSkipMatcher(t *testing.T) {
  function TestRuleSpecClear (line 1435) | func TestRuleSpecClear(t *testing.T) {
  function TestRuleSpecAddOpen (line 1448) | func TestRuleSpecAddOpen(t *testing.T) {
  function TestRuleSpecPrependOpen (line 1459) | func TestRuleSpecPrependOpen(t *testing.T) {
  function TestRuleSpecAddClose (line 1471) | func TestRuleSpecAddClose(t *testing.T) {
  function TestRuleSpecPrependClose (line 1479) | func TestRuleSpecPrependClose(t *testing.T) {
  function TestRuleSpecStateActions (line 1488) | func TestRuleSpecStateActions(t *testing.T) {
  function TestDebugDescribe (line 1503) | func TestDebugDescribe(t *testing.T) {
  function TestDebugPlugin (line 1526) | func TestDebugPlugin(t *testing.T) {
  function TestRuleExcludeFromOptions (line 1537) | func TestRuleExcludeFromOptions(t *testing.T) {
  function TestDeriveTokenInheritance (line 1579) | func TestDeriveTokenInheritance(t *testing.T) {
  function makeTokenPlugin (line 1611) | func makeTokenPlugin(char, val string) Plugin {
  function TestDeriveMultiLevelPluginInheritance (line 1632) | func TestDeriveMultiLevelPluginInheritance(t *testing.T) {
  function expectMap (line 1707) | func expectMap(t *testing.T, label string, result any, expected map[stri...
  function TestCustomParserStartError (line 1722) | func TestCustomParserStartError(t *testing.T) {
  function TestPluginErrorHints (line 1765) | func TestPluginErrorHints(t *testing.T) {
  function TestDecorate (line 1795) | func TestDecorate(t *testing.T) {
  function TestDecorateChaining (line 1809) | func TestDecorateChaining(t *testing.T) {
  function TestDecorateInherited (line 1829) | func TestDecorateInherited(t *testing.T) {
  function TestDecorateUnset (line 1853) | func TestDecorateUnset(t *testing.T) {
  function TestDecorateFunction (line 1860) | func TestDecorateFunction(t *testing.T) {
  function TestContextInst (line 1875) | func TestContextInst(t *testing.T) {
  function TestContextOpts (line 1893) | func TestContextOpts(t *testing.T) {
  function TestContextCfg (line 1913) | func TestContextCfg(t *testing.T) {
  function TestContextSrc (line 1933) | func TestContextSrc(t *testing.T) {
  function TestContextU (line 1950) | func TestContextU(t *testing.T) {
  function TestContextMeta (line 1974) | func TestContextMeta(t *testing.T) {
  function TestPluginOptions (line 1993) | func TestPluginOptions(t *testing.T) {
  function TestPluginOptionsInherited (line 2009) | func TestPluginOptionsInherited(t *testing.T) {
  function TestErrMsgName (line 2028) | func TestErrMsgName(t *testing.T) {
  function TestErrMsgNameViaPlugin (line 2045) | func TestErrMsgNameViaPlugin(t *testing.T) {
  function TestFixedLookup (line 2064) | func TestFixedLookup(t *testing.T) {
  function TestFixedCustomToken (line 2086) | func TestFixedCustomToken(t *testing.T) {
  function TestFixedOptionsTokenOverride (line 2102) | func TestFixedOptionsTokenOverride(t *testing.T) {
  function TestFixedOptionsTokenDelete (line 2126) | func TestFixedOptionsTokenDelete(t *testing.T) {
  function TestFixedOptionsTokenViaMake (line 2136) | func TestFixedOptionsTokenViaMake(t *testing.T) {
  function TestModifyOpen (line 2151) | func TestModifyOpen(t *testing.T) {
  function TestModifyOpenCustom (line 2163) | func TestModifyOpenCustom(t *testing.T) {
  function TestContextRoot (line 2181) | func TestContextRoot(t *testing.T) {
  function TestContextSentinels (line 2203) | func TestContextSentinels(t *testing.T) {
  function TestContextTC (line 2227) | func TestContextTC(t *testing.T) {
  function TestContextF (line 2244) | func TestContextF(t *testing.T) {
  function TestTokenUse (line 2265) | func TestTokenUse(t *testing.T) {
  function TestTokenBad (line 2300) | func TestTokenBad(t *testing.T) {
  function TestLexBad (line 2314) | func TestLexBad(t *testing.T) {
  function TestJsonicId (line 2328) | func TestJsonicId(t *testing.T) {
  function TestJsonicIdWithTag (line 2338) | func TestJsonicIdWithTag(t *testing.T) {
  function TestJsonicIdUnique (line 2345) | func TestJsonicIdUnique(t *testing.T) {
  function TestEmpty (line 2355) | func TestEmpty(t *testing.T) {
  function TestResultFail (line 2368) | func TestResultFail(t *testing.T) {
  function TestResultFailCustomValue (line 2383) | func TestResultFailCustomValue(t *testing.T) {
  function TestLexFwd (line 2412) | func TestLexFwd(t *testing.T) {
  function TestCustomTokenSet (line 2430) | func TestCustomTokenSet(t *testing.T) {
  function TestCustomTokenSetInherited (line 2445) | func TestCustomTokenSetInherited(t *testing.T) {

FILE: go/readme_test.go
  function boolp (line 8) | func boolp(b bool) *bool { return &b }
  function toJSON (line 11) | func toJSON(t *testing.T, v any) string {
  function TestReadmeQuickExample (line 22) | func TestReadmeQuickExample(t *testing.T) {
  function TestReadmeSyntaxExamples (line 35) | func TestReadmeSyntaxExamples(t *testing.T) {
  function TestReadmeRelaxations (line 62) | func TestReadmeRelaxations(t *testing.T) {
  function TestGoReadmeQuickExample (line 99) | func TestGoReadmeQuickExample(t *testing.T) {
  function TestGoReadmeConfiguredInstance (line 116) | func TestGoReadmeConfiguredInstance(t *testing.T) {
  function TestGoReadmeSyntaxHighlights (line 140) | func TestGoReadmeSyntaxHighlights(t *testing.T) {

FILE: go/rule.go
  function ValidateGroupTags (line 16) | func ValidateGroupTags(g string) error {
  constant OPEN (line 36) | OPEN  RuleState = "o"
  constant CLOSE (line 37) | CLOSE RuleState = "c"
  type undefinedType (line 42) | type undefinedType struct
  function IsUndefined (line 47) | func IsUndefined(v any) bool {
  type skipType (line 54) | type skipType struct
  function IsSkip (line 59) | func IsSkip(v any) bool {
  function UnwrapUndefined (line 65) | func UnwrapUndefined(v any) any {
  type AltCond (line 85) | type AltCond
  type AltAction (line 88) | type AltAction
  type AltError (line 91) | type AltError
  type AltModifier (line 94) | type AltModifier
  type StateAction (line 97) | type StateAction
  type CondOp (line 102) | type CondOp struct
  function CEq (line 108) | func CEq(val int) CondOp  { return CondOp{Op: "$eq", Val: val} }
  function CNe (line 109) | func CNe(val int) CondOp  { return CondOp{Op: "$ne", Val: val} }
  function CLt (line 110) | func CLt(val int) CondOp  { return CondOp{Op: "$lt", Val: val} }
  function CLte (line 111) | func CLte(val int) CondOp { return CondOp{Op: "$lte", Val: val} }
  function CGt (line 112) | func CGt(val int) CondOp  { return CondOp{Op: "$gt", Val: val} }
  function CGte (line 113) | func CGte(val int) CondOp { return CondOp{Op: "$gte", Val: val} }
  type AltSpec (line 116) | type AltSpec struct
  type RuleSpec (line 136) | type RuleSpec struct
    method Clear (line 154) | func (rs *RuleSpec) Clear() *RuleSpec {
    method AddOpen (line 165) | func (rs *RuleSpec) AddOpen(alts ...*AltSpec) *RuleSpec {
    method AddClose (line 171) | func (rs *RuleSpec) AddClose(alts ...*AltSpec) *RuleSpec {
    method PrependOpen (line 177) | func (rs *RuleSpec) PrependOpen(alts ...*AltSpec) *RuleSpec {
    method PrependClose (line 183) | func (rs *RuleSpec) PrependClose(alts ...*AltSpec) *RuleSpec {
    method ModifyOpen (line 198) | func (rs *RuleSpec) ModifyOpen(mods *AltModListOpts) *RuleSpec {
    method ModifyClose (line 204) | func (rs *RuleSpec) ModifyClose(mods *AltModListOpts) *RuleSpec {
    method AddBO (line 235) | func (rs *RuleSpec) AddBO(action StateAction) *RuleSpec {
    method AddAO (line 241) | func (rs *RuleSpec) AddAO(action StateAction) *RuleSpec {
    method AddBC (line 247) | func (rs *RuleSpec) AddBC(action StateAction) *RuleSpec {
    method AddAC (line 253) | func (rs *RuleSpec) AddAC(action StateAction) *RuleSpec {
  type AltModListOpts (line 190) | type AltModListOpts struct
  function modifyAltList (line 209) | func modifyAltList(list []*AltSpec, mods *AltModListOpts) []*AltSpec {
  function getRuleProp (line 261) | func getRuleProp(r *Rule, prop string, subprop string) (int, bool) {
  function MakeRuleCond (line 280) | func MakeRuleCond(op string, prop string, subprop string, val int) AltCo...
  function NormAlt (line 321) | func NormAlt(alt *AltSpec) error {
  function NormAlts (line 369) | func NormAlts(spec *RuleSpec) error {
  type Rule (line 384) | type Rule struct
    method Eq (line 432) | func (r *Rule) Eq(counter string, limit int) bool {
    method Lt (line 438) | func (r *Rule) Lt(counter string, limit int) bool {
    method Gt (line 444) | func (r *Rule) Gt(counter string, limit int) bool {
    method Lte (line 450) | func (r *Rule) Lte(counter string, limit int) bool {
    method Gte (line 456) | func (r *Rule) Gte(counter string, limit int) bool {
    method Process (line 476) | func (r *Rule) Process(ctx *Context, lex *Lex) *Rule {
  function init (line 426) | func init() {
  function MakeRule (line 462) | func MakeRule(spec *RuleSpec, ctx *Context, node any) *Rule {
  function ParseAlts (line 713) | func ParseAlts(isOpen bool, alts []*AltSpec, lex *Lex, rule *Rule, ctx *...
  function tinMatch (line 821) | func tinMatch(tin Tin, tins []Tin) bool {

FILE: go/rule_include_test.go
  function TestRuleIncludeKeepsOnlyTaggedAlts (line 10) | func TestRuleIncludeKeepsOnlyTaggedAlts(t *testing.T) {
  function TestRuleIncludeDropsUntaggedAlts (line 54) | func TestRuleIncludeDropsUntaggedAlts(t *testing.T) {
  function TestRuleIncludeEmptyIsNoop (line 80) | func TestRuleIncludeEmptyIsNoop(t *testing.T) {
  function TestRuleIncludeMultipleTags (line 92) | func TestRuleIncludeMultipleTags(t *testing.T) {
  function TestRuleIncludeThenExclude (line 138) | func TestRuleIncludeThenExclude(t *testing.T) {
  function TestGrammarTextAppliesInclude (line 175) | func TestGrammarTextAppliesInclude(t *testing.T) {
  function TestSetOptionsTextInclude (line 213) | func TestSetOptionsTextInclude(t *testing.T) {
  function TestRuleIncludePreservesParsingForTaggedAlts (line 245) | func TestRuleIncludePreservesParsingForTaggedAlts(t *testing.T) {
  function TestRuleIncludeBreaksParsingWhenGrammarHasNoMatchingTags (line 279) | func TestRuleIncludeBreaksParsingWhenGrammarHasNoMatchingTags(t *testing...
  function appendTag (line 291) | func appendTag(g, tag string) string {

FILE: go/safe_test.go
  function TestSafeKey_ConstructorBlockedOnList (line 13) | func TestSafeKey_ConstructorBlockedOnList(t *testing.T) {
  function TestSafeKey_ConstructorAllowedOnObject (line 26) | func TestSafeKey_ConstructorAllowedOnObject(t *testing.T) {
  function TestSafeKey_FalseAllowsProtoOnList (line 41) | func TestSafeKey_FalseAllowsProtoOnList(t *testing.T) {
  function TestSafeKey_FalseAllowsConstructorOnList (line 65) | func TestSafeKey_FalseAllowsConstructorOnList(t *testing.T) {
  function TestSafeKey_PathDiveWithProtoOnList (line 85) | func TestSafeKey_PathDiveWithProtoOnList(t *testing.T) {

FILE: go/text.go
  type Text (line 6) | type Text struct
  type ListRef (line 21) | type ListRef struct
  type MapRef (line 48) | type MapRef struct

FILE: go/textinfo_test.go
  function expectTextInfo (line 8) | func expectTextInfo(t *testing.T, input string, expected any) {
  function textInfoEqual (line 23) | func textInfoEqual(a, b any) bool {
  function tx (line 76) | func tx(quote, str string) Text {
  function TestTextInfoOff (line 80) | func TestTextInfoOff(t *testing.T) {
  function TestTextInfoDoubleQuote (line 100) | func TestTextInfoDoubleQuote(t *testing.T) {
  function TestTextInfoSingleQuote (line 104) | func TestTextInfoSingleQuote(t *testing.T) {
  function TestTextInfoBacktickQuote (line 108) | func TestTextInfoBacktickQuote(t *testing.T) {
  function TestTextInfoUnquotedText (line 112) | func TestTextInfoUnquotedText(t *testing.T) {
  function TestTextInfoEmptyStrings (line 117) | func TestTextInfoEmptyStrings(t *testing.T) {
  function TestTextInfoEscapes (line 123) | func TestTextInfoEscapes(t *testing.T) {
  function TestTextInfoMapValues (line 129) | func TestTextInfoMapValues(t *testing.T) {
  function TestTextInfoMapMultipleKeys (line 142) | func TestTextInfoMapMultipleKeys(t *testing.T) {
  function TestTextInfoArrayValues (line 149) | func TestTextInfoArrayValues(t *testing.T) {
  function TestTextInfoMixedTypes (line 157) | func TestTextInfoMixedTypes(t *testing.T) {
  function TestTextInfoNestedMap (line 167) | func TestTextInfoNestedMap(t *testing.T) {
  function TestTextInfoKeysRemainStrings (line 175) | func TestTextInfoKeysRemainStrings(t *testing.T) {
  function TestTextInfoNumbersUnaffected (line 199) | func TestTextInfoNumbersUnaffected(t *testing.T) {
  function TestTextInfoBoolsUnaffected (line 210) | func TestTextInfoBoolsUnaffected(t *testing.T) {
  function TestTextInfoNullUnaffected (line 221) | func TestTextInfoNullUnaffected(t *testing.T) {
  function TestTextInfoExplicitOff (line 232) | func TestTextInfoExplicitOff(t *testing.T) {
  function TestTextInfoImplicitList (line 244) | func TestTextInfoImplicitList(t *testing.T) {
  function TestTextInfoSpaceSeparatedList (line 252) | func TestTextInfoSpaceSeparatedList(t *testing.T) {
  function TestTextInfoPathDive (line 261) | func TestTextInfoPathDive(t *testing.T) {

FILE: go/token.go
  constant TinBD (line 8) | TinBD  Tin = 1
  constant TinZZ (line 9) | TinZZ  Tin = 2
  constant TinUK (line 10) | TinUK  Tin = 3
  constant TinAA (line 11) | TinAA  Tin = 4
  constant TinSP (line 12) | TinSP  Tin = 5
  constant TinLN (line 13) | TinLN  Tin = 6
  constant TinCM (line 14) | TinCM  Tin = 7
  constant TinNR (line 15) | TinNR  Tin = 8
  constant TinST (line 16) | TinST  Tin = 9
  constant TinTX (line 17) | TinTX  Tin = 10
  constant TinVL (line 18) | TinVL  Tin = 11
  constant TinOB (line 19) | TinOB  Tin = 12
  constant TinCB (line 20) | TinCB  Tin = 13
  constant TinOS (line 21) | TinOS  Tin = 14
  constant TinCS (line 22) | TinCS  Tin = 15
  constant TinCL (line 23) | TinCL  Tin = 16
  constant TinCA (line 24) | TinCA  Tin = 17
  constant TinMAX (line 25) | TinMAX Tin = 18
  type Point (line 39) | type Point struct
  type Token (line 47) | type Token struct
    method Bad (line 62) | func (t *Token) Bad(err string, details ...map[string]any) *Token {
    method IsNoToken (line 76) | func (t *Token) IsNoToken() bool {
    method ResolveVal (line 88) | func (t *Token) ResolveVal(r *Rule, ctx *Context) any {
  type TokenValFunc (line 83) | type TokenValFunc
  function MakeToken (line 96) | func MakeToken(name string, tin Tin, val any, src string, pnt Point) *To...

FILE: go/token_test.go
  function TestResolveVal_StaticValue (line 8) | func TestResolveVal_StaticValue(t *testing.T) {
  function TestResolveVal_NilValueUnchanged (line 15) | func TestResolveVal_NilValueUnchanged(t *testing.T) {
  function TestResolveVal_LazyFunction (line 22) | func TestResolveVal_LazyFunction(t *testing.T) {
  function TestResolveVal_LazyFunctionReceivesRuleAndCtx (line 36) | func TestResolveVal_LazyFunctionReceivesRuleAndCtx(t *testing.T) {
  function TestResolveVal_LazyValueThroughParser (line 57) | func TestResolveVal_LazyValueThroughParser(t *testing.T) {

FILE: go/util.go
  type UtilBag (line 9) | type UtilBag struct
  type Entry (line 21) | type Entry struct
  function Keys (line 28) | func Keys(m map[string]any) []string {
  function Values (line 42) | func Values(m map[string]any) []any {
  function Entries (line 55) | func Entries(m map[string]any) []Entry {
  function Omap (line 70) | func Omap(m map[string]any, fn func(Entry) []any) map[string]any {
  method Util (line 101) | func (j *Jsonic) Util() UtilBag {

FILE: go/util_test.go
  function TestKeys_NilMapReturnsEmpty (line 11) | func TestKeys_NilMapReturnsEmpty(t *testing.T) {
  function TestKeys_Sorted (line 17) | func TestKeys_Sorted(t *testing.T) {
  function TestValues_NilMapReturnsEmpty (line 24) | func TestValues_NilMapReturnsEmpty(t *testing.T) {
  function TestValues_KeySortedOrder (line 30) | func TestValues_KeySortedOrder(t *testing.T) {
  function TestEntries_NilMapReturnsEmpty (line 37) | func TestEntries_NilMapReturnsEmpty(t *testing.T) {
  function TestEntries_KeySortedOrder (line 43) | func TestEntries_KeySortedOrder(t *testing.T) {
  function TestOmap_Identity (line 52) | func TestOmap_Identity(t *testing.T) {
  function TestOmap_Rewrite (line 60) | func TestOmap_Rewrite(t *testing.T) {
  function TestOmap_Drop (line 70) | func TestOmap_Drop(t *testing.T) {
  function TestOmap_ExtraPairs (line 83) | func TestOmap_ExtraPairs(t *testing.T) {
  function TestJsonic_Util_ExposesHelpers (line 94) | func TestJsonic_Util_ExposesHelpers(t *testing.T) {

FILE: go/utility.go
  function Deep (line 16) | func Deep(base any, rest ...any) any {
  function deepMerge (line 23) | func deepMerge(base, over any) any {
  function deepMergeStruct (line 131) | func deepMergeStruct(base, over any) (any, bool) {
  function cloneMeta (line 232) | func cloneMeta(meta map[string]any) map[string]any {
  function mergeMeta (line 244) | func mergeMeta(base, over map[string]any) map[string]any {
  function deepClone (line 259) | func deepClone(val any) any {
  function Snip (line 295) | func Snip(s string, maxlen int) string {
  function Str (line 310) | func Str(val any, maxlen int) string {
  function StrInject (line 358) | func StrInject(template string, vals any) string {
  function resolvePath (line 404) | func resolvePath(path string, valsMap map[string]any, valsArr []any, isM...
  function formatInjectValue (line 435) | func formatInjectValue(val any) string {
  function formatCompactValue (line 462) | func formatCompactValue(val any) string {
  type ModListOpts (line 511) | type ModListOpts struct
  function ModList (line 519) | func ModList(list []any, opts *ModListOpts) []any {
  function deepEqual (line 588) | func deepEqual(a, b any) bool {
  function IsFuncRef (line 593) | func IsFuncRef(s string) bool {
  function RequireRef (line 598) | func RequireRef(ref map[FuncRef]any, name string, kind string) (any, err...
  function LookupRef (line 610) | func LookupRef(ref map[FuncRef]any, name string) any {
  function MapToOptions (line 619) | func MapToOptions(m map[string]any) Options {
  function ResolveFuncRefs (line 1032) | func ResolveFuncRefs(obj any, ref map[FuncRef]any) any {

FILE: go/variant_test.go
  function TestVariant_StrictJSON_Happy (line 11) | func TestVariant_StrictJSON_Happy(t *testing.T) {
  function TestVariant_StrictJSON_Rejects (line 48) | func TestVariant_StrictJSON_Rejects(t *testing.T) {

FILE: src/bnf.ts
  type BnfElement (line 31) | type BnfElement =
  type BnfSequence (line 50) | type BnfSequence = BnfElement[]
  type BnfProduction (line 52) | type BnfProduction = {
  type ProbeDispatchSpec (line 94) | type ProbeDispatchSpec = {
  type BnfGrammar (line 101) | type BnfGrammar = {
  type AmbiguityReport (line 109) | type AmbiguityReport = {
  function getBnfParser (line 469) | function getBnfParser(): (src: string) => BnfProduction[] {
  function eliminateLeftRecursion (line 581) | function eliminateLeftRecursion(grammar: BnfGrammar): BnfGrammar {
  function findLeadingRefCycleMembers (line 636) | function findLeadingRefCycleMembers(prods: BnfProduction[]): Set<string> {
  function topoOrderForPaull (line 703) | function topoOrderForPaull(prods: BnfProduction[]): BnfProduction[] {
  function substituteLeadingRef (line 734) | function substituteLeadingRef(
  function eliminateDirectLeftRec (line 760) | function eliminateDirectLeftRec(prod: BnfProduction): BnfProduction {
  function desugar (line 810) | function desugar(grammar: BnfGrammar): BnfGrammar {
  class BnfParseError (line 948) | class BnfParseError extends Error {
    method constructor (line 952) | constructor(message: string, location?: { line?: number; column?: numb...
  function parseBnf (line 963) | function parseBnf(src: string): BnfGrammar {
  constant CORE_RULES_ABNF (line 994) | const CORE_RULES_ABNF = `
  function getCoreRules (line 1014) | function getCoreRules(): Map<string, BnfProduction> {
  function refsIn (line 1027) | function refsIn(alt: BnfSequence, out: Set<string>): void {
  function withCoreRules (line 1044) | function withCoreRules(user: BnfProduction[]): BnfProduction[] {
  function mergeIncrementals (line 1078) | function mergeIncrementals(prods: BnfProduction[]): BnfProduction[] {
  function isProbeableOpt (line 1140) | function isProbeableOpt(el: BnfElement): null | {
  function collectTerminalVocabElements (line 1160) | function collectTerminalVocabElements(
  function collectSeqVocabElements (line 1200) | function collectSeqVocabElements(
  function mapsOverlap (line 1212) | function mapsOverlap<K, V>(a: Map<K, V>, b: Map<K, V>): boolean {
  function rewriteProbeDispatches (line 1224) | function rewriteProbeDispatches(grammar: BnfGrammar): BnfGrammar {
  function emitProbeHelper (line 1355) | function emitProbeHelper(
  function emitProbeDispatch (line 1380) | function emitProbeDispatch(
  function emitGrammarSpec (line 1458) | function emitGrammarSpec(
  type Segment (line 1616) | type Segment = {
  function segmentize (line 1626) | function segmentize(
  function regexKey (line 1657) | function regexKey(el: { pattern: string; flags: string }): string {
  function isSingleSegment (line 1662) | function isSingleSegment(alt: BnfSequence): boolean {
  function validateRefs (line 1679) | function validateRefs(
  class RefRegistry (line 1697) | class RefRegistry {
    method register (line 1700) | register(fn: Function): `@${string}` {
    method map (line 1705) | get map(): Record<string, Function> {
  type AstNode (line 1717) | type AstNode = {
  function mkAstNode (line 1723) | function mkAstNode(ruleName: string, nodeKind: BnfProduction['nodeKind']...
  function segmentToAlt (line 1730) | function segmentToAlt(
  function captureChildRef (line 1763) | function captureChildRef(
  function emitProduction (line 1789) | function emitProduction(
  function emitChain (line 1982) | function emitChain(
  function computeFirstSets (line 2028) | function computeFirstSets(
  function firstOfAlt (line 2084) | function firstOfAlt(
  function ruleLiteralPrefix (line 2121) | function ruleLiteralPrefix(
  function altLiteralPrefix (line 2147) | function altLiteralPrefix(
  type PrefixPath (line 2175) | type PrefixPath = { tokens: string[]; done: boolean }
  function altPrefixesRaw (line 2187) | function altPrefixesRaw(
  function altPrefixes (line 2248) | function altPrefixes(
  function isEffectivelyCaseSensitive (line 2270) | function isEffectivelyCaseSensitive(el: {
  function termKey (line 2283) | function termKey(el: { literal: string; caseSensitive?: boolean }): stri...
  function escapeRegExp (line 2288) | function escapeRegExp(s: string): string {
  function parseNumericValue (line 2303) | function parseNumericValue(src: string): BnfElement {
  function allocTokenName (line 2330) | function allocTokenName(literal: string, used: Set<string>): string {
  function bnf (line 2349) | function bnf(src: string, opts?: BnfConvertOptions): GrammarSpec {

FILE: src/debug.ts
  type DebugOptions (line 26) | type DebugOptions = {
  constant DEFAULTS (line 39) | const DEFAULTS: DebugOptions = {
  function descAlt (line 191) | function descAlt(jsonic: Jsonic, rs: RuleSpec, kind: 'open' | 'close') {
  function ruleTree (line 245) | function ruleTree(jsonic: Jsonic, rn: string[], rsm: any) {
  function ruleTreeStep (line 275) | function ruleTreeStep(
  function descTokenState (line 291) | function descTokenState(ctx: Context) {
  function descParseState (line 303) | function descParseState(ctx: Context, rule: Rule, lex: Lex) {
  function descRuleState (line 313) | function descRuleState(ctx: Context, rule: Rule) {
  function descAltSeq (line 337) | function descAltSeq(alt: NormAltSpec, cfg: Config) {
  constant LOG (line 353) | const LOG = {
  constant LOGKIND (line 360) | const LOGKIND: any = {

FILE: src/error.ts
  class JsonicError (line 32) | class JsonicError extends SyntaxError {
    method constructor (line 33) | constructor(
  function errinject (line 51) | function errinject<T extends string | string[] | { [key: string]: string...
  function trimstk (line 73) | function trimstk(err: Error) {
  function errsite (line 84) | function errsite(spec: {
  function errmsg (line 150) | function errmsg(spec: {
  function errdesc (line 254) | function errdesc(
  function strinject (line 377) | function strinject<T extends string | string[] | { [key: string]: string...
  function prop (line 434) | function prop(obj: any, path: string, val?: any): any {
  function str (line 468) | function str(o: any, len: number = 44) {
  function snip (line 478) | function snip(s: any, len: number = 5) {

FILE: src/grammar.ts
  function mark (line 14) | function mark(node: any, marker: string, data: any): void {
  function grammar (line 20) | function grammar(jsonic: Jsonic) {
  function makeJSON (line 980) | function makeJSON(jsonic: any) {

FILE: src/jsonic-bnf-cli.ts
  function run (line 13) | async function run(argv: string[], console: Console) {
  function readStdin (line 111) | async function readStdin(console: Console): Promise<string> {
  function help (line 123) | function help(console: Console) {

FILE: src/jsonic-cli.ts
  function run (line 9) | async function run(argv: string[], console: Console) {
  function read_stdin (line 118) | async function read_stdin(console: Console) {
  function handle_props (line 133) | function handle_props(propvals: string[]): Bag {
  function handle_plugins (line 146) | function handle_plugins(plugins: string[]): Bag {
  function camel (line 199) | function camel(s: string) {
  function help (line 208) | function help(console: Console) {

FILE: src/jsonic.ts
  type Jsonic (line 141) | type Jsonic = JsonicParse & // A function that parses.
  function make (line 144) | function make(param_options?: Bag | string, parent?: Jsonic): Jsonic {

FILE: src/lexer.ts
  class PointImpl (line 40) | class PointImpl implements Point {
    method constructor (line 48) | constructor(len: number, sI?: number, rI?: number, cI?: number) {
    method toString (line 61) | toString() {
    method [INSPECT] (line 70) | [INSPECT]() {
  class TokenImpl (line 79) | class TokenImpl implements Token {
    method constructor (line 93) | constructor(
    method resolveVal (line 115) | resolveVal(rule: Rule, ctx: Context): any {
    method bad (line 121) | bad(err: string, details?: any): Token {
    method toString (line 129) | toString() {
    method [INSPECT] (line 151) | [INSPECT]() {
  type CommentDef (line 316) | type CommentDef = Config['comment']['def'] extends { [_: string]: infer T }
  function normalizeCommentSuffix (line 502) | function normalizeCommentSuffix(raw: any):
  function commentSuffixMatch (line 530) | function commentSuffixMatch(fwd: string, fI: number, suffixes?: string[]...
  function commentSuffixFnMatch (line 542) | function commentSuffixFnMatch(lex: Lex, fI: number, fn?: LexMatcher): nu...
  function subMatchFixed (line 1048) | function subMatchFixed(
  class LexImpl (line 1081) | class LexImpl implements Lex {
    method refwd (line 1088) | refwd(): string {
    method constructor (line 1093) | constructor(ctx: Context) {
    method token (line 1100) | token(
    method next (line 1123) | next(rule: Rule, alt?: NormAltSpec, altI?: number, tI?: number): Token {
    method tokenize (line 1196) | tokenize<R extends string | Tin, T extends R extends Tin ? string : Tin>(
    method bad (line 1202) | bad(why: string, pstart: number, pend: number) {

FILE: src/parser.ts
  function defineLookaheadAliases (line 44) | function defineLookaheadAliases(ctx: any, notoken: any) {
  function attachRewind (line 102) | function attachRewind(ctx: any): void {
  class ParserImpl (line 156) | class ParserImpl implements Parser {
    method constructor (line 162) | constructor(options: Options, cfg: Config, j: Jsonic) {
    method rule (line 170) | rule(
    method start (line 200) | start(src: string, jsonic: any, meta?: any, parent_ctx?: any): any {
    method clone (line 339) | clone(options: Options, config: Config, j: Jsonic) {
    method norm (line 353) | norm() {

FILE: src/rules.ts
  class RuleImpl (line 47) | class RuleImpl implements Rule {
    method constructor (line 81) | constructor(spec: RuleSpec, ctx: Context, node?: any) {
    method o0 (line 106) | get o0(): Token { return this.o[0] ?? (this._NOTOKEN as Token) }
    method o0 (line 107) | set o0(v: Token) { this.o[0] = v }
    method o1 (line 108) | get o1(): Token { return this.o[1] ?? (this._NOTOKEN as Token) }
    method o1 (line 109) | set o1(v: Token) { this.o[1] = v }
    method c0 (line 110) | get c0(): Token { return this.c[0] ?? (this._NOTOKEN as Token) }
    method c0 (line 111) | set c0(v: Token) { this.c[0] = v }
    method c1 (line 112) | get c1(): Token { return this.c[1] ?? (this._NOTOKEN as Token) }
    method c1 (line 113) | set c1(v: Token) { this.c[1] = v }
    method os (line 114) | get os(): number { return this.oN }
    method os (line 115) | set os(v: number) { this.oN = v }
    method cs (line 116) | get cs(): number { return this.cN }
    method cs (line 117) | set cs(v: number) { this.cN = v }
    method process (line 119) | process(ctx: Context, lex: Lex): Rule {
    method eq (line 124) | eq(counter: string, limit: number = 0): boolean {
    method lt (line 129) | lt(counter: string, limit: number = 0): boolean {
    method gt (line 134) | gt(counter: string, limit: number = 0): boolean {
    method lte (line 139) | lte(counter: string, limit: number = 0): boolean {
    method gte (line 144) | gte(counter: string, limit: number = 0): boolean {
    method toString (line 149) | toString() {
  class AltMatchImpl (line 160) | class AltMatchImpl implements AltMatch {
  constant PALT (line 177) | const PALT: AltMatch = makeAltMatch() // Only one alt object is created.
  constant EMPTY_ALT (line 178) | const EMPTY_ALT = makeAltMatch()
  class RuleSpecImpl (line 180) | class RuleSpecImpl implements RuleSpec {
    method constructor (line 196) | constructor(j: Jsonic, cfg: Config, def: any) {
    method tin (line 227) | tin<R extends string | Tin, T extends R extends Tin ? string : Tin>(
    method fnref (line 234) | fnref(frm: Record<FuncRef, Function>): RuleSpec {
    method add (line 275) | add(rs: RuleState, a: AltSpec | AltSpec[], mods?: ListMods): RuleSpec {
    method open (line 295) | open(a: AltSpec | AltSpec[], mods?: ListMods): RuleSpec {
    method close (line 299) | close(a: AltSpec | AltSpec[], mods?: ListMods): RuleSpec {
    method action (line 303) | action(
    method bo (line 318) | bo(append: StateAction | boolean | FuncRef, action?: StateAction): Rul...
    method ao (line 328) | ao(append: StateAction | boolean, action?: StateAction): RuleSpec {
    method bc (line 338) | bc(append: StateAction | boolean, action?: StateAction): RuleSpec {
    method ac (line 348) | ac(append: StateAction | boolean, action?: StateAction): RuleSpec {
    method clear (line 358) | clear() {
    method norm (line 368) | norm() {
    method process (line 425) | process(rule: Rule, ctx: Context, lex: Lex, state: RuleState): Rule {
    method bad (line 615) | bad(tkn: Token, rule: Rule, ctx: Context, parse: { is_open: boolean })...
    method unknownRule (line 628) | unknownRule(tkn: Token, name: string): Token {
  function parse_alts (line 641) | function parse_alts(
  constant GROUP_TAG_RE (line 806) | const GROUP_TAG_RE = /^[a-z][a-z0-9-]+$/
  function normalt (line 809) | function normalt(a: AltSpec, rs: RuleState, r: RuleSpec): NormAltSpec {
  function isfnref (line 995) | function isfnref(v: any) {
  function resolveFunctionRef (line 1000) | function resolveFunctionRef(
  constant COND_OPS (line 1020) | const COND_OPS: Record<string, number> = {
  function makeRuleCond (line 1030) | function makeRuleCond(co: string, prop: string, val: any) {

FILE: src/types.ts
  constant OPEN (line 7) | const OPEN: RuleState = 'o'
  constant CLOSE (line 8) | const CLOSE: RuleState = 'c'
  constant BEFORE (line 9) | const BEFORE: RuleStep = 'b'
  constant AFTER (line 10) | const AFTER: RuleStep = 'a'
  constant EMPTY (line 11) | const EMPTY = ''
  constant INSPECT (line 12) | const INSPECT = Symbol.for('nodejs.util.inspect.custom')
  constant SKIP (line 16) | const SKIP: unique symbol = Symbol.for('jsonic.SKIP')
  constant STRING (line 21) | const STRING = 'string'
  type JsonicParse (line 24) | type JsonicParse = (src: any, meta?: any, parent_ctx?: any) => any
  type JsonicAPI (line 27) | interface JsonicAPI {
  type BnfConvertOptions (line 97) | type BnfConvertOptions = {
  type GrammarSetting (line 106) | type GrammarSetting = {
  type Jsonic (line 116) | type Jsonic = JsonicParse & // A function that parses.
  type Plugin (line 120) | type Plugin = ((
  type Options (line 129) | type Options = {
  type RuleSpec (line 321) | interface RuleSpec {
  type Rule (line 364) | interface Rule {
  type Context (line 418) | type Context = {
  type Lex (line 464) | interface Lex {
  type NextToken (line 490) | type NextToken = (rule: Rule) => Token
  type Config (line 494) | type Config = {
  type Point (line 700) | interface Point {
  type Token (line 718) | interface Token {
  type AltSpec (line 741) | interface AltSpec {
  type AltSpecish (line 772) | type AltSpecish = AltSpec | undefined | null | false | 0 | typeof NaN
  type ListMods (line 775) | type ListMods = {
  type AltMatch (line 783) | interface AltMatch {
  type Bag (line 798) | type Bag = { [key: string]: any }
  type FuncRef (line 800) | type FuncRef = `@${string}`
  type FuncRefMap (line 803) | type FuncRefMap<FT> = Record<FuncRef, FT>
  type Counters (line 806) | type Counters = { [key: string]: number }
  type Tin (line 809) | type Tin = number
  type TokenMap (line 812) | type TokenMap = { [name: string]: Tin }
  type TokenSetMap (line 815) | type TokenSetMap = { [name: string]: Tin[] }
  type TinMap (line 818) | type TinMap = { [ref: number]: string }
  type TinSetMap (line 821) | type TinSetMap = { [ref: number]: string }
  type MatchMap (line 824) | type MatchMap = { [name: string]: RegExp | LexMatcher }
  type Chars (line 827) | type Chars = { [char: string]: number }
  type StrMap (line 830) | type StrMap = { [name: string]: string }
  type RuleState (line 834) | type RuleState = 'o' | 'c'
  type RuleStep (line 838) | type RuleStep = 'b' | 'a'
  type LexMatcher (line 841) | type LexMatcher = (
  type MakeLexMatcher (line 848) | type MakeLexMatcher = (
  type LexCheck (line 853) | type LexCheck = (
  type ParsePrepare (line 857) | type ParsePrepare = (jsonic: Jsonic, ctx: Context, meta?: any) => void
  type RuleSpecMap (line 859) | type RuleSpecMap = { [name: string]: RuleSpec }
  type RuleDefiner (line 861) | type RuleDefiner = (rs: RuleSpec, p: Parser) => void | RuleSpec
  type NormAltSpec (line 864) | interface NormAltSpec extends AltSpec {
  type AltCond (line 883) | type AltCond =
  type NormAltCond (line 887) | type NormAltCond =
  type AltModifier (line 892) | type AltModifier = (
  type AltAction (line 900) | type AltAction = (rule: Rule, ctx: Context, alt: AltMatch) => any
  type AltNext (line 903) | type AltNext = (
  type AltBack (line 910) | type AltBack = (
  type StateAction (line 918) | type StateAction = (
  type AltError (line 927) | type AltError = (
  type ValModifier (line 933) | type ValModifier = (
  type LexSub (line 940) | type LexSub = (tkn: Token, rule: Rule, ctx: Context) => void
  type RuleSub (line 941) | type RuleSub = (rule: Rule, ctx: Context) => void
  type Parser (line 943) | interface Parser {
  type GrammarSpec (line 961) | type GrammarSpec = {
  type GrammarAltSpec (line 985) | type GrammarAltSpec = {

FILE: src/utility.ts
  function configure (line 113) | function configure(
  function tokenize (line 470) | function tokenize<
  function findTokenSet (line 492) | function findTokenSet<
  function mesc (line 503) | function mesc(s: string, _?: any) {
  function regexp (line 509) | function regexp(
  function escre (line 526) | function escre(s: string | undefined) {
  function deep (line 540) | function deep(base?: any, ...rest: any): any {
  function badlex (line 578) | function badlex(lex: Lex, BD: Tin, ctx: Context) {
  function makelog (line 607) | function makelog(ctx: Context, meta: any) {
  function srcfmt (line 637) | function srcfmt(config: Config): (s: any) => string {
  function str (line 666) | function str(o: any, len: number = 44) {
  function snip (line 676) | function snip(s: any, len: number = 5) {
  function clone (line 682) | function clone(class_instance: any) {
  function charset (line 690) | function charset(...parts: (string | object | boolean | undefined)[]): C...
  function clean (line 702) | function clean<T>(o: T): T {
  function filterRules (line 712) | function filterRules(rs: RuleSpec, cfg: Config) {
  function prop (line 748) | function prop(obj: any, path: string, val?: any): any {
  function modlist (line 783) | function modlist(list: any[], mods?: ListMods) {
  function parserwrap (line 829) | function parserwrap(parser: any) {
  function getpath (line 921) | function getpath(root: any, path: string | string[]): any {
  function resolveFuncRefs (line 933) | function resolveFuncRefs(

FILE: test/aa-wildcard.test.js
  function make_norules (line 23) | function make_norules(opts) {

FILE: test/alignment.test.js
  function deepEqual (line 18) | function deepEqual(actual, expected, msg) {
  function tsvTest (line 24) | function tsvTest(name, parser) {
  function tsvErrorTest (line 34) | function tsvErrorTest(name, parser) {
  function tsvNullTest (line 48) | function tsvNullTest(name) {

FILE: test/bnf.test.js
  constant FIXTURES (line 19) | const FIXTURES = Path.join(__dirname, 'grammar')
  function loadFixture (line 21) | function loadFixture(name) {
  function stripActions (line 28) | function stripActions(alt) {
  function makeConsole (line 1027) | function makeConsole() {

FILE: test/cli.test.js
  function make_cn (line 204) | function make_cn() {

FILE: test/comma.test.js
  function tsvTest (line 10) | function tsvTest(name) {

FILE: test/csv-grammar.test.js
  function makeCsv (line 14) | function makeCsv() {

FILE: test/custom.test.js
  function Car (line 482) | function Car() {
  function make_norules (line 759) | function make_norules(opts) {

FILE: test/directive-grammar.test.js
  function defineDirective (line 16) | function defineDirective(j, { name, open, action }) {
  function makeJ (line 32) | function makeJ() {

FILE: test/doc.test.js
  function sepper (line 112) | function sepper(jsonic) {
  function foo (line 122) | function foo(jsonic) {
  function bar (line 127) | function bar(jsonic) {

FILE: test/exhaust.js
  function exhaust (line 14) | function exhaust(size, print) {
  function make_strgen (line 112) | function make_strgen(size, max, init) {

FILE: test/feature.test.js
  function tsvTest (line 18) | function tsvTest(name) {
  function tsvTestWith (line 30) | function tsvTestWith(name, opts) {
  function tsvTestListChild (line 43) | function tsvTestListChild(name, opts) {
  function match (line 1248) | function match(src, pat, ctx) {

FILE: test/first-version-perf.js
  function pv_perf (line 6) | function pv_perf(dur) {

FILE: test/first-version.test.js
  function tsvTest (line 13) | function tsvTest(name) {

FILE: test/grammar.test.js
  function altGTags (line 928) | function altGTags(j, rulename, state) {

FILE: test/jsonic.test.js
  function tsvTest (line 26) | function tsvTest(name) {
  function make_empty (line 435) | function make_empty(opts) {

FILE: test/large.js
  function large (line 14) | function large(size, print) {

FILE: test/lex.test.js
  function lexall (line 12) | function lexall(src) {
  function alleq (line 22) | function alleq(ta) {
  function lexstart (line 29) | function lexstart(src) {
  function st (line 535) | function st(tkn) {

FILE: test/long.js
  function run (line 32) | function run(print, size, step) {
  function long (line 68) | function long(print, str, count, lencheck) {

FILE: test/nlookahead.test.js
  function make_norules (line 12) | function make_norules(opts) {

FILE: test/perf.js
  function run_parse (line 38) | function run_parse() {
  function count_parse (line 59) | function count_parse(input) {

FILE: test/plugin.test.js
  function make_token_plugin (line 338) | function make_token_plugin(char, val) {

FILE: test/prep.ts
  function prep (line 4) | function prep() { return null }

FILE: test/readme.test.js
  function deq (line 10) | function deq(actual, expected, msg) {
  function myPlugin (line 119) | function myPlugin(jsonic, options) {

FILE: test/rewind.test.js
  function make_norules (line 17) | function make_norules(opts) {

FILE: test/rfc3986.test.js
  constant GRAMMAR (line 35) | const GRAMMAR = Fs.readFileSync(

FILE: test/utility.js
  function unescape (line 4) | function unescape(str) {
  function loadTSV (line 13) | function loadTSV(name) {
Condensed preview — 296 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,065K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 977,
    "preview": "name: build\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n\n    strategy:\n  "
  },
  {
    "path": ".gitignore",
    "chars": 176,
    "preview": "lib-cov\n*.seed\n*.log\n*.csv\n*.dat\n*.out\n*.pid\n*.gz\n\npids\nlogs\nresults\n\nnpm-debug.log\n\n*~\nnode_modules\n\n.idea/\n\n\ntrial\n\nte"
  },
  {
    "path": "CNAME",
    "chars": 24,
    "preview": "jsonic.richardrodger.com"
  },
  {
    "path": "LICENSE",
    "chars": 1086,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2013-2020 Richard Rodger\n\nPermission is hereby granted, free of charge, to any pers"
  },
  {
    "path": "Makefile",
    "chars": 1055,
    "preview": ".PHONY: all build test clean build-ts build-go test-ts test-go clean-ts clean-go publish-go tags-go reset\n\nall: build te"
  },
  {
    "path": "README.md",
    "chars": 4627,
    "preview": "# jsonic\n\nJSON is great. JSON parsers are not. They punish you for every missing\nquote and misplaced comma. You're a pro"
  },
  {
    "path": "TODO.md",
    "chars": 1933,
    "preview": "# TODO\n\n* P1; exception inside matcher needs own error code - too easy to miss!\n* P1; remove console colors in browser? "
  },
  {
    "path": "bin/jsonic",
    "chars": 116,
    "preview": "#!/usr/bin/env node\nrequire('../dist/jsonic-cli').run(process.argv, console).catch((e) => console.error(e.message))\n"
  },
  {
    "path": "bin/jsonic-bnf",
    "chars": 120,
    "preview": "#!/usr/bin/env node\nrequire('../dist/jsonic-bnf-cli').run(process.argv, console).catch((e) => console.error(e.message))\n"
  },
  {
    "path": "dist/bnf.d.ts",
    "chars": 1942,
    "preview": "import type { BnfConvertOptions, GrammarSpec, Rule } from './types';\ntype BnfElement = {\n    kind: 'term';\n    literal: "
  },
  {
    "path": "dist/bnf.js",
    "chars": 78785,
    "preview": "\"use strict\";\n/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */\nObject.defineProperty(exports,"
  },
  {
    "path": "dist/debug.d.ts",
    "chars": 87,
    "preview": "import type { Plugin } from './jsonic';\ndeclare const Debug: Plugin;\nexport { Debug };\n"
  },
  {
    "path": "dist/debug.js",
    "chars": 12209,
    "preview": "\"use strict\";\n/* Copyright (c) 2021-2023 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/defaults.d.ts",
    "chars": 90,
    "preview": "import { Options } from './jsonic';\ndeclare const defaults: Options;\nexport { defaults };\n"
  },
  {
    "path": "dist/defaults.js",
    "chars": 10757,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/error.d.ts",
    "chars": 1480,
    "preview": "import type { Bag, Context, Rule, Token } from './types';\ndeclare class JsonicError extends SyntaxError {\n    constructo"
  },
  {
    "path": "dist/error.js",
    "chars": 11049,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/grammar.d.ts",
    "chars": 158,
    "preview": "import { Jsonic } from './jsonic';\ndeclare function grammar(jsonic: Jsonic): void;\ndeclare function makeJSON(jsonic: any"
  },
  {
    "path": "dist/grammar.js",
    "chars": 30508,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/jsonic-bnf-cli.d.ts",
    "chars": 78,
    "preview": "export declare function run(argv: string[], console: Console): Promise<void>;\n"
  },
  {
    "path": "dist/jsonic-bnf-cli.js",
    "chars": 5083,
    "preview": "\"use strict\";\n/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */\nvar __importDefault = (this &&"
  },
  {
    "path": "dist/jsonic-cli.d.ts",
    "chars": 78,
    "preview": "export declare function run(argv: string[], console: Console): Promise<void>;\n"
  },
  {
    "path": "dist/jsonic-cli.js",
    "chars": 8353,
    "preview": "\"use strict\";\n/* Copyright (c) 2020-2024 Richard Rodger, Oliver Sturm, and other contributors, MIT License */\nvar __impo"
  },
  {
    "path": "dist/jsonic.d.ts",
    "chars": 2581,
    "preview": "import type { AltAction, AltCond, AltError, AltMatch, AltModifier, AltSpec, Bag, Config, Context, Counters, FuncRef, Jso"
  },
  {
    "path": "dist/jsonic.js",
    "chars": 15361,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/lexer.d.ts",
    "chars": 2298,
    "preview": "import type { Tin, Token, Point, Lex, Rule, Config, Context, MakeLexMatcher, Bag, NormAltSpec } from './types';\nimport {"
  },
  {
    "path": "dist/lexer.js",
    "chars": 35133,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2022 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/parser.d.ts",
    "chars": 723,
    "preview": "import type { Config, Options, Parser, RuleDefiner, RuleSpec, RuleSpecMap, Jsonic } from './types';\nimport { makeRule, m"
  },
  {
    "path": "dist/parser.js",
    "chars": 11714,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2026 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/rules.d.ts",
    "chars": 2899,
    "preview": "import type { AltSpec, Config, Context, FuncRef, FuncRefMap, Jsonic, Lex, ListMods, Rule, RuleSpec, RuleState, RuleStep,"
  },
  {
    "path": "dist/rules.js",
    "chars": 30288,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/self.d.ts",
    "chars": 78,
    "preview": "import { Plugin } from './jsonic';\ndeclare let Self: Plugin;\nexport { Self };\n"
  },
  {
    "path": "dist/self.js",
    "chars": 1070,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Self = void 0;\n//  See aontu lang.t"
  },
  {
    "path": "dist/tsconfig.tsbuildinfo",
    "chars": 300,
    "preview": "{\"root\":[\"../src/bnf.ts\",\"../src/debug.ts\",\"../src/defaults.ts\",\"../src/error.ts\",\"../src/grammar.ts\",\"../src/jsonic-bnf"
  },
  {
    "path": "dist/types.d.ts",
    "chars": 17620,
    "preview": "export declare const OPEN: RuleState;\nexport declare const CLOSE: RuleState;\nexport declare const BEFORE: RuleStep;\nexpo"
  },
  {
    "path": "dist/types.js",
    "chars": 835,
    "preview": "\"use strict\";\n/* Copyright (c) 2021-2022 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist/utility.d.ts",
    "chars": 3176,
    "preview": "import type { Chars, Config, Context, Lex, Options, RuleSpec, Tin, ListMods } from './types';\ndeclare const keys: (x: an"
  },
  {
    "path": "dist/utility.js",
    "chars": 27219,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "dist-test/prep.js",
    "chars": 217,
    "preview": "\"use strict\";\n// temporary file to help prepare test rewrite in ts \nObject.defineProperty(exports, \"__esModule\", { value"
  },
  {
    "path": "dist-test/tsconfig.tsbuildinfo",
    "chars": 46,
    "preview": "{\"root\":[\"../test/prep.ts\"],\"version\":\"6.0.3\"}"
  },
  {
    "path": "doc/api.md",
    "chars": 4715,
    "preview": "# API Reference\n\n## Parsing\n\n### `Jsonic(src, meta?, parent_ctx?)`\n\nParse a string using default settings. `Jsonic` is b"
  },
  {
    "path": "doc/bnf-to-jsonic-feasibility.md",
    "chars": 16997,
    "preview": "# Feasibility Report: Converting BNF Grammars into Jsonic Grammars\n\n## Summary\n\nA converter from Backus–Naur Form (BNF) "
  },
  {
    "path": "doc/lsp-feasibility.md",
    "chars": 12969,
    "preview": "# Feasibility Report: Language Server Protocol Support for Jsonic\n\n## Summary\n\nAdding a Language Server Protocol (LSP) i"
  },
  {
    "path": "doc/options.md",
    "chars": 5868,
    "preview": "# Options Reference\n\nOptions are passed to `Jsonic.make()` to create a configured parser instance.\nAll fields are option"
  },
  {
    "path": "doc/plugins.md",
    "chars": 4011,
    "preview": "# Writing Plugins\n\nPlugins extend jsonic by modifying the grammar, adding new token types,\nregistering custom matchers, "
  },
  {
    "path": "doc/syntax.md",
    "chars": 3639,
    "preview": "# Syntax Reference\n\njsonic accepts standard JSON and extends it with the relaxations described\nbelow. All extensions are"
  },
  {
    "path": "docs/404.html",
    "chars": 2720,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/CNAME",
    "chars": 24,
    "preview": "jsonic.richardrodger.com"
  },
  {
    "path": "docs/assets/css/0.styles.610e9dca.css",
    "chars": 25309,
    "preview": "code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu M"
  },
  {
    "path": "docs/assets/js/10.88d9a57b.js",
    "chars": 436,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{193:function(t,s,r){\"use strict\";r.r(s);var a=r(6),e=Object(a."
  },
  {
    "path": "docs/assets/js/11.7988a5fa.js",
    "chars": 29834,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{195:function(t,s,a){\"use strict\";a.r(s);var n=a(6),e=Object(n."
  },
  {
    "path": "docs/assets/js/12.d9f3d941.js",
    "chars": 454,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{194:function(t,s,e){\"use strict\";e.r(s);var i=e(6),r=Object(i."
  },
  {
    "path": "docs/assets/js/13.775f91ca.js",
    "chars": 14542,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{198:function(s,t,a){\"use strict\";a.r(t);var n=a(6),e=Object(n."
  },
  {
    "path": "docs/assets/js/14.f56c2700.js",
    "chars": 12240,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{197:function(e,a,t){\"use strict\";t.r(a);var n=t(6),s=Object(n."
  },
  {
    "path": "docs/assets/js/15.00058088.js",
    "chars": 1087,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{196:function(t,a,r){\"use strict\";r.r(a);var s=r(6),i=Object(s."
  },
  {
    "path": "docs/assets/js/16.70a6eea0.js",
    "chars": 319,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{199:function(t,s,n){\"use strict\";n.r(s);var e=n(6),o=Object(e."
  },
  {
    "path": "docs/assets/js/17.0d1f36b1.js",
    "chars": 7315,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{203:function(t,s,a){\"use strict\";a.r(s);var e=a(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/18.0f184e32.js",
    "chars": 7383,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{200:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/19.57ad231b.js",
    "chars": 7366,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{202:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/2.34930047.js",
    "chars": 26585,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{149:function(t,e,n){\"use strict\";n.d(e,\"d\",(function(){return s"
  },
  {
    "path": "docs/assets/js/20.58c8b075.js",
    "chars": 8218,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{201:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/21.0c46ffa9.js",
    "chars": 7332,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{204:function(t,s,a){\"use strict\";a.r(s);var e=a(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/22.965cbc0d.js",
    "chars": 7816,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{206:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/23.18c270f0.js",
    "chars": 7417,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{207:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/24.5895d76a.js",
    "chars": 7366,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{205:function(t,a,s){\"use strict\";s.r(a);var e=s(6),n=Object(e."
  },
  {
    "path": "docs/assets/js/25.a347f1d6.js",
    "chars": 69075,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{208:function(t,s,a){\"use strict\";a.r(s);var n=a(6),e=Object(n."
  },
  {
    "path": "docs/assets/js/26.c7b8345d.js",
    "chars": 466,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{209:function(t,e,s){\"use strict\";s.r(e);var r=s(6),n=Object(r."
  },
  {
    "path": "docs/assets/js/27.4e6f90b7.js",
    "chars": 39062,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{210:function(a,t,s){\"use strict\";s.r(t);var e=s(6),r=Object(e."
  },
  {
    "path": "docs/assets/js/28.6e0fa7bc.js",
    "chars": 1742,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{214:function(a,t,n){\"use strict\";n.r(t);var s=n(6),e=Object(s."
  },
  {
    "path": "docs/assets/js/29.77b8e3b6.js",
    "chars": 708,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{211:function(t,r,a){\"use strict\";a.r(r);var s=a(6),i=Object(s."
  },
  {
    "path": "docs/assets/js/3.6ce1235a.js",
    "chars": 337,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{164:function(n,s,t){},184:function(n,s,t){\"use strict\";t(164)},"
  },
  {
    "path": "docs/assets/js/30.69b1b865.js",
    "chars": 427,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{213:function(t,s,n){\"use strict\";n.r(s);var r=n(6),a=Object(r."
  },
  {
    "path": "docs/assets/js/31.c68f976d.js",
    "chars": 319,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{215:function(t,n,s){\"use strict\";s.r(n);var e=s(6),o=Object(e."
  },
  {
    "path": "docs/assets/js/32.0a08a140.js",
    "chars": 436,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{212:function(t,s,i){\"use strict\";i.r(s);var n=i(6),r=Object(n."
  },
  {
    "path": "docs/assets/js/4.064b2ac3.js",
    "chars": 485,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{165:function(t,e,n){},185:function(t,e,n){\"use strict\";n(165)},"
  },
  {
    "path": "docs/assets/js/5.46815478.js",
    "chars": 562,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{166:function(t,e,a){},186:function(t,e,a){\"use strict\";a(166)},"
  },
  {
    "path": "docs/assets/js/6.f03d59ff.js",
    "chars": 1667,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{167:function(e,t,a){},187:function(e,t,a){\"use strict\";a(167)},"
  },
  {
    "path": "docs/assets/js/7.6be3acca.js",
    "chars": 52210,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{216:function(t,a,h){\"use strict\";h.r(a);var s=h(6),r=Object(s.a"
  },
  {
    "path": "docs/assets/js/8.0a081a71.js",
    "chars": 667,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{189:function(t,e,s){\"use strict\";s.r(e);const o=[\"There's nothi"
  },
  {
    "path": "docs/assets/js/9.9b6e31d5.js",
    "chars": 679,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{192:function(t,a,r){\"use strict\";r.r(a);var s=r(6),e=Object(s.a"
  },
  {
    "path": "docs/assets/js/app.0c621e62.js",
    "chars": 159213,
    "preview": "(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,s=e[0],u=e[1],l=e[2]"
  },
  {
    "path": "docs/guide/alternatives.html",
    "chars": 7070,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/custom-parsers.html",
    "chars": 6786,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/getting-started.html",
    "chars": 28987,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/index.html",
    "chars": 6568,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/install.html",
    "chars": 17398,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/syntax-introduction.html",
    "chars": 17671,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/guide/tutorials.html",
    "chars": 7395,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/index.html",
    "chars": 6369,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/jsonic.js",
    "chars": 67500,
    "preview": "\"use strict\";\n/* Copyright (c) 2013-2021 Richard Rodger, MIT License */\nObject.defineProperty(exports, \"__esModule\", { v"
  },
  {
    "path": "docs/plugin/csv.html",
    "chars": 12478,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/dynamic.html",
    "chars": 12580,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/hoover.html",
    "chars": 12543,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/index.html",
    "chars": 12960,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/json.html",
    "chars": 12505,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/multifile.html",
    "chars": 12650,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/plugin/native.html",
    "chars": 12444,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/railroad-diagrams.css",
    "chars": 999,
    "preview": "svg.railroad-diagram {\n    background-color: hsl(30,20%,95%);\n}\nsvg.railroad-diagram path {\n    stroke-width: 3;\n    str"
  },
  {
    "path": "docs/ref/api.html",
    "chars": 50558,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/ref/index.html",
    "chars": 6287,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/ref/options.html",
    "chars": 36147,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/ref/syntax.html",
    "chars": 44683,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/tutorial/index.html",
    "chars": 6119,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/tutorial/parsing-csv.html",
    "chars": 5938,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/tutorial/write-a-parser.html",
    "chars": 5855,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "docs/tutorial/write-a-plugin.html",
    "chars": 5950,
    "preview": "<!DOCTYPE html>\n<html lang=\"en-US\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-"
  },
  {
    "path": "go/README.md",
    "chars": 2251,
    "preview": "# jsonic (Go)\n\nVersion: 0.1.22\n\nA Go port of [jsonic](https://github.com/jsonicjs/jsonic), the lenient\nJSON parser. Same"
  },
  {
    "path": "go/alignment_test.go",
    "chars": 34045,
    "preview": "package jsonic\n\n// Alignment tests validate that Go behavior matches the authoritative TypeScript\n// implementation. Tes"
  },
  {
    "path": "go/both_ref_test.go",
    "chars": 15765,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// expectBothRef parses input with both MapRef and ListRef enabled and checks the"
  },
  {
    "path": "go/color_test.go",
    "chars": 5536,
    "preview": "package jsonic\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\n// --- Defaults: active, matches TS ---\n\nfunc TestColorDefaultsActive("
  },
  {
    "path": "go/comment_suffix_test.go",
    "chars": 9313,
    "preview": "package jsonic\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\n// --- Line comment suffixes ---\n\nfunc TestCommentLineSuffixSingleStri"
  },
  {
    "path": "go/coverage.html",
    "chars": 294851,
    "preview": "\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n\t\t<title>go: Go Co"
  },
  {
    "path": "go/csv_grammar_test.go",
    "chars": 5780,
    "preview": "package jsonic\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\n// Minimal CSV grammar built directly on the jsonic parser API.\n// Mir"
  },
  {
    "path": "go/debug.go",
    "chars": 3889,
    "preview": "package jsonic\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// Debug is a plugin that provides introspection and tracing capab"
  },
  {
    "path": "go/directive_grammar_test.go",
    "chars": 3030,
    "preview": "package jsonic\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n)\n\n// Minimal directive-style plugin defined inline for"
  },
  {
    "path": "go/doc/api.md",
    "chars": 7128,
    "preview": "# API Reference (Go)\n\n```go\nimport \"github.com/jsonicjs/jsonic/go\"\n```\n\n## Parsing\n\n### `Parse(src string) (any, error)`"
  },
  {
    "path": "go/doc/differences.md",
    "chars": 3119,
    "preview": "# Differences from TypeScript\n\nThe TypeScript version is the authoritative implementation. The Go version is\na faithful "
  },
  {
    "path": "go/doc/options.md",
    "chars": 6282,
    "preview": "# Options Reference (Go)\n\nOptions are passed to `Make()` to configure a parser instance. All fields use\npointer types --"
  },
  {
    "path": "go/doc/plugins.md",
    "chars": 4607,
    "preview": "# Writing Plugins (Go)\n\nPlugins extend jsonic by modifying the grammar, adding token types,\nregistering custom matchers,"
  },
  {
    "path": "go/doc/syntax.md",
    "chars": 1410,
    "preview": "# Syntax Reference (Go)\n\nThe Go version of jsonic supports the same core syntax as the TypeScript\nversion. See the [top-"
  },
  {
    "path": "go/feature_tsv_test.go",
    "chars": 5928,
    "preview": "package jsonic\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\n// stripRefs recursively unwraps ListRef"
  },
  {
    "path": "go/fnref_identity_test.go",
    "chars": 1488,
    "preview": "package jsonic\n\nimport \"testing\"\n\n// TestFnrefDedupeByFunctionIdentity verifies that registering the same\n// StateAction"
  },
  {
    "path": "go/fnref_reinstall_test.go",
    "chars": 1589,
    "preview": "package jsonic\n\nimport \"testing\"\n\n// TestFnrefNoReinstallOnSubsequentCall is the Go counterpart of the JS\n// fnref-no-re"
  },
  {
    "path": "go/go.mod",
    "chars": 48,
    "preview": "module github.com/jsonicjs/jsonic/go\n\ngo 1.24.7\n"
  },
  {
    "path": "go/grammar.go",
    "chars": 17759,
    "preview": "package jsonic\n\n// buildGrammar populates the default jsonic grammar rules using declarative GrammarAltSpec.\n// This is "
  },
  {
    "path": "go/grammar_decl_test.go",
    "chars": 47492,
    "preview": "package jsonic\n\nimport (\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n)\n\n// mustGrammar calls Grammar and fails the test o"
  },
  {
    "path": "go/grammar_setting_test.go",
    "chars": 9147,
    "preview": "package jsonic\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n)\n\n// --- Helpers ---\n\n// altGTags returns, for the named rule an"
  },
  {
    "path": "go/grammarspec.go",
    "chars": 22362,
    "preview": "package jsonic\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// FuncRef is a string starting with \"@\" that references a func"
  },
  {
    "path": "go/jsonic.go",
    "chars": 6458,
    "preview": "// Package jsonic provides a lenient JSON parser that supports relaxed syntax\n// including unquoted keys, implicit objec"
  },
  {
    "path": "go/jsonic_nontsv_test.go",
    "chars": 32993,
    "preview": "package jsonic\n\n// Non-TSV tests ported from the TypeScript test suite.\n// Tests that rely on TS-specific features (plug"
  },
  {
    "path": "go/jsonic_test.go",
    "chars": 9784,
    "preview": "package jsonic\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings"
  },
  {
    "path": "go/lexer.go",
    "chars": 44784,
    "preview": "package jsonic\n\nimport (\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// MatchValueEntry holds a resolved match.value matcher entry.\n"
  },
  {
    "path": "go/listchild_test.go",
    "chars": 11384,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// makeChildParser creates a parser with List.Child enabled.\n// ListRef is automa"
  },
  {
    "path": "go/listref_test.go",
    "chars": 6925,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// expectListRef parses input with ListRef enabled and checks the result.\nfunc ex"
  },
  {
    "path": "go/mapref_test.go",
    "chars": 7158,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// expectMapRef parses input with MapRef enabled and checks the result.\nfunc expe"
  },
  {
    "path": "go/nlookahead_test.go",
    "chars": 7460,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// N-token lookahead tests. Previously Go's ParseAlts only inspected\n// alt.S[0] "
  },
  {
    "path": "go/options.go",
    "chars": 35165,
    "preview": "package jsonic\n\nimport (\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n)\n\n// Options configures a Jsonic parser instance.\n// All fields u"
  },
  {
    "path": "go/options_parity_test.go",
    "chars": 5537,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// --- LexCheck hooks ---\n\nfunc TestFixedCheckHookFires(t *testing.T) {\n\tcalled :"
  },
  {
    "path": "go/parser.go",
    "chars": 8859,
    "preview": "package jsonic\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Context holds the parse state, matching the TypeScript Cont"
  },
  {
    "path": "go/plugin.go",
    "chars": 24576,
    "preview": "package jsonic\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// Plugin is a function that modifies a Jsonic instance.\n// Plugin"
  },
  {
    "path": "go/plugin_test.go",
    "chars": 60471,
    "preview": "package jsonic\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\n// hasExactTag checks if tagStr (comma-separated) contains the exact t"
  },
  {
    "path": "go/readme_test.go",
    "chars": 4176,
    "preview": "package jsonic\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc boolp(b bool) *bool { return &b }\n\n// toJSON converts a val"
  },
  {
    "path": "go/rule.go",
    "chars": 21077,
    "preview": "package jsonic\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// groupTagRe is the regex every g tag must match: a lowercase l"
  },
  {
    "path": "go/rule_include_test.go",
    "chars": 7144,
    "preview": "package jsonic\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\n// --- include-only filter ---\n\nfunc TestRuleIncludeKeepsOnlyTaggedAlt"
  },
  {
    "path": "go/safe_test.go",
    "chars": 3216,
    "preview": "package jsonic\n\nimport \"testing\"\n\n// Mirrors test/safe.test.js. TS protects against __proto__ / constructor\n// key pollu"
  },
  {
    "path": "go/text.go",
    "chars": 2347,
    "preview": "package jsonic\n\n// Text represents a string value with metadata about how it was quoted\n// in the source. When the TextI"
  },
  {
    "path": "go/textinfo_test.go",
    "chars": 6283,
    "preview": "package jsonic\n\nimport (\n\t\"testing\"\n)\n\n// expectTextInfo parses input with TextInfo enabled and checks the result.\nfunc "
  },
  {
    "path": "go/token.go",
    "chars": 3437,
    "preview": "package jsonic\n\n// Tin is a token identification number.\ntype Tin = int\n\n// Standard token Tins - assigned in order matc"
  },
  {
    "path": "go/token_test.go",
    "chars": 2286,
    "preview": "package jsonic\n\nimport \"testing\"\n\n// Mirrors TS src/lexer.ts:115 — when Token.Val is a function, ResolveVal\n// invokes i"
  },
  {
    "path": "go/util.go",
    "chars": 2926,
    "preview": "package jsonic\n\nimport \"sort\"\n\n// Util exposes helper functions that plugins commonly need, mirroring\n// TS jsonic.util "
  },
  {
    "path": "go/util_test.go",
    "chars": 3025,
    "preview": "package jsonic\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\n// Tests for the Util bag and its helpers. Mirrors the TS util functio"
  },
  {
    "path": "go/utility.go",
    "chars": 25476,
    "preview": "package jsonic\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Deep performs a recurs"
  },
  {
    "path": "go/variant_test.go",
    "chars": 1753,
    "preview": "package jsonic\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\n// Port of test/variant.test.js `just-json-happy`. Uses MakeJSON(),\n//"
  },
  {
    "path": "package.json",
    "chars": 1928,
    "preview": "{\n  \"name\": \"jsonic\",\n  \"version\": \"2.28.0\",\n  \"main\": \"dist/jsonic.js\",\n  \"type\": \"commonjs\",\n  \"types\": \"dist/jsonic.d"
  },
  {
    "path": "src/bnf.ts",
    "chars": 78279,
    "preview": "/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */\n\n/*  bnf.ts\n *  BNF -> jsonic grammar spec c"
  },
  {
    "path": "src/debug.ts",
    "chars": 11838,
    "preview": "/* Copyright (c) 2021-2023 Richard Rodger, MIT License */\n\n/*  debug.ts\n *  Debug tools\n */\n\nimport type {\n  Context,\n  "
  },
  {
    "path": "src/defaults.ts",
    "chars": 9847,
    "preview": "/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\n\n/*  defaults.ts\n *  Default option values.\n */\n\nimport { Opti"
  },
  {
    "path": "src/error.ts",
    "chars": 10512,
    "preview": "/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\n\n/*  error.ts\n *  Error handling functions and classes.\n */\n\ni"
  },
  {
    "path": "src/grammar.ts",
    "chars": 26336,
    "preview": "/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\n\n/*  grammar.ts\n *  Grammar definition.\n *\n *  First, a pure J"
  },
  {
    "path": "src/jsonic-bnf-cli.ts",
    "chars": 4443,
    "preview": "/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */\n\n/*  jsonic-bnf-cli.ts\n *  CLI wrapper for t"
  },
  {
    "path": "src/jsonic-cli.ts",
    "chars": 7443,
    "preview": "/* Copyright (c) 2020-2024 Richard Rodger, Oliver Sturm, and other contributors, MIT License */\n\nimport Fs from 'node:fs"
  },
  {
    "path": "src/jsonic.ts",
    "chars": 12786,
    "preview": "/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\n\n/*  jsonic.ts\n *  Entry point and API.\n */\n\nimport type {\n  A"
  },
  {
    "path": "src/lexer.ts",
    "chars": 30081,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger, MIT License */\n\n/*  lexer.ts\n *  Lexer implementation, converts source text i"
  },
  {
    "path": "src/mfix.js",
    "chars": 441,
    "preview": "/* Copyright (c) 2021 Richard Rodger and other contributors, MIT License */\n'use strict'\n\n// Uncomments a special fix th"
  },
  {
    "path": "src/parser.ts",
    "chars": 10826,
    "preview": "/* Copyright (c) 2013-2026 Richard Rodger, MIT License */\n\n/*  parser.ts\n *  Parser implementation, converts the lexer t"
  },
  {
    "path": "src/rules.ts",
    "chars": 29383,
    "preview": "/* Copyright (c) 2013-2023 Richard Rodger, MIT License */\n\n/*  rules.ts\n *  Parser rules.\n */\n\nimport type {\n  AltAction"
  },
  {
    "path": "src/self.ts",
    "chars": 1003,
    "preview": "\nimport { Jsonic, Plugin } from './jsonic'\n\n\n//  See aontu lang.ts\n//\n//  plugin: aontu: {\n//\n//    rule: val: open: '& "
  },
  {
    "path": "src/tsconfig.json",
    "chars": 333,
    "preview": "{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true,\n    \"module\": \"nodenext\",\n    \"noEmitOnError\": true,\n    \"outDir\":"
  },
  {
    "path": "src/types.ts",
    "chars": 26772,
    "preview": "/* Copyright (c) 2021-2022 Richard Rodger, MIT License */\n\n/*  types.ts\n *  Type and constant definitions.\n */\n\nexport c"
  },
  {
    "path": "src/utility.ts",
    "chars": 25623,
    "preview": "/* Copyright (c) 2013-2024 Richard Rodger, MIT License */\n\n/*  utility.ts\n *  Utility functions and constants.\n */\n\nimpo"
  },
  {
    "path": "test/aa-wildcard.test.js",
    "chars": 3289,
    "preview": "/* Copyright (c) 2026 Richard Rodger and other contributors, MIT License */\n'use strict'\n\n// Coverage for `#AA` as a tru"
  },
  {
    "path": "test/alignment.test.js",
    "chars": 10666,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\n// Alignment tests valida"
  },
  {
    "path": "test/also-bad-plugin.js",
    "chars": 30,
    "preview": "module.exports = 'bad-plugin'\n"
  },
  {
    "path": "test/angle.js",
    "chars": 152,
    "preview": "module.exports = function angle(jsonic) {\n  jsonic.options({\n    fixed: {\n      token: {\n        '#OB': '<',\n        '#C"
  },
  {
    "path": "test/api.test.js",
    "chars": 1007,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/bad-plugin.js",
    "chars": 35,
    "preview": "module.exports = B A D S Y N T A X\n"
  },
  {
    "path": "test/bar.jsonic",
    "chars": 7,
    "preview": "\nqaz: 2"
  },
  {
    "path": "test/bnf.test.js",
    "chars": 32289,
    "preview": "/* Copyright (c) 2025 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = requi"
  },
  {
    "path": "test/cli.test.js",
    "chars": 5458,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/comma.test.js",
    "chars": 766,
    "preview": "/* Copyright (c) 2013-2023 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/comment.test.js",
    "chars": 2802,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/csv-grammar.test.js",
    "chars": 4324,
    "preview": "/* Copyright (c) 2013-2026 Richard Rodger and other contributors, MIT License */\n'use strict'\n\n// Minimal CSV grammar ex"
  },
  {
    "path": "test/custom.test.js",
    "chars": 17970,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/debug.test.js",
    "chars": 414,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/directive-grammar.test.js",
    "chars": 2349,
    "preview": "/* Copyright (c) 2013-2026 Richard Rodger and other contributors, MIT License */\n'use strict'\n\n// Minimal directive-styl"
  },
  {
    "path": "test/dive.js",
    "chars": 1094,
    "preview": "const { Jsonic, util } = require('..')\nconst { Debug } = require('../dist/debug')\n\nlet j = Jsonic.make()\n  .use(function"
  },
  {
    "path": "test/doc.test.js",
    "chars": 5609,
    "preview": "/* Copyright (c) 2021 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = requi"
  },
  {
    "path": "test/error.test.js",
    "chars": 6046,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/exhaust.js",
    "chars": 2816,
    "preview": "// Fuzz test; measure memory usage.\n\nconst Util = require('util')\nconst I = Util.inspect\n\nconst { Jsonic, Lexer } = requ"
  },
  {
    "path": "test/feature.test.js",
    "chars": 47930,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/first-version-perf.js",
    "chars": 629,
    "preview": "// NOTE: the perf test used in the first version, reused against this version.\n// *Not* a test of the perf of the first "
  },
  {
    "path": "test/first-version.test.js",
    "chars": 5339,
    "preview": "/* Copyright (c) 2013-2022 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  },
  {
    "path": "test/foo.jsonic",
    "chars": 5,
    "preview": "bar:1"
  },
  {
    "path": "test/grammar/arith-leftrec.bnf",
    "chars": 317,
    "preview": "; Same arithmetic language as arith.bnf, in the natural\n; left-recursive form. The converter rewrites direct left recurs"
  },
  {
    "path": "test/grammar/arith.bnf",
    "chars": 298,
    "preview": "; Arithmetic grammar, stratified to avoid left recursion.\n; Uses the RFC 5234 core rule DIGIT — auto-included by the\n; c"
  },
  {
    "path": "test/grammar/greet.bnf",
    "chars": 78,
    "preview": "; Simple BNF fixture: alternation of terminal strings.\ngreet = \"hi\" / \"hello\"\n"
  },
  {
    "path": "test/grammar/json-subset.bnf",
    "chars": 392,
    "preview": "; Minimal JSON-like subset: digits, nested objects, arrays.\n; Names / strings are simplified to single-letter terminals "
  },
  {
    "path": "test/grammar/pair.bnf",
    "chars": 60,
    "preview": "; Simple BNF fixture: two-terminal sequence.\npair = \"a\" \"b\"\n"
  },
  {
    "path": "test/grammar/rfc3986-uri.abnf",
    "chars": 2705,
    "preview": "; RFC 3986 Appendix A — Collected ABNF for URI\n; https://www.rfc-editor.org/rfc/rfc3986.txt\n;\n; Notes on differences fro"
  },
  {
    "path": "test/grammar.test.js",
    "chars": 35663,
    "preview": "/* Copyright (c) 2013-2024 Richard Rodger and other contributors, MIT License */\n'use strict'\n\nconst { describe, it } = "
  }
]

// ... and 96 more files (download for full content)

About this extraction

This page contains the full source code of the rjrodger/jsonic GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 296 files (2.7 MB), approximately 727.9k tokens, and a symbol index with 1894 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!