chore(release): prepare public source release

This commit is contained in:
MercuryToolbox Release
2026-07-18 15:41:59 +08:00
commit e365e5df4d
508 changed files with 163373 additions and 0 deletions
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
This is not a PE file.
+2
View File
@@ -0,0 +1,2 @@
{"ok":true,"event":"login"}
{"ok":false,"event":"logout"}
+14
View File
@@ -0,0 +1,14 @@
{
"z": 3,
"a": {
"y": 2,
"x": 1
},
"items": [
{
"b": 2,
"a": 1
}
],
"name": "Ada"
}
+5
View File
@@ -0,0 +1,5 @@
name,age,city,score
Ada,34,London,9.5
Bob,,Paris,7
Cara,29,Paris,8.25
Drew,41,,6
1 name age city score
2 Ada 34 London 9.5
3 Bob Paris 7
4 Cara 29 Paris 8.25
5 Drew 41 6
+5
View File
@@ -0,0 +1,5 @@
name age city score
Ada 34 London 9.5
Bob Paris 7
Cara 29 Paris 8.25
Drew 41 6
1 name age city score
2 Ada 34 London 9.5
3 Bob Paris 7
4 Cara 29 Paris 8.25
5 Drew 41 6
+11
View File
@@ -0,0 +1,11 @@
error[E0425]: cannot find value `modee` in this scope
--> fixtures/reading/sample.rs:25:11
|
25 | match modee {
| ^^^^^ not found in this scope
warning: function `helper` is never used
--> fixtures/reading/sample.rs:33:4
|
33 | fn helper(value: i32) -> i32 {
| ^^^^^^
+2
View File
@@ -0,0 +1,2 @@
fixtures\reading\sample.cs(9,17): error CS0103: The name 'speeed' does not exist in the current context
fixtures\reading\sample.cs(4,21): warning CS0168: The variable 'unusedValue' is declared but never used
+4
View File
@@ -0,0 +1,4 @@
fixtures\reading\sample.rs:18:pub fn run(args: &[String]) -> Result<(), String> {
fixtures\reading\sample.rs:22: Mode::Fast
fixtures\reading\sample.rs:26: Mode::Fast => println!("fast"),
fixtures\reading\sample.cs:9: private int ComputeScore(int baseScore) {
+6
View File
@@ -0,0 +1,6 @@
# ISON Fixtures
These fixtures track the public examples on https://ison.dev/: `table.<name>`
block syntax for ISON and `object.<name>|fields|values` line records for ISONL.
The local v1 implementation covers deterministic JSON object and JSONL record
roundtrips without adding a Node, TypeScript, or external runtime dependency.
+4
View File
@@ -0,0 +1,4 @@
table.users
id:int name:str active:bool
1 Ada true
2 Bob false
+2
View File
@@ -0,0 +1,2 @@
object.record|id:int name:str active:bool|1 Ada true
object.record|id:int name:str active:bool|2 Bob false
+1
View File
@@ -0,0 +1 @@
{"users":[{"id":1,"name":"Ada","active":true},{"id":2,"name":"Bob","active":false}]}
+15
View File
@@ -0,0 +1,15 @@
# TONL v1 fixture assumptions
These fixtures define Mercury Toolbox's Rust-native TONL v1 surface for tests
and examples.
The representation is JSON-backed and line-oriented:
- A document object is written as `key = <JSON value>` per non-empty line.
- Record streams are separated by `---`.
- Lines beginning with `#` are comments.
- Values after `=` must be valid JSON literals, arrays, or objects.
- Non-object root values are represented by the reserved `$ = <JSON value>` key.
This keeps TONL deterministic, streamable, and easy to convert to and from JSON
or JSONL without a Node/TypeScript runtime.
+3
View File
@@ -0,0 +1,3 @@
# Invalid because TONL values must be JSON values.
name = "Ada"
score = not-json
+2
View File
@@ -0,0 +1,2 @@
{"id":"user-1","name":"Ada","active":true,"score":42}
{"id":"user-2","name":"Bob","active":false,"score":7}
+11
View File
@@ -0,0 +1,11 @@
# TONL v1 stream fixture: records separated by ---.
---
id = "user-1"
name = "Ada"
active = true
score = 42
---
id = "user-2"
name = "Bob"
active = false
score = 7
+1
View File
@@ -0,0 +1 @@
{"id":"user-1","name":"Ada","active":true,"score":42,"tags":["math","logic"],"meta":{"city":"London"}}
+7
View File
@@ -0,0 +1,7 @@
# TONL v1 fixture: JSON-backed key/value lines.
id = "user-1"
name = "Ada"
active = true
score = 42
tags = ["math","logic"]
meta = {"city":"London"}
@@ -0,0 +1,3 @@
name:"Ada"
profile:
city:"London"
+10
View File
@@ -0,0 +1,10 @@
{
"name": "Ada",
"active": true,
"score": 42,
"tags": ["math", "logic"],
"profile": {
"city": "London",
"year": 1843
}
}
+5
View File
@@ -0,0 +1,5 @@
name:"Ada"
active:true
score:42
tags:["math","logic"]
profile:{"city":"London","year":1843}
+2
View File
@@ -0,0 +1,2 @@
{"name":"Ada","score":10,"active":true}
{"name":"Bob","score":11,"active":false}
+3
View File
@@ -0,0 +1,3 @@
@(2):name,score,active
Ada,10,true
Bob,11,false
+4
View File
@@ -0,0 +1,4 @@
{"ts":"2026-04-20T12:00:00Z","level":"info","msg":"boot complete","component":"engine"}
{"ts":"2026-04-20T12:01:00Z","level":"error","msg":"failed login","component":"auth"}
{"ts":"2026-04-20T12:02:00Z","level":"warn","msg":"cache warmup","component":"cache"}
{"ts":"2026-04-20T12:03:00Z","level":"error","msg":"login throttled","component":"auth"}
+2
View File
@@ -0,0 +1,2 @@
{"event":"login","user":{"id":7,"name":"Ada"},"ok":true}
{"event":"logout","user":{"id":7,"name":"Ada"},"ok":false,"error":null}
+5
View File
@@ -0,0 +1,5 @@
2026-04-21T12:00:01Z INFO worker=12 user=42 connected to tcp://127.0.0.1:8080
2026-04-21T12:00:02Z INFO worker=18 user=57 connected to tcp://127.0.0.1:8080
2026-04-21T12:00:03Z ERROR worker=18 user=57 failed request id=991 path=C:\games\demo\mods\plugin.dll
2026-04-21T12:00:04Z ERROR worker=22 user=98 failed request id=992 path=C:\games\demo\mods\plugin.dll
2026-04-21T12:00:05Z WARN worker=22 retry in 3s for request id=992
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>FixtureSupport</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>MercuryFixture.Support</RootNamespace>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>
@@ -0,0 +1,22 @@
namespace MercuryFixture.Support;
public interface ILaunchable
{
}
public abstract class LaunchVehicleBase
{
public int QueueSize;
protected int HiddenCounter;
public virtual string StartLaunch(int count)
{
HiddenCounter += count;
return $"launch:{count}";
}
protected void FinishLaunch()
{
HiddenCounter += 1;
}
}
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\FixtureSupport\FixtureSupport.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>GameAssembly</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>Game</RootNamespace>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>
@@ -0,0 +1,65 @@
using MercuryFixture.Support;
namespace Game.UI.Windows.Windows
{
public class SpaceCraftConstructionWindow : LaunchVehicleBase, ILaunchable
{
private int _buildTicks;
private static int GlobalProjects;
public string ProjectName { get; private set; } = "Mercury";
internal int QueueDepth { get; set; }
public bool Completed => _buildTicks > 100;
public void StartProject(int units, string tag)
{
_buildTicks += units;
ProjectName = tag;
GlobalProjects += 1;
}
private int FinishProject(bool instant)
{
if (instant)
{
_buildTicks = 999;
}
return _buildTicks;
}
public override string StartLaunch(int count)
{
return base.StartLaunch(count);
}
}
public class SpaceCraftProjectWindow
{
public void QueueVehicle()
{
}
internal void CancelProject()
{
}
}
public class SpaceCraftInfoWindow
{
public int BuildProgress { get; set; }
}
}
namespace Data
{
public struct SpacecraftConstructData
{
public float buildTime;
public float progress;
public string VehicleName { get; set; }
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
not a managed assembly
@@ -0,0 +1,9 @@
namespace MissingOnly
{
public static class MissingMarker
{
public static void Touch()
{
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>MissingOnly</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>MissingOnly</RootNamespace>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
</Project>
@@ -0,0 +1,18 @@
using HarmonyLib;
using MissingOnly;
using Rocket.Runtime;
using TestOnlySupport;
namespace Rocket.Plugin
{
public sealed class PluginEntry
{
public string Run(string value)
{
CompileOnlyType.Touch();
MissingMarker.Touch();
TestMarker.Touch();
return RuntimeFeature.RequiredMethod(value) + Harmony.VersionInfo();
}
}
}
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>RootPlugin</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>Rocket.Plugin</RootNamespace>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<Reference Include="RuntimeDependency">
<HintPath>..\..\diagnose-bin\compile\RuntimeDependency.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="0Harmony">
<HintPath>..\..\diagnose-bin\compile\0Harmony.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="TestOnlySupport">
<HintPath>..\..\diagnose-bin\compile\TestOnlySupport.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="MissingOnly">
<HintPath>..\..\diagnose-bin\compile\MissingOnly.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
</Project>
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>RuntimeDependency</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>Rocket.Runtime</RootNamespace>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
</Project>
@@ -0,0 +1,17 @@
namespace Rocket.Runtime
{
public sealed class RuntimeFeature
{
public static string RequiredMethod(string value)
{
return "compile:" + value;
}
}
public sealed class CompileOnlyType
{
public static void Touch()
{
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>RuntimeDependency</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>Rocket.Runtime</RootNamespace>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<FileVersion>2.0.0.0</FileVersion>
<Version>2.0.0</Version>
</PropertyGroup>
</Project>
@@ -0,0 +1,10 @@
namespace Rocket.Runtime
{
public sealed class RuntimeFeature
{
public static string ReplacementOnly(string value)
{
return "server:" + value;
}
}
}
@@ -0,0 +1,9 @@
namespace TestOnlySupport
{
public static class TestMarker
{
public static void Touch()
{
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>TestOnlySupport</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>TestOnlySupport</RootNamespace>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
</Project>
@@ -0,0 +1,10 @@
namespace HarmonyLib
{
public static class Harmony
{
public static string VersionInfo()
{
return "2.2.2";
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyName>0Harmony</AssemblyName>
<DebugType>none</DebugType>
<RootNamespace>HarmonyLib</RootNamespace>
<AssemblyVersion>2.2.2.0</AssemblyVersion>
<FileVersion>2.2.2.0</FileVersion>
<Version>2.2.2</Version>
</PropertyGroup>
</Project>
+3
View File
@@ -0,0 +1,3 @@
rg
cargo
pwsh
+12
View File
@@ -0,0 +1,12 @@
class Worker:
def build(self, value: int) -> int:
return value + 1
def helper(value: int) -> int:
return value * 2
def build_twice(value: int) -> int:
worker = Worker()
return helper(worker.build(value))
@@ -0,0 +1,7 @@
function Invoke-ModuleTask {
param(
[int]$Count
)
$Count + 1
}
+28
View File
@@ -0,0 +1,28 @@
function Invoke-Helper {
param(
[string]$Name
)
"hello $Name"
}
class TaskRunner {
[string] Format([string]$Name) {
return "task:$Name"
}
}
function Invoke-Formatting {
param(
[string]$Name
)
$runner = [TaskRunner]::new()
Invoke-Helper -Name $Name | Out-Null
$runner.Format($Name)
}
enum TaskState {
Ready = 0
Running = 1
}
+28
View File
@@ -0,0 +1,28 @@
namespace Mercury.Game;
public class RocketBuilder
{
public void Build(string name)
{
}
public class NestedThing
{
public int Build(int value)
{
return value + 1;
}
}
}
public record BuildPlan(string Name);
public static class BuildPlanFactory
{
public static void BuildRocket(string name)
{
var builder = new RocketBuilder();
builder.Build(name);
_ = new RocketBuilder.NestedThing().Build(1);
}
}
+9
View File
@@ -0,0 +1,9 @@
package mercury.demo;
public class Service {
public void execute() {
}
private record Result(String name) {
}
}
+29
View File
@@ -0,0 +1,29 @@
pub mod nested {
pub struct Widget {
value: i32,
}
impl Widget {
pub fn new(value: i32) -> Self {
Self { value }
}
pub fn helper(&self) -> i32 {
self.value + 1
}
}
}
pub trait Runner {
fn run(&self) -> bool;
}
pub fn helper(name: &str) -> String {
format!("hello, {name}")
}
pub fn call_helper(widget: &nested::Widget, name: &str) -> (String, i32) {
(helper(name), widget.helper())
}
pub const HELPER_LABEL: &str = "widget";
+21
View File
@@ -0,0 +1,21 @@
package service
type Runner interface {
Run() error
}
type Worker struct {
Name string
}
func NewWorker(name string) *Worker {
return &Worker{Name: name}
}
func (w *Worker) Run() error {
return w.help()
}
func (w *Worker) help() error {
return nil
}
+18
View File
@@ -0,0 +1,18 @@
export function helper(value) {
return value.trim();
}
export const makeGreeter = (name) => {
return `hello ${name}`;
};
export class BrowserThing {
open(url) {
return url;
}
}
export function demo(value, url) {
const browser = new BrowserThing();
return helper(browser.open(url ?? value));
}
+25
View File
@@ -0,0 +1,25 @@
export interface Report {
title: string;
}
export type Builder = (name: string) => string;
export function helper(name: string): string {
return name.toUpperCase();
}
export const makeTyped = (value: number): number => {
return value + 1;
};
export namespace Tools {
export function open(path: string): string {
return path;
}
}
export function renderReport(name: string, path: string): Report {
return {
title: helper(Tools.open(path)) + name,
};
}
+13
View File
@@ -0,0 +1,13 @@
export abstract class Screen {
render(): string {
return "screen";
}
}
export const makeScreen = (name: string): string => {
return `<div>${name}</div>`;
};
export const renderScreen = (screen: Screen): string => {
return screen.render();
};
+2
View File
@@ -0,0 +1,2 @@
tcp://127.0.0.1:65535
http://127.0.0.1:8080/health
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
{
"app": {
"name": "toolbox",
"logging": {
"level": "debug",
"targets": [
"stderr"
]
}
},
"workspace": {
"root": "C:/src/toolbox",
"cache": true
}
}
+8
View File
@@ -0,0 +1,8 @@
[workspace]
root = "C:/src/toolbox"
[logging]
level = "debug"
[plugins.metrics]
enabled = true
+9
View File
@@ -0,0 +1,9 @@
app:
name: toolbox
logging:
level: debug
outputs:
- stderr
plugins:
metrics:
enabled: true
+3
View File
@@ -0,0 +1,3 @@
# This file is automatically @generated by the build system.
package = "toolbox"
version = 4
+1
View File
@@ -0,0 +1 @@
function boot(){const state={ready:true,mode:"fast",retries:3};if(state.ready){console.log("boot",state.mode,state.retries)}}boot();
+17
View File
@@ -0,0 +1,17 @@
using UnityEngine;
namespace Demo.Game {
public class PlayerController : MonoBehaviour {
public void Start() {
Debug.Log("ready");
}
private int ComputeScore(int baseScore) {
if (baseScore < 0) {
return 0;
}
return baseScore + 10;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
package demo
import "context"
const DefaultLimit = 10
var SharedName = "mercury"
type Runner interface {
Run(context.Context) error
}
type Service struct {
name string
}
func NewService(name string) *Service {
return &Service{name: name}
}
func (s *Service) Run(ctx context.Context) error {
return s.helper(ctx)
}
func (s *Service) helper(ctx context.Context) error {
return nil
}
+25
View File
@@ -0,0 +1,25 @@
package com.acme.demo;
import java.util.List;
public final class OutlineDemo<T> extends BaseDemo implements Runnable {
private static final int LIMIT = 10;
public OutlineDemo() {
}
@Override
public void run() {
helper("demo");
}
private List<String> helper(String name) throws IOException {
return List.of(name);
}
public record Result(String name, int score) {}
interface Nested {
void call();
}
}
+15
View File
@@ -0,0 +1,15 @@
class Widget {
constructor(name) {
this.name = name;
}
render() {
return this.name.toUpperCase();
}
}
function createWidget(name) {
return new Widget(name);
}
const loadWidget = async (id) => createWidget(String(id));
+15
View File
@@ -0,0 +1,15 @@
function Get-Widget {
param([string]$Name)
"widget:$Name"
}
class WidgetBuilder {
[string] Build([string]$Name) {
return $Name.ToUpperInvariant()
}
}
enum WidgetMode {
Fast = 1
Safe = 2
}
+13
View File
@@ -0,0 +1,13 @@
class Worker:
def __init__(self, name: str) -> None:
self.name = name
def run(self) -> str:
return self._format()
def _format(self) -> str:
return f"worker:{self.name}"
def build_worker(name: str) -> Worker:
return Worker(name)
+35
View File
@@ -0,0 +1,35 @@
pub mod net {
pub struct Client {
pub id: u32,
}
impl Client {
pub fn connect(id: u32) -> Self {
Self { id }
}
}
}
pub enum Mode {
Fast,
Safe,
}
pub fn run(args: &[String]) -> Result<(), String> {
let mode = if args.is_empty() {
Mode::Safe
} else {
Mode::Fast
};
match mode {
Mode::Fast => println!("fast"),
Mode::Safe => println!("safe"),
}
Ok(())
}
fn helper(value: i32) -> i32 {
value + 1
}
+21
View File
@@ -0,0 +1,21 @@
interface Runner {
run(): Promise<string>;
}
type WorkerOptions = {
name: string;
};
class Worker implements Runner {
constructor(private readonly options: WorkerOptions) {}
async run(): Promise<string> {
return this.options.name;
}
}
export function createWorker(options: WorkerOptions): Runner {
return new Worker(options);
}
export const defaultWorker = () => createWorker({ name: "default" });
Binary file not shown.
Binary file not shown.
View File
+29
View File
@@ -0,0 +1,29 @@
PRAGMA journal_mode = WAL;
CREATE TABLE users(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
city TEXT,
active INTEGER NOT NULL
);
CREATE TABLE events(
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
kind TEXT NOT NULL,
created_at TEXT NOT NULL,
payload TEXT,
FOREIGN KEY(user_id) REFERENCES users(id)
);
CREATE INDEX idx_events_user_kind ON events(user_id, kind);
INSERT INTO users(name, city, active) VALUES
('Ada', 'London', 1),
('Bob', NULL, 0),
('Cara', 'Paris', 1);
INSERT INTO events(user_id, kind, created_at, payload) VALUES
(1, 'login', '2026-04-21T09:00:00Z', '{"ip":"127.0.0.1"}'),
(1, 'build', '2026-04-21T09:05:00Z', '{"target":"release-fast"}'),
(3, 'login', '2026-04-21T10:00:00Z', NULL);
+3
View File
@@ -0,0 +1,3 @@
panic in module
cache warmup complete
login accepted
@@ -0,0 +1,217 @@
{
"version": "3.0",
"category": "decode",
"description": "Nested and mixed array decoding - list format, arrays of arrays, root arrays, mixed types",
"tests": [
{
"name": "parses list arrays for non-uniform objects",
"input": "items[2]:\n - id: 1\n name: First\n - id: 2\n name: Second\n extra: true",
"expected": {
"items": [
{ "id": 1, "name": "First" },
{ "id": 2, "name": "Second", "extra": true }
]
},
"specSection": "9.4"
},
{
"name": "parses list arrays with empty items",
"input": "items[3]:\n - first\n - second\n -",
"expected": {
"items": ["first", "second", {}]
},
"specSection": "9.4"
},
{
"name": "parses list arrays with deeply nested objects",
"input": "items[2]:\n - properties:\n state:\n type: string\n - id: 2",
"expected": {
"items": [
{
"properties": {
"state": {
"type": "string"
}
}
},
{
"id": 2
}
]
},
"specSection": "10"
},
{
"name": "parses list arrays containing objects with nested properties",
"input": "items[1]:\n - id: 1\n nested:\n x: 1",
"expected": {
"items": [
{ "id": 1, "nested": { "x": 1 } }
]
},
"specSection": "9.4"
},
{
"name": "parses list items whose first field is a tabular array",
"input": "items[1]:\n - users[2]{id,name}:\n 1,Ada\n 2,Bob\n status: active",
"expected": {
"items": [
{
"users": [
{ "id": 1, "name": "Ada" },
{ "id": 2, "name": "Bob" }
],
"status": "active"
}
]
},
"specSection": "10",
"note": "Canonical encoding: tabular header on hyphen line, rows at depth +2, sibling fields at depth +1"
},
{
"name": "parses single-field list-item object with tabular array",
"input": "items[1]:\n - users[2]{id,name}:\n 1,Ada\n 2,Bob",
"expected": {
"items": [
{
"users": [
{ "id": 1, "name": "Ada" },
{ "id": 2, "name": "Bob" }
]
}
]
},
"specSection": "10",
"note": "Single-field list-item object: only the tabular array, no sibling fields"
},
{
"name": "parses objects containing arrays (including empty arrays) in list format",
"input": "items[1]:\n - name: Ada\n data[0]:",
"expected": {
"items": [
{ "name": "Ada", "data": [] }
]
},
"specSection": "9.4"
},
{
"name": "parses arrays of arrays within objects",
"input": "items[1]:\n - matrix[2]:\n - [2]: 1,2\n - [2]: 3,4\n name: grid",
"expected": {
"items": [
{ "matrix": [[1, 2], [3, 4]], "name": "grid" }
]
},
"specSection": "9.2"
},
{
"name": "parses nested arrays of primitives",
"input": "pairs[2]:\n - [2]: a,b\n - [2]: c,d",
"expected": {
"pairs": [["a", "b"], ["c", "d"]]
},
"specSection": "9.2"
},
{
"name": "parses quoted strings and mixed lengths in nested arrays",
"input": "pairs[2]:\n - [2]: a,b\n - [3]: \"c,d\",\"e:f\",\"true\"",
"expected": {
"pairs": [["a", "b"], ["c,d", "e:f", "true"]]
},
"specSection": "9.2"
},
{
"name": "parses empty inner arrays",
"input": "pairs[2]:\n - [0]:\n - [0]:",
"expected": {
"pairs": [[], []]
},
"specSection": "9.2"
},
{
"name": "parses mixed-length inner arrays",
"input": "pairs[2]:\n - [1]: 1\n - [2]: 2,3",
"expected": {
"pairs": [[1], [2, 3]]
},
"specSection": "9.2"
},
{
"name": "parses root-level primitive array inline",
"input": "[5]: x,y,\"true\",true,10",
"expected": ["x", "y", "true", true, 10],
"specSection": "9.1"
},
{
"name": "parses root-level array of uniform objects in tabular format",
"input": "[2]{id}:\n 1\n 2",
"expected": [{ "id": 1 }, { "id": 2 }],
"specSection": "9.3"
},
{
"name": "parses root-level array of non-uniform objects in list format",
"input": "[2]:\n - id: 1\n - id: 2\n name: Ada",
"expected": [{ "id": 1 }, { "id": 2, "name": "Ada" }],
"specSection": "9.4"
},
{
"name": "parses root-level array mixing primitive, object, and array of objects in list format",
"input": "[3]:\n - summary\n - id: 1\n name: Ada\n - [2]:\n - id: 2\n - status: draft",
"expected": ["summary", { "id": 1, "name": "Ada" }, [{ "id": 2 }, { "status": "draft" }]],
"specSection": "9.4"
},
{
"name": "parses root-level array of arrays",
"input": "[2]:\n - [2]: 1,2\n - [0]:",
"expected": [[1, 2], []],
"specSection": "9.2"
},
{
"name": "parses empty root-level array",
"input": "[0]:",
"expected": [],
"specSection": "9.1"
},
{
"name": "parses complex mixed object with arrays and nested objects",
"input": "user:\n id: 123\n name: Ada\n tags[2]: reading,gaming\n active: true\n prefs[0]:",
"expected": {
"user": {
"id": 123,
"name": "Ada",
"tags": ["reading", "gaming"],
"active": true,
"prefs": []
}
},
"specSection": "8"
},
{
"name": "parses arrays mixing primitives, objects, and strings in list format",
"input": "items[3]:\n - 1\n - a: 1\n - text",
"expected": {
"items": [1, { "a": 1 }, "text"]
},
"specSection": "9.4"
},
{
"name": "parses arrays mixing objects and arrays",
"input": "items[2]:\n - a: 1\n - [2]: 1,2",
"expected": {
"items": [{ "a": 1 }, [1, 2]]
},
"specSection": "9.4"
},
{
"name": "parses quoted key with list array format",
"input": "\"x-items\"[2]:\n - id: 1\n - id: 2",
"expected": {
"x-items": [
{ "id": 1 },
{ "id": 2 }
]
},
"specSection": "9.4"
}
]
}
@@ -0,0 +1,127 @@
{
"version": "1.4",
"category": "decode",
"description": "Primitive array decoding - inline arrays of strings, numbers, booleans, quoted strings",
"tests": [
{
"name": "parses string arrays inline",
"input": "tags[3]: reading,gaming,coding",
"expected": {
"tags": ["reading", "gaming", "coding"]
},
"specSection": "9.1"
},
{
"name": "parses number arrays inline",
"input": "nums[3]: 1,2,3",
"expected": {
"nums": [1, 2, 3]
},
"specSection": "9.1"
},
{
"name": "parses mixed primitive arrays inline",
"input": "data[4]: x,y,true,10",
"expected": {
"data": ["x", "y", true, 10]
},
"specSection": "9.1"
},
{
"name": "parses empty arrays",
"input": "items[0]:",
"expected": {
"items": []
},
"specSection": "9.1"
},
{
"name": "parses single-item array with empty string",
"input": "items[1]: \"\"",
"expected": {
"items": [""]
},
"specSection": "9.1"
},
{
"name": "parses multi-item array with empty string",
"input": "items[3]: a,\"\",b",
"expected": {
"items": ["a", "", "b"]
},
"specSection": "9.1"
},
{
"name": "parses whitespace-only strings in arrays",
"input": "items[2]: \" \",\" \"",
"expected": {
"items": [" ", " "]
},
"specSection": "9.1"
},
{
"name": "parses strings with delimiters in arrays",
"input": "items[3]: a,\"b,c\",\"d:e\"",
"expected": {
"items": ["a", "b,c", "d:e"]
},
"specSection": "9.1"
},
{
"name": "parses strings that look like primitives when quoted",
"input": "items[4]: x,\"true\",\"42\",\"-3.14\"",
"expected": {
"items": ["x", "true", "42", "-3.14"]
},
"specSection": "9.1"
},
{
"name": "parses strings with structural tokens in arrays",
"input": "items[3]: \"[5]\",\"- item\",\"{key}\"",
"expected": {
"items": ["[5]", "- item", "{key}"]
},
"specSection": "9.1"
},
{
"name": "parses quoted key with inline array",
"input": "\"my-key\"[3]: 1,2,3",
"expected": {
"my-key": [1, 2, 3]
},
"specSection": "9.1"
},
{
"name": "parses quoted empty string key with inline array",
"input": "\"\"[3]: 1,2,3",
"expected": {
"": [1, 2, 3]
},
"specSection": "9.1"
},
{
"name": "parses quoted key containing brackets with inline array",
"input": "\"key[test]\"[3]: 1,2,3",
"expected": {
"key[test]": [1, 2, 3]
},
"specSection": "9.1"
},
{
"name": "parses quoted key with empty array",
"input": "\"x-custom\"[0]:",
"expected": {
"x-custom": []
},
"specSection": "9.1"
},
{
"name": "parses quoted empty string key with empty array",
"input": "\"\"[0]:",
"expected": {
"": []
},
"specSection": "9.1"
}
]
}
@@ -0,0 +1,85 @@
{
"version": "1.4",
"category": "decode",
"description": "Tabular array decoding - parsing arrays of uniform objects with headers",
"tests": [
{
"name": "parses tabular arrays of uniform objects",
"input": "items[2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5",
"expected": {
"items": [
{ "sku": "A1", "qty": 2, "price": 9.99 },
{ "sku": "B2", "qty": 1, "price": 14.5 }
]
},
"specSection": "9.3"
},
{
"name": "parses nulls and quoted values in tabular rows",
"input": "items[2]{id,value}:\n 1,null\n 2,\"test\"",
"expected": {
"items": [
{ "id": 1, "value": null },
{ "id": 2, "value": "test" }
]
},
"specSection": "9.3"
},
{
"name": "parses quoted colon in tabular row as data",
"input": "items[2]{id,note}:\n 1,\"a:b\"\n 2,\"c:d\"",
"expected": {
"items": [
{ "id": 1, "note": "a:b" },
{ "id": 2, "note": "c:d" }
]
},
"specSection": "9.3"
},
{
"name": "parses quoted header keys in tabular arrays",
"input": "items[2]{\"order:id\",\"full name\"}:\n 1,Ada\n 2,Bob",
"expected": {
"items": [
{ "order:id": 1, "full name": "Ada" },
{ "order:id": 2, "full name": "Bob" }
]
},
"specSection": "9.3"
},
{
"name": "parses quoted key with tabular array format",
"input": "\"x-items\"[2]{id,name}:\n 1,Ada\n 2,Bob",
"expected": {
"x-items": [
{ "id": 1, "name": "Ada" },
{ "id": 2, "name": "Bob" }
]
},
"specSection": "9.3"
},
{
"name": "parses quoted empty string key with tabular array format",
"input": "\"\"[2]{id,name}:\n 1,Ada\n 2,Bob",
"expected": {
"": [
{ "id": 1, "name": "Ada" },
{ "id": 2, "name": "Bob" }
]
},
"specSection": "9.3"
},
{
"name": "treats unquoted colon as terminator for tabular rows and start of key-value pair",
"input": "items[2]{id,name}:\n 1,Alice\n 2,Bob\ncount: 2",
"expected": {
"items": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
],
"count": 2
},
"specSection": "9.3"
}
]
}
+153
View File
@@ -0,0 +1,153 @@
{
"version": "1.4",
"category": "decode",
"description": "Blank line handling - strict mode errors on blank lines inside arrays, accepts blank lines outside arrays",
"tests": [
{
"name": "throws on blank line inside list array",
"input": "items[3]:\n - a\n\n - b\n - c",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.4"
},
{
"name": "throws on blank line inside tabular array",
"input": "items[2]{id}:\n 1\n\n 2",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.4"
},
{
"name": "throws on multiple blank lines inside array",
"input": "items[2]:\n - a\n\n\n - b",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.4"
},
{
"name": "throws on blank line with spaces inside array",
"input": "items[2]:\n - a\n \n - b",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.4"
},
{
"name": "throws on blank line in nested list array",
"input": "outer[2]:\n - inner[2]:\n - a\n\n - b\n - x",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.4"
},
{
"name": "accepts blank line between root-level fields",
"input": "a: 1\n\nb: 2",
"expected": {
"a": 1,
"b": 2
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts trailing newline at end of file",
"input": "a: 1\n",
"expected": {
"a": 1
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts multiple trailing newlines",
"input": "a: 1\n\n\n",
"expected": {
"a": 1
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts blank line after array ends",
"input": "items[1]:\n - a\n\nb: 2",
"expected": {
"items": ["a"],
"b": 2
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts blank line between nested object fields",
"input": "a:\n b: 1\n\n c: 2",
"expected": {
"a": {
"b": 1,
"c": 2
}
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "ignores blank lines inside list array when strict=false",
"input": "items[3]:\n - a\n\n - b\n - c",
"expected": {
"items": ["a", "b", "c"]
},
"options": {
"strict": false
},
"specSection": "12"
},
{
"name": "ignores blank lines inside tabular array when strict=false",
"input": "items[2]{id,name}:\n 1,Alice\n\n 2,Bob",
"expected": {
"items": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
},
"options": {
"strict": false
},
"specSection": "12"
},
{
"name": "ignores multiple blank lines in arrays when strict=false",
"input": "items[2]:\n - a\n\n\n - b",
"expected": {
"items": ["a", "b"]
},
"options": {
"strict": false
},
"specSection": "12"
}
]
}
+246
View File
@@ -0,0 +1,246 @@
{
"version": "1.4",
"category": "decode",
"description": "Delimiter decoding - tab and pipe delimiter parsing, delimiter-aware value splitting",
"tests": [
{
"name": "parses primitive arrays with tab delimiter",
"input": "tags[3\t]: reading\tgaming\tcoding",
"expected": {
"tags": ["reading", "gaming", "coding"]
},
"specSection": "11"
},
{
"name": "parses primitive arrays with pipe delimiter",
"input": "tags[3|]: reading|gaming|coding",
"expected": {
"tags": ["reading", "gaming", "coding"]
},
"specSection": "11"
},
{
"name": "parses primitive arrays with comma delimiter",
"input": "tags[3]: reading,gaming,coding",
"expected": {
"tags": ["reading", "gaming", "coding"]
},
"specSection": "11"
},
{
"name": "parses tabular arrays with tab delimiter",
"input": "items[2\t]{sku\tqty\tprice}:\n A1\t2\t9.99\n B2\t1\t14.5",
"expected": {
"items": [
{ "sku": "A1", "qty": 2, "price": 9.99 },
{ "sku": "B2", "qty": 1, "price": 14.5 }
]
},
"specSection": "11"
},
{
"name": "parses tabular arrays with pipe delimiter",
"input": "items[2|]{sku|qty|price}:\n A1|2|9.99\n B2|1|14.5",
"expected": {
"items": [
{ "sku": "A1", "qty": 2, "price": 9.99 },
{ "sku": "B2", "qty": 1, "price": 14.5 }
]
},
"specSection": "11"
},
{
"name": "parses nested arrays with tab delimiter",
"input": "pairs[2\t]:\n - [2\t]: a\tb\n - [2\t]: c\td",
"expected": {
"pairs": [["a", "b"], ["c", "d"]]
},
"specSection": "11"
},
{
"name": "parses nested arrays with pipe delimiter",
"input": "pairs[2|]:\n - [2|]: a|b\n - [2|]: c|d",
"expected": {
"pairs": [["a", "b"], ["c", "d"]]
},
"specSection": "11"
},
{
"name": "parses nested arrays inside list items with default comma delimiter",
"input": "items[1\t]:\n - tags[3]: a,b,c",
"expected": {
"items": [{ "tags": ["a", "b", "c"] }]
},
"specSection": "11",
"note": "Parent uses tab, nested defaults to comma"
},
{
"name": "parses nested arrays inside list items with default comma delimiter when parent uses pipe",
"input": "items[1|]:\n - tags[3]: a,b,c",
"expected": {
"items": [{ "tags": ["a", "b", "c"] }]
},
"specSection": "11"
},
{
"name": "parses root-level array with tab delimiter",
"input": "[3\t]: x\ty\tz",
"expected": ["x", "y", "z"],
"specSection": "11"
},
{
"name": "parses root-level array with pipe delimiter",
"input": "[3|]: x|y|z",
"expected": ["x", "y", "z"],
"specSection": "11"
},
{
"name": "parses root-level array of objects with tab delimiter",
"input": "[2\t]{id}:\n 1\n 2",
"expected": [{ "id": 1 }, { "id": 2 }],
"specSection": "11"
},
{
"name": "parses root-level array of objects with pipe delimiter",
"input": "[2|]{id}:\n 1\n 2",
"expected": [{ "id": 1 }, { "id": 2 }],
"specSection": "11"
},
{
"name": "parses values containing tab delimiter when quoted",
"input": "items[3\t]: a\t\"b\\tc\"\td",
"expected": {
"items": ["a", "b\tc", "d"]
},
"specSection": "11"
},
{
"name": "parses values containing pipe delimiter when quoted",
"input": "items[3|]: a|\"b|c\"|d",
"expected": {
"items": ["a", "b|c", "d"]
},
"specSection": "11"
},
{
"name": "does not split on commas when using tab delimiter",
"input": "items[2\t]: a,b\tc,d",
"expected": {
"items": ["a,b", "c,d"]
},
"specSection": "11"
},
{
"name": "does not split on commas when using pipe delimiter",
"input": "items[2|]: a,b|c,d",
"expected": {
"items": ["a,b", "c,d"]
},
"specSection": "11"
},
{
"name": "parses tabular values containing comma with comma delimiter",
"input": "items[2]{id,note}:\n 1,\"a,b\"\n 2,\"c,d\"",
"expected": {
"items": [
{ "id": 1, "note": "a,b" },
{ "id": 2, "note": "c,d" }
]
},
"specSection": "11"
},
{
"name": "does not require quoting commas with tab delimiter",
"input": "items[2\t]{id\tnote}:\n 1\ta,b\n 2\tc,d",
"expected": {
"items": [
{ "id": 1, "note": "a,b" },
{ "id": 2, "note": "c,d" }
]
},
"specSection": "11"
},
{
"name": "does not require quoting commas in object values",
"input": "note: a,b",
"expected": {
"note": "a,b"
},
"specSection": "11",
"note": "Object values don't require comma quoting regardless of delimiter"
},
{
"name": "object values in list items follow document delimiter",
"input": "items[2\t]:\n - status: a,b\n - status: c,d",
"expected": {
"items": [{ "status": "a,b" }, { "status": "c,d" }]
},
"specSection": "11",
"note": "Active delimiter is tab, but object values use document delimiter for quoting"
},
{
"name": "object values with comma must be quoted when document delimiter is comma",
"input": "items[2]:\n - status: \"a,b\"\n - status: \"c,d\"",
"expected": {
"items": [{ "status": "a,b" }, { "status": "c,d" }]
},
"specSection": "11"
},
{
"name": "parses nested array values containing pipe delimiter",
"input": "pairs[1|]:\n - [2|]: a|\"b|c\"",
"expected": {
"pairs": [["a", "b|c"]]
},
"specSection": "11"
},
{
"name": "parses nested array values containing tab delimiter",
"input": "pairs[1\t]:\n - [2\t]: a\t\"b\\tc\"",
"expected": {
"pairs": [["a", "b\tc"]]
},
"specSection": "11"
},
{
"name": "preserves quoted ambiguity with pipe delimiter",
"input": "items[3|]: \"true\"|\"42\"|\"-3.14\"",
"expected": {
"items": ["true", "42", "-3.14"]
},
"specSection": "11"
},
{
"name": "preserves quoted ambiguity with tab delimiter",
"input": "items[3\t]: \"true\"\t\"42\"\t\"-3.14\"",
"expected": {
"items": ["true", "42", "-3.14"]
},
"specSection": "11"
},
{
"name": "parses structural-looking strings when quoted with pipe delimiter",
"input": "items[3|]: \"[5]\"|\"{key}\"|\"- item\"",
"expected": {
"items": ["[5]", "{key}", "- item"]
},
"specSection": "11"
},
{
"name": "parses structural-looking strings when quoted with tab delimiter",
"input": "items[3\t]: \"[5]\"\t\"{key}\"\t\"- item\"",
"expected": {
"items": ["[5]", "{key}", "- item"]
},
"specSection": "11"
},
{
"name": "parses tabular headers with keys containing the active delimiter",
"input": "items[2|]{\"a|b\"}:\n 1\n 2",
"expected": {
"items": [{ "a|b": 1 }, { "a|b": 2 }]
},
"specSection": "11"
}
]
}
@@ -0,0 +1,184 @@
{
"version": "1.4",
"category": "decode",
"description": "Strict mode indentation validation - non-multiple indentation, tab characters, custom indent sizes",
"tests": [
{
"name": "throws on object field with non-multiple indentation (3 spaces with indent=2)",
"input": "a:\n b: 1",
"expected": null,
"shouldError": true,
"options": {
"indent": 2,
"strict": true
},
"specSection": "14.3"
},
{
"name": "throws on list item with non-multiple indentation (3 spaces with indent=2)",
"input": "items[2]:\n - id: 1\n - id: 2",
"expected": null,
"shouldError": true,
"options": {
"indent": 2,
"strict": true
},
"specSection": "14.3"
},
{
"name": "throws on non-multiple indentation with custom indent=4 (3 spaces)",
"input": "a:\n b: 1",
"expected": null,
"shouldError": true,
"options": {
"indent": 4,
"strict": true
},
"specSection": "14.3"
},
{
"name": "accepts correct indentation with custom indent size (4 spaces with indent=4)",
"input": "a:\n b: 1",
"expected": {
"a": {
"b": 1
}
},
"options": {
"indent": 4,
"strict": true
},
"specSection": "12"
},
{
"name": "throws on tab character used in indentation",
"input": "a:\n\tb: 1",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.3"
},
{
"name": "throws on mixed tabs and spaces in indentation",
"input": "a:\n \tb: 1",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.3"
},
{
"name": "throws on tab at start of line",
"input": "\ta: 1",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "14.3"
},
{
"name": "accepts tabs in quoted string values",
"input": "text: \"hello\tworld\"",
"expected": {
"text": "hello\tworld"
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts tabs in quoted keys",
"input": "\"key\ttab\": value",
"expected": {
"key\ttab": "value"
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts tabs in quoted array elements",
"input": "items[2]: \"a\tb\",\"c\td\"",
"expected": {
"items": ["a\tb", "c\td"]
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "accepts non-multiple indentation when strict=false",
"input": "a:\n b: 1",
"expected": {
"a": {
"b": 1
}
},
"options": {
"indent": 2,
"strict": false
},
"specSection": "12"
},
{
"name": "accepts deeply nested non-multiples when strict=false",
"input": "a:\n b:\n c: 1",
"expected": {
"a": {
"b": {
"c": 1
}
}
},
"options": {
"indent": 2,
"strict": false
},
"specSection": "12"
},
{
"name": "parses empty lines without validation errors",
"input": "a: 1\n\nb: 2",
"expected": {
"a": 1,
"b": 2
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "parses root-level content (0 indentation) as always valid",
"input": "a: 1\nb: 2\nc: 3",
"expected": {
"a": 1,
"b": 2,
"c": 3
},
"options": {
"strict": true
},
"specSection": "12"
},
{
"name": "parses lines with only spaces without validation if empty",
"input": "a: 1\n \nb: 2",
"expected": {
"a": 1,
"b": 2
},
"options": {
"strict": true
},
"specSection": "12"
}
]
}
+175
View File
@@ -0,0 +1,175 @@
{
"version": "1.4",
"category": "decode",
"description": "Number decoding edge cases - trailing zeros, exponent forms, negative zero",
"tests": [
{
"name": "parses number with trailing zeros in fractional part",
"input": "value: 1.5000",
"expected": {
"value": 1.5
},
"specSection": "4",
"note": "Decoders accept trailing zeros; numeric value is 1.5"
},
{
"name": "parses negative number with positive exponent",
"input": "value: -1E+03",
"expected": {
"value": -1000
},
"specSection": "4",
"note": "Exponent forms are accepted by decoders"
},
{
"name": "parses lowercase exponent",
"input": "value: 2.5e2",
"expected": {
"value": 250
},
"specSection": "4"
},
{
"name": "parses uppercase exponent with negative sign",
"input": "value: 3E-02",
"expected": {
"value": 0.03
},
"specSection": "4"
},
{
"name": "parses negative zero as zero",
"input": "value: -0",
"expected": {
"value": 0
},
"specSection": "4",
"note": "Negative zero decodes to 0; most host environments do not distinguish -0 from 0"
},
{
"name": "parses negative zero with fractional part",
"input": "value: -0.0",
"expected": {
"value": 0
},
"specSection": "4"
},
{
"name": "parses array with mixed numeric forms",
"input": "nums[5]: 42,-1E+03,1.5000,-0,2.5e2",
"expected": {
"nums": [42, -1000, 1.5, 0, 250]
},
"specSection": "4",
"note": "Decoders normalize all numeric forms to host numeric values"
},
{
"name": "treats leading zero as string not number",
"input": "value: 05",
"expected": {
"value": "05"
},
"specSection": "4",
"note": "Forbidden leading zeros cause tokens to be treated as strings"
},
{
"name": "parses very small exponent",
"input": "value: 1e-10",
"expected": {
"value": 0.0000000001
},
"specSection": "4"
},
{
"name": "parses integer with positive exponent",
"input": "value: 5E+00",
"expected": {
"value": 5
},
"specSection": "4",
"note": "Exponent +00 results in the integer 5"
},
{
"name": "parses zero with exponent as number",
"input": "value: 0e1",
"expected": {
"value": 0
},
"specSection": "4",
"note": "Exponent forms with a zero integer part (0e1) are valid numbers"
},
{
"name": "parses negative zero with exponent as number",
"input": "value: -0e1",
"expected": {
"value": 0
},
"specSection": "4",
"note": "Negative zero with exponent (-0e1) decodes to numeric 0"
},
{
"name": "parses exponent notation",
"input": "1e6",
"expected": 1000000,
"specSection": "4"
},
{
"name": "parses exponent notation with uppercase E",
"input": "1E+6",
"expected": 1000000,
"specSection": "4"
},
{
"name": "parses negative exponent notation",
"input": "-1e-3",
"expected": -0.001,
"specSection": "4"
},
{
"name": "treats unquoted leading-zero number as string",
"input": "05",
"expected": "05",
"specSection": "4",
"note": "Leading zeros make it a string"
},
{
"name": "treats unquoted multi-leading-zero as string",
"input": "007",
"expected": "007",
"specSection": "4"
},
{
"name": "treats unquoted octal-like as string",
"input": "0123",
"expected": "0123",
"specSection": "4"
},
{
"name": "treats leading-zero in object value as string",
"input": "a: 05",
"expected": { "a": "05" },
"specSection": "4"
},
{
"name": "treats leading-zeros in array as strings",
"input": "nums[3]: 05,007,0123",
"expected": { "nums": ["05", "007", "0123"] },
"specSection": "4"
},
{
"name": "treats unquoted negative leading-zero number as string",
"input": "-05",
"expected": "-05",
"specSection": "4",
"note": "Negative numbers with leading zeros in the integer part are treated as strings"
},
{
"name": "treats negative leading-zeros in array as strings",
"input": "nums[2]: -05,-007",
"expected": {
"nums": ["-05", "-007"]
},
"specSection": "4"
}
]
}
+265
View File
@@ -0,0 +1,265 @@
{
"version": "1.4",
"category": "decode",
"description": "Object decoding - simple objects, nested objects, key parsing, quoted values",
"tests": [
{
"name": "parses objects with primitive values",
"input": "id: 123\nname: Ada\nactive: true",
"expected": {
"id": 123,
"name": "Ada",
"active": true
},
"specSection": "8"
},
{
"name": "parses null values in objects",
"input": "id: 123\nvalue: null",
"expected": {
"id": 123,
"value": null
},
"specSection": "8"
},
{
"name": "parses empty nested object header",
"input": "user:",
"expected": {
"user": {}
},
"specSection": "8"
},
{
"name": "parses quoted object value with colon",
"input": "note: \"a:b\"",
"expected": {
"note": "a:b"
},
"specSection": "8"
},
{
"name": "parses quoted object value with comma",
"input": "note: \"a,b\"",
"expected": {
"note": "a,b"
},
"specSection": "8"
},
{
"name": "parses quoted object value with newline escape",
"input": "text: \"line1\\nline2\"",
"expected": {
"text": "line1\nline2"
},
"specSection": "8"
},
{
"name": "parses quoted object value with escaped quotes",
"input": "text: \"say \\\"hello\\\"\"",
"expected": {
"text": "say \"hello\""
},
"specSection": "8"
},
{
"name": "parses quoted object value with leading/trailing spaces",
"input": "text: \" padded \"",
"expected": {
"text": " padded "
},
"specSection": "8"
},
{
"name": "parses quoted object value with only spaces",
"input": "text: \" \"",
"expected": {
"text": " "
},
"specSection": "8"
},
{
"name": "parses quoted string value that looks like true",
"input": "v: \"true\"",
"expected": {
"v": "true"
},
"specSection": "8"
},
{
"name": "parses quoted string value that looks like integer",
"input": "v: \"42\"",
"expected": {
"v": "42"
},
"specSection": "8"
},
{
"name": "parses quoted string value that looks like negative decimal",
"input": "v: \"-7.5\"",
"expected": {
"v": "-7.5"
},
"specSection": "8"
},
{
"name": "parses quoted key with colon",
"input": "\"order:id\": 7",
"expected": {
"order:id": 7
},
"specSection": "8"
},
{
"name": "parses quoted key with brackets",
"input": "\"[index]\": 5",
"expected": {
"[index]": 5
},
"specSection": "8"
},
{
"name": "treats extra brackets after valid array segment as literal key",
"input": "foo[1][bar]: 10",
"expected": {
"foo[1][bar]": 10
},
"specSection": "6",
"note": "Non-whitespace [bar] between ] and : prevents array header interpretation"
},
{
"name": "treats non-integer bracket content as literal key",
"input": "foo[bar][1]: 20",
"expected": {
"foo[bar][1]": 20
},
"specSection": "6",
"note": "[bar] fails integer parsing; line is not an array header"
},
{
"name": "treats text between bracket segment and colon as literal key",
"input": "foo[2]extra: a,b",
"expected": {
"foo[2]extra": "a,b"
},
"specSection": "6",
"note": "Non-whitespace content between ] and : prevents array header interpretation"
},
{
"name": "parses quoted key with braces",
"input": "\"{key}\": 5",
"expected": {
"{key}": 5
},
"specSection": "8"
},
{
"name": "parses quoted key with comma",
"input": "\"a,b\": 1",
"expected": {
"a,b": 1
},
"specSection": "8"
},
{
"name": "parses quoted key with spaces",
"input": "\"full name\": Ada",
"expected": {
"full name": "Ada"
},
"specSection": "8"
},
{
"name": "parses quoted key with leading hyphen",
"input": "\"-lead\": 1",
"expected": {
"-lead": 1
},
"specSection": "8"
},
{
"name": "parses quoted key with leading and trailing spaces",
"input": "\" a \": 1",
"expected": {
" a ": 1
},
"specSection": "8"
},
{
"name": "parses quoted numeric key",
"input": "\"123\": x",
"expected": {
"123": "x"
},
"specSection": "8"
},
{
"name": "parses quoted empty string key",
"input": "\"\": 1",
"expected": {
"": 1
},
"specSection": "8"
},
{
"name": "parses dotted keys as identifiers",
"input": "user.name: Ada",
"expected": {
"user.name": "Ada"
},
"specSection": "8"
},
{
"name": "parses underscore-prefixed keys",
"input": "_private: 1",
"expected": {
"_private": 1
},
"specSection": "8"
},
{
"name": "parses underscore-containing keys",
"input": "user_name: 1",
"expected": {
"user_name": 1
},
"specSection": "8"
},
{
"name": "unescapes newline in key",
"input": "\"line\\nbreak\": 1",
"expected": {
"line\nbreak": 1
},
"specSection": "8"
},
{
"name": "unescapes tab in key",
"input": "\"tab\\there\": 2",
"expected": {
"tab\there": 2
},
"specSection": "8"
},
{
"name": "unescapes quotes in key",
"input": "\"he said \\\"hi\\\"\": 1",
"expected": {
"he said \"hi\"": 1
},
"specSection": "8"
},
{
"name": "parses deeply nested objects with indentation",
"input": "a:\n b:\n c: deep",
"expected": {
"a": {
"b": {
"c": "deep"
}
}
},
"specSection": "8"
}
]
}
@@ -0,0 +1,173 @@
{
"version": "1.5",
"category": "decode",
"description": "Path expansion with safe mode, deep merge, conflict resolution tied to strict mode",
"tests": [
{
"name": "expands dotted key to nested object in safe mode",
"input": "a.b.c: 1",
"expected": {
"a": {
"b": {
"c": 1
}
}
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "expands dotted key with inline array",
"input": "data.meta.items[2]: a,b",
"expected": {
"data": {
"meta": {
"items": ["a", "b"]
}
}
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "expands dotted key with tabular array",
"input": "a.b.items[2]{id,name}:\n 1,A\n 2,B",
"expected": {
"a": {
"b": {
"items": [
{ "id": 1, "name": "A" },
{ "id": 2, "name": "B" }
]
}
}
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "preserves literal dotted keys when expansion is off",
"input": "user.name: Ada",
"expected": {
"user.name": "Ada"
},
"options": {
"expandPaths": "off"
},
"specSection": "13.4"
},
{
"name": "expands and deep-merges preserving document-order insertion",
"input": "a.b.c: 1\na.b.d: 2\na.e: 3",
"expected": {
"a": {
"b": {
"c": 1,
"d": 2
},
"e": 3
}
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "throws on expansion conflict (object vs primitive) when strict=true",
"input": "a.b: 1\na: 2",
"expected": null,
"shouldError": true,
"options": {
"expandPaths": "safe",
"strict": true
},
"specSection": "14.5"
},
{
"name": "throws on expansion conflict (object vs array) when strict=true",
"input": "a.b: 1\na[2]: 2,3",
"expected": null,
"shouldError": true,
"options": {
"expandPaths": "safe",
"strict": true
},
"specSection": "14.5"
},
{
"name": "applies LWW when strict=false (primitive overwrites expanded object)",
"input": "a.b: 1\na: 2",
"expected": {
"a": 2
},
"options": {
"expandPaths": "safe",
"strict": false
},
"specSection": "13.4",
"note": "Document order determines winner: later key overwrites earlier"
},
{
"name": "applies LWW when strict=false (expanded object overwrites primitive)",
"input": "a: 1\na.b: 2",
"expected": {
"a": {
"b": 2
}
},
"options": {
"expandPaths": "safe",
"strict": false
},
"specSection": "13.4",
"note": "Document order determines winner: later key overwrites earlier"
},
{
"name": "preserves quoted dotted key as literal when expandPaths=safe",
"input": "a.b: 1\n\"c.d\": 2",
"expected": {
"a": {
"b": 1
},
"c.d": 2
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "preserves non-IdentifierSegment keys as literals",
"input": "full-name.x: 1",
"expected": {
"full-name.x": 1
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
},
{
"name": "expands keys creating empty nested objects",
"input": "a.b.c:",
"expected": {
"a": {
"b": {
"c": {}
}
}
},
"options": {
"expandPaths": "safe"
},
"specSection": "13.4"
}
]
}
+158
View File
@@ -0,0 +1,158 @@
{
"version": "1.4",
"category": "decode",
"description": "Primitive value decoding - strings, numbers, booleans, null, unescaping",
"tests": [
{
"name": "parses safe unquoted string",
"input": "hello",
"expected": "hello",
"specSection": "7.4"
},
{
"name": "parses unquoted string with underscore and numbers",
"input": "Ada_99",
"expected": "Ada_99",
"specSection": "7.4"
},
{
"name": "parses empty quoted string",
"input": "\"\"",
"expected": "",
"specSection": "7.4"
},
{
"name": "parses quoted string with newline escape",
"input": "\"line1\\nline2\"",
"expected": "line1\nline2",
"specSection": "7.1"
},
{
"name": "parses quoted string with tab escape",
"input": "\"tab\\there\"",
"expected": "tab\there",
"specSection": "7.1"
},
{
"name": "parses quoted string with carriage return escape",
"input": "\"return\\rcarriage\"",
"expected": "return\rcarriage",
"specSection": "7.1"
},
{
"name": "parses quoted string with backslash escape",
"input": "\"C:\\\\Users\\\\path\"",
"expected": "C:\\Users\\path",
"specSection": "7.1"
},
{
"name": "parses quoted string with escaped quotes",
"input": "\"say \\\"hello\\\"\"",
"expected": "say \"hello\"",
"specSection": "7.1"
},
{
"name": "parses Unicode string",
"input": "café",
"expected": "café",
"specSection": "7.4"
},
{
"name": "parses Chinese characters",
"input": "你好",
"expected": "你好",
"specSection": "7.4"
},
{
"name": "parses emoji",
"input": "🚀",
"expected": "🚀",
"specSection": "7.4"
},
{
"name": "parses string with emoji and spaces",
"input": "hello 👋 world",
"expected": "hello 👋 world",
"specSection": "7.4"
},
{
"name": "parses positive integer",
"input": "42",
"expected": 42,
"specSection": "4"
},
{
"name": "parses decimal number",
"input": "3.14",
"expected": 3.14,
"specSection": "4"
},
{
"name": "parses negative integer",
"input": "-7",
"expected": -7,
"specSection": "4"
},
{
"name": "parses true",
"input": "true",
"expected": true,
"specSection": "4"
},
{
"name": "parses false",
"input": "false",
"expected": false,
"specSection": "4"
},
{
"name": "parses null",
"input": "null",
"expected": null,
"specSection": "4"
},
{
"name": "respects ambiguity quoting for true",
"input": "\"true\"",
"expected": "true",
"specSection": "7.4",
"note": "Quoted primitive remains string"
},
{
"name": "respects ambiguity quoting for false",
"input": "\"false\"",
"expected": "false",
"specSection": "7.4"
},
{
"name": "respects ambiguity quoting for null",
"input": "\"null\"",
"expected": "null",
"specSection": "7.4"
},
{
"name": "respects ambiguity quoting for integer",
"input": "\"42\"",
"expected": "42",
"specSection": "7.4"
},
{
"name": "respects ambiguity quoting for negative decimal",
"input": "\"-3.14\"",
"expected": "-3.14",
"specSection": "7.4"
},
{
"name": "respects ambiguity quoting for scientific notation",
"input": "\"1e-6\"",
"expected": "1e-6",
"specSection": "7.4"
},
{
"name": "respects ambiguity quoting for leading-zero",
"input": "\"05\"",
"expected": "05",
"specSection": "7.4"
}
]
}
+17
View File
@@ -0,0 +1,17 @@
{
"version": "1.4",
"category": "decode",
"description": "Root form detection - empty document, single primitive, multiple primitives",
"tests": [
{
"name": "parses empty document as empty object",
"input": "",
"expected": {},
"options": {
"strict": true
},
"specSection": "5",
"note": "Empty input (no non-empty lines) decodes to empty object"
}
]
}
@@ -0,0 +1,83 @@
{
"version": "1.4",
"category": "decode",
"description": "Validation errors - length mismatches, invalid escapes, syntax errors, delimiter mismatches",
"tests": [
{
"name": "throws on array length mismatch (inline primitives - too many)",
"input": "tags[2]: a,b,c",
"expected": null,
"shouldError": true,
"specSection": "14.1"
},
{
"name": "throws on array length mismatch (list format - too many)",
"input": "items[1]:\n - 1\n - 2",
"expected": null,
"shouldError": true,
"specSection": "14.1"
},
{
"name": "throws on tabular row value count mismatch with header field count",
"input": "items[2]{id,name}:\n 1,Ada\n 2",
"expected": null,
"shouldError": true,
"specSection": "14.1"
},
{
"name": "throws on tabular row count mismatch with header length",
"input": "[1]{id}:\n 1\n 2",
"expected": null,
"shouldError": true,
"specSection": "14.1"
},
{
"name": "throws on invalid escape sequence",
"input": "\"a\\x\"",
"expected": null,
"shouldError": true,
"specSection": "14.2"
},
{
"name": "throws on unterminated string",
"input": "\"unterminated",
"expected": null,
"shouldError": true,
"specSection": "14.2"
},
{
"name": "throws on missing colon in key-value context",
"input": "a:\n user",
"expected": null,
"shouldError": true,
"specSection": "14.2"
},
{
"name": "throws on two primitives at root depth in strict mode",
"input": "hello\nworld",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "5"
},
{
"name": "throws on delimiter mismatch (header declares tab, row uses comma)",
"input": "items[2\t]{a\tb}:\n 1,2\n 3,4",
"expected": null,
"shouldError": true,
"specSection": "14.2"
},
{
"name": "throws on mismatched delimiter between bracket and brace fields",
"input": "items[2\t]{a,b}:\n 1\t2\n 3\t4",
"expected": null,
"shouldError": true,
"options": {
"strict": true
},
"specSection": "6"
}
]
}
+61
View File
@@ -0,0 +1,61 @@
{
"version": "1.4",
"category": "decode",
"description": "Whitespace tolerance in decoding - surrounding spaces around delimiters and values",
"tests": [
{
"name": "tolerates spaces around commas in inline arrays",
"input": "tags[3]: a , b , c",
"expected": {
"tags": ["a", "b", "c"]
},
"specSection": "12",
"note": "Surrounding whitespace SHOULD be tolerated; tokens are trimmed"
},
{
"name": "tolerates spaces around pipes in inline arrays",
"input": "tags[3|]: a | b | c",
"expected": {
"tags": ["a", "b", "c"]
},
"specSection": "12"
},
{
"name": "tolerates spaces around tabs in inline arrays",
"input": "tags[3\t]: a \t b \t c",
"expected": {
"tags": ["a", "b", "c"]
},
"specSection": "12"
},
{
"name": "tolerates leading and trailing spaces in tabular row values",
"input": "items[2]{id,name}:\n 1 , Alice \n 2 , Bob ",
"expected": {
"items": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
},
"specSection": "12",
"note": "Values in tabular rows are trimmed"
},
{
"name": "tolerates spaces around delimiters with quoted values",
"input": "items[3]: \"a\" , \"b\" , \"c\"",
"expected": {
"items": ["a", "b", "c"]
},
"specSection": "12"
},
{
"name": "parses empty tokens as empty string",
"input": "items[3]: a,,c",
"expected": {
"items": ["a", "", "c"]
},
"specSection": "12",
"note": "Empty token (nothing between delimiters) decodes to empty string"
}
]
}
@@ -0,0 +1,105 @@
{
"version": "3.0",
"category": "encode",
"description": "Nested and mixed array encoding - arrays of arrays, mixed type arrays, root arrays",
"tests": [
{
"name": "encodes nested arrays of primitives",
"input": {
"pairs": [["a", "b"], ["c", "d"]]
},
"expected": "pairs[2]:\n - [2]: a,b\n - [2]: c,d",
"specSection": "9.2"
},
{
"name": "quotes strings containing delimiters in nested arrays",
"input": {
"pairs": [["a", "b"], ["c,d", "e:f", "true"]]
},
"expected": "pairs[2]:\n - [2]: a,b\n - [3]: \"c,d\",\"e:f\",\"true\"",
"specSection": "9.2"
},
{
"name": "encodes empty inner arrays",
"input": {
"pairs": [[], []]
},
"expected": "pairs[2]:\n - [0]:\n - [0]:",
"specSection": "9.2"
},
{
"name": "encodes mixed-length inner arrays",
"input": {
"pairs": [[1], [2, 3]]
},
"expected": "pairs[2]:\n - [1]: 1\n - [2]: 2,3",
"specSection": "9.2"
},
{
"name": "encodes root-level primitive array",
"input": ["x", "y", "true", true, 10],
"expected": "[5]: x,y,\"true\",true,10",
"specSection": "9.1"
},
{
"name": "encodes root-level array of uniform objects in tabular format",
"input": [{ "id": 1 }, { "id": 2 }],
"expected": "[2]{id}:\n 1\n 2",
"specSection": "9.3"
},
{
"name": "encodes root-level array of non-uniform objects in list format",
"input": [{ "id": 1 }, { "id": 2, "name": "Ada" }],
"expected": "[2]:\n - id: 1\n - id: 2\n name: Ada",
"specSection": "9.4"
},
{
"name": "encodes root-level array mixing primitive, object, and array of objects in list format",
"input": ["summary", { "id": 1, "name": "Ada" }, [{ "id": 2 }, { "status": "draft" }]],
"expected": "[3]:\n - summary\n - id: 1\n name: Ada\n - [2]:\n - id: 2\n - status: draft",
"specSection": "9.4"
},
{
"name": "encodes root-level arrays of arrays",
"input": [[1, 2], []],
"expected": "[2]:\n - [2]: 1,2\n - [0]:",
"specSection": "9.2"
},
{
"name": "encodes empty root-level array",
"input": [],
"expected": "[0]:",
"specSection": "9.1"
},
{
"name": "encodes complex nested structure",
"input": {
"user": {
"id": 123,
"name": "Ada",
"tags": ["reading", "gaming"],
"active": true,
"prefs": []
}
},
"expected": "user:\n id: 123\n name: Ada\n tags[2]: reading,gaming\n active: true\n prefs[0]:",
"specSection": "8"
},
{
"name": "uses list format for arrays mixing primitives and objects",
"input": {
"items": [1, { "a": 1 }, "text"]
},
"expected": "items[3]:\n - 1\n - a: 1\n - text",
"specSection": "9.4"
},
{
"name": "uses list format for arrays mixing objects and arrays",
"input": {
"items": [{ "a": 1 }, [1, 2]]
},
"expected": "items[2]:\n - a: 1\n - [2]: 1,2",
"specSection": "9.4"
}
]
}

Some files were not shown because too many files have changed in this diff Show More