Releases: ISON-format/isongraph
Release list
ISONGraph 1.4.0
Rust, C# and C++ change their property API. Those three stored every value
as a string, so they serialized differently from Python, JS and TS - one
graph produced two different documents depending on which language wrote
it. They now use their parser's own value type.
Changed — breaking (Rust, C#, C++ only)
-
Properties carry types.
HashMap<String, String>becomes
HashMap<String, ison_rs::Value>,Dictionary<string, string>becomes
Dictionary<string, object?>, andmap<string, string>becomes
map<string, ison::Value>. Not a new union - the parser already models
exactly the types the format has, and keeping a second one beside it is
what caused the split.# 1.3.0 (Rust, C#, C++) # 1.4.0 - matching Python/JS/TS nodes.company nodes.company id listed name staff id listed name staff acme "false" "Acme" "42" acme false "Acme Corp" 42 -
Rust callers use
props!. AVecis homogeneous, so a literal mixing
an int and a string cannot be written directly, and the orphan rule stops
this crate addingFromimpls toison_rs::Value.props![("name", "Acme"), ("staff", 42i64)]converts each value before collecting.
vec![("k", "v")]no longer compiles for properties. -
A number now compares as a number in queries, rather than as a parse
of its rendering. A string holding a number still compares numerically,
so filters written against the old storage keep working. Schema
validation is unchanged - it still validates the rendered text; making it
type-aware is a separate change.
Fixed
-
The three string-only ports round-trip values without flattening them.
Loading42gave back the string"42", which then re-emitted quoted. -
schema-generatoremitted Python that could not run. It imported
StringField/IntField/FloatField/BoolField- the names the Rust, JS,
TS, C# and C++ ports use - where Python hasString/Int/Float/Bool;
it called.min_length()/.max_length(), spelled.min()/.max()on
Python'sString; it called the singular.node_type()/.edge_type();
and it chained across lines without brackets, so the output was a syntax
error regardless. Its tests asserted substrings and so passed throughout;
they now execute the generated code.
Known limitation
- An integral float originated in JavaScript or TypeScript cannot be
distinguished from an integer.1.0 === 1in JS, so a JS-authored
{weight: 1.0}emits1where Python emits1.0. This is a property of
the language, not of ISONGraph. Values arriving from ISON keep their
form in every port; only origination is affected. The shared test fixture
deliberately contains no integral float for this reason.
Install
pip install ison-graph==1.4.0
cargo add ison-graph@1.4.0
npm install ison-graph-js@1.4.0 # or ison-graph-ts@1.4.0
dotnet add package IsonGraph --version 1.4.0C++ is header-only: copy ison-graph-cpp/include/ison_graph.hpp. It needs
ison-cpp >= 1.2.0 on the include path.
All six ports serialize identically; the shared fixture is 488 bytes ISON,
636 bytes ISONL.
ISONGraph 1.3.0
Serialized output changes in this release. A graph written by 1.3.0 is not
byte-identical to one written by 1.2.0, and identifiers that 1.2.0 accepted
are now refused at construction. Both changes remove ways the old code lost
data silently; see Migrating below.
Changed — breaking
-
Every port now emits through its ISON parser's canonical writer. Each
port used to hand-roll its own ISON emitter beside the parser's, so ISON
syntax had two implementations per language that had to agree forever.
They did not: the id column was written unquoted, so a node id containing
a space produced output that would not reparse, and a string id like"1"
came back as the integer1.Blocks now sort by
kind.nameand columns sort within a block, soedges
precedesnodesand column order is the writer's rather than the caller's.
Strings that would otherwise reparse as numbers are quoted, which is what
makes the round trip lossless.# 1.2.0 # 1.3.0 nodes.person edges.KNOWS id name age since source target 1 Alice 30 2020 :person:1 :person:2 edges.KNOWS nodes.person source target since id age name :person:1 :person:2 2020 1 30 Alice -
Unrepresentable identifiers are refused at construction. Node types,
node ids and relation types may no longer be empty or contain whitespace,
:or|; types additionally may not contain"or\because they
become block names, which ISONL cannot quote. Property names are checked
against a wider set — they become ISON field names, where a leading#
turns the header into a comment and loses the whole block.An audit of hostile values across all three identifier positions found 18
of 24 combinations corrupting or crashing on round trip before this change. -
Node ids that differ only by type are refused. A reference carries no
type, so1and"1"both write as:p:1. A graph holding both was
addressable in memory and ambiguous on the wire; the second is now
rejected when the first exists. -
All six ports are on one version. Python, JS and TS were at 1.2.0;
Rust and C# at 1.0.0; C++ untagged.ISONGraph 1.3.0now means the same
code in every language. -
C++ requires ison-cpp >= 1.1.2.
ison_graph.hppincludes
ison_parser.hpprather than vendoring a copy, so an ISON fix arrives on
the next build instead of when someone re-cuts the copy. CMake takes
ISON_CPP_INCLUDE_DIRand fails configuration when the header is absent;
a header older than 1.1.2 is a compile error rather than a behavioural
difference.
Added
-
ison_graph.multigraph.MultiGraph(Python, experimental) — parallel
edges keyed by a stable integer, so the same relationship can be recorded
more than once between the same pair without inventing synthetic relation
types. Serialized output carries anison-graph-multigraph-v1marker, and
plainISONGraphrefuses to load it rather than silently dropping the
parallel edges. -
ison_graph.structural.ProtectedGraph(Python, experimental) —
refuses properties that shadow structural fields, hands properties out as
read-only views, and sealstype/id/rel_type/source/targetso an
object cannot report an identity the graph's indexes never used. -
convertersandschema-generatorpackages, with the crash bugs
found while testing them fixed.
Fixed
- Canonical serialization is genuinely insertion-order independent. Row
order previously depended on the order rows were added whenever the first
column tied. from_isonresolves references against the loaded nodes instead of
guessing that a numeric-looking id is an integer, which silently broke
graphs with string ids like"1".- Loaders take nodes before edges regardless of block order, which the
canonical writer changed. - Duplicate-edge imports no longer crash the CSV and GraphML converters.
- C++ tests assert with a macro that survives
NDEBUG. All 134 assertions
were compiled out under CMake's Release config, so the suite reported
every case as passing while checking nothing.
Migrating
- Regenerate stored
.isong/.isonlfiles from source data, or accept
that 1.3.0 output differs from 1.2.0. Content-addressed caches keyed on
the old bytes will miss once. - Check identifiers. If node ids or relation types contain whitespace,
:or|, they were already corrupting on round trip — map them to
graph-safe values at your boundary and translate back on the way out. - C++ users: put
ison_parser.hppon your include path.
Install
pip install ison-graph==1.3.0
cargo add ison-graph@1.3.0
npm install ison-graph-js@1.3.0 # or ison-graph-ts@1.3.0
dotnet add package IsonGraph --version 1.3.0C++ is header-only: copy ison-graph-cpp/include/ison_graph.hpp. It needs
ison-cpp >= 1.2.0 on the include path.
All six ports serialize identically; the shared fixture is 488 bytes ISON,
636 bytes ISONL.
ISONGraph 1.2.0
Radius-aware layout: compute_layout gains radii + spacing options enforcing (r_a + r_b) * spacing between node pairs via a deterministic collision pass - identical in Python, TypeScript, and JavaScript (cross-language parity tested). npm packages also add the ./viz subpath export. Omitting radii keeps geometry byte-identical to 1.1.0.
ISONGraph 1.1.0
Visualization: ison_graph.viz module + ISONGraph Viz VS Code extension