{"id":22281767,"url":"https://github.com/squirrelchat/smol-toml","last_synced_at":"2025-05-15T04:08:01.113Z","repository":{"id":165243692,"uuid":"635832264","full_name":"squirrelchat/smol-toml","owner":"squirrelchat","description":"A small, fast, and correct TOML (1.0.0) parser and serializer","archived":false,"fork":false,"pushed_at":"2025-04-24T18:53:03.000Z","size":3788,"stargazers_count":187,"open_issues_count":6,"forks_count":9,"subscribers_count":3,"default_branch":"mistress","last_synced_at":"2025-05-09T08:41:40.499Z","etag":null,"topics":["javascript","nodejs","parser","serializer","toml","toml-parser","toml-serializer","toml-stringify","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/squirrelchat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-05-03T14:46:49.000Z","updated_at":"2025-05-06T22:27:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"a7172db5-446e-46a2-8384-1a0a63fffcc6","html_url":"https://github.com/squirrelchat/smol-toml","commit_stats":{"total_commits":39,"total_committers":5,"mean_commits":7.8,"dds":"0.10256410256410253","last_synced_commit":"f72e14a3a9238cf72d4ee7cd5274aff0a924eb5a"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squirrelchat%2Fsmol-toml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squirrelchat%2Fsmol-toml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squirrelchat%2Fsmol-toml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squirrelchat%2Fsmol-toml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/squirrelchat","download_url":"https://codeload.github.com/squirrelchat/smol-toml/tar.gz/refs/heads/mistress","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254270656,"owners_count":22042860,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","nodejs","parser","serializer","toml","toml-parser","toml-serializer","toml-stringify","typescript"],"created_at":"2024-12-03T16:21:46.854Z","updated_at":"2025-05-15T04:07:56.096Z","avatar_url":"https://github.com/squirrelchat.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# smol-toml\n[![TOML 1.0.0](https://img.shields.io/badge/TOML-1.0.0-9c4221?style=flat-square)](https://toml.io/en/v1.0.0)\n[![License](https://img.shields.io/github/license/squirrelchat/smol-toml.svg?style=flat-square)](https://github.com/squirrelchat/smol-toml/blob/mistress/LICENSE)\n[![npm](https://img.shields.io/npm/v/smol-toml?style=flat-square)](https://npm.im/smol-toml)\n[![Build](https://img.shields.io/github/actions/workflow/status/squirrelchat/smol-toml/build.yml?style=flat-square\u0026logo=github)](https://github.com/squirrelchat/smol-toml/actions/workflows/build.yml)\n\nA small, fast, and correct TOML parser and serializer. smol-toml is fully(ish) spec-compliant with TOML v1.0.0.\n\nWhy yet another TOML parser? Well, the ecosystem of TOML parsers in JavaScript is quite underwhelming, most likely due\nto a lack of interest. With most parsers being outdated, unmaintained, non-compliant, or a combination of these, a new\nparser didn't feel too out of place.\n\n*[insert xkcd 927]*\n\nsmol-toml passes most of the tests from the [`toml-test` suite](https://github.com/toml-lang/toml-test); use the\n`run-toml-test.bash` script to run the tests. Due to the nature of JavaScript and the limits of the language,\nit doesn't pass certain tests, namely:\n- Invalid UTF-8 strings are not rejected\n- Certain invalid UTF-8 codepoints are not rejected\n- Certain invalid dates are not rejected\n  - For instance, `2023-02-30` would be accepted and parsed as `2023-03-02`. While additional checks could be performed\n\tto reject these, they've not been added for performance reasons.\n- smol-toml doesn't preserve type information between integers and floats (in JS, everything is a float)\n\nYou can see a list of all tests smol-toml fails (and the reason why it fails these) in the list of skipped tests in\n`run-toml-test.bash`. Note that some failures are *not* specification violations per-se. For instance, the TOML spec\ndoes not require 64-bit integer range support or sub-millisecond time precision, but are included in the `toml-test`\nsuite. See https://github.com/toml-lang/toml-test/issues/154 and https://github.com/toml-lang/toml-test/issues/155\n\n## Installation\n```\n[pnpm | yarn | npm] i smol-toml\n```\n\n## Usage\n```js\nimport { parse, stringify } from 'smol-toml'\n\nconst doc = '...'\nconst parsed = parse(doc)\nconsole.log(parsed)\n\nconst toml = stringify(parsed)\nconsole.log(toml)\n```\n\nAlternatively, if you prefer something similar to the JSON global, you can import the library as follows\n```js\nimport TOML from 'smol-toml'\n\nTOML.stringify({ ... })\n```\n\nA few notes on the `stringify` function:\n- `undefined` and `null` values on objects are ignored (does not produce a key/value).\n- `undefined` and `null` values in arrays are **rejected**.\n- Functions, classes and symbols are **rejected**.\n- floats will be serialized as integers if they don't have a decimal part.\n  - `stringify(parse('a = 1.0')) === 'a = 1'`\n- JS `Date` will be serialized as Offset Date Time\n  - Use the [`TomlDate` object](#dates) for representing other types.\n\n### Dates\n`smol-toml` uses an extended `Date` object to represent all types of TOML Dates. In the future, `smol-toml` will use\nobjects from the Temporal proposal, but for now we're stuck with the legacy Date object.\n\n```js\nimport { TomlDate } from 'smol-toml'\n\n// Offset Date Time\nconst date = new TomlDate('1979-05-27T07:32:00.000-08:00')\nconsole.log(date.isDateTime(), date.isDate(), date.isTime(), date.isLocal()) // ~\u003e true, false, false, false\nconsole.log(date.toISOString()) // ~\u003e 1979-05-27T07:32:00.000-08:00\n\n// Local Date Time\nconst date = new TomlDate('1979-05-27T07:32:00.000')\nconsole.log(date.isDateTime(), date.isDate(), date.isTime(), date.isLocal()) // ~\u003e true, false, false, true\nconsole.log(date.toISOString()) // ~\u003e 1979-05-27T07:32:00.000\n\n// Local Date\nconst date = new TomlDate('1979-05-27')\nconsole.log(date.isDateTime(), date.isDate(), date.isTime(), date.isLocal()) // ~\u003e false, true, false, true\nconsole.log(date.toISOString()) // ~\u003e 1979-05-27\n\n// Local Time\nconst date = new TomlDate('07:32:00')\nconsole.log(date.isDateTime(), date.isDate(), date.isTime(), date.isLocal()) // ~\u003e false, false, true, true\nconsole.log(date.toISOString()) // ~\u003e 07:32:00.000\n```\n\nYou can also wrap a native `Date` object and specify using different methods depending on the type of date you wish\nto represent:\n\n```js\nimport { TomlDate } from 'smol-toml'\n\nconst jsDate = new Date()\n\nconst offsetDateTime = TomlDate.wrapAsOffsetDateTime(jsDate)\nconst localDateTime = TomlDate.wrapAsLocalDateTime(jsDate)\nconst localDate = TomlDate.wrapAsLocalDate(jsDate)\nconst localTime = TomlDate.wrapAsLocalTime(jsDate)\n```\n\n## Performance\nA note on these performance numbers: in some highly synthetic tests, other parsers such as `fast-toml` greatly\noutperform other parsers, mostly due to their lack of compliance with the spec. For example, to parse a string,\n`fast-toml` skips the entire string while `smol-toml` does validate the string, costing a fair share of performance.\n\nThe ~5MB test file used for benchmark here is filled with random data which attempts to be close-ish to reality in\nterms of structure. The idea is to have a file relatively close to a real-world application, with moderately sized\nstrings etc.\n\nThe large TOML generator can be found [here](https://gist.github.com/cyyynthia/e77c744cb6494dabe37d0182506526b9)\n\n| **Parse**      | smol-toml           | @iarna/toml@3.0.0 | @ltd/j-toml     | fast-toml       |\n|----------------|---------------------|-------------------|-----------------|-----------------|\n| Spec example   | **71,356.51 op/s**  | 33,629.31 op/s    | 16,433.86 op/s  | 29,421.60 op/s  |\n| ~5MB test file | **3.8091 op/s**     | *DNF*             | 2.4369 op/s     | 2.6078 op/s     |\n\n| **Stringify**  | smol-toml            | @iarna/toml@3.0.0 | @ltd/j-toml    |\n|----------------|----------------------|-------------------|----------------|\n| Spec example   | **195,191.99 op/s**  | 46,583.07 op/s    | 5,670.12 op/s  |\n| ~5MB test file | **14.6709 op/s**     | 3.5941 op/s       | 0.7856 op/s    |\n\n\u003cdetails\u003e\n\u003csummary\u003eDetailed benchmark data\u003c/summary\u003e\n\nTests ran using Vitest v0.31.0 on commit f58cb6152e667e9cea09f31c93d90652e3b82bf5\n\nCPU: Intel Core i7 7700K (4.2GHz)\n\n```\n RUN  v0.31.0\n\n ✓ bench/parseSpecExample.bench.ts (4) 2462ms\n     name                hz     min     max    mean     p75     p99    p995    p999     rme  samples\n   · smol-toml    71,356.51  0.0132  0.2633  0.0140  0.0137  0.0219  0.0266  0.1135  ±0.37%    35679   fastest\n   · @iarna/toml  33,629.31  0.0272  0.2629  0.0297  0.0287  0.0571  0.0650  0.1593  ±0.45%    16815\n   · @ltd/j-toml  16,433.86  0.0523  1.3088  0.0608  0.0550  0.1140  0.1525  0.7348  ±1.47%     8217   slowest\n   · fast-toml    29,421.60  0.0305  0.2995  0.0340  0.0312  0.0618  0.0640  0.1553  ±0.47%    14711\n ✓ bench/parseLargeMixed.bench.ts (3) 16062ms\n     name             hz     min     max    mean     p75     p99    p995    p999     rme  samples\n   · smol-toml    3.8091  239.60  287.30  262.53  274.17  287.30  287.30  287.30  ±3.66%       10   fastest\n   · @ltd/j-toml  2.4369  376.73  493.49  410.35  442.58  493.49  493.49  493.49  ±7.08%       10   slowest\n   · fast-toml    2.6078  373.88  412.79  383.47  388.62  412.79  412.79  412.79  ±2.72%       10\n ✓ bench/stringifySpecExample.bench.ts (3) 1886ms\n     name                 hz     min     max    mean     p75     p99    p995    p999     rme  samples\n   · smol-toml    195,191.99  0.0047  0.2704  0.0051  0.0050  0.0099  0.0110  0.0152  ±0.41%    97596   fastest\n   · @iarna/toml   46,583.07  0.0197  0.2808  0.0215  0.0208  0.0448  0.0470  0.1704  ±0.47%    23292\n   · @ltd/j-toml    5,670.12  0.1613  0.5768  0.1764  0.1726  0.3036  0.3129  0.4324  ±0.56%     2836   slowest\n ✓ bench/stringifyLargeMixed.bench.ts (3) 24057ms\n     name              hz       min       max      mean       p75       p99      p995      p999     rme  samples\n   · smol-toml    14.6709   65.1071   79.2199   68.1623   67.1088   79.2199   79.2199   79.2199  ±5.25%       10   fastest\n   · @iarna/toml   3.5941    266.48    295.24    278.24    290.10    295.24    295.24    295.24  ±2.83%       10\n   · @ltd/j-toml   0.7856  1,254.33  1,322.05  1,272.87  1,286.82  1,322.05  1,322.05  1,322.05  ±1.37%       10   slowest\n\n\n BENCH  Summary\n\n  smol-toml - bench/parseLargeMixed.bench.ts \u003e\n    1.46x faster than fast-toml\n    1.56x faster than @ltd/j-toml\n\n  smol-toml - bench/parseSpecExample.bench.ts \u003e\n    2.12x faster than @iarna/toml\n    2.43x faster than fast-toml\n    4.34x faster than @ltd/j-toml\n\n  smol-toml - bench/stringifyLargeMixed.bench.ts \u003e\n    4.00x faster than @iarna/toml\n    18.33x faster than @ltd/j-toml\n\n  smol-toml - bench/stringifySpecExample.bench.ts \u003e\n    4.19x faster than @iarna/toml\n    34.42x faster than @ltd/j-toml\n```\n\n---\nAdditional notes:\n\nI initially tried to benchmark `toml-nodejs`, but the 0.3.0 package is broken.\nI initially reported this to the library author, but the author decided to\n- a) advise to use a custom loader (via *experimental* flag) to circumvent the invalid imports.\n  - Said flag, `--experimental-specifier-resolution`, has been removed in Node v20.\n- b) [delete the issue](https://github.com/huan231/toml-nodejs/issues/12) when pointed out links to the NodeJS\ndocumentation about the flag removal and standard resolution algorithm.\n\nFor the reference anyway, `toml-nodejs` (with proper imports) is ~8x slower on both parse benchmark with:\n- spec example: 7,543.47 op/s\n- 5mb mixed: 0.7006 op/s\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquirrelchat%2Fsmol-toml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsquirrelchat%2Fsmol-toml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquirrelchat%2Fsmol-toml/lists"}