parent
38281da7a6
commit
fbd777c909
42
CHANGELOG.md
42
CHANGELOG.md
|
|
@ -1,3 +1,21 @@
|
||||||
|
# [3.3.0](https://github.com/TriPSs/conventional-changelog-action/compare/v3.2.0...v3.3.0) (2020-08-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Empty version files ([091fdfc](https://github.com/TriPSs/conventional-changelog-action/commit/091fdfc6a55a151e3adff5ada382986ead85d58e))
|
||||||
|
* Message when using the fallback version ([b525f9a](https://github.com/TriPSs/conventional-changelog-action/commit/b525f9ae66cb03aa2a58cd043963504b911bac31))
|
||||||
|
* Pull all tags ([3396dfc](https://github.com/TriPSs/conventional-changelog-action/commit/3396dfc4323e48de090308fff522ef4c557f73e5))
|
||||||
|
* Show info if the version couldn't be detected ([9a324db](https://github.com/TriPSs/conventional-changelog-action/commit/9a324dbd51d0d32c1b9df1a291e14cc20a5bbaff))
|
||||||
|
* Use fallback if it's not a valid JSON-File ([97f1bb3](https://github.com/TriPSs/conventional-changelog-action/commit/97f1bb3543e6f2480ef3e699fc695ecb8b3f881b))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add fallback version ([63d0e46](https://github.com/TriPSs/conventional-changelog-action/commit/63d0e46a0b69e3db3f7a5f44e963323afc35d29c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [3.2.0](https://github.com/TriPSs/conventional-changelog-action/compare/v3.1.2...v3.2.0) (2020-08-03)
|
# [3.2.0](https://github.com/TriPSs/conventional-changelog-action/compare/v3.1.2...v3.2.0) (2020-08-03)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,27 +60,3 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [3.0.0](https://github.com/TriPSs/conventional-changelog-action/compare/v2.4.0...v3.0.0) (2020-07-03)
|
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
* Updated README ([000434c](https://github.com/TriPSs/conventional-changelog-action/commit/000434c4469403159c004a4ed0f5715a06f80448))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Added skip commit and skip tag ([3eab241](https://github.com/TriPSs/conventional-changelog-action/commit/3eab2417f9b3e1db3d630b6ec1820106da9a21a9))
|
|
||||||
* Added support for toml files ([5aff23f](https://github.com/TriPSs/conventional-changelog-action/commit/5aff23f51411f417adf6ea22364d158d335a5fce))
|
|
||||||
* Added support for yaml files ([bdf8ec0](https://github.com/TriPSs/conventional-changelog-action/commit/bdf8ec04e6f0d493ef859df06ffbeecb1f47a970))
|
|
||||||
* Added version-file, version-path, skip-version-file options ([d022b0d](https://github.com/TriPSs/conventional-changelog-action/commit/d022b0d7e98b6b13ce0af3e6c44a550256b0ca59))
|
|
||||||
* Added versioning through GIT ([7143306](https://github.com/TriPSs/conventional-changelog-action/commit/714330612535ae25eb483d0f24fb2fe0c091dc86))
|
|
||||||
* More git configurations are possible ([9ee9c27](https://github.com/TriPSs/conventional-changelog-action/commit/9ee9c274488b9013bf3dd5e5a1f9af3345901f7e))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* `package-json` is now renamed to `version-file`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
# 2.2.5
|
||||||
|
|
||||||
|
* Docs: Updated benchmark results. Add fast-toml to result list. Improved benchmark layout.
|
||||||
|
* Update @sgarciac/bombadil and @ltd/j-toml in benchmarks and compliance tests.
|
||||||
|
* Dev: Some dev dep updates that shouldn't have any impact.
|
||||||
|
|
||||||
|
# 2.2.4
|
||||||
|
|
||||||
|
* Bug fix: Plain date literals (not datetime) immediately followed by another statement (no whitespace or blank line) would crash. Fixes [#19](https://github.com/iarna/iarna-toml/issues/19) and [#23](https://github.com/iarna/iarna-toml/issues/23), thank you [@arnau](https://github.com/arnau) and [@jschaf](https://github.com/jschaf) for reporting this!
|
||||||
|
* Bug fix: Hex literals with lowercase Es would throw errors. (Thank you [@DaeCatt](https://github.com/DaeCatt) for this fix!) Fixed [#20](https://github.com/iarna/iarna-toml/issues/20)
|
||||||
|
* Some minor doc tweaks
|
||||||
|
* Added Node 12 and 13 to Travis. (Node 6 is failing there now, mysteriously. It works on my machine™, shipping anyway. 🙃)
|
||||||
|
|
||||||
|
# 2.2.3
|
||||||
|
|
||||||
|
This release just updates the spec compliance tests and benchmark data to
|
||||||
|
better represent @ltd/j-toml.
|
||||||
|
|
||||||
|
# 2.2.2
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* Support parsing and stringifying objects with `__proto__` properties. ([@LongTengDao](https://github.com/LongTengDao))
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
|
||||||
|
* Updates for spec compliance and benchmarking:
|
||||||
|
* @sgarciac/bombadil -> 2.1.0
|
||||||
|
* toml -> 3.0.0
|
||||||
|
* Added spec compliance and benchmarking for:
|
||||||
|
* @ltd/j-toml
|
||||||
|
|
||||||
|
# 2.2.1
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* Fix bug where keys with names matching javascript Object methods would
|
||||||
|
error. Thanks [@LongTengDao](https://github.com/LongTengDao) for finding this!
|
||||||
|
* Fix bug where a bundled version would fail if `util.inspect` wasn't
|
||||||
|
provided. This was supposed to be guarded against, but there was a bug in
|
||||||
|
the guard. Thanks [@agriffis](https://github.com/agriffis) for finding and fixing this!
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
|
||||||
|
* Update the version of bombadil for spec compliance and benchmarking purposes to 2.0.0
|
||||||
|
|
||||||
|
## Did you know?
|
||||||
|
|
||||||
|
Node 6 and 8 are measurably slower than Node 6, 10 and 11, at least when it comes to parsing TOML!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# 2.2.0
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Typescript: Lots of improvements to our type definitions, many many to
|
||||||
|
[@jorgegonzalez](https://github.com/jorgegonzalez) and [@momocow](https://github.com/momocow) for working through these.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* Very large integers (>52bit) are stored as BigInts on runtimes that
|
||||||
|
support them. BigInts are 128bits, but the TOML spec limits its integers
|
||||||
|
to 64bits. We now limit our integers to 64bits
|
||||||
|
as well.
|
||||||
|
* Fix a bug in stringify where control characters were being emitted as unicode chars and not escape sequences.
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
|
||||||
|
* Moved our spec tests out to an external repo
|
||||||
|
* Improved the styling of the spec compliance comparison
|
||||||
|
|
||||||
|
# 2.1.1
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* Oops, type defs didn't end up in the tarball, ty [@jorgegonzalez](https://github.com/jorgegonzalez)‼
|
||||||
|
|
||||||
|
# 2.1.0
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Types for typescript support, thank you [@momocow](https://github.com/momocow)!
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* stringify: always strip invalid dates. This fixes a bug where an
|
||||||
|
invalid date in an inline array would not be removed and would instead
|
||||||
|
result in an error.
|
||||||
|
* stringify: if an invalid type is found make sure it's thrown as an
|
||||||
|
error object. Previously the type name was, unhelpfully, being thrown.
|
||||||
|
* stringify: Multiline strings ending in a quote would generate invalid TOML.
|
||||||
|
* parse: Error if a signed integer has a leading zero, eg, `-01` or `+01`.
|
||||||
|
* parse: Error if \_ appears at the end of the integer part of a float, eg `1_.0`. \_ is only valid between _digits_.
|
||||||
|
|
||||||
|
## Fun
|
||||||
|
|
||||||
|
* BurntSushi's comprehensive TOML 0.4.0 test suite is now used in addition to our existing test suite.
|
||||||
|
* You can see exactly how the other JS TOML libraries stack up in testing
|
||||||
|
against both BurntSushi's tests and my own in the new
|
||||||
|
[TOML-SPEC-SUPPORT](TOML-SPEC-SUPPORT.md) doc.
|
||||||
|
|
||||||
|
# 2.0.0
|
||||||
|
|
||||||
|
With 2.0.0, @iarna/toml supports the TOML v0.5.0 specification. TOML 0.5.0
|
||||||
|
brings some changes:
|
||||||
|
|
||||||
|
* Delete characters (U+007F) are not allowed in plain strings. You can include them with
|
||||||
|
escaped unicode characters, eg `\u007f`.
|
||||||
|
* Integers are specified as being 64bit unsigned values. These are
|
||||||
|
supported using `BigInt`s if you are using Node 10 or later.
|
||||||
|
* Keys may be literal strings, that is, you can use single quoted strings to
|
||||||
|
quote key names, so the following is now valid:
|
||||||
|
'a"b"c' = 123
|
||||||
|
* The floating point values `nan`, `inf` and `-inf` are supported. The stringifier will no
|
||||||
|
longer strip NaN, Infinity and -Infinity, instead serializing them as these new values..
|
||||||
|
* Datetimes can separate the date and time with a space instead of a T, so
|
||||||
|
`2017-12-01T00:00:00Z` can be written as `2017-12-01 00:00:00Z`.
|
||||||
|
* Datetimes can be floating, that is, they can be represented without a timezone.
|
||||||
|
These are represented in javascript as Date objects whose `isFloating` property is true and
|
||||||
|
whose `toISOString` method will return a representation without a timezone.
|
||||||
|
* Dates without times are now supported. Dates do not have timezones. Dates
|
||||||
|
are represented in javascript as a Date object whose `isDate` property is true and
|
||||||
|
whose `toISOString` method returns just the date.
|
||||||
|
* Times without dates are now supported. Times do not have timezones. Times
|
||||||
|
are represented in javascript as a Date object whose `isTime` property is true and
|
||||||
|
whose `toISOString` method returns just the time.
|
||||||
|
* Keys can now include dots to directly address deeper structures, so `a.b = 23` is
|
||||||
|
the equivalent of `a = {b = 23}` or ```[a]
|
||||||
|
b = 23```. These can be used both as keys to regular tables and inline tables.
|
||||||
|
* Integers can now be specified in binary, octal and hexadecimal by prefixing the
|
||||||
|
number with `0b`, `0o` and `0x` respectively. It is now illegal to left
|
||||||
|
pad a decimal value with zeros.
|
||||||
|
|
||||||
|
Some parser details were also fixed:
|
||||||
|
|
||||||
|
* Negative zero (`-0.0`) and positive zero (`0.0`) are distinct floating point values.
|
||||||
|
* Negative integer zero (`-0`) is not distinguished from positive zero (`0`).
|
||||||
|
|
||||||
|
# 1.7.1
|
||||||
|
|
||||||
|
Another 18% speed boost on our overall benchmarks! This time it came from
|
||||||
|
switching from string comparisons to integer by converting each character to
|
||||||
|
its respective code point. This also necessitated rewriting the boolean
|
||||||
|
parser to actually parse character-by-character as it should. End-of-stream
|
||||||
|
is now marked with a numeric value outside of the Unicode range, rather than
|
||||||
|
a Symbol, meaning that the parser's char property is now monomorphic.
|
||||||
|
|
||||||
|
Bug fix, previously, `'abc''def'''` was accepted (as the value: `abcdef`).
|
||||||
|
Now it will correctly raise an error.
|
||||||
|
|
||||||
|
Spec tests now run against bombadil as well (it fails some, which is unsurprising
|
||||||
|
given its incomplete state).
|
||||||
|
|
||||||
|
# 1.7.0
|
||||||
|
|
||||||
|
This release features an overall 15% speed boost on our benchmarks. This
|
||||||
|
came from a few things:
|
||||||
|
|
||||||
|
* Date parsing was rewritten to not use regexps, resulting in a huge speed increase.
|
||||||
|
* Strings of all kinds and bare keywords now use tight loops to collect characters when this will help.
|
||||||
|
* Regexps in general were mostly removed. This didn't result in a speed
|
||||||
|
change, but it did allow refactoring the parser to be a lot easier to
|
||||||
|
follow.
|
||||||
|
* The internal state tracking now uses a class and is constructed with a
|
||||||
|
fixed set of properties, allowing v8's optimizer to be more effective.
|
||||||
|
|
||||||
|
In the land of new features:
|
||||||
|
|
||||||
|
* Errors in the syntax of your TOML will now have the `fromTOML` property
|
||||||
|
set to true. This is in addition to the `line`, `col` and `pos`
|
||||||
|
properties they already have.
|
||||||
|
|
||||||
|
The main use of this is to make it possible to distinguish between errors
|
||||||
|
in the TOML and errors in the parser code itself. This is of particular utility
|
||||||
|
when testing parse errors.
|
||||||
|
|
||||||
|
# 1.6.0
|
||||||
|
|
||||||
|
**FIXES**
|
||||||
|
|
||||||
|
* TOML.stringify: Allow toJSON properties that aren't functions, to align with JSON.stringify's behavior.
|
||||||
|
* TOML.stringify: Don't use ever render keys as literal strings.
|
||||||
|
* TOML.stringify: Don't try to escape control characters in literal strings.
|
||||||
|
|
||||||
|
**FEATURES**
|
||||||
|
|
||||||
|
* New Export: TOML.stringify.value, for encoding a stand alone inline value as TOML would. This produces
|
||||||
|
a TOML fragment, not a complete valid document.
|
||||||
|
|
||||||
|
# 1.5.6
|
||||||
|
|
||||||
|
* String literals are NOT supported as key names.
|
||||||
|
* Accessing a shallower table after accessing it more deeply is ok and no longer crashes, eg:
|
||||||
|
```toml
|
||||||
|
[a.b]
|
||||||
|
[a]
|
||||||
|
```
|
||||||
|
* Unicode characters in the reserved range now crash.
|
||||||
|
* Empty bare keys, eg `[.abc]` or `[]` now crash.
|
||||||
|
* Multiline backslash trimming supports CRs.
|
||||||
|
* Multiline post quote trimming supports CRs.
|
||||||
|
* Strings may not contain bare control chars (0x00-0x1f), except for \n, \r and \t.
|
||||||
|
|
||||||
|
# 1.5.5
|
||||||
|
|
||||||
|
* Yet MORE README fixes. 🙃
|
||||||
|
|
||||||
|
# 1.5.4
|
||||||
|
|
||||||
|
* README fix
|
||||||
|
|
||||||
|
# 1.5.3
|
||||||
|
|
||||||
|
* Benchmarks!
|
||||||
|
* More tests!
|
||||||
|
* More complete LICENSE information (some dev files are from other, MIT
|
||||||
|
licensed, projects, this is now more explicitly documented.)
|
||||||
|
|
||||||
|
# 1.5.2
|
||||||
|
|
||||||
|
* parse: Arrays with mixed types now throw errors, per the spec.
|
||||||
|
* parse: Fix a parser bug that would result in errors when trying to parse arrays of numbers or dates
|
||||||
|
that were not separated by a space from the closing ].
|
||||||
|
* parse: Fix a bug in the error pretty printer that resulted in errors on
|
||||||
|
the first line not getting the pretty print treatment.
|
||||||
|
* stringify: Fix long standing bug where an array of Numbers, some of which required
|
||||||
|
decimals, would be emitted in a way that parsers would treat as mixed
|
||||||
|
Integer and Float values. Now if any Numbers in an array must be
|
||||||
|
represented with a decimal then all will be emitted such that parsers will
|
||||||
|
understand them to be Float.
|
||||||
|
|
||||||
|
# 1.5.1
|
||||||
|
|
||||||
|
* README fix
|
||||||
|
|
||||||
|
# 1.5.0
|
||||||
|
|
||||||
|
* A brand new TOML parser, from scratch, that performs like `toml-j0.4`
|
||||||
|
without the crashes and with vastly better error messages.
|
||||||
|
* 100% test coverage for both the new parser and the existing stringifier. Some subtle bugs squashed!
|
||||||
|
|
||||||
|
# v1.4.2
|
||||||
|
|
||||||
|
* Revert fallback due to its having issues with the same files. (New plan
|
||||||
|
will be to write my own.)
|
||||||
|
|
||||||
|
# v1.4.1
|
||||||
|
|
||||||
|
* Depend on both `toml` and `toml-j0.4` with fallback from the latter to the
|
||||||
|
former when the latter crashes.
|
||||||
|
|
||||||
|
# v1.4.0
|
||||||
|
|
||||||
|
* Ducktype dates to make them compatible with `moment` and other `Date` replacements.
|
||||||
|
|
||||||
|
# v1.3.1
|
||||||
|
|
||||||
|
* Update docs with new toml module.
|
||||||
|
|
||||||
|
# v1.3.0
|
||||||
|
|
||||||
|
* Switch from `toml` to `toml-j0.4`, which is between 20x and 200x faster.
|
||||||
|
(The larger the input, the faster it is compared to `toml`).
|
||||||
|
|
||||||
|
# v1.2.0
|
||||||
|
|
||||||
|
* Return null when passed in null as the top level object.
|
||||||
|
* Detect and skip invalid dates and numbers
|
||||||
|
|
||||||
|
# v1.1.0
|
||||||
|
|
||||||
|
* toJSON transformations are now honored (for everything except Date objects, as JSON represents them as strings).
|
||||||
|
* Undefined/null values no longer result in exceptions, they now just result in the associated key being elided.
|
||||||
|
|
||||||
|
# v1.0.1
|
||||||
|
|
||||||
|
* Initial release
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
Copyright (c) 2016, Rebecca Turner <me@re-becca.org>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,301 @@
|
||||||
|
# @iarna/toml
|
||||||
|
|
||||||
|
Better TOML parsing and stringifying all in that familiar JSON interface.
|
||||||
|
|
||||||
|
[](https://coveralls.io/github/iarna/iarna-toml)
|
||||||
|
|
||||||
|
# ** TOML 0.5.0 **
|
||||||
|
|
||||||
|
### TOML Spec Support
|
||||||
|
|
||||||
|
The most recent version as of 2018-07-26: [v0.5.0](https://github.com/mojombo/toml/blob/master/versions/en/toml-v0.5.0.md)
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
const TOML = require('@iarna/toml')
|
||||||
|
const obj = TOML.parse(`[abc]
|
||||||
|
foo = 123
|
||||||
|
bar = [1,2,3]`)
|
||||||
|
/* obj =
|
||||||
|
{abc: {foo: 123, bar: [1,2,3]}}
|
||||||
|
*/
|
||||||
|
const str = TOML.stringify(obj)
|
||||||
|
/* str =
|
||||||
|
[abc]
|
||||||
|
foo = 123
|
||||||
|
bar = [ 1, 2, 3 ]
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit the project github [for more examples](https://github.com/iarna/iarna-toml/tree/latest/examples)!
|
||||||
|
|
||||||
|
|
||||||
|
## Why @iarna/toml
|
||||||
|
|
||||||
|
* See [TOML-SPEC-SUPPORT](https://shared.by.re-becca.org/misc/TOML-SPEC-SUPPORT.html)
|
||||||
|
for a comparison of which TOML features are supported by the various
|
||||||
|
Node.js TOML parsers.
|
||||||
|
* BigInt support on Node 10!
|
||||||
|
* 100% test coverage.
|
||||||
|
* Fast parsing. It's as much as 100 times
|
||||||
|
faster than `toml` and 3 times faster than `toml-j0.4`. However a recent
|
||||||
|
newcomer [`@ltd/j-toml`](https://www.npmjs.com/package/@ltd/j-toml) has
|
||||||
|
appeared with 0.5 support and astoundingly fast parsing speeds for large
|
||||||
|
text blocks. All I can say is you'll have to test your specific work loads
|
||||||
|
if you want to know which of @iarna/toml and @ltd/j-toml is faster for
|
||||||
|
you, as we currently excell in different areas.
|
||||||
|
* Careful adherence to spec. Tests go beyond simple coverage.
|
||||||
|
* Smallest parser bundle (if you use `@iarna/toml/parse-string`).
|
||||||
|
* No deps.
|
||||||
|
* Detailed and easy to read error messages‼
|
||||||
|
|
||||||
|
```console
|
||||||
|
> TOML.parse(src)
|
||||||
|
Error: Unexpected character, expecting string, number, datetime, boolean, inline array or inline table at row 6, col 5, pos 87:
|
||||||
|
5: "abc\"" = { abc=123,def="abc" }
|
||||||
|
6> foo=sdkfj
|
||||||
|
^
|
||||||
|
7:
|
||||||
|
```
|
||||||
|
|
||||||
|
## TOML.parse(str) → Object [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse.js)
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/parse-string')`
|
||||||
|
|
||||||
|
Synchronously parse a TOML string and return an object.
|
||||||
|
|
||||||
|
|
||||||
|
## TOML.stringify(obj) → String [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/stringify.js)
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/stringify)`
|
||||||
|
|
||||||
|
Serialize an object as TOML.
|
||||||
|
|
||||||
|
## [your-object].toJSON
|
||||||
|
|
||||||
|
If an object `TOML.stringify` is serializing has a `toJSON` method then it
|
||||||
|
will call it to transform the object before serializing it. This matches
|
||||||
|
the behavior of `JSON.stringify`.
|
||||||
|
|
||||||
|
The one exception to this is that `toJSON` is not called for `Date` objects
|
||||||
|
because `JSON` represents dates as strings and TOML can represent them natively.
|
||||||
|
|
||||||
|
[`moment`](https://www.npmjs.com/package/moment) objects are treated the
|
||||||
|
same as native `Date` objects, in this respect.
|
||||||
|
|
||||||
|
## TOML.stringify.value(obj) -> String
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/stringify').value`
|
||||||
|
|
||||||
|
Serialize a value as TOML would. This is a fragment and not a complete
|
||||||
|
valid TOML document.
|
||||||
|
|
||||||
|
## Promises and Streaming
|
||||||
|
|
||||||
|
The parser provides alternative async and streaming interfaces, for times
|
||||||
|
that you're working with really absurdly big TOML files and don't want to
|
||||||
|
tie-up the event loop while it parses.
|
||||||
|
|
||||||
|
### TOML.parse.async(str[, opts]) → Promise(Object) [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse-async.js)
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/parse-async')`
|
||||||
|
|
||||||
|
`opts.blocksize` is the amount text to parser per pass through the event loop. Defaults to 40kb.
|
||||||
|
|
||||||
|
Asynchronously parse a TOML string and return a promise of the resulting object.
|
||||||
|
|
||||||
|
### TOML.parse.stream(readable) → Promise(Object) [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse-stream-readable.js)
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/parse-stream')`
|
||||||
|
|
||||||
|
Given a readable stream, parse it as it feeds us data. Return a promise of the resulting object.
|
||||||
|
|
||||||
|
### readable.pipe(TOML.parse.stream()) → Transform [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse-stream-through.js)
|
||||||
|
|
||||||
|
Also available with: `require('@iarna/toml/parse-stream')`
|
||||||
|
|
||||||
|
Returns a transform stream in object mode. When it completes, emit the
|
||||||
|
resulting object. Only one object will ever be emitted.
|
||||||
|
|
||||||
|
## Lowlevel Interface [(example)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse-lowlevel.js) [(example w/ parser debugging)](https://github.com/iarna/iarna-toml/blob/latest/examples/parse-lowlevel-debug.js)
|
||||||
|
|
||||||
|
You construct a parser object, per TOML file you want to process:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const TOMLParser = require('@iarna/toml/lib/toml-parser.js')
|
||||||
|
const parser = new TOMLParser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you call the `parse` method for each chunk as you read them, or in a
|
||||||
|
single call:
|
||||||
|
|
||||||
|
```js
|
||||||
|
parser.parse(`hello = 'world'`)
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally, you call the `finish` method to complete parsing and retrieve
|
||||||
|
the resulting object.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const data = parser.finish()
|
||||||
|
```
|
||||||
|
|
||||||
|
Both the `parse` method and `finish` method will throw if they find a
|
||||||
|
problem with the string they were given. Error objects thrown from the
|
||||||
|
parser have `pos`, `line` and `col` attributes. `TOML.parse` adds a visual
|
||||||
|
summary of where in the source string there were issues using
|
||||||
|
`parse-pretty-error` and you can too:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const prettyError = require('./parse-pretty-error.js')
|
||||||
|
const newErr = prettyError(err, sourceString)
|
||||||
|
```
|
||||||
|
|
||||||
|
## What's Different
|
||||||
|
|
||||||
|
Version 2 of this module supports TOML 0.5.0. Other modules currently
|
||||||
|
published to the npm registry support 0.4.0. 0.5.0 is mostly backwards
|
||||||
|
compatible with 0.4.0, but if you have need, you can install @iarna/toml@1
|
||||||
|
to get a version of this module that supports 0.4.0. Please see the
|
||||||
|
[CHANGELOG](CHANGELOG.md#2.0.0) for details on exactly whats changed.
|
||||||
|
|
||||||
|
## TOML we can't do
|
||||||
|
|
||||||
|
* `-nan` is a valid TOML value and is converted into `NaN`. There is no way to
|
||||||
|
produce `-nan` when stringifying. Stringification will produce positive `nan`.
|
||||||
|
* Detecting and erroring on invalid utf8 documents: This is because Node's
|
||||||
|
UTF8 processing converts invalid sequences into the placeholder character
|
||||||
|
and does not have facilities for reporting these as errors instead. We
|
||||||
|
_can_ detect the placeholder character, but it's valid to intentionally
|
||||||
|
include them in documents, so erroring on them is not great.
|
||||||
|
* On versions of Node < 10, very large Integer values will lose precision.
|
||||||
|
On Node >=10, bigints are used.
|
||||||
|
* Floating/local dates and times are still represented by JavaScript Date
|
||||||
|
objects, which don't actually support these concepts. The objects
|
||||||
|
returned have been modified so that you can determine what kind of thing
|
||||||
|
they are (with `isFloating`, `isDate`, `isTime` properties) and that
|
||||||
|
their ISO representation (via `toISOString`) is representative of their
|
||||||
|
TOML value. They will correctly round trip if you pass them to
|
||||||
|
`TOML.stringify`.
|
||||||
|
* Binary, hexadecimal and octal values are converted to ordinary integers and
|
||||||
|
will be decimal if you stringify them.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
I write a by hand, honest-to-god,
|
||||||
|
[CHANGELOG](https://github.com/iarna/iarna-toml/blob/latest/CHANGELOG.md)
|
||||||
|
for this project. It's a description of what went into a release that you
|
||||||
|
the consumer of the module could care about, not a list of git commits, so
|
||||||
|
please check it out!
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
You can run them yourself with:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ npm run benchmark
|
||||||
|
```
|
||||||
|
|
||||||
|
The results below are from my desktop using Node 13.13.0. The library
|
||||||
|
versions tested were `@iarna/toml@2.2.4`, `toml-j0.4@1.1.1`, `toml@3.0.0`,
|
||||||
|
`@sgarciac/bombadil@2.3.0`, `@ltd/j-toml@0.5.107`, and `fast-toml@0.5.4`. The speed value is
|
||||||
|
megabytes-per-second that the parser can process of that document type.
|
||||||
|
Bigger is better. The percentage after average results is the margin of error.
|
||||||
|
|
||||||
|
New here is fast-toml. fast-toml is very fast, for some datatypes, but it
|
||||||
|
also is missing most error checking demanded by the spec. For 0.4, it is
|
||||||
|
complete except for detail of multiline strings caught by the compliance
|
||||||
|
tests. Its support for 0.5 is incomplete. Check out the
|
||||||
|
[spec compliance](https://shared.by.re-becca.org/misc/TOML-SPEC-SUPPORT.html) doc
|
||||||
|
for details.
|
||||||
|
|
||||||
|
As this table is getting a little wide, with how npm and github display it,
|
||||||
|
you can also view it seperately in the
|
||||||
|
[BENCHMARK](https://shared.by.re-becca.org/misc/BENCHMARK.html) document.
|
||||||
|
|
||||||
|
| | @iarna/<wbr>toml | toml-j0.4 | toml | @sgarciac/<wbr>bombadil | @ltd/<wbr>j-toml | fast-toml |
|
||||||
|
| - | :---------: | :-------: | :--: | :----------------: | :---------: | :-------: |
|
||||||
|
| **Overall** | 28MB/sec<br><small>0.35%</small> | 6.5MB/sec<br><small>0.25%</small> | 0.2MB/sec<br><small>0.70%</small> | - | 35MB/sec<br><small>0.23%</small> | - |
|
||||||
|
| **Spec Example: v0.4.0** | 26MB/sec<br><small>0.37%</small> | 10MB/sec<br><small>0.27%</small> | 1MB/sec<br><small>0.42%</small> | 1.2MB/sec<br><small>0.95%</small> | 28MB/sec<br><small>0.31%</small> | - |
|
||||||
|
| **Spec Example: Hard Unicode** | 64MB/sec<br><small>0.59%</small> | 18MB/sec<br><small>0.12%</small> | 2MB/sec<br><small>0.20%</small> | 0.6MB/sec<br><small>0.53%</small> | 68MB/sec<br><small>0.31%</small> | 78MB/sec<br><small>0.28%</small> |
|
||||||
|
| **Types: Array, Inline** | 7.3MB/sec<br><small>0.60%</small> | 4MB/sec<br><small>0.16%</small> | 0.1MB/sec<br><small>0.91%</small> | 1.3MB/sec<br><small>0.81%</small> | 10MB/sec<br><small>0.35%</small> | 9MB/sec<br><small>0.16%</small> |
|
||||||
|
| **Types: Array** | 6.8MB/sec<br><small>0.19%</small> | 6.7MB/sec<br><small>0.15%</small> | 0.2MB/sec<br><small>0.79%</small> | 1.2MB/sec<br><small>0.93%</small> | 8.8MB/sec<br><small>0.47%</small> | 27MB/sec<br><small>0.21%</small> |
|
||||||
|
| **Types: Boolean,** | 21MB/sec<br><small>0.20%</small> | 9.4MB/sec<br><small>0.17%</small> | 0.2MB/sec<br><small>0.96%</small> | 1.8MB/sec<br><small>0.70%</small> | 16MB/sec<br><small>0.20%</small> | 8.4MB/sec<br><small>0.22%</small> |
|
||||||
|
| **Types: Datetime** | 18MB/sec<br><small>0.14%</small> | 11MB/sec<br><small>0.15%</small> | 0.3MB/sec<br><small>0.85%</small> | 1.6MB/sec<br><small>0.45%</small> | 9.8MB/sec<br><small>0.48%</small> | 6.5MB/sec<br><small>0.23%</small> |
|
||||||
|
| **Types: Float** | 8.8MB/sec<br><small>0.09%</small> | 5.9MB/sec<br><small>0.14%</small> | 0.2MB/sec<br><small>0.51%</small> | 2.1MB/sec<br><small>0.82%</small> | 14MB/sec<br><small>0.15%</small> | 7.9MB/sec<br><small>0.14%</small> |
|
||||||
|
| **Types: Int** | 5.9MB/sec<br><small>0.11%</small> | 4.5MB/sec<br><small>0.28%</small> | 0.1MB/sec<br><small>0.78%</small> | 1.5MB/sec<br><small>0.64%</small> | 10MB/sec<br><small>0.14%</small> | 8MB/sec<br><small>0.17%</small> |
|
||||||
|
| **Types: Literal String, 7 char** | 26MB/sec<br><small>0.29%</small> | 8.5MB/sec<br><small>0.32%</small> | 0.3MB/sec<br><small>0.84%</small> | 2.3MB/sec<br><small>1.02%</small> | 23MB/sec<br><small>0.15%</small> | 13MB/sec<br><small>0.15%</small> |
|
||||||
|
| **Types: Literal String, 92 char** | 46MB/sec<br><small>0.19%</small> | 11MB/sec<br><small>0.20%</small> | 0.3MB/sec<br><small>0.56%</small> | 12MB/sec<br><small>0.92%</small> | 101MB/sec<br><small>0.17%</small> | 75MB/sec<br><small>0.29%</small> |
|
||||||
|
| **Types: Literal String, Multiline, 1079 char** | 22MB/sec<br><small>0.42%</small> | 6.7MB/sec<br><small>0.55%</small> | 0.9MB/sec<br><small>0.78%</small> | 44MB/sec<br><small>1.00%</small> | 350MB/sec<br><small>0.16%</small> | 636MB/sec<br><small>0.16%</small> |
|
||||||
|
| **Types: Basic String, 7 char** | 25MB/sec<br><small>0.15%</small> | 7.3MB/sec<br><small>0.18%</small> | 0.2MB/sec<br><small>0.96%</small> | 2.2MB/sec<br><small>1.09%</small> | 14MB/sec<br><small>0.16%</small> | 12MB/sec<br><small>0.22%</small> |
|
||||||
|
| **Types: Basic String, 92 char** | 43MB/sec<br><small>0.30%</small> | 7.2MB/sec<br><small>0.16%</small> | 0.1MB/sec<br><small>4.04%</small> | 12MB/sec<br><small>1.33%</small> | 71MB/sec<br><small>0.19%</small> | 70MB/sec<br><small>0.23%</small> |
|
||||||
|
| **Types: Basic String, 1079 char** | 24MB/sec<br><small>0.45%</small> | 5.8MB/sec<br><small>0.17%</small> | 0.1MB/sec<br><small>3.64%</small> | 44MB/sec<br><small>1.05%</small> | 93MB/sec<br><small>0.29%</small> | 635MB/sec<br><small>0.28%</small> |
|
||||||
|
| **Types: Table, Inline** | 9.7MB/sec<br><small>0.10%</small> | 5.5MB/sec<br><small>0.22%</small> | 0.1MB/sec<br><small>0.87%</small> | 1.4MB/sec<br><small>1.18%</small> | 8.7MB/sec<br><small>0.60%</small> | 8.7MB/sec<br><small>0.22%</small> |
|
||||||
|
| **Types: Table** | 7.1MB/sec<br><small>0.14%</small> | 5.6MB/sec<br><small>0.42%</small> | 0.1MB/sec<br><small>0.65%</small> | 1.4MB/sec<br><small>1.11%</small> | 7.4MB/sec<br><small>0.70%</small> | 18MB/sec<br><small>0.20%</small> |
|
||||||
|
| **Scaling: Array, Inline, 1000 elements** | 40MB/sec<br><small>0.21%</small> | 2.4MB/sec<br><small>0.19%</small> | 0.1MB/sec<br><small>0.35%</small> | 1.6MB/sec<br><small>1.02%</small> | 17MB/sec<br><small>0.15%</small> | 32MB/sec<br><small>0.16%</small> |
|
||||||
|
| **Scaling: Array, Nested, 1000 deep** | 2MB/sec<br><small>0.15%</small> | 1.7MB/sec<br><small>0.26%</small> | 0.3MB/sec<br><small>0.58%</small> | - | 1.8MB/sec<br><small>0.74%</small> | 13MB/sec<br><small>0.20%</small> |
|
||||||
|
| **Scaling: Literal String, 40kb** | 61MB/sec<br><small>0.18%</small> | 10MB/sec<br><small>0.15%</small> | 3MB/sec<br><small>0.84%</small> | 12MB/sec<br><small>0.51%</small> | 551MB/sec<br><small>0.44%</small> | 19kMB/sec<br><small>0.19%</small> |
|
||||||
|
| **Scaling: Literal String, Multiline, 40kb** | 62MB/sec<br><small>0.16%</small> | 5MB/sec<br><small>0.45%</small> | 0.2MB/sec<br><small>1.70%</small> | 11MB/sec<br><small>0.74%</small> | 291MB/sec<br><small>0.24%</small> | 21kMB/sec<br><small>0.22%</small> |
|
||||||
|
| **Scaling: Basic String, Multiline, 40kb** | 62MB/sec<br><small>0.18%</small> | 5.8MB/sec<br><small>0.38%</small> | 2.9MB/sec<br><small>0.86%</small> | 11MB/sec<br><small>0.41%</small> | 949MB/sec<br><small>0.44%</small> | 26kMB/sec<br><small>0.16%</small> |
|
||||||
|
| **Scaling: Basic String, 40kb** | 59MB/sec<br><small>0.20%</small> | 6.3MB/sec<br><small>0.17%</small> | 0.2MB/sec<br><small>1.95%</small> | 12MB/sec<br><small>0.44%</small> | 508MB/sec<br><small>0.35%</small> | 18kMB/sec<br><small>0.15%</small> |
|
||||||
|
| **Scaling: Table, Inline, 1000 elements** | 28MB/sec<br><small>0.12%</small> | 8.2MB/sec<br><small>0.19%</small> | 0.3MB/sec<br><small>0.89%</small> | 2.3MB/sec<br><small>1.14%</small> | 5.3MB/sec<br><small>0.24%</small> | 13MB/sec<br><small>0.20%</small> |
|
||||||
|
| **Scaling: Table, Inline, Nested, 1000 deep** | 7.8MB/sec<br><small>0.28%</small> | 5MB/sec<br><small>0.20%</small> | 0.1MB/sec<br><small>0.84%</small> | - | 3.2MB/sec<br><small>0.52%</small> | 10MB/sec<br><small>0.23%</small> |
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
The test suite is maintained at 100% coverage: [](https://coveralls.io/github/iarna/iarna-toml)
|
||||||
|
|
||||||
|
The spec was carefully hand converted into a series of test framework
|
||||||
|
independent (and mostly language independent) assertions, as pairs of TOML
|
||||||
|
and YAML files. You can find those files here:
|
||||||
|
[spec-test](https://github.com/iarna/iarna-toml/blob/latest/test/spec-test/).
|
||||||
|
A number of examples of invalid Unicode were also written, but are difficult
|
||||||
|
to make use of in Node.js where Unicode errors are silently hidden. You can
|
||||||
|
find those here: [spec-test-disabled](https://github.com/iarna/iarna-toml/blob/latest/test/spec-test-disabled/).
|
||||||
|
|
||||||
|
Further tests were written to increase coverage to 100%, these may be more
|
||||||
|
implementation specific, but they can be found in [coverage](https://github.com/iarna/iarna-toml/blob/latest/test/coverage.js) and
|
||||||
|
[coverage-error](https://github.com/iarna/iarna-toml/blob/latest/test/coverage-error.js).
|
||||||
|
|
||||||
|
I've also written some quality assurance style tests, which don't contribute
|
||||||
|
to coverage but do cover scenarios that could easily be problematic for some
|
||||||
|
implementations can be found in:
|
||||||
|
[test/qa.js](https://github.com/iarna/iarna-toml/blob/latest/test/qa.js) and
|
||||||
|
[test/qa-error.js](https://github.com/iarna/iarna-toml/blob/latest/test/qa-error.js).
|
||||||
|
|
||||||
|
All of the official example files from the TOML spec are run through this
|
||||||
|
parser and compared to the official YAML files when available. These files are from the TOML spec as of:
|
||||||
|
[357a4ba6](https://github.com/toml-lang/toml/tree/357a4ba6782e48ff26e646780bab11c90ed0a7bc)
|
||||||
|
and specifically are:
|
||||||
|
|
||||||
|
* [github.com/toml-lang/toml/tree/357a4ba6/examples](https://github.com/toml-lang/toml/tree/357a4ba6782e48ff26e646780bab11c90ed0a7bc/examples)
|
||||||
|
* [github.com/toml-lang/toml/tree/357a4ba6/tests](https://github.com/toml-lang/toml/tree/357a4ba6782e48ff26e646780bab11c90ed0a7bc/tests)
|
||||||
|
|
||||||
|
The stringifier is tested by round-tripping these same files, asserting that
|
||||||
|
`TOML.parse(sourcefile)` deepEqual
|
||||||
|
`TOML.parse(TOML.stringify(TOML.parse(sourcefile))`. This is done in
|
||||||
|
[test/roundtrip-examples.js](https://github.com/iarna/iarna-toml/blob/latest/test/round-tripping.js)
|
||||||
|
There are also some tests written to complete coverage from stringification in:
|
||||||
|
[test/stringify.js](https://github.com/iarna/iarna-toml/blob/latest/test/stringify.js)
|
||||||
|
|
||||||
|
Tests for the async and streaming interfaces are in [test/async.js](https://github.com/iarna/iarna-toml/blob/latest/test/async.js) and [test/stream.js](https://github.com/iarna/iarna-toml/blob/latest/test/stream.js) respectively.
|
||||||
|
|
||||||
|
Tests for the parsers debugging mode live in [test/devel.js](https://github.com/iarna/iarna-toml/blob/latest/test/devel.js).
|
||||||
|
|
||||||
|
And finally, many more stringification tests were borrowed from [@othiym23](https://github.com/othiym23)'s
|
||||||
|
[toml-stream](https://npmjs.com/package/toml-stream) module. They were fetched as of
|
||||||
|
[b6f1e26b572d49742d49fa6a6d11524d003441fa](https://github.com/othiym23/toml-stream/tree/b6f1e26b572d49742d49fa6a6d11524d003441fa/test) and live in
|
||||||
|
[test/toml-stream](https://github.com/iarna/iarna-toml/blob/latest/test/toml-stream/).
|
||||||
|
|
||||||
|
## Improvements to make
|
||||||
|
|
||||||
|
* In stringify:
|
||||||
|
* Any way to produce comments. As a JSON stand-in I'm not too worried
|
||||||
|
about this. That said, a document orientated fork is something I'd like
|
||||||
|
to look at eventually…
|
||||||
|
* Stringification could use some work on its error reporting. It reports
|
||||||
|
_what's_ wrong, but not where in your data structure it was.
|
||||||
|
* Further optimize the parser:
|
||||||
|
* There are some debugging assertions left in the main parser, these should be moved to a subclass.
|
||||||
|
* Make the whole debugging parser thing work as a mixin instead of as a superclass.
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { Transform } from "stream";
|
||||||
|
|
||||||
|
type JsonArray = boolean[] | number[] | string[] | JsonMap[] | Date[]
|
||||||
|
type AnyJson = boolean | number | string | JsonMap | Date | JsonArray | JsonArray[]
|
||||||
|
|
||||||
|
interface JsonMap {
|
||||||
|
[key: string]: AnyJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParseOptions {
|
||||||
|
/**
|
||||||
|
* The amount text to parser per pass through the event loop. Defaults to 40kb (`40000`).
|
||||||
|
*/
|
||||||
|
blocksize: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FuncParse {
|
||||||
|
/**
|
||||||
|
* Synchronously parse a TOML string and return an object.
|
||||||
|
*/
|
||||||
|
(toml: string): JsonMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously parse a TOML string and return a promise of the resulting object.
|
||||||
|
*/
|
||||||
|
async (toml: string, options?: ParseOptions): Promise<JsonMap>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a readable stream, parse it as it feeds us data. Return a promise of the resulting object.
|
||||||
|
*/
|
||||||
|
stream (readable: NodeJS.ReadableStream): Promise<JsonMap>
|
||||||
|
stream (): Transform
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FuncStringify {
|
||||||
|
/**
|
||||||
|
* Serialize an object as TOML.
|
||||||
|
*
|
||||||
|
* If an object `TOML.stringify` is serializing has a `toJSON` method
|
||||||
|
* then it will call it to transform the object before serializing it.
|
||||||
|
* This matches the behavior of JSON.stringify.
|
||||||
|
*
|
||||||
|
* The one exception to this is that `toJSON` is not called for `Date` objects
|
||||||
|
* because JSON represents dates as strings and TOML can represent them natively.
|
||||||
|
*
|
||||||
|
* `moment` objects are treated the same as native `Date` objects, in this respect.
|
||||||
|
*/
|
||||||
|
(obj: JsonMap): string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a value as TOML would. This is a fragment and not a complete valid TOML document.
|
||||||
|
*/
|
||||||
|
value (any: AnyJson): string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parse: FuncParse
|
||||||
|
export const stringify: FuncStringify
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict'
|
||||||
|
const f = require('./format-num.js')
|
||||||
|
const DateTime = global.Date
|
||||||
|
|
||||||
|
class Date extends DateTime {
|
||||||
|
constructor (value) {
|
||||||
|
super(value)
|
||||||
|
this.isDate = true
|
||||||
|
}
|
||||||
|
toISOString () {
|
||||||
|
return `${this.getUTCFullYear()}-${f(2, this.getUTCMonth() + 1)}-${f(2, this.getUTCDate())}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = value => {
|
||||||
|
const date = new Date(value)
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (isNaN(date)) {
|
||||||
|
throw new TypeError('Invalid Datetime')
|
||||||
|
} else {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
'use strict'
|
||||||
|
const f = require('./format-num.js')
|
||||||
|
|
||||||
|
class FloatingDateTime extends Date {
|
||||||
|
constructor (value) {
|
||||||
|
super(value + 'Z')
|
||||||
|
this.isFloating = true
|
||||||
|
}
|
||||||
|
toISOString () {
|
||||||
|
const date = `${this.getUTCFullYear()}-${f(2, this.getUTCMonth() + 1)}-${f(2, this.getUTCDate())}`
|
||||||
|
const time = `${f(2, this.getUTCHours())}:${f(2, this.getUTCMinutes())}:${f(2, this.getUTCSeconds())}.${f(3, this.getUTCMilliseconds())}`
|
||||||
|
return `${date}T${time}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = value => {
|
||||||
|
const date = new FloatingDateTime(value)
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (isNaN(date)) {
|
||||||
|
throw new TypeError('Invalid Datetime')
|
||||||
|
} else {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = value => {
|
||||||
|
const date = new Date(value)
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (isNaN(date)) {
|
||||||
|
throw new TypeError('Invalid Datetime')
|
||||||
|
} else {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict'
|
||||||
|
const f = require('./format-num.js')
|
||||||
|
|
||||||
|
class Time extends Date {
|
||||||
|
constructor (value) {
|
||||||
|
super(`0000-01-01T${value}Z`)
|
||||||
|
this.isTime = true
|
||||||
|
}
|
||||||
|
toISOString () {
|
||||||
|
return `${f(2, this.getUTCHours())}:${f(2, this.getUTCMinutes())}:${f(2, this.getUTCSeconds())}.${f(3, this.getUTCMilliseconds())}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = value => {
|
||||||
|
const date = new Time(value)
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (isNaN(date)) {
|
||||||
|
throw new TypeError('Invalid Datetime')
|
||||||
|
} else {
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = (d, num) => {
|
||||||
|
num = String(num)
|
||||||
|
while (num.length < d) num = '0' + num
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
'use strict'
|
||||||
|
const Parser = require('./parser.js')
|
||||||
|
const util = require('util')
|
||||||
|
|
||||||
|
const dump = _ => util.inspect(_, {colors: true, depth: 10, breakLength: Infinity})
|
||||||
|
class DebugParser extends Parser {
|
||||||
|
stateName (state) {
|
||||||
|
// istanbul ignore next
|
||||||
|
return (state.parser && state.parser.name) || state.name || ('anonymous')
|
||||||
|
}
|
||||||
|
runOne () {
|
||||||
|
const callStack = this.stack.concat(this.state).map(_ => this.stateName(_)).join(' <- ')
|
||||||
|
console.log('RUN', callStack, dump({line: this.line, col: this.col, char: this.char, ret: this.state.returned}))
|
||||||
|
return super.runOne()
|
||||||
|
}
|
||||||
|
finish () {
|
||||||
|
const obj = super.finish()
|
||||||
|
// istanbul ignore if
|
||||||
|
if (this.stack.length !== 0) {
|
||||||
|
throw new Parser.Error('All states did not return by end of stream')
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
callStack () {
|
||||||
|
const callStack = this.stack.map(_ => this.stateName(_)).join(' ').replace(/\S/g, ' ')
|
||||||
|
return callStack ? callStack + ' ' : ''
|
||||||
|
}
|
||||||
|
next (fn) {
|
||||||
|
console.log(' ', this.callStack(), 'NEXT', this.stateName(fn))
|
||||||
|
return super.next(fn)
|
||||||
|
}
|
||||||
|
goto (fn) {
|
||||||
|
console.log(' ', this.callStack(), 'GOTO', this.stateName(fn))
|
||||||
|
super.next(fn)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
call (fn, returnWith) {
|
||||||
|
console.log(' ', this.callStack(), 'CALL', fn.name, returnWith ? '-> ' + returnWith.name : '')
|
||||||
|
if (returnWith) super.next(returnWith)
|
||||||
|
this.stack.push(this.state)
|
||||||
|
this.state = {parser: fn, buf: '', returned: null}
|
||||||
|
}
|
||||||
|
callNow (fn, returnWith) {
|
||||||
|
console.log(' ', this.callStack(), 'CALLNOW', fn.name, returnWith ? '-> ' + returnWith.name : '')
|
||||||
|
if (returnWith) super.next(returnWith)
|
||||||
|
this.stack.push(this.state)
|
||||||
|
this.state = {parser: fn, buf: '', returned: null}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (value) {
|
||||||
|
console.log(' ', this.callStack(), 'RETURN')
|
||||||
|
return super.return(value)
|
||||||
|
}
|
||||||
|
returnNow (value) {
|
||||||
|
console.log(' ', this.callStack(), 'RETURNNOW')
|
||||||
|
super.return(value)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = DebugParser
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
'use strict'
|
||||||
|
const ParserEND = 0x110000
|
||||||
|
class ParserError extends Error {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
constructor (msg, filename, linenumber) {
|
||||||
|
super('[ParserError] ' + msg, filename, linenumber)
|
||||||
|
this.name = 'ParserError'
|
||||||
|
this.code = 'ParserError'
|
||||||
|
if (Error.captureStackTrace) Error.captureStackTrace(this, ParserError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class State {
|
||||||
|
constructor (parser) {
|
||||||
|
this.parser = parser
|
||||||
|
this.buf = ''
|
||||||
|
this.returned = null
|
||||||
|
this.result = null
|
||||||
|
this.resultTable = null
|
||||||
|
this.resultArr = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Parser {
|
||||||
|
constructor () {
|
||||||
|
this.pos = 0
|
||||||
|
this.col = 0
|
||||||
|
this.line = 0
|
||||||
|
this.obj = {}
|
||||||
|
this.ctx = this.obj
|
||||||
|
this.stack = []
|
||||||
|
this._buf = ''
|
||||||
|
this.char = null
|
||||||
|
this.ii = 0
|
||||||
|
this.state = new State(this.parseStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
parse (str) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (str.length === 0 || str.length == null) return
|
||||||
|
|
||||||
|
this._buf = String(str)
|
||||||
|
this.ii = -1
|
||||||
|
this.char = -1
|
||||||
|
let getNext
|
||||||
|
while (getNext === false || this.nextChar()) {
|
||||||
|
getNext = this.runOne()
|
||||||
|
}
|
||||||
|
this._buf = null
|
||||||
|
}
|
||||||
|
nextChar () {
|
||||||
|
if (this.char === 0x0A) {
|
||||||
|
++this.line
|
||||||
|
this.col = -1
|
||||||
|
}
|
||||||
|
++this.ii
|
||||||
|
this.char = this._buf.codePointAt(this.ii)
|
||||||
|
++this.pos
|
||||||
|
++this.col
|
||||||
|
return this.haveBuffer()
|
||||||
|
}
|
||||||
|
haveBuffer () {
|
||||||
|
return this.ii < this._buf.length
|
||||||
|
}
|
||||||
|
runOne () {
|
||||||
|
return this.state.parser.call(this, this.state.returned)
|
||||||
|
}
|
||||||
|
finish () {
|
||||||
|
this.char = ParserEND
|
||||||
|
let last
|
||||||
|
do {
|
||||||
|
last = this.state.parser
|
||||||
|
this.runOne()
|
||||||
|
} while (this.state.parser !== last)
|
||||||
|
|
||||||
|
this.ctx = null
|
||||||
|
this.state = null
|
||||||
|
this._buf = null
|
||||||
|
|
||||||
|
return this.obj
|
||||||
|
}
|
||||||
|
next (fn) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (typeof fn !== 'function') throw new ParserError('Tried to set state to non-existent state: ' + JSON.stringify(fn))
|
||||||
|
this.state.parser = fn
|
||||||
|
}
|
||||||
|
goto (fn) {
|
||||||
|
this.next(fn)
|
||||||
|
return this.runOne()
|
||||||
|
}
|
||||||
|
call (fn, returnWith) {
|
||||||
|
if (returnWith) this.next(returnWith)
|
||||||
|
this.stack.push(this.state)
|
||||||
|
this.state = new State(fn)
|
||||||
|
}
|
||||||
|
callNow (fn, returnWith) {
|
||||||
|
this.call(fn, returnWith)
|
||||||
|
return this.runOne()
|
||||||
|
}
|
||||||
|
return (value) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (this.stack.length === 0) throw this.error(new ParserError('Stack underflow'))
|
||||||
|
if (value === undefined) value = this.state.buf
|
||||||
|
this.state = this.stack.pop()
|
||||||
|
this.state.returned = value
|
||||||
|
}
|
||||||
|
returnNow (value) {
|
||||||
|
this.return(value)
|
||||||
|
return this.runOne()
|
||||||
|
}
|
||||||
|
consume () {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (this.char === ParserEND) throw this.error(new ParserError('Unexpected end-of-buffer'))
|
||||||
|
this.state.buf += this._buf[this.ii]
|
||||||
|
}
|
||||||
|
error (err) {
|
||||||
|
err.line = this.line
|
||||||
|
err.col = this.col
|
||||||
|
err.pos = this.pos
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/* istanbul ignore next */
|
||||||
|
parseStart () {
|
||||||
|
throw new ParserError('Must declare a parseStart method')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Parser.END = ParserEND
|
||||||
|
Parser.Error = ParserError
|
||||||
|
module.exports = Parser
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,86 @@
|
||||||
|
{
|
||||||
|
"name": "@iarna/toml",
|
||||||
|
"version": "2.2.5",
|
||||||
|
"main": "toml.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "tap -J --100 test/*.js test/toml-stream/*.js",
|
||||||
|
"benchmark": "node benchmark.js && node benchmark-per-file.js && node results2table.js",
|
||||||
|
"prerelease": "npm t",
|
||||||
|
"prepack": "rm -f *~",
|
||||||
|
"postpublish": "git push --follow-tags",
|
||||||
|
"pretest": "iarna-standard",
|
||||||
|
"update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'",
|
||||||
|
"update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'",
|
||||||
|
"setup-burntsushi-toml-suite": "[ -d test/burntsushi-toml-test ] || (git clone https://github.com/BurntSushi/toml-test test/burntsushi-toml-test; rimraf test/burntsushi-toml-test/.git/hooks/*); cd test/burntsushi-toml-test; git pull",
|
||||||
|
"setup-iarna-toml-suite": "[ -d test/spec-test ] || (git clone https://github.com/iarna/toml-spec-tests -b 0.5.0 test/spec-test; rimraf test/spec-test/.git/hooks/*); cd test/spec-test; git pull",
|
||||||
|
"prepare": "npm run setup-burntsushi-toml-suite && npm run setup-iarna-toml-suite"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"toml",
|
||||||
|
"toml-parser",
|
||||||
|
"toml-stringifier",
|
||||||
|
"parser",
|
||||||
|
"stringifer",
|
||||||
|
"emitter",
|
||||||
|
"ini",
|
||||||
|
"tomlify",
|
||||||
|
"encoder",
|
||||||
|
"decoder"
|
||||||
|
],
|
||||||
|
"author": "Rebecca Turner <me@re-becca.org> (http://re-becca.org/)",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "Better TOML parsing and stringifying all in that familiar JSON interface.",
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@iarna/standard": "^2.0.2",
|
||||||
|
"@ltd/j-toml": "^0.5.107",
|
||||||
|
"@perl/qx": "^1.1.0",
|
||||||
|
"@sgarciac/bombadil": "^2.3.0",
|
||||||
|
"ansi": "^0.3.1",
|
||||||
|
"approximate-number": "^2.0.0",
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"fast-toml": "^0.5.4",
|
||||||
|
"funstream": "^4.2.0",
|
||||||
|
"glob": "^7.1.6",
|
||||||
|
"js-yaml": "^3.13.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"tap": "^12.0.1",
|
||||||
|
"toml": "^3.0.0",
|
||||||
|
"toml-j0.4": "^1.1.1",
|
||||||
|
"weallbehave": "*",
|
||||||
|
"weallcontribute": "*"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"toml.js",
|
||||||
|
"stringify.js",
|
||||||
|
"parse.js",
|
||||||
|
"parse-string.js",
|
||||||
|
"parse-stream.js",
|
||||||
|
"parse-async.js",
|
||||||
|
"parse-pretty-error.js",
|
||||||
|
"lib/parser.js",
|
||||||
|
"lib/parser-debug.js",
|
||||||
|
"lib/toml-parser.js",
|
||||||
|
"lib/create-datetime.js",
|
||||||
|
"lib/create-date.js",
|
||||||
|
"lib/create-datetime-float.js",
|
||||||
|
"lib/create-time.js",
|
||||||
|
"lib/format-num.js",
|
||||||
|
"index.d.ts"
|
||||||
|
],
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/iarna/iarna-toml.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/iarna/iarna-toml/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/iarna/iarna-toml#readme"
|
||||||
|
|
||||||
|
,"_resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz"
|
||||||
|
,"_integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
|
||||||
|
,"_from": "@iarna/toml@2.2.5"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = parseAsync
|
||||||
|
|
||||||
|
const TOMLParser = require('./lib/toml-parser.js')
|
||||||
|
const prettyError = require('./parse-pretty-error.js')
|
||||||
|
|
||||||
|
function parseAsync (str, opts) {
|
||||||
|
if (!opts) opts = {}
|
||||||
|
const index = 0
|
||||||
|
const blocksize = opts.blocksize || 40960
|
||||||
|
const parser = new TOMLParser()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setImmediate(parseAsyncNext, index, blocksize, resolve, reject)
|
||||||
|
})
|
||||||
|
function parseAsyncNext (index, blocksize, resolve, reject) {
|
||||||
|
if (index >= str.length) {
|
||||||
|
try {
|
||||||
|
return resolve(parser.finish())
|
||||||
|
} catch (err) {
|
||||||
|
return reject(prettyError(err, str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
parser.parse(str.slice(index, index + blocksize))
|
||||||
|
setImmediate(parseAsyncNext, index + blocksize, blocksize, resolve, reject)
|
||||||
|
} catch (err) {
|
||||||
|
reject(prettyError(err, str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = prettyError
|
||||||
|
|
||||||
|
function prettyError (err, buf) {
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (err.pos == null || err.line == null) return err
|
||||||
|
let msg = err.message
|
||||||
|
msg += ` at row ${err.line + 1}, col ${err.col + 1}, pos ${err.pos}:\n`
|
||||||
|
|
||||||
|
/* istanbul ignore else */
|
||||||
|
if (buf && buf.split) {
|
||||||
|
const lines = buf.split(/\n/)
|
||||||
|
const lineNumWidth = String(Math.min(lines.length, err.line + 3)).length
|
||||||
|
let linePadding = ' '
|
||||||
|
while (linePadding.length < lineNumWidth) linePadding += ' '
|
||||||
|
for (let ii = Math.max(0, err.line - 1); ii < Math.min(lines.length, err.line + 2); ++ii) {
|
||||||
|
let lineNum = String(ii + 1)
|
||||||
|
if (lineNum.length < lineNumWidth) lineNum = ' ' + lineNum
|
||||||
|
if (err.line === ii) {
|
||||||
|
msg += lineNum + '> ' + lines[ii] + '\n'
|
||||||
|
msg += linePadding + ' '
|
||||||
|
for (let hh = 0; hh < err.col; ++hh) {
|
||||||
|
msg += ' '
|
||||||
|
}
|
||||||
|
msg += '^\n'
|
||||||
|
} else {
|
||||||
|
msg += lineNum + ': ' + lines[ii] + '\n'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.message = msg + '\n'
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = parseStream
|
||||||
|
|
||||||
|
const stream = require('stream')
|
||||||
|
const TOMLParser = require('./lib/toml-parser.js')
|
||||||
|
|
||||||
|
function parseStream (stm) {
|
||||||
|
if (stm) {
|
||||||
|
return parseReadable(stm)
|
||||||
|
} else {
|
||||||
|
return parseTransform(stm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseReadable (stm) {
|
||||||
|
const parser = new TOMLParser()
|
||||||
|
stm.setEncoding('utf8')
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let readable
|
||||||
|
let ended = false
|
||||||
|
let errored = false
|
||||||
|
function finish () {
|
||||||
|
ended = true
|
||||||
|
if (readable) return
|
||||||
|
try {
|
||||||
|
resolve(parser.finish())
|
||||||
|
} catch (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function error (err) {
|
||||||
|
errored = true
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
stm.once('end', finish)
|
||||||
|
stm.once('error', error)
|
||||||
|
readNext()
|
||||||
|
|
||||||
|
function readNext () {
|
||||||
|
readable = true
|
||||||
|
let data
|
||||||
|
while ((data = stm.read()) !== null) {
|
||||||
|
try {
|
||||||
|
parser.parse(data)
|
||||||
|
} catch (err) {
|
||||||
|
return error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readable = false
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (ended) return finish()
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (errored) return
|
||||||
|
stm.once('readable', readNext)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTransform () {
|
||||||
|
const parser = new TOMLParser()
|
||||||
|
return new stream.Transform({
|
||||||
|
objectMode: true,
|
||||||
|
transform (chunk, encoding, cb) {
|
||||||
|
try {
|
||||||
|
parser.parse(chunk.toString(encoding))
|
||||||
|
} catch (err) {
|
||||||
|
this.emit('error', err)
|
||||||
|
}
|
||||||
|
cb()
|
||||||
|
},
|
||||||
|
flush (cb) {
|
||||||
|
try {
|
||||||
|
this.push(parser.finish())
|
||||||
|
} catch (err) {
|
||||||
|
this.emit('error', err)
|
||||||
|
}
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = parseString
|
||||||
|
|
||||||
|
const TOMLParser = require('./lib/toml-parser.js')
|
||||||
|
const prettyError = require('./parse-pretty-error.js')
|
||||||
|
|
||||||
|
function parseString (str) {
|
||||||
|
if (global.Buffer && global.Buffer.isBuffer(str)) {
|
||||||
|
str = str.toString('utf8')
|
||||||
|
}
|
||||||
|
const parser = new TOMLParser()
|
||||||
|
try {
|
||||||
|
parser.parse(str)
|
||||||
|
return parser.finish()
|
||||||
|
} catch (err) {
|
||||||
|
throw prettyError(err, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = require('./parse-string.js')
|
||||||
|
module.exports.async = require('./parse-async.js')
|
||||||
|
module.exports.stream = require('./parse-stream.js')
|
||||||
|
module.exports.prettyError = require('./parse-pretty-error.js')
|
||||||
|
|
@ -0,0 +1,296 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = stringify
|
||||||
|
module.exports.value = stringifyInline
|
||||||
|
|
||||||
|
function stringify (obj) {
|
||||||
|
if (obj === null) throw typeError('null')
|
||||||
|
if (obj === void (0)) throw typeError('undefined')
|
||||||
|
if (typeof obj !== 'object') throw typeError(typeof obj)
|
||||||
|
|
||||||
|
if (typeof obj.toJSON === 'function') obj = obj.toJSON()
|
||||||
|
if (obj == null) return null
|
||||||
|
const type = tomlType(obj)
|
||||||
|
if (type !== 'table') throw typeError(type)
|
||||||
|
return stringifyObject('', '', obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeError (type) {
|
||||||
|
return new Error('Can only stringify objects, not ' + type)
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayOneTypeError () {
|
||||||
|
return new Error("Array values can't have mixed types")
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInlineKeys (obj) {
|
||||||
|
return Object.keys(obj).filter(key => isInline(obj[key]))
|
||||||
|
}
|
||||||
|
function getComplexKeys (obj) {
|
||||||
|
return Object.keys(obj).filter(key => !isInline(obj[key]))
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJSON (obj) {
|
||||||
|
let nobj = Array.isArray(obj) ? [] : Object.prototype.hasOwnProperty.call(obj, '__proto__') ? {['__proto__']: undefined} : {}
|
||||||
|
for (let prop of Object.keys(obj)) {
|
||||||
|
if (obj[prop] && typeof obj[prop].toJSON === 'function' && !('toISOString' in obj[prop])) {
|
||||||
|
nobj[prop] = obj[prop].toJSON()
|
||||||
|
} else {
|
||||||
|
nobj[prop] = obj[prop]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nobj
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyObject (prefix, indent, obj) {
|
||||||
|
obj = toJSON(obj)
|
||||||
|
var inlineKeys
|
||||||
|
var complexKeys
|
||||||
|
inlineKeys = getInlineKeys(obj)
|
||||||
|
complexKeys = getComplexKeys(obj)
|
||||||
|
var result = []
|
||||||
|
var inlineIndent = indent || ''
|
||||||
|
inlineKeys.forEach(key => {
|
||||||
|
var type = tomlType(obj[key])
|
||||||
|
if (type !== 'undefined' && type !== 'null') {
|
||||||
|
result.push(inlineIndent + stringifyKey(key) + ' = ' + stringifyAnyInline(obj[key], true))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (result.length > 0) result.push('')
|
||||||
|
var complexIndent = prefix && inlineKeys.length > 0 ? indent + ' ' : ''
|
||||||
|
complexKeys.forEach(key => {
|
||||||
|
result.push(stringifyComplex(prefix, complexIndent, key, obj[key]))
|
||||||
|
})
|
||||||
|
return result.join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInline (value) {
|
||||||
|
switch (tomlType(value)) {
|
||||||
|
case 'undefined':
|
||||||
|
case 'null':
|
||||||
|
case 'integer':
|
||||||
|
case 'nan':
|
||||||
|
case 'float':
|
||||||
|
case 'boolean':
|
||||||
|
case 'string':
|
||||||
|
case 'datetime':
|
||||||
|
return true
|
||||||
|
case 'array':
|
||||||
|
return value.length === 0 || tomlType(value[0]) !== 'table'
|
||||||
|
case 'table':
|
||||||
|
return Object.keys(value).length === 0
|
||||||
|
/* istanbul ignore next */
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tomlType (value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
return 'undefined'
|
||||||
|
} else if (value === null) {
|
||||||
|
return 'null'
|
||||||
|
/* eslint-disable valid-typeof */
|
||||||
|
} else if (typeof value === 'bigint' || (Number.isInteger(value) && !Object.is(value, -0))) {
|
||||||
|
return 'integer'
|
||||||
|
} else if (typeof value === 'number') {
|
||||||
|
return 'float'
|
||||||
|
} else if (typeof value === 'boolean') {
|
||||||
|
return 'boolean'
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return 'string'
|
||||||
|
} else if ('toISOString' in value) {
|
||||||
|
return isNaN(value) ? 'undefined' : 'datetime'
|
||||||
|
} else if (Array.isArray(value)) {
|
||||||
|
return 'array'
|
||||||
|
} else {
|
||||||
|
return 'table'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyKey (key) {
|
||||||
|
var keyStr = String(key)
|
||||||
|
if (/^[-A-Za-z0-9_]+$/.test(keyStr)) {
|
||||||
|
return keyStr
|
||||||
|
} else {
|
||||||
|
return stringifyBasicString(keyStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyBasicString (str) {
|
||||||
|
return '"' + escapeString(str).replace(/"/g, '\\"') + '"'
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyLiteralString (str) {
|
||||||
|
return "'" + str + "'"
|
||||||
|
}
|
||||||
|
|
||||||
|
function numpad (num, str) {
|
||||||
|
while (str.length < num) str = '0' + str
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeString (str) {
|
||||||
|
return str.replace(/\\/g, '\\\\')
|
||||||
|
.replace(/[\b]/g, '\\b')
|
||||||
|
.replace(/\t/g, '\\t')
|
||||||
|
.replace(/\n/g, '\\n')
|
||||||
|
.replace(/\f/g, '\\f')
|
||||||
|
.replace(/\r/g, '\\r')
|
||||||
|
/* eslint-disable no-control-regex */
|
||||||
|
.replace(/([\u0000-\u001f\u007f])/, c => '\\u' + numpad(4, c.codePointAt(0).toString(16)))
|
||||||
|
/* eslint-enable no-control-regex */
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyMultilineString (str) {
|
||||||
|
let escaped = str.split(/\n/).map(str => {
|
||||||
|
return escapeString(str).replace(/"(?="")/g, '\\"')
|
||||||
|
}).join('\n')
|
||||||
|
if (escaped.slice(-1) === '"') escaped += '\\\n'
|
||||||
|
return '"""\n' + escaped + '"""'
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyAnyInline (value, multilineOk) {
|
||||||
|
let type = tomlType(value)
|
||||||
|
if (type === 'string') {
|
||||||
|
if (multilineOk && /\n/.test(value)) {
|
||||||
|
type = 'string-multiline'
|
||||||
|
} else if (!/[\b\t\n\f\r']/.test(value) && /"/.test(value)) {
|
||||||
|
type = 'string-literal'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringifyInline(value, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyInline (value, type) {
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (!type) type = tomlType(value)
|
||||||
|
switch (type) {
|
||||||
|
case 'string-multiline':
|
||||||
|
return stringifyMultilineString(value)
|
||||||
|
case 'string':
|
||||||
|
return stringifyBasicString(value)
|
||||||
|
case 'string-literal':
|
||||||
|
return stringifyLiteralString(value)
|
||||||
|
case 'integer':
|
||||||
|
return stringifyInteger(value)
|
||||||
|
case 'float':
|
||||||
|
return stringifyFloat(value)
|
||||||
|
case 'boolean':
|
||||||
|
return stringifyBoolean(value)
|
||||||
|
case 'datetime':
|
||||||
|
return stringifyDatetime(value)
|
||||||
|
case 'array':
|
||||||
|
return stringifyInlineArray(value.filter(_ => tomlType(_) !== 'null' && tomlType(_) !== 'undefined' && tomlType(_) !== 'nan'))
|
||||||
|
case 'table':
|
||||||
|
return stringifyInlineTable(value)
|
||||||
|
/* istanbul ignore next */
|
||||||
|
default:
|
||||||
|
throw typeError(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyInteger (value) {
|
||||||
|
/* eslint-disable security/detect-unsafe-regex */
|
||||||
|
return String(value).replace(/\B(?=(\d{3})+(?!\d))/g, '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyFloat (value) {
|
||||||
|
if (value === Infinity) {
|
||||||
|
return 'inf'
|
||||||
|
} else if (value === -Infinity) {
|
||||||
|
return '-inf'
|
||||||
|
} else if (Object.is(value, NaN)) {
|
||||||
|
return 'nan'
|
||||||
|
} else if (Object.is(value, -0)) {
|
||||||
|
return '-0.0'
|
||||||
|
}
|
||||||
|
var chunks = String(value).split('.')
|
||||||
|
var int = chunks[0]
|
||||||
|
var dec = chunks[1] || 0
|
||||||
|
return stringifyInteger(int) + '.' + dec
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyBoolean (value) {
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyDatetime (value) {
|
||||||
|
return value.toISOString()
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNumber (type) {
|
||||||
|
return type === 'float' || type === 'integer'
|
||||||
|
}
|
||||||
|
function arrayType (values) {
|
||||||
|
var contentType = tomlType(values[0])
|
||||||
|
if (values.every(_ => tomlType(_) === contentType)) return contentType
|
||||||
|
// mixed integer/float, emit as floats
|
||||||
|
if (values.every(_ => isNumber(tomlType(_)))) return 'float'
|
||||||
|
return 'mixed'
|
||||||
|
}
|
||||||
|
function validateArray (values) {
|
||||||
|
const type = arrayType(values)
|
||||||
|
if (type === 'mixed') {
|
||||||
|
throw arrayOneTypeError()
|
||||||
|
}
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyInlineArray (values) {
|
||||||
|
values = toJSON(values)
|
||||||
|
const type = validateArray(values)
|
||||||
|
var result = '['
|
||||||
|
var stringified = values.map(_ => stringifyInline(_, type))
|
||||||
|
if (stringified.join(', ').length > 60 || /\n/.test(stringified)) {
|
||||||
|
result += '\n ' + stringified.join(',\n ') + '\n'
|
||||||
|
} else {
|
||||||
|
result += ' ' + stringified.join(', ') + (stringified.length > 0 ? ' ' : '')
|
||||||
|
}
|
||||||
|
return result + ']'
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyInlineTable (value) {
|
||||||
|
value = toJSON(value)
|
||||||
|
var result = []
|
||||||
|
Object.keys(value).forEach(key => {
|
||||||
|
result.push(stringifyKey(key) + ' = ' + stringifyAnyInline(value[key], false))
|
||||||
|
})
|
||||||
|
return '{ ' + result.join(', ') + (result.length > 0 ? ' ' : '') + '}'
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyComplex (prefix, indent, key, value) {
|
||||||
|
var valueType = tomlType(value)
|
||||||
|
/* istanbul ignore else */
|
||||||
|
if (valueType === 'array') {
|
||||||
|
return stringifyArrayOfTables(prefix, indent, key, value)
|
||||||
|
} else if (valueType === 'table') {
|
||||||
|
return stringifyComplexTable(prefix, indent, key, value)
|
||||||
|
} else {
|
||||||
|
throw typeError(valueType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyArrayOfTables (prefix, indent, key, values) {
|
||||||
|
values = toJSON(values)
|
||||||
|
validateArray(values)
|
||||||
|
var firstValueType = tomlType(values[0])
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (firstValueType !== 'table') throw typeError(firstValueType)
|
||||||
|
var fullKey = prefix + stringifyKey(key)
|
||||||
|
var result = ''
|
||||||
|
values.forEach(table => {
|
||||||
|
if (result.length > 0) result += '\n'
|
||||||
|
result += indent + '[[' + fullKey + ']]\n'
|
||||||
|
result += stringifyObject(fullKey + '.', indent, table)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyComplexTable (prefix, indent, key, value) {
|
||||||
|
var fullKey = prefix + stringifyKey(key)
|
||||||
|
var result = ''
|
||||||
|
if (getInlineKeys(value).length > 0) {
|
||||||
|
result += indent + '[' + fullKey + ']\n'
|
||||||
|
}
|
||||||
|
return result + stringifyObject(fullKey + '.', indent, value)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
'use strict'
|
||||||
|
exports.parse = require('./parse.js')
|
||||||
|
exports.stringify = require('./stringify.js')
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"node": true,
|
|
||||||
"browser": true,
|
|
||||||
"browserify": true,
|
|
||||||
"curly": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"eqnull": false,
|
|
||||||
"latedef": "nofunc",
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"undef": true,
|
|
||||||
"strict": true,
|
|
||||||
"trailing": true,
|
|
||||||
"smarttabs": true,
|
|
||||||
"indent": 2,
|
|
||||||
"quotmark": true,
|
|
||||||
"laxbreak": true
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
language: node_js
|
|
||||||
sudo: false
|
|
||||||
node_js:
|
|
||||||
- "4.1"
|
|
||||||
- "4.0"
|
|
||||||
- "0.12"
|
|
||||||
- "0.10"
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
2.3.0 - July 13 2015
|
|
||||||
====================
|
|
||||||
|
|
||||||
* Correctly handle quoted keys ([#21](https://github.com/BinaryMuse/toml-node/issues/21))
|
|
||||||
|
|
||||||
2.2.3 - June 8 2015
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Support empty inline tables ([#24](https://github.com/BinaryMuse/toml-node/issues/24))
|
|
||||||
* Do not allow implicit table definitions to replace value ([#23](https://github.com/BinaryMuse/toml-node/issues/23))
|
|
||||||
* Don't allow tables to replace inline tables ([#25](https://github.com/BinaryMuse/toml-node/issues/25))
|
|
||||||
|
|
||||||
2.2.2 - April 3 2015
|
|
||||||
====================
|
|
||||||
|
|
||||||
* Correctly handle newlines at beginning of string ([#22](https://github.com/BinaryMuse/toml-node/issues/22))
|
|
||||||
|
|
||||||
2.2.1 - March 17 2015
|
|
||||||
=====================
|
|
||||||
|
|
||||||
* Parse dates generated by Date#toISOString() ([#20](https://github.com/BinaryMuse/toml-node/issues/20))
|
|
||||||
|
|
||||||
2.2.0 - Feb 26 2015
|
|
||||||
===================
|
|
||||||
|
|
||||||
* Support TOML spec v0.4.0
|
|
||||||
|
|
||||||
2.1.0 - Jan 7 2015
|
|
||||||
==================
|
|
||||||
|
|
||||||
* Support TOML spec v0.3.1
|
|
||||||
|
|
||||||
2.0.6 - May 23 2014
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix support for empty arrays with newlines ([#13](https://github.com/BinaryMuse/toml-node/issues/13))
|
|
||||||
|
|
||||||
2.0.5 - May 5 2014
|
|
||||||
==================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix loop iteration leak, by [sebmck](https://github.com/sebmck) ([#12](https://github.com/BinaryMuse/toml-node/pull/12))
|
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
* Tests now run JSHint on `lib/compiler.js`
|
|
||||||
|
|
||||||
2.0.4 - Mar 9 2014
|
|
||||||
==================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix failure on duplicate table name inside table array ([#11](https://github.com/BinaryMuse/toml-node/issues/11))
|
|
||||||
|
|
||||||
2.0.2 - Feb 23 2014
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix absence of errors when table path starts or ends with period
|
|
||||||
|
|
||||||
2.0.1 - Feb 23 2014
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix incorrect messaging in array type errors
|
|
||||||
* Fix missing error when overwriting key with table array
|
|
||||||
|
|
||||||
2.0.0 - Feb 23 2014
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Add support for [version 0.2 of the TOML spec](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md) ([#9](https://github.com/BinaryMuse/toml-node/issues/9))
|
|
||||||
|
|
||||||
### Internals
|
|
||||||
|
|
||||||
* Upgrade to PEG.js v0.8 and rewrite compiler; parser is now considerably faster (from ~7000ms to ~1000ms to parse `example.toml` 1000 times on Node.js v0.10)
|
|
||||||
|
|
||||||
1.0.4 - Aug 17 2013
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix support for empty arrays
|
|
||||||
|
|
||||||
1.0.3 - Aug 17 2013
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix typo in array type error message
|
|
||||||
* Fix single-element arrays with no trailing commas
|
|
||||||
|
|
||||||
1.0.2 - Aug 17 2013
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix errors on lines that contain only whitespace ([#7](https://github.com/BinaryMuse/toml-node/issues/7))
|
|
||||||
|
|
||||||
1.0.1 - Aug 17 2013
|
|
||||||
===================
|
|
||||||
|
|
||||||
### Internals
|
|
||||||
|
|
||||||
* Remove old code remaining from the remove streaming API
|
|
||||||
|
|
||||||
1.0.0 - Aug 17 2013
|
|
||||||
===================
|
|
||||||
|
|
||||||
Initial stable release
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
Copyright (c) 2012 Michelle Tilley
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without
|
|
||||||
restriction, including without limitation the rights to use,
|
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
TOML Parser for Node.js
|
|
||||||
=======================
|
|
||||||
|
|
||||||
[](https://travis-ci.org/BinaryMuse/toml-node)
|
|
||||||
|
|
||||||
[](https://nodei.co/npm/toml/)
|
|
||||||
|
|
||||||
If you haven't heard of TOML, well you're just missing out. [Go check it out now.](https://github.com/mojombo/toml) Back? Good.
|
|
||||||
|
|
||||||
TOML Spec Support
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
toml-node supports version 0.4.0 the TOML spec as specified by [mojombo/toml@v0.4.0](https://github.com/mojombo/toml/blob/master/versions/en/toml-v0.4.0.md)
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
toml-node is available via npm.
|
|
||||||
|
|
||||||
npm install toml
|
|
||||||
|
|
||||||
toml-node also works with browser module bundlers like Browserify and webpack.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
### Standalone
|
|
||||||
|
|
||||||
Say you have some awesome TOML in a variable called `someTomlString`. Maybe it came from the web; maybe it came from a file; wherever it came from, it came asynchronously! Let's turn that sucker into a JavaScript object.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var toml = require('toml');
|
|
||||||
var data = toml.parse(someTomlString);
|
|
||||||
console.dir(data);
|
|
||||||
```
|
|
||||||
|
|
||||||
`toml.parse` throws an exception in the case of a parsing error; such exceptions have a `line` and `column` property on them to help identify the offending text.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
try {
|
|
||||||
toml.parse(someCrazyKnuckleHeadedTrblToml);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Parsing error on line " + e.line + ", column " + e.column +
|
|
||||||
": " + e.message);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Streaming
|
|
||||||
|
|
||||||
As of toml-node version 1.0, the streaming interface has been removed. Instead, use a module like [concat-stream](https://npmjs.org/package/concat-stream):
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var toml = require('toml');
|
|
||||||
var concat = require('concat-stream');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
fs.createReadStream('tomlFile.toml', 'utf8').pipe(concat(function(data) {
|
|
||||||
var parsed = toml.parse(data);
|
|
||||||
}));
|
|
||||||
```
|
|
||||||
|
|
||||||
Thanks [@ForbesLindesay](https://github.com/ForbesLindesay) for the suggestion.
|
|
||||||
|
|
||||||
### Requiring with Node.js
|
|
||||||
|
|
||||||
You can use the [toml-require package](https://github.com/BinaryMuse/toml-require) to `require()` your `.toml` files with Node.js
|
|
||||||
|
|
||||||
Live Demo
|
|
||||||
---------
|
|
||||||
|
|
||||||
You can experiment with TOML online at http://binarymuse.github.io/toml-node/, which uses the latest version of this library.
|
|
||||||
|
|
||||||
Building & Testing
|
|
||||||
------------------
|
|
||||||
|
|
||||||
toml-node uses [the PEG.js parser generator](http://pegjs.majda.cz/).
|
|
||||||
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
npm test
|
|
||||||
|
|
||||||
Any changes to `src/toml.peg` requires a regeneration of the parser with `npm run build`.
|
|
||||||
|
|
||||||
toml-node is tested on Travis CI and is tested against:
|
|
||||||
|
|
||||||
* Node 0.10
|
|
||||||
* Node 0.12
|
|
||||||
* Latest stable io.js
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
toml-node is licensed under the MIT license agreement. See the LICENSE file for more information.
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
var toml = require('./index');
|
|
||||||
var fs = require('fs');
|
|
||||||
var data = fs.readFileSync('./test/example.toml', 'utf8');
|
|
||||||
|
|
||||||
var iterations = 1000;
|
|
||||||
|
|
||||||
var start = new Date();
|
|
||||||
for(var i = 0; i < iterations; i++) {
|
|
||||||
toml.parse(data);
|
|
||||||
}
|
|
||||||
var end = new Date();
|
|
||||||
console.log("%s iterations in %sms", iterations, end - start);
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
declare module 'toml' {
|
|
||||||
export function parse(input: string): any;
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
var parser = require('./lib/parser');
|
|
||||||
var compiler = require('./lib/compiler');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
parse: function(input) {
|
|
||||||
var nodes = parser.parse(input.toString());
|
|
||||||
return compiler.compile(nodes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
"use strict";
|
|
||||||
function compile(nodes) {
|
|
||||||
var assignedPaths = [];
|
|
||||||
var valueAssignments = [];
|
|
||||||
var currentPath = "";
|
|
||||||
var data = Object.create(null);
|
|
||||||
var context = data;
|
|
||||||
var arrayMode = false;
|
|
||||||
|
|
||||||
return reduce(nodes);
|
|
||||||
|
|
||||||
function reduce(nodes) {
|
|
||||||
var node;
|
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
|
||||||
node = nodes[i];
|
|
||||||
switch (node.type) {
|
|
||||||
case "Assign":
|
|
||||||
assign(node);
|
|
||||||
break;
|
|
||||||
case "ObjectPath":
|
|
||||||
setPath(node);
|
|
||||||
break;
|
|
||||||
case "ArrayPath":
|
|
||||||
addTableArray(node);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function genError(err, line, col) {
|
|
||||||
var ex = new Error(err);
|
|
||||||
ex.line = line;
|
|
||||||
ex.column = col;
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function assign(node) {
|
|
||||||
var key = node.key;
|
|
||||||
var value = node.value;
|
|
||||||
var line = node.line;
|
|
||||||
var column = node.column;
|
|
||||||
|
|
||||||
var fullPath;
|
|
||||||
if (currentPath) {
|
|
||||||
fullPath = currentPath + "." + key;
|
|
||||||
} else {
|
|
||||||
fullPath = key;
|
|
||||||
}
|
|
||||||
if (typeof context[key] !== "undefined") {
|
|
||||||
genError("Cannot redefine existing key '" + fullPath + "'.", line, column);
|
|
||||||
}
|
|
||||||
|
|
||||||
context[key] = reduceValueNode(value);
|
|
||||||
|
|
||||||
if (!pathAssigned(fullPath)) {
|
|
||||||
assignedPaths.push(fullPath);
|
|
||||||
valueAssignments.push(fullPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function pathAssigned(path) {
|
|
||||||
return assignedPaths.indexOf(path) !== -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reduceValueNode(node) {
|
|
||||||
if (node.type === "Array") {
|
|
||||||
return reduceArrayWithTypeChecking(node.value);
|
|
||||||
} else if (node.type === "InlineTable") {
|
|
||||||
return reduceInlineTableNode(node.value);
|
|
||||||
} else {
|
|
||||||
return node.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function reduceInlineTableNode(values) {
|
|
||||||
var obj = Object.create(null);
|
|
||||||
for (var i = 0; i < values.length; i++) {
|
|
||||||
var val = values[i];
|
|
||||||
if (val.value.type === "InlineTable") {
|
|
||||||
obj[val.key] = reduceInlineTableNode(val.value.value);
|
|
||||||
} else if (val.type === "InlineTableValue") {
|
|
||||||
obj[val.key] = reduceValueNode(val.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPath(node) {
|
|
||||||
var path = node.value;
|
|
||||||
var quotedPath = path.map(quoteDottedString).join(".");
|
|
||||||
var line = node.line;
|
|
||||||
var column = node.column;
|
|
||||||
|
|
||||||
if (pathAssigned(quotedPath)) {
|
|
||||||
genError("Cannot redefine existing key '" + path + "'.", line, column);
|
|
||||||
}
|
|
||||||
assignedPaths.push(quotedPath);
|
|
||||||
context = deepRef(data, path, Object.create(null), line, column);
|
|
||||||
currentPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addTableArray(node) {
|
|
||||||
var path = node.value;
|
|
||||||
var quotedPath = path.map(quoteDottedString).join(".");
|
|
||||||
var line = node.line;
|
|
||||||
var column = node.column;
|
|
||||||
|
|
||||||
if (!pathAssigned(quotedPath)) {
|
|
||||||
assignedPaths.push(quotedPath);
|
|
||||||
}
|
|
||||||
assignedPaths = assignedPaths.filter(function(p) {
|
|
||||||
return p.indexOf(quotedPath) !== 0;
|
|
||||||
});
|
|
||||||
assignedPaths.push(quotedPath);
|
|
||||||
context = deepRef(data, path, [], line, column);
|
|
||||||
currentPath = quotedPath;
|
|
||||||
|
|
||||||
if (context instanceof Array) {
|
|
||||||
var newObj = Object.create(null);
|
|
||||||
context.push(newObj);
|
|
||||||
context = newObj;
|
|
||||||
} else {
|
|
||||||
genError("Cannot redefine existing key '" + path + "'.", line, column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a path 'a.b.c', create (as necessary) `start.a`,
|
|
||||||
// `start.a.b`, and `start.a.b.c`, assigning `value` to `start.a.b.c`.
|
|
||||||
// If `a` or `b` are arrays and have items in them, the last item in the
|
|
||||||
// array is used as the context for the next sub-path.
|
|
||||||
function deepRef(start, keys, value, line, column) {
|
|
||||||
var traversed = [];
|
|
||||||
var traversedPath = "";
|
|
||||||
var path = keys.join(".");
|
|
||||||
var ctx = start;
|
|
||||||
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
traversed.push(key);
|
|
||||||
traversedPath = traversed.join(".");
|
|
||||||
if (typeof ctx[key] === "undefined") {
|
|
||||||
if (i === keys.length - 1) {
|
|
||||||
ctx[key] = value;
|
|
||||||
} else {
|
|
||||||
ctx[key] = Object.create(null);
|
|
||||||
}
|
|
||||||
} else if (i !== keys.length - 1 && valueAssignments.indexOf(traversedPath) > -1) {
|
|
||||||
// already a non-object value at key, can't be used as part of a new path
|
|
||||||
genError("Cannot redefine existing key '" + traversedPath + "'.", line, column);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = ctx[key];
|
|
||||||
if (ctx instanceof Array && ctx.length && i < keys.length - 1) {
|
|
||||||
ctx = ctx[ctx.length - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reduceArrayWithTypeChecking(array) {
|
|
||||||
// Ensure that all items in the array are of the same type
|
|
||||||
var firstType = null;
|
|
||||||
for (var i = 0; i < array.length; i++) {
|
|
||||||
var node = array[i];
|
|
||||||
if (firstType === null) {
|
|
||||||
firstType = node.type;
|
|
||||||
} else {
|
|
||||||
if (node.type !== firstType) {
|
|
||||||
genError("Cannot add value of type " + node.type + " to array of type " +
|
|
||||||
firstType + ".", node.line, node.column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively reduce array of nodes into array of the nodes' values
|
|
||||||
return array.map(reduceValueNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function quoteDottedString(str) {
|
|
||||||
if (str.indexOf(".") > -1) {
|
|
||||||
return "\"" + str + "\"";
|
|
||||||
} else {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
compile: compile
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"name": "toml",
|
|
||||||
"version": "3.0.0",
|
|
||||||
"description": "TOML parser for Node.js (parses TOML spec v0.4.0)",
|
|
||||||
"main": "index.js",
|
|
||||||
"types": "index.d.ts",
|
|
||||||
"scripts": {
|
|
||||||
"build": "pegjs --cache src/toml.pegjs lib/parser.js",
|
|
||||||
"test": "jshint lib/compiler.js && nodeunit test/test_*.js",
|
|
||||||
"prepublish": "npm run build"
|
|
||||||
},
|
|
||||||
"repository": "git://github.com/BinaryMuse/toml-node.git",
|
|
||||||
"keywords": [
|
|
||||||
"toml",
|
|
||||||
"parser"
|
|
||||||
],
|
|
||||||
"author": "Michelle Tilley <michelle@michelletilley.net>",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"jshint": "*",
|
|
||||||
"nodeunit": "~0.9.0",
|
|
||||||
"pegjs": "~0.8.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
,"_resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz"
|
|
||||||
,"_integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
|
|
||||||
,"_from": "toml@3.0.0"
|
|
||||||
}
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
{
|
|
||||||
var nodes = [];
|
|
||||||
|
|
||||||
function genError(err, line, col) {
|
|
||||||
var ex = new Error(err);
|
|
||||||
ex.line = line;
|
|
||||||
ex.column = col;
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addNode(node) {
|
|
||||||
nodes.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
function node(type, value, line, column, key) {
|
|
||||||
var obj = { type: type, value: value, line: line(), column: column() };
|
|
||||||
if (key) obj.key = key;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertCodePoint(str, line, col) {
|
|
||||||
var num = parseInt("0x" + str);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isFinite(num) ||
|
|
||||||
Math.floor(num) != num ||
|
|
||||||
num < 0 ||
|
|
||||||
num > 0x10FFFF ||
|
|
||||||
(num > 0xD7FF && num < 0xE000)
|
|
||||||
) {
|
|
||||||
genError("Invalid Unicode escape code: " + str, line, col);
|
|
||||||
} else {
|
|
||||||
return fromCodePoint(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromCodePoint() {
|
|
||||||
var MAX_SIZE = 0x4000;
|
|
||||||
var codeUnits = [];
|
|
||||||
var highSurrogate;
|
|
||||||
var lowSurrogate;
|
|
||||||
var index = -1;
|
|
||||||
var length = arguments.length;
|
|
||||||
if (!length) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
var result = '';
|
|
||||||
while (++index < length) {
|
|
||||||
var codePoint = Number(arguments[index]);
|
|
||||||
if (codePoint <= 0xFFFF) { // BMP code point
|
|
||||||
codeUnits.push(codePoint);
|
|
||||||
} else { // Astral code point; split in surrogate halves
|
|
||||||
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
|
||||||
codePoint -= 0x10000;
|
|
||||||
highSurrogate = (codePoint >> 10) + 0xD800;
|
|
||||||
lowSurrogate = (codePoint % 0x400) + 0xDC00;
|
|
||||||
codeUnits.push(highSurrogate, lowSurrogate);
|
|
||||||
}
|
|
||||||
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
|
|
||||||
result += String.fromCharCode.apply(null, codeUnits);
|
|
||||||
codeUnits.length = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start
|
|
||||||
= line* { return nodes }
|
|
||||||
|
|
||||||
line
|
|
||||||
= S* expr:expression S* comment* (NL+ / EOF)
|
|
||||||
/ S+ (NL+ / EOF)
|
|
||||||
/ NL
|
|
||||||
|
|
||||||
expression
|
|
||||||
= comment / path / tablearray / assignment
|
|
||||||
|
|
||||||
comment
|
|
||||||
= '#' (!(NL / EOF) .)*
|
|
||||||
|
|
||||||
path
|
|
||||||
= '[' S* name:table_key S* ']' { addNode(node('ObjectPath', name, line, column)) }
|
|
||||||
|
|
||||||
tablearray
|
|
||||||
= '[' '[' S* name:table_key S* ']' ']' { addNode(node('ArrayPath', name, line, column)) }
|
|
||||||
|
|
||||||
table_key
|
|
||||||
= parts:dot_ended_table_key_part+ name:table_key_part { return parts.concat(name) }
|
|
||||||
/ name:table_key_part { return [name] }
|
|
||||||
|
|
||||||
table_key_part
|
|
||||||
= S* name:key S* { return name }
|
|
||||||
/ S* name:quoted_key S* { return name }
|
|
||||||
|
|
||||||
dot_ended_table_key_part
|
|
||||||
= S* name:key S* '.' S* { return name }
|
|
||||||
/ S* name:quoted_key S* '.' S* { return name }
|
|
||||||
|
|
||||||
assignment
|
|
||||||
= key:key S* '=' S* value:value { addNode(node('Assign', value, line, column, key)) }
|
|
||||||
/ key:quoted_key S* '=' S* value:value { addNode(node('Assign', value, line, column, key)) }
|
|
||||||
|
|
||||||
key
|
|
||||||
= chars:ASCII_BASIC+ { return chars.join('') }
|
|
||||||
|
|
||||||
quoted_key
|
|
||||||
= node:double_quoted_single_line_string { return node.value }
|
|
||||||
/ node:single_quoted_single_line_string { return node.value }
|
|
||||||
|
|
||||||
value
|
|
||||||
= string / datetime / float / integer / boolean / array / inline_table
|
|
||||||
|
|
||||||
string
|
|
||||||
= double_quoted_multiline_string
|
|
||||||
/ double_quoted_single_line_string
|
|
||||||
/ single_quoted_multiline_string
|
|
||||||
/ single_quoted_single_line_string
|
|
||||||
|
|
||||||
double_quoted_multiline_string
|
|
||||||
= '"""' NL? chars:multiline_string_char* '"""' { return node('String', chars.join(''), line, column) }
|
|
||||||
double_quoted_single_line_string
|
|
||||||
= '"' chars:string_char* '"' { return node('String', chars.join(''), line, column) }
|
|
||||||
single_quoted_multiline_string
|
|
||||||
= "'''" NL? chars:multiline_literal_char* "'''" { return node('String', chars.join(''), line, column) }
|
|
||||||
single_quoted_single_line_string
|
|
||||||
= "'" chars:literal_char* "'" { return node('String', chars.join(''), line, column) }
|
|
||||||
|
|
||||||
string_char
|
|
||||||
= ESCAPED / (!'"' char:. { return char })
|
|
||||||
|
|
||||||
literal_char
|
|
||||||
= (!"'" char:. { return char })
|
|
||||||
|
|
||||||
multiline_string_char
|
|
||||||
= ESCAPED / multiline_string_delim / (!'"""' char:. { return char})
|
|
||||||
|
|
||||||
multiline_string_delim
|
|
||||||
= '\\' NL NLS* { return '' }
|
|
||||||
|
|
||||||
multiline_literal_char
|
|
||||||
= (!"'''" char:. { return char })
|
|
||||||
|
|
||||||
float
|
|
||||||
= left:(float_text / integer_text) ('e' / 'E') right:integer_text { return node('Float', parseFloat(left + 'e' + right), line, column) }
|
|
||||||
/ text:float_text { return node('Float', parseFloat(text), line, column) }
|
|
||||||
|
|
||||||
float_text
|
|
||||||
= '+'? digits:(DIGITS '.' DIGITS) { return digits.join('') }
|
|
||||||
/ '-' digits:(DIGITS '.' DIGITS) { return '-' + digits.join('') }
|
|
||||||
|
|
||||||
integer
|
|
||||||
= text:integer_text { return node('Integer', parseInt(text, 10), line, column) }
|
|
||||||
|
|
||||||
integer_text
|
|
||||||
= '+'? digits:DIGIT+ !'.' { return digits.join('') }
|
|
||||||
/ '-' digits:DIGIT+ !'.' { return '-' + digits.join('') }
|
|
||||||
|
|
||||||
boolean
|
|
||||||
= 'true' { return node('Boolean', true, line, column) }
|
|
||||||
/ 'false' { return node('Boolean', false, line, column) }
|
|
||||||
|
|
||||||
array
|
|
||||||
= '[' array_sep* ']' { return node('Array', [], line, column) }
|
|
||||||
/ '[' value:array_value? ']' { return node('Array', value ? [value] : [], line, column) }
|
|
||||||
/ '[' values:array_value_list+ ']' { return node('Array', values, line, column) }
|
|
||||||
/ '[' values:array_value_list+ value:array_value ']' { return node('Array', values.concat(value), line, column) }
|
|
||||||
|
|
||||||
array_value
|
|
||||||
= array_sep* value:value array_sep* { return value }
|
|
||||||
|
|
||||||
array_value_list
|
|
||||||
= array_sep* value:value array_sep* ',' array_sep* { return value }
|
|
||||||
|
|
||||||
array_sep
|
|
||||||
= S / NL / comment
|
|
||||||
|
|
||||||
inline_table
|
|
||||||
= '{' S* values:inline_table_assignment* S* '}' { return node('InlineTable', values, line, column) }
|
|
||||||
|
|
||||||
inline_table_assignment
|
|
||||||
= S* key:key S* '=' S* value:value S* ',' S* { return node('InlineTableValue', value, line, column, key) }
|
|
||||||
/ S* key:key S* '=' S* value:value { return node('InlineTableValue', value, line, column, key) }
|
|
||||||
|
|
||||||
secfragment
|
|
||||||
= '.' digits:DIGITS { return "." + digits }
|
|
||||||
|
|
||||||
date
|
|
||||||
= date:(
|
|
||||||
DIGIT DIGIT DIGIT DIGIT
|
|
||||||
'-'
|
|
||||||
DIGIT DIGIT
|
|
||||||
'-'
|
|
||||||
DIGIT DIGIT
|
|
||||||
) { return date.join('') }
|
|
||||||
|
|
||||||
time
|
|
||||||
= time:(DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT secfragment?) { return time.join('') }
|
|
||||||
|
|
||||||
time_with_offset
|
|
||||||
= time:(
|
|
||||||
DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT secfragment?
|
|
||||||
('-' / '+')
|
|
||||||
DIGIT DIGIT ':' DIGIT DIGIT
|
|
||||||
) { return time.join('') }
|
|
||||||
|
|
||||||
datetime
|
|
||||||
= date:date 'T' time:time 'Z' { return node('Date', new Date(date + "T" + time + "Z"), line, column) }
|
|
||||||
/ date:date 'T' time:time_with_offset { return node('Date', new Date(date + "T" + time), line, column) }
|
|
||||||
|
|
||||||
|
|
||||||
S = [ \t]
|
|
||||||
NL = "\n" / "\r" "\n"
|
|
||||||
NLS = NL / S
|
|
||||||
EOF = !.
|
|
||||||
HEX = [0-9a-f]i
|
|
||||||
DIGIT = DIGIT_OR_UNDER
|
|
||||||
DIGIT_OR_UNDER = [0-9]
|
|
||||||
/ '_' { return "" }
|
|
||||||
ASCII_BASIC = [A-Za-z0-9_\-]
|
|
||||||
DIGITS = d:DIGIT_OR_UNDER+ { return d.join('') }
|
|
||||||
ESCAPED = '\\"' { return '"' }
|
|
||||||
/ '\\\\' { return '\\' }
|
|
||||||
/ '\\b' { return '\b' }
|
|
||||||
/ '\\t' { return '\t' }
|
|
||||||
/ '\\n' { return '\n' }
|
|
||||||
/ '\\f' { return '\f' }
|
|
||||||
/ '\\r' { return '\r' }
|
|
||||||
/ ESCAPED_UNICODE
|
|
||||||
ESCAPED_UNICODE = "\\U" digits:(HEX HEX HEX HEX HEX HEX HEX HEX) { return convertCodePoint(digits.join('')) }
|
|
||||||
/ "\\u" digits:(HEX HEX HEX HEX) { return convertCodePoint(digits.join('')) }
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[something]
|
|
||||||
awesome = "this is"
|
|
||||||
|
|
||||||
[something.awesome]
|
|
||||||
this = "isn't"
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
# This is a TOML document. Boom.
|
|
||||||
|
|
||||||
title = "TOML Example"
|
|
||||||
|
|
||||||
[owner]
|
|
||||||
name = "Tom Preston-Werner"
|
|
||||||
organization = "GitHub"
|
|
||||||
bio = "GitHub Cofounder & CEO\n\tLikes \"tater tots\" and beer and backslashes: \\"
|
|
||||||
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
|
||||||
|
|
||||||
[database]
|
|
||||||
server = "192.168.1.1"
|
|
||||||
ports = [ 8001, 8001, 8003 ]
|
|
||||||
connection_max = 5000
|
|
||||||
connection_min = -2 # Don't ask me how
|
|
||||||
max_temp = 87.1 # It's a float
|
|
||||||
min_temp = -17.76
|
|
||||||
enabled = true
|
|
||||||
|
|
||||||
[servers]
|
|
||||||
|
|
||||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
|
||||||
[servers.alpha]
|
|
||||||
ip = "10.0.0.1"
|
|
||||||
dc = "eqdc10"
|
|
||||||
|
|
||||||
[servers.beta]
|
|
||||||
ip = "10.0.0.2"
|
|
||||||
dc = "eqdc10"
|
|
||||||
|
|
||||||
[clients]
|
|
||||||
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
# Test file for TOML
|
|
||||||
# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
|
|
||||||
# This part you'll really hate
|
|
||||||
|
|
||||||
[the]
|
|
||||||
test_string = "You'll hate me after this - #" # " Annoying, isn't it?
|
|
||||||
|
|
||||||
[the.hard]
|
|
||||||
test_array = [ "] ", " # "] # ] There you go, parse this!
|
|
||||||
test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
|
|
||||||
# You didn't think it'd as easy as chucking out the last #, did you?
|
|
||||||
another_test_string = " Same thing, but with a string #"
|
|
||||||
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
|
|
||||||
# Things will get harder
|
|
||||||
|
|
||||||
[the.hard."bit#"]
|
|
||||||
"what?" = "You don't think some user won't do that?"
|
|
||||||
multi_line_array = [
|
|
||||||
"]",
|
|
||||||
# ] Oh yes I did
|
|
||||||
]
|
|
||||||
|
|
||||||
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
|
|
||||||
|
|
||||||
#[error] if you didn't catch this, your parser is broken
|
|
||||||
#string = "Anything other than tabs, spaces and newline after a keygroup or key value pair has ended should produce an error unless it is a comment" like this
|
|
||||||
#array = [
|
|
||||||
# "This might most likely happen in multiline arrays",
|
|
||||||
# Like here,
|
|
||||||
# "or here,
|
|
||||||
# and here"
|
|
||||||
# ] End of array comment, forgot the #
|
|
||||||
#number = 3.14 pi <--again forgot the #
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
name = { first = "Tom", last = "Preston-Werner" }
|
|
||||||
point = { x = 1, y = 2 }
|
|
||||||
nested = { x = { a = { b = 3 } } }
|
|
||||||
|
|
||||||
points = [ { x = 1, y = 2, z = 3 },
|
|
||||||
{ x = 7, y = 8, z = 9 },
|
|
||||||
{ x = 2, y = 4, z = 8 } ]
|
|
||||||
|
|
||||||
arrays = [ { x = [1, 2, 3], y = [4, 5, 6] },
|
|
||||||
{ x = [7, 8, 9], y = [0, 1, 2] } ]
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# What you see is what you get.
|
|
||||||
winpath = 'C:\Users\nodejs\templates'
|
|
||||||
winpath2 = '\\ServerX\admin$\system32\'
|
|
||||||
quoted = 'Tom "Dubs" Preston-Werner'
|
|
||||||
regex = '<\i\c*\s*>'
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
# The following strings are byte-for-byte equivalent:
|
|
||||||
key1 = "The quick brown fox jumps over the lazy dog."
|
|
||||||
|
|
||||||
key2 = """
|
|
||||||
The quick brown \
|
|
||||||
|
|
||||||
|
|
||||||
fox jumps over \
|
|
||||||
the lazy dog."""
|
|
||||||
|
|
||||||
key3 = """\
|
|
||||||
The quick brown \
|
|
||||||
fox jumps over \
|
|
||||||
the lazy dog.\
|
|
||||||
"""
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
regex2 = '''I [dw]on't need \d{2} apples'''
|
|
||||||
lines = '''
|
|
||||||
The first newline is
|
|
||||||
trimmed in raw strings.
|
|
||||||
All other whitespace
|
|
||||||
is preserved.
|
|
||||||
'''
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
# The following strings are byte-for-byte equivalent:
|
|
||||||
key1 = "One\nTwo"
|
|
||||||
key2 = """One\nTwo"""
|
|
||||||
key3 = """
|
|
||||||
One
|
|
||||||
Two"""
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
var fs = require('fs');
|
|
||||||
var parser = require('../index');
|
|
||||||
|
|
||||||
var codes = [
|
|
||||||
"# test\n my.key=\"value\"\nother = 101\nthird = -37",
|
|
||||||
"first = 1.2\nsecond = -56.02\nth = true\nfth = false",
|
|
||||||
"time = 1979-05-27T07:32:00Z",
|
|
||||||
"test = [\"one\", ]",
|
|
||||||
"test = [[1, 2,], [true, false,],]",
|
|
||||||
"[my.sub.path]\nkey = true\nother = -15.3\n[my.sub]\nkey=false",
|
|
||||||
"arry = [\"one\", \"two\",\"thr\nee\", \"\\u03EA\"]",
|
|
||||||
fs.readFileSync(__dirname + '/example.toml', 'utf8'),
|
|
||||||
fs.readFileSync(__dirname + '/hard_example.toml', 'utf8')
|
|
||||||
]
|
|
||||||
|
|
||||||
console.log("=============================================");
|
|
||||||
for(i in codes) {
|
|
||||||
var code = codes[i];
|
|
||||||
console.log(code + "\n");
|
|
||||||
console.log(JSON.stringify(parser.parse(code)));
|
|
||||||
console.log("=============================================");
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
[[products]]
|
|
||||||
name = "Hammer"
|
|
||||||
sku = 738594937
|
|
||||||
|
|
||||||
[[products]]
|
|
||||||
|
|
||||||
[[products]]
|
|
||||||
name = "Nail"
|
|
||||||
sku = 284758393
|
|
||||||
color = "gray"
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
[[fruit]]
|
|
||||||
name = "durian"
|
|
||||||
variety = []
|
|
||||||
|
|
||||||
[[fruit]]
|
|
||||||
name = "apple"
|
|
||||||
|
|
||||||
[fruit.physical]
|
|
||||||
color = "red"
|
|
||||||
shape = "round"
|
|
||||||
|
|
||||||
[[fruit.variety]]
|
|
||||||
name = "red delicious"
|
|
||||||
|
|
||||||
[[fruit.variety]]
|
|
||||||
name = "granny smith"
|
|
||||||
|
|
||||||
[[fruit]]
|
|
||||||
|
|
||||||
[[fruit]]
|
|
||||||
name = "banana"
|
|
||||||
|
|
||||||
[[fruit.variety]]
|
|
||||||
name = "plantain"
|
|
||||||
|
|
||||||
[[fruit]]
|
|
||||||
name = "orange"
|
|
||||||
|
|
||||||
[fruit.physical]
|
|
||||||
color = "orange"
|
|
||||||
shape = "round"
|
|
||||||
|
|
@ -1,596 +0,0 @@
|
||||||
var toml = require('../');
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
var assert = require("nodeunit").assert;
|
|
||||||
|
|
||||||
assert.parsesToml = function(tomlStr, expected) {
|
|
||||||
try {
|
|
||||||
var actual = toml.parse(tomlStr);
|
|
||||||
} catch (e) {
|
|
||||||
var errInfo = "line: " + e.line + ", column: " + e.column;
|
|
||||||
return assert.fail("TOML parse error: " + e.message, errInfo, null, "at", assert.parsesToml);
|
|
||||||
}
|
|
||||||
return assert.deepEqual(actual, expected);
|
|
||||||
};
|
|
||||||
|
|
||||||
var exampleExpected = {
|
|
||||||
title: "TOML Example",
|
|
||||||
owner: {
|
|
||||||
name: "Tom Preston-Werner",
|
|
||||||
organization: "GitHub",
|
|
||||||
bio: "GitHub Cofounder & CEO\n\tLikes \"tater tots\" and beer and backslashes: \\",
|
|
||||||
dob: new Date("1979-05-27T07:32:00Z")
|
|
||||||
},
|
|
||||||
database: {
|
|
||||||
server: "192.168.1.1",
|
|
||||||
ports: [8001, 8001, 8003],
|
|
||||||
connection_max: 5000,
|
|
||||||
connection_min: -2,
|
|
||||||
max_temp: 87.1,
|
|
||||||
min_temp: -17.76,
|
|
||||||
enabled: true
|
|
||||||
},
|
|
||||||
servers: {
|
|
||||||
alpha: {
|
|
||||||
ip: "10.0.0.1",
|
|
||||||
dc: "eqdc10"
|
|
||||||
},
|
|
||||||
beta: {
|
|
||||||
ip: "10.0.0.2",
|
|
||||||
dc: "eqdc10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clients: {
|
|
||||||
data: [ ["gamma", "delta"], [1, 2] ]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var hardExampleExpected = {
|
|
||||||
the: {
|
|
||||||
hard: {
|
|
||||||
another_test_string: ' Same thing, but with a string #',
|
|
||||||
'bit#': {
|
|
||||||
multi_line_array: [']'],
|
|
||||||
'what?': "You don't think some user won't do that?"
|
|
||||||
},
|
|
||||||
harder_test_string: " And when \"'s are in the string, along with # \"",
|
|
||||||
test_array: ['] ', ' # '],
|
|
||||||
test_array2: ['Test #11 ]proved that', 'Experiment #9 was a success']
|
|
||||||
},
|
|
||||||
test_string: "You'll hate me after this - #"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var easyTableArrayExpected = {
|
|
||||||
"products": [
|
|
||||||
{ "name": "Hammer", "sku": 738594937 },
|
|
||||||
{ },
|
|
||||||
{ "name": "Nail", "sku": 284758393, "color": "gray" }
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
var hardTableArrayExpected = {
|
|
||||||
"fruit": [
|
|
||||||
{
|
|
||||||
"name": "durian",
|
|
||||||
"variety": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "apple",
|
|
||||||
"physical": {
|
|
||||||
"color": "red",
|
|
||||||
"shape": "round"
|
|
||||||
},
|
|
||||||
"variety": [
|
|
||||||
{ "name": "red delicious" },
|
|
||||||
{ "name": "granny smith" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
"name": "banana",
|
|
||||||
"variety": [
|
|
||||||
{ "name": "plantain" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "orange",
|
|
||||||
"physical": {
|
|
||||||
"color": "orange",
|
|
||||||
"shape": "round"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
var badInputs = [
|
|
||||||
'[error] if you didn\'t catch this, your parser is broken',
|
|
||||||
'string = "Anything other than tabs, spaces and newline after a table or key value pair has ended should produce an error unless it is a comment" like this',
|
|
||||||
'array = [\n \"This might most likely happen in multiline arrays\",\n Like here,\n \"or here,\n and here\"\n ] End of array comment, forgot the #',
|
|
||||||
'number = 3.14 pi <--again forgot the #'
|
|
||||||
];
|
|
||||||
|
|
||||||
exports.testParsesExample = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/example.toml", 'utf-8')
|
|
||||||
test.parsesToml(str, exampleExpected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testParsesHardExample = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/hard_example.toml", 'utf-8')
|
|
||||||
test.parsesToml(str, hardExampleExpected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testEasyTableArrays = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/table_arrays_easy.toml", 'utf8')
|
|
||||||
test.parsesToml(str, easyTableArrayExpected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testHarderTableArrays = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/table_arrays_hard.toml", 'utf8')
|
|
||||||
test.parsesToml(str, hardTableArrayExpected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testSupportsTrailingCommasInArrays = function(test) {
|
|
||||||
var str = 'arr = [1, 2, 3,]';
|
|
||||||
var expected = { arr: [1, 2, 3] };
|
|
||||||
test.parsesToml(str, expected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testSingleElementArrayWithNoTrailingComma = function(test) {
|
|
||||||
var str = "a = [1]";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: [1]
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testEmptyArray = function(test) {
|
|
||||||
var str = "a = []";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: []
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testArrayWithWhitespace = function(test) {
|
|
||||||
var str = "[versions]\nfiles = [\n 3, \n 5 \n\n ]";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
versions: {
|
|
||||||
files: [3, 5]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testEmptyArrayWithWhitespace = function(test) {
|
|
||||||
var str = "[versions]\nfiles = [\n \n ]";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
versions: {
|
|
||||||
files: []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testDefineOnSuperkey = function(test) {
|
|
||||||
var str = "[a.b]\nc = 1\n\n[a]\nd = 2";
|
|
||||||
var expected = {
|
|
||||||
a: {
|
|
||||||
b: {
|
|
||||||
c: 1
|
|
||||||
},
|
|
||||||
d: 2
|
|
||||||
}
|
|
||||||
};
|
|
||||||
test.parsesToml(str, expected);
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testWhitespace = function(test) {
|
|
||||||
var str = "a = 1\n \n b = 2 ";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: 1, b: 2
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testUnicode = function(test) {
|
|
||||||
var str = "str = \"My name is Jos\\u00E9\"";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
str: "My name is Jos\u00E9"
|
|
||||||
});
|
|
||||||
|
|
||||||
var str = "str = \"My name is Jos\\U000000E9\"";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
str: "My name is Jos\u00E9"
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testMultilineStrings = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/multiline_strings.toml", 'utf8');
|
|
||||||
test.parsesToml(str, {
|
|
||||||
key1: "One\nTwo",
|
|
||||||
key2: "One\nTwo",
|
|
||||||
key3: "One\nTwo"
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testMultilineEatWhitespace = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/multiline_eat_whitespace.toml", 'utf8');
|
|
||||||
test.parsesToml(str, {
|
|
||||||
key1: "The quick brown fox jumps over the lazy dog.",
|
|
||||||
key2: "The quick brown fox jumps over the lazy dog.",
|
|
||||||
key3: "The quick brown fox jumps over the lazy dog."
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testLiteralStrings = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/literal_strings.toml", 'utf8');
|
|
||||||
test.parsesToml(str, {
|
|
||||||
winpath: "C:\\Users\\nodejs\\templates",
|
|
||||||
winpath2: "\\\\ServerX\\admin$\\system32\\",
|
|
||||||
quoted: "Tom \"Dubs\" Preston-Werner",
|
|
||||||
regex: "<\\i\\c*\\s*>"
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testMultilineLiteralStrings = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/multiline_literal_strings.toml", 'utf8');
|
|
||||||
test.parsesToml(str, {
|
|
||||||
regex2: "I [dw]on't need \\d{2} apples",
|
|
||||||
lines: "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n"
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testIntegerFormats = function(test) {
|
|
||||||
var str = "a = +99\nb = 42\nc = 0\nd = -17\ne = 1_000_001\nf = 1_2_3_4_5 # why u do dis";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: 99,
|
|
||||||
b: 42,
|
|
||||||
c: 0,
|
|
||||||
d: -17,
|
|
||||||
e: 1000001,
|
|
||||||
f: 12345
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testFloatFormats = function(test) {
|
|
||||||
var str = "a = +1.0\nb = 3.1415\nc = -0.01\n" +
|
|
||||||
"d = 5e+22\ne = 1e6\nf = -2E-2\n" +
|
|
||||||
"g = 6.626e-34\n" +
|
|
||||||
"h = 9_224_617.445_991_228_313\n" +
|
|
||||||
"i = 1e1_000";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: 1.0,
|
|
||||||
b: 3.1415,
|
|
||||||
c: -0.01,
|
|
||||||
d: 5e22,
|
|
||||||
e: 1e6,
|
|
||||||
f: -2e-2,
|
|
||||||
g: 6.626e-34,
|
|
||||||
h: 9224617.445991228313,
|
|
||||||
i: 1e1000
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testDate = function(test) {
|
|
||||||
var date = new Date("1979-05-27T07:32:00Z");
|
|
||||||
test.parsesToml("a = 1979-05-27T07:32:00Z", {
|
|
||||||
a: date
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testDateWithOffset = function(test) {
|
|
||||||
var date1 = new Date("1979-05-27T07:32:00-07:00"),
|
|
||||||
date2 = new Date("1979-05-27T07:32:00+02:00");
|
|
||||||
test.parsesToml("a = 1979-05-27T07:32:00-07:00\nb = 1979-05-27T07:32:00+02:00", {
|
|
||||||
a: date1,
|
|
||||||
b: date2
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testDateWithSecondFraction = function(test) {
|
|
||||||
var date = new Date("1979-05-27T00:32:00.999999-07:00");
|
|
||||||
test.parsesToml("a = 1979-05-27T00:32:00.999999-07:00", {
|
|
||||||
a: date
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testDateFromIsoString = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/20
|
|
||||||
var date = new Date(),
|
|
||||||
dateStr = date.toISOString(),
|
|
||||||
tomlStr = "a = " + dateStr;
|
|
||||||
|
|
||||||
test.parsesToml(tomlStr, {
|
|
||||||
a: date
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testLeadingNewlines = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/22
|
|
||||||
var str = "\ntest = \"ing\"";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
test: "ing"
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testInlineTables = function(test) {
|
|
||||||
var str = fs.readFileSync(__dirname + "/inline_tables.toml", 'utf8');
|
|
||||||
test.parsesToml(str, {
|
|
||||||
name: {
|
|
||||||
first: "Tom",
|
|
||||||
last: "Preston-Werner"
|
|
||||||
},
|
|
||||||
point: {
|
|
||||||
x: 1,
|
|
||||||
y: 2
|
|
||||||
},
|
|
||||||
nested: {
|
|
||||||
x: {
|
|
||||||
a: {
|
|
||||||
b: 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
points: [
|
|
||||||
{ x: 1, y: 2, z: 3 },
|
|
||||||
{ x: 7, y: 8, z: 9 },
|
|
||||||
{ x: 2, y: 4, z: 8 }
|
|
||||||
],
|
|
||||||
arrays: [
|
|
||||||
{ x: [1, 2, 3], y: [4, 5, 6] },
|
|
||||||
{ x: [7, 8, 9], y: [0, 1, 2] }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testEmptyInlineTables = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/24
|
|
||||||
var str = "a = { }";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: {}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testKeyNamesWithWhitespaceAroundStartAndFinish = function(test) {
|
|
||||||
var str = "[ a ]\nb = 1";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: {
|
|
||||||
b: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testKeyNamesWithWhitespaceAroundDots = function(test) {
|
|
||||||
var str = "[ a . b . c]\nd = 1";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: {
|
|
||||||
b: {
|
|
||||||
c: {
|
|
||||||
d: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testSimpleQuotedKeyNames = function(test) {
|
|
||||||
var str = "[\"ʞ\"]\na = 1";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
"ʞ": {
|
|
||||||
a: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testComplexQuotedKeyNames = function(test) {
|
|
||||||
var str = "[ a . \"ʞ\" . c ]\nd = 1";
|
|
||||||
test.parsesToml(str, {
|
|
||||||
a: {
|
|
||||||
"ʞ": {
|
|
||||||
c: {
|
|
||||||
d: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testEscapedQuotesInQuotedKeyNames = function(test) {
|
|
||||||
test.parsesToml("[\"the \\\"thing\\\"\"]\na = true", {
|
|
||||||
'the "thing"': {
|
|
||||||
a: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testMoreComplexQuotedKeyNames = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/21
|
|
||||||
test.parsesToml('["the\\ key"]\n\none = "one"\ntwo = 2\nthree = false', {
|
|
||||||
"the\\ key": {
|
|
||||||
one: "one",
|
|
||||||
two: 2,
|
|
||||||
three: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.parsesToml('[a."the\\ key"]\n\none = "one"\ntwo = 2\nthree = false', {
|
|
||||||
a: {
|
|
||||||
"the\\ key": {
|
|
||||||
one: "one",
|
|
||||||
two: 2,
|
|
||||||
three: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.parsesToml('[a."the-key"]\n\none = "one"\ntwo = 2\nthree = false', {
|
|
||||||
a: {
|
|
||||||
"the-key": {
|
|
||||||
one: "one",
|
|
||||||
two: 2,
|
|
||||||
three: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
test.parsesToml('[a."the.key"]\n\none = "one"\ntwo = 2\nthree = false', {
|
|
||||||
a: {
|
|
||||||
"the.key": {
|
|
||||||
one: "one",
|
|
||||||
two: 2,
|
|
||||||
three: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/34
|
|
||||||
test.parsesToml('[table]\n\'a "quoted value"\' = "value"', {
|
|
||||||
table: {
|
|
||||||
'a "quoted value"': "value"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/33
|
|
||||||
test.parsesToml('[module]\n"foo=bar" = "zzz"', {
|
|
||||||
module: {
|
|
||||||
"foo=bar": "zzz"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnBadUnicode = function(test) {
|
|
||||||
var str = "str = \"My name is Jos\\uD800\"";
|
|
||||||
test.throws(function() {
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnDotAtStartOfKey = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[.a]\nb = 1";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnDotAtEndOfKey = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[.a]\nb = 1";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnTableOverride = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[a]\nb = 1\n\n[a]\nc = 2";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnKeyOverride = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[a]\nb = 1\n[a.b]\nc = 2";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnKeyOverrideWithNested = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/23
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[a]\nb = \"a\"\n[a.b.c]";
|
|
||||||
toml.parse(str);
|
|
||||||
}, "existing key 'a.b'");
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnKeyOverrideWithArrayTable = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[a]\nb = 1\n[[a]]\nc = 2";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnKeyReplace = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "[a]\nb = 1\nb = 2";
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done()
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnInlineTableReplace = function(test) {
|
|
||||||
// https://github.com/BinaryMuse/toml-node/issues/25
|
|
||||||
test.throws(function() {
|
|
||||||
var str = "a = { b = 1 }\n[a]\nc = 2";
|
|
||||||
toml.parse(str);
|
|
||||||
}, "existing key 'a'");
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnArrayMismatch = function(test) {
|
|
||||||
test.throws(function() {
|
|
||||||
var str = 'data = [1, 2, "test"]'
|
|
||||||
toml.parse(str);
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorOnBadInputs = function(test) {
|
|
||||||
var count = 0;
|
|
||||||
for (i in badInputs) {
|
|
||||||
(function(num) {
|
|
||||||
test.throws(function() {
|
|
||||||
toml.parse(badInputs[num]);
|
|
||||||
});
|
|
||||||
})(i);
|
|
||||||
}
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testErrorsHaveCorrectLineAndColumn = function(test) {
|
|
||||||
var str = "[a]\nb = 1\n [a.b]\nc = 2";
|
|
||||||
try { toml.parse(str); }
|
|
||||||
catch (e) {
|
|
||||||
test.equal(e.line, 3);
|
|
||||||
test.equal(e.column, 2);
|
|
||||||
test.done();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.testUsingConstructorAsKey = function(test) {
|
|
||||||
test.parsesToml("[empty]\n[emptier]\n[constructor]\nconstructor = 1\n[emptiest]", {
|
|
||||||
"empty": {},
|
|
||||||
"emptier": {},
|
|
||||||
"constructor": { "constructor": 1 },
|
|
||||||
"emptiest": {}
|
|
||||||
});
|
|
||||||
test.done();
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "conventional-changelog-action",
|
"name": "conventional-changelog-action",
|
||||||
"version": "3.2.0",
|
"version": "3.3.0",
|
||||||
"description": "Github Action that generates a changelog with the Conventional Changelog CLI",
|
"description": "Github Action that generates a changelog with the Conventional Changelog CLI",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"actions",
|
"actions",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue