tinyaml
Switching from another library
Change one import to move from js-yaml, yaml, yamljs or @std/yaml, and what each drop-in does differently.
Each subpath exports the functions, options and types of the library it replaces, apart from the gaps listed below, so switching is a change to the import line. The sizes are esbuild bundles of the published files, minified, then gzip -9. The last column is that library's own test suite, run with tinyaml in its place.
| Library | Change the import to | Size, gzip | Its own tests on tinyaml |
|---|---|---|---|
| js-yaml 4.3.2 | "tinyaml/js-yaml" |
14.4 → 11.7 KiB | 301 of 304 pass |
| js-yaml 5.5.0 | "tinyaml/js-yaml-v5" |
17.1 → 16.0 KiB | 1,023 of 1,646 pass |
| yaml 2.9.1 | "tinyaml/yaml" |
29.9 → 16.8 KiB | 195 of 220 pass |
| yamljs 0.3.0 | "tinyaml/yamljs" |
8.8 → 8.0 KiB | 103 of 103 pass |
| @std/yaml 1.3.0 | "tinyaml/std" |
11.3 → 10.7 KiB | 92 of 95 pass |
// before
import yaml from "js-yaml";
// after
import yaml from "tinyaml/js-yaml";Of js-yaml 5's 1,646 tests, 610 call the events and AST API that tinyaml/js-yaml-v5 leaves out, and js-yaml 5 skips 13 itself. The other 1,023 pass. yaml's five test files that cover parse and stringify hold 531 tests, and the 220 counted are the ones that call tinyaml. The rest test yaml's Document API.
For yamljs and @std/yaml the swap saves less than 1 KiB. The bigger change is the parser. On the yaml-test-suite, tinyaml/yamljs loads 144 cases that yamljs throws on, and in 39 where the two disagree only tinyaml/yamljs matches the suite.
Every subpath runs the same parser code as the root. The details below list each known difference from the original.
js-yaml 4: what's different
Section titled "js-yaml 4: what's different"- The
listeneroption isn't supported. It accounts for 2 of the 3 tests that don't pass. js-yaml skips the third test itself. safeLoad,safeLoadAllandsafeDumpwork and do whatload,loadAllanddumpdo. js-yaml 4 throws for them.- js-yaml's tests make 746 calls to
load,loadAllanddump. Replayed through tinyaml, 740 give the same result, and 6 throw the same error at a different position. tinyaml throws in every case js-yaml does. - On the yaml-test-suite, 399 of 402 cases give the same result as js-yaml. 1 is valid YAML that tinyaml loads and js-yaml rejects (9KAX). The other 2 are js-yaml bugs tinyaml doesn't copy: js-yaml drops a tag on its own line above a less indented block scalar (M5C3), and it loads the invalid H7J7.
- 5,000 randomly edited suite inputs: none load to a different value, none throw only in tinyaml, and 10 load where js-yaml throws, 1 of them invalid YAML. 5,000 random values give matching outcomes, including matching errors: 4,021 dump to the same text and 979 throw the same error.
js-yaml 5: what's different
Section titled "js-yaml 5: what's different"- Only the load and dump API:
load,loadAll,dump,YAMLException,Schema, the schemas, the tag definitions and the style constants. The events, AST, presenter and visit API isn't there:parseEvents,getScalarValue,constructFromEvents,eventsToAst,jsToAst,present,visit, and theEVENT_*,VISIT_*andCHOMPING_*constants. dump'stransformoption works.dumpbuilds the same AST as js-yaml 5 and passes it totransform, but there is novisitto walk it with.- js-yaml 5's tests make 10,085 calls to
load,loadAllanddump, 5,256 of them different in function, input or options. Replayed through tinyaml, 5,213 of those 5,256 give the same result. 20 throw the same error at a different position, and 22 throw with a different message. tinyaml throws in every case js-yaml 5 does. - The one call that loads to a different value is an empty key tagged
!!mergewithmergeTagin the schema,? !!merge\n: []. js-yaml 5 loads{}, and tinyaml loads{ "<<": [] }. - A custom mapping tag gets js-yaml 5's
has,addPairandgetcalls for each node, in the same order, but tinyaml builds a node when it ends. So an outer node'screatecomes after the nodes inside it, a merge calls its source'skeysbeforecreatefor the node it merges into, and a repeated key throws before the node's earlier pairs are added. - When the schema has a mapping tag other than the object maps, a repeated symbol or function key in an untagged mapping throws with the start of the input as its position, since tinyaml builds that mapping after reading the whole stream.
- On the yaml-test-suite, all 402 cases give the same result as js-yaml 5. Both reject 126, and 109 of those throw the same message.
- 5,000 randomly edited suite inputs: none load to a different value, and 2 load where js-yaml 5 throws. 5,000 random values give matching outcomes, including matching errors: 3,584 dump to the same text and 1,416 throw the same error.
yaml: what's different
Section titled "yaml: what's different"- Only
parseandstringify. There is noparseDocument,parseAllDocuments, Document, CST, Lexer, Parser, Composer, LineCounter or visitor API. parsedoesn't supportmapAsMap,stringKeys,strict: false(whichstrict: undefinedalso means to yaml), or recovering from errors withlogLevel: "silent". Collection keys are turned into strings that don't always match yaml's.- A lone carriage return is a line break, as the YAML spec has it. yaml reads it as text, so
- a\r- bis["a", "b"]where yaml gives["a\r- b"]. Error positions count such input as one line, as yaml's do. stringifydoesn't take Document or Node values, writes no comments, and doesn't usecustomTagsor the YAML 1.1!!set,!!omapand!!binarytags.- A collection tag's
resolvegets a stand-in for yaml's YAMLMap or YAMLSeq node. It hasitems, with Scalar, Pair and collection nodes in them,get,has,toJSONandtoString, and nothing else of yaml's node API. An alias in it is a node of the alias's value,toJSONreturns the collection as tinyaml parsed it, andnodeClassisn't used. Its scalars have notag, so!!settakes a value tagged!!nullas null, where yaml rejects it. Whenresolvereturns a node from inside the collection,onAnchorstill hears of the anchors elsewhere in it. When it returns something else, a later alias to an anchor in the collection reads the anchor's value, where yaml throws. - A
<<that merges a!!setmerges nothing. yaml splits each member into a key and a value, so{<<: !!set {abc}}gives{ a: "b" }, and throws a TypeError on a member it can't split, like a number. - With
compat,stringifyquotes what yaml quotes andparsewarns where yaml warns about plain scalars, butparsedoesn't warn about a flow collection whose closing bracket is at its parent's indentation. - The upstream run covers yaml's tests of
parseandstringify, thestringify,parse,errors,typesandanchorsfiles intests/doc/. Of the 25 that fail, 4 arelogLeveltests that fail against yaml itself under Vitest, and 13 use the features above. 5 stringify withindent: 1,indent: 4orindentSeq: false, where the output differs. The last 3 are parse cases: a merge key missing its space, which throws another message, carriage returns inside double quotes, and a collection key in an alias expansion test with the limits turned off. - Across 7 option sets on the yaml-test-suite, 2,593 of 2,814 runs agree with yaml.
- 5,000 randomly edited suite inputs: 1,943 give the same value and the same warnings. 21 more throw the same error with other warnings, since tinyaml stops at the first error and yaml warns about what follows it, unknown aliases included. 2,923 throw in both: 353 the same error, 763 another error code, and the rest the same code at another position or with another message, since tinyaml marks one character where yaml marks the whole token, and words most errors as js-yaml 4 does. 36 load to a different value, 20 of those with a collection key. 47 load only in tinyaml and 30 only in yaml. Lone carriage returns, which yaml reads as text, cause most of these: all 16 other values without a collection key, 39 of the 47 and 22 of the 30. 5,000 random values: 4,932 stringify to the same text, 68 throw the same error, none differ.
yamljs: what's different
Section titled "yamljs: what's different"stringify writes what yamljs writes, byte for byte. parse gives yamljs's values but reads structure as YAML does where yamljs's result is broken:
- Multi-line plain and quoted scalars fold line breaks to spaces, and folded block scalars keep more-indented lines.
a: x\n yis"x y", where yamljs gives"x\ny". - - ais[["a"]], where yamljs gives["- a"].- ? ais[{ a: null }], where yamljs gives["? a"].- Flow mapping keys are read whole:
{a b: 1}is{ "a b": 1 }, where yamljs gives{ a: "b: 1" }. \x,\uand\Uescapes give the character, not its UTF-8 bytes.- Block scalars keep trailing spaces on their last line.
- Quoted strings stay strings.
['*a']is["*a"]and!!str "x"is"x", where yamljs gives[undefined]and'"x"'. - An alias in a flow collection gives its anchor's value. After
a: &x 1,b: {c: *x}is{ c: 1 }andb: [*x]is[1], where yamljs gives the text"*x". - Keys named like built-in object properties, such as
constructor,toStringorhasOwnProperty, are kept. yamljs drops them:constructor: 1givesnulland{constructor: 1}gives{}. <<merges in flow mappings too. yamljs merges only in block mappings, so{<<: {a: 1}}gives{ "<<": { a: 1 } }there.- A merge doesn't replace a key already set to null. After
x: &x {a: 1},y:\n a: ~\n <<: *xkeepsa: null, where yamljs givesa: 1. - A quoted
"<<"or'<<'is a key and doesn't merge, where yamljs merges it. <<merges mappings only. yamljs also merges a sequence by index: afterx: &x [1, 2],<<: *xcopies0: 1and1: 2, where tinyaml throws.- A comment line is never read as a value or key.
- Errors are
ParseExceptions with the root's messages.
On the yaml-test-suite's 402 cases, 186 give the same result as yamljs, and 144 load where yamljs throws. In 39 the values differ and only tinyaml/yamljs matches the suite. In 33 neither matches or the case is invalid YAML. There is no case where only yamljs is right. 5,000 random values give matching outcomes, including matching errors: 4,994 dump to the same text and 6 throw the same error.
@std/yaml: what's different
Section titled "@std/yaml: what's different"unstable_parseandunstable_stringifyaren't supported. They account for 2 of the 3 tests that don't pass. The third starts a Deno subprocess, which can't run under Node.- On the yaml-test-suite, 360 of 402 cases give the same result as std, 99 of them the same error message. 11 parse where std throws. The other 31 differ, and in all 31 std's own result is wrong by the suite's answers.
- 5,000 randomly edited suite inputs: 117 parse to a different value, 146 throw only in tinyaml, and 48 parse where std throws, so values or acceptance differ in 311 of them, 6.2%. 2,866 throw in both, 2,542 of them with the same message and 2,570 with the same message apart from the position.
- 5,000 random values give matching outcomes, including matching errors: 3,499 stringify to the same text and 1,501 throw the same error.