Spittoon.Core
0.1.5.1
dotnet add package Spittoon.Core --version 0.1.5.1
NuGet\Install-Package Spittoon.Core -Version 0.1.5.1
<PackageReference Include="Spittoon.Core" Version="0.1.5.1" />
<PackageVersion Include="Spittoon.Core" Version="0.1.5.1" />
<PackageReference Include="Spittoon.Core" />
paket add Spittoon.Core --version 0.1.5.1
#r "nuget: Spittoon.Core, 0.1.5.1"
#:package Spittoon.Core@0.1.5.1
#addin nuget:?package=Spittoon.Core&version=0.1.5.1
#tool nuget:?package=Spittoon.Core&version=0.1.5.1
SPITTOON–Semicolon-Punctuated, Interoperable, Tersely-Typed Open Object Notation
Version: 0.1.5.1

First there was CSV. Then XML arrived wearing a tuxedo nobody asked for. Then JSON showed up, drunk on quotes and braces. Then TOON tried to fix everything and mostly just confused people. And now, finally, the format to end the format wars: SPITTOON.
Why SPITTOON exists
- JSON is quote-heavy and verbose — delightful for machines, exhausting for humans who must edit configuration at 02:13.
- XML is a war crime against readability; it insists every opening tag bring a plus-one.
- CSV can’t represent hierarchy without melting into a puddle of ambiguity.
- TOON’s bracketed counts and mandatory semicolons feel like a tax on comprehension.
- Real-world config files and log payloads are getting bigger and more nested, yet humans still need to read and tweak them.
SPITTOON aims to be the smallest set of sensible rules that solves these problems. It is:
- More compact than JSON (fewer quotes, terser separators).
- Strictly unambiguous (no
is this key quoted or not?arguments at 3 a.m.). - Actually pleasant to hand-edit (line-oriented, optional semicolons for cleanliness).
- Supporting multiple proper typed tabular sections, even embedded within hierarchical data (think CSV with structure and nesting).
- Unlike JSON, allows line- and stream comments.
Comparison (short and rude)
| Format | Readability | Typical Size | Feature completeness |
|---|---|---|---|
| CSV | Fast to scan if flat; hopeless with nesting | Small | Flat only — collapses under pressure |
| XML | Machine-robust, human-hostile | Large | Complete, but did you enjoy reading it? |
| JSON | Familiar, verbose, quote-hungry | Medium | Great all-rounder; heavy on punctuation |
| TOON | Ambitious, fiddly | Medium | Adds complexity that rarely pays for itself |
| SPITTOON | Designed for humans who still care | Small → Medium | Compact, unambiguous, tabular + nested — actually useful |
Hello World
Simple object (valid SPITTOON — strings with spaces are quoted):
/* hello.spit */
{
message: "Hello, world",
count: 3,
active: true
}
A real-world before/after — typical appsettings.json (abridged)
// appsettings.json (typical, quote soup)
{
"Logging": {
"LogLevel": { "Default": "Information", "Microsoft": "Warning" },
"Console": { "IncludeScopes": false }
},
"ConnectionStrings": { "DefaultConnection": "Server=.;Database=App;Trusted_Connection=True;" },
"FeatureFlags": { "NewSearch": true }
}
Same thing in SPITTOON (explicit, balanced punctuation, connection string quoted because of delimiters):
/* appsettings.spit */
{
Logging: {
LogLevel: { Default: Information, Microsoft: Warning },
Console: { IncludeScopes: false }
},
ConnectionStrings: { DefaultConnection: "Server=.;Database=App;Trusted_Connection=True;" },
FeatureFlags: { NewSearch: true }
}
Usage (C#)
Serializing a POCO to a .spit file:
// create and write .spit file
var poco = new AppSettings { /* ... */ };
var serializer = new SpittoonSerializer();
string text = serializer.Serialize(poco, Formatting.Indented);
File.WriteAllText("appsettings.spit", text); // yes, really that simple
Deserializing to a strongly-typed object:
// read and map to strongly-typed object
string raw = File.ReadAllText("appsettings.spit");
var deserializer = new SpittoonDeserializer();
var settings = deserializer.Deserialize<AppSettings>(raw);
// properties are mapped by name; use [SpittoonName("custom")] to rename
Forgiving vs Strict mode
// Forgiving: acceptable for human-written configs (allows small syntax relaxations)
var forgiving = new SpittoonDeserializer(SpittoonMode.Forgiving);
var dyn = forgiving.DeserializeDynamic(File.ReadAllText("loose.spit"));
// Strict: used for validation pipelines and CI gates — rejects ambiguities
var strict = new SpittoonDeserializer(SpittoonMode.Strict);
var typed = strict.Deserialize<MyConfig>(File.ReadAllText("clean.spit"));
Simple syntax validation
bool ok = Spittoon.Validation.SpittoonValidator.IsValid(text, SpittoonMode.Forgiving);
var result = Spittoon.Validation.SpittoonValidator.ValidateSyntax(text);
// result contains detailed error info when syntax is broken
Full (SPITSD) schema validation
// load schema (SPITSD is a compact schema language for SPITTOON)
var ssch = File.ReadAllText("my-schema.spitsd");
var validator = new Spittoon.Validation.SschValidator(spitsd);
var validation = validator.Validate(File.ReadAllText("candidate.spit"), SpittoonMode.Strict);
if (!validation.IsValid) foreach (var e in validation.Errors) Console.WriteLine(e);
File extension
We strongly recommend *.spit. If you are terminally verbose, *.spittoon is also allowed but please seek help.
Tabular examples — because real data repeats
When you have lots of repeated rows (user lists, metrics, logs), JSON becomes a parade of identical keys, CSV loses structure, and both invite typos. SPITTOON lets you declare a header once and express rows tersely — with optional column types — so the same information is clearer and smaller.
JSON (verbose, repetitive):
[
{ "id": 1, "name": "Alice", "active": true },
{ "id": 2, "name": "Bob", "active": false },
{ "id": 3, "name": "Carol", "active": true }
]
SPITTOON tabular form (clear header, compact rows). Note: header types are recommended; rows omit labels for brevity:
users: {
header: { id:int, name:str, active:bool },
rows: [
[1, Alice, true],
[2, Bob, false],
[3, Carol, true]
]
}
If you prefer the rows as objects (more explicit, still compact):
users: {
header: { id:int, name:str, active:bool },
rows: [
{ id: 1, name: Alice, active: true },
{ id: 2, name: Bob, active: false },
{ id: 3, name: Carol, active: true }
]
}
Why this helps:
- The header documents column names and types once — less noise when skimming.
- Rows are short and line-oriented; commas (or semicolons) make row boundaries obvious in formatted output.
- Parsers normalize arrays-of-arrays into arrays-of-objects for convenient access (
header+rows→ list of dictionaries). - Compared to the JSON form above you typically shave both characters and cognitive load.
A slightly more realistic example — log lines with metadata. Per RFC, timestamps and messages containing colons or spaces must be quoted:
logs: {
header: { ts:str, lvl:str, msg:str, meta:obj },
rows: [
["2025-01-01T12:00:00Z", INFO, "Started", { pid: 123 }],
["2025-01-01T12:01:00Z", WARN, "Slow query", { ms: 512 }]
]
}
The serializer and validator already understand this header+rows shape and will normalize rows for you — meaning short, readable source and convenient programmatic access.
Reserved keywords
SPITTOON uses a small set of well-known member names for special data shapes. The two primary reserved keywords are:
header— declares a typed column header for tabular sectionsrows— contains the rows for a tabular section (arrays or objects normalized to rows)
If your object model naturally contains properties named header or rows, you have several options:
- Rename the property in source and use
[SpittoonName("header")](orrows) on the property to explicitly map the name. - Keep the property but quote the key in the
.spitfile so the parser treats it as a normal object member (e.g."header": { ... }). - Nest your model under a container object so the top-level
header/rowspair is not confused with your domain property.
Reserved keywords are only treated specially when they form a header+rows pair with the appropriate shapes; otherwise they behave like normal members.
Recommended schema extension
We recommend using the extension .spitsd for SPITTOON schema files (Spittoon Schema Definition).
Because JSON had too much baggage, CSV was too flat, TOON too quirky in the brackets, and we needed something with actual spit. Terse, human-readable, hierarchical + tabular-ready serialization: comma-or-semicolon separators, optional SPITSD schema validation, and a mullet that’s strictly business in the front, pure party in the back.
Badges
Go forth. Expectoration of clean data is now in your hands.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial package release