Skip to content

Commit

Permalink
Merge pull request #189 from eemeli/json-like
Browse files Browse the repository at this point in the history
Improve JSON compatibility
  • Loading branch information
eemeli committed Sep 6, 2020
2 parents 0e94ef6 + c5fb6ca commit f6a9f6f
Show file tree
Hide file tree
Showing 39 changed files with 639 additions and 192 deletions.
12 changes: 6 additions & 6 deletions README.md
Expand Up @@ -28,21 +28,21 @@ const YAML = require('yaml')

### Parse & Stringify

- [`YAML.parse(str, options): value`](https://eemeli.org/yaml/#yaml-parse)
- [`YAML.stringify(value, options): string`](https://eemeli.org/yaml/#yaml-stringify)
- [`YAML.parse(str, reviver?, options?): value`](https://eemeli.org/yaml/#yaml-parse)
- [`YAML.stringify(value, replacer?, options?): string`](https://eemeli.org/yaml/#yaml-stringify)

### YAML Documents

- [`YAML.defaultOptions`](https://eemeli.org/yaml/#options)
- [`YAML.Document`](https://eemeli.org/yaml/#yaml-documents)
- [`constructor(value, options)`](https://eemeli.org/yaml/#creating-documents)
- [`constructor(value, replacer?, options?)`](https://eemeli.org/yaml/#creating-documents)
- [`defaults`](https://eemeli.org/yaml/#options)
- [`#createNode(value, options): Node`](https://eemeli.org/yaml/#creating-nodes)
- [`#createNode(value, options?): Node`](https://eemeli.org/yaml/#creating-nodes)
- [`#anchors`](https://eemeli.org/yaml/#working-with-anchors)
- [`#contents`](https://eemeli.org/yaml/#content-nodes)
- [`#errors`](https://eemeli.org/yaml/#errors)
- [`YAML.parseAllDocuments(str, options): YAML.Document[]`](https://eemeli.org/yaml/#parsing-documents)
- [`YAML.parseDocument(str, options): YAML.Document`](https://eemeli.org/yaml/#parsing-documents)
- [`YAML.parseAllDocuments(str, options?): YAML.Document[]`](https://eemeli.org/yaml/#parsing-documents)
- [`YAML.parseDocument(str, options?): YAML.Document`](https://eemeli.org/yaml/#parsing-documents)

```js
import { Pair, YAMLMap, YAMLSeq } from 'yaml/types'
Expand Down
12 changes: 6 additions & 6 deletions docs/01_intro.md
Expand Up @@ -33,21 +33,21 @@ import YAML from 'yaml'
const YAML = require('yaml')
```

- [`YAML.parse(str, options): value`](#yaml-parse)
- [`YAML.stringify(value, options): string`](#yaml-stringify)
- [`YAML.parse(str, reviver?, options?): value`](#yaml-parse)
- [`YAML.stringify(value, replacer?, options?): string`](#yaml-stringify)

<h3>Documents</h3>

- [`YAML.defaultOptions`](#options)
- [`YAML.Document`](#documents)
- [`constructor(value, options)`](#creating-documents)
- [`constructor(value, replacer?, options?)`](#creating-documents)
- [`defaults`](#options)
- [`#createNode(value, options): Node`](#creating-nodes)
- [`#createNode(value, options?): Node`](#creating-nodes)
- [`#anchors`](#working-with-anchors)
- [`#contents`](#content-nodes)
- [`#errors`](#errors)
- [`YAML.parseAllDocuments(str, options): YAML.Document[]`](#parsing-documents)
- [`YAML.parseDocument(str, options): YAML.Document`](#parsing-documents)
- [`YAML.parseAllDocuments(str, options?): YAML.Document[]`](#parsing-documents)
- [`YAML.parseDocument(str, options?): YAML.Document`](#parsing-documents)

```js
import { Pair, YAMLMap, YAMLSeq } from 'yaml/types'
Expand Down
8 changes: 4 additions & 4 deletions docs/02_parse_stringify.md
Expand Up @@ -34,9 +34,9 @@ YAML.parse(file)
// 'https://www.npmjs.com/package/yaml' ] }
```

#### `YAML.parse(str, options = {}): any`
#### `YAML.parse(str, reviver?, options = {}): any`

`str` should be a string with YAML formatting. See [Options](#options) for more information on the second parameter, an optional configuration object.
`str` should be a string with YAML formatting. If defined, the `reviver` function follows the [JSON implementation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter). See [Options](#options) for more information on the last argument, an optional configuration object.

The returned value will match the type of the root value of the parsed YAML document, so Maps become objects, Sequences arrays, and scalars result in nulls, booleans, numbers and strings.

Expand Down Expand Up @@ -65,9 +65,9 @@ YAML.stringify({ number: 3, plain: 'string', block: 'two\nlines\n' })
// `
```

#### `YAML.stringify(value, options = {}): string`
#### `YAML.stringify(value, replacer?, options = {}): string`

`value` can be of any type. The returned string will always include `\n` as the last character, as is expected of YAML documents. See [Options](#options) for more information on the second parameter, an optional configuration object.
`value` can be of any type. The returned string will always include `\n` as the last character, as is expected of YAML documents. If defined, the `replacer` array or function follows the [JSON implementation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter). See [Options](#options) for more information on the last argument, an optional configuration object. For JSON compatibility, using a number or a string as the `options` value will set the `indent` option accordingly.

As strings in particular may be represented in a number of different styles, the simplest option for the value in question will always be chosen, depending mostly on the presence of escaped or control characters and leading & trailing whitespace.

Expand Down
4 changes: 2 additions & 2 deletions docs/03_options.md
Expand Up @@ -2,8 +2,9 @@

```js
YAML.defaultOptions
// { keepBlobsInJSON: true,
// { indent: 2,
// keepNodeTypes: true,
// mapAsMap: false,
// version: '1.2' }

YAML.Document.defaults
Expand All @@ -26,7 +27,6 @@ The `version` option value (`'1.2'` by default) may be overridden by any documen
| customTags | `Tag[] ⎮ function` | Array of [additional tags](#custom-data-types) to include in the schema |
| indent | `number` | The number of spaces to use when indenting code. By default `2`. |
| indentSeq | `boolean` | Whether block sequences should be indented. By default `true`. |
| keepBlobsInJSON | `boolean` | Allow non-JSON JavaScript objects to remain in the `toJSON` output. Relevant with the YAML 1.1 `!!timestamp` and `!!binary` tags as well as BigInts. By default `true`. |
| keepCstNodes | `boolean` | Include references in the AST to each node's corresponding CST node. By default `false`. |
| keepNodeTypes | `boolean` | Store the original node type when parsing documents. By default `true`. |
| mapAsMap | `boolean` | When outputting JS, use Map rather than Object to represent mappings. By default `false`. |
Expand Down
22 changes: 13 additions & 9 deletions docs/04_documents.md
Expand Up @@ -61,9 +61,9 @@ The `contents` of a parsed document will always consist of `Scalar`, `Map`, `Seq

## Creating Documents

#### `new YAML.Document(value, options = {})`
#### `new YAML.Document(value, replacer?, options = {})`

Creates a new document. If `value` is defined, the document `contents` are initialised with that value, wrapped recursively in appropriate [content nodes](#content-nodes). If `value` is `undefined`, the document's `contents` and `schema` are initialised as `null`. See [Options](#options) for more information on the second parameter.
Creates a new document. If `value` is defined, the document `contents` are initialised with that value, wrapped recursively in appropriate [content nodes](#content-nodes). If `value` is `undefined`, the document's `contents` and `schema` are initialised as `null`. If defined, a `replacer` may filter or modify the initial document contents, following the same algorithm as the [JSON implementation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter). See [Options](#options) for more information on the last argument.

| Member | Type | Description |
| ------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
Expand Down Expand Up @@ -106,7 +106,8 @@ During stringification, a document with a true-ish `version` value will include
| parse(cst) | `Document` | Parse a CST into this document. Mostly an internal method, modifying the document according to the contents of the parsed `cst`. Calling this multiple times on a Document is not recommended. |
| setSchema(id?, customTags?) | `void` | Set the schema used by the document. `id` may either be a YAML version, or the identifier of a YAML 1.2 schema; if set, `customTags` should have the same shape as the similarly-named option. |
| setTagPrefix(handle, prefix) | `void` | Set `handle` as a shorthand string for the `prefix` tag namespace. |
| toJSON() | `any` | A plain JavaScript representation of the document `contents`. |
| toJS(options?) | `any` | A plain JavaScript representation of the document `contents`. |
| toJSON() | `any` | A JSON representation of the document `contents`. |
| toString() | `string` | A YAML representation of the document. |

```js
Expand All @@ -123,22 +124,25 @@ In addition to the above, the document object also provides the same **accessor

To define a tag prefix to use when stringifying, use **`setTagPrefix(handle, prefix)`** rather than setting a value directly in `tagPrefixes`. This will guarantee that the `handle` is valid (by throwing an error), and will overwrite any previous definition for the `handle`. Use an empty `prefix` value to remove a prefix.

#### `Document#toJS()`, `Document#toJSON()` and `Document#toString()`

```js
const src = '1969-07-21T02:56:15Z'
const doc = YAML.parseDocument(src, { customTags: ['timestamp'] })

doc.toJSON()
doc.toJS()
// Date { 1969-07-21T02:56:15.000Z }

doc.options.keepBlobsInJSON = false
doc.toJSON()
// '1969-07-21T02:56:15.000Z'

String(doc)
// '1969-07-21T02:56:15\n'
```

For a plain JavaScript representation of the document, **`toJSON()`** is your friend. By default the values wrapped in scalar nodes will not be forced to JSON, so e.g. a `!!timestamp` will remain a `Date` in the output. To change this behaviour and enforce JSON values only, set the [`keepBlobsInJSON` option](#options) to `false`.
For a plain JavaScript representation of the document, **`toJS()`** is your friend. Its output may include `Map` and `Set` collections (e.g. if the `mapAsMap` option is true) and complex scalar values like `Date` for `!!timestamp`, but all YAML nodes will be resolved. For a representation consisting only of JSON values, use **`toJSON()`**.

Use `toJS({ mapAsMap, onAnchor, reviver })` to explicitly set the `mapAsMap` option, define an `onAnchor` callback `(value: any, count: number) => void` for each aliased anchor in the document, or to apply a [reviver function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) to the output.

Conversely, to stringify a document as YAML, use **`toString()`**. This will also be called by `String(doc)`. This method will throw if the `errors` array is not empty.

Expand Down Expand Up @@ -174,7 +178,7 @@ String(doc)
const alias = doc.anchors.createAlias(doc.get(0, true), 'AA')
// Alias { source: YAMLMap { items: [ [Pair] ] } }
doc.add(alias)
doc.toJSON()
doc.toJS()
// [ { a: 'A' }, { b: 'B' }, { a: 'A' } ]
String(doc)
// [ &AA { a: A }, { b: &a2 B }, *AA ]
Expand All @@ -184,14 +188,14 @@ const merge = doc.anchors.createMergePair(alias)
// key: Scalar { value: '<<' },
// value: YAMLSeq { items: [ [Alias] ] } }
doc.addIn([1], merge)
doc.toJSON()
doc.toJS()
// [ { a: 'A' }, { b: 'B', a: 'A' }, { a: 'A' } ]
String(doc)
// [ &AA { a: A }, { b: &a2 B, <<: *AA }, *AA ]

// This creates a circular reference
merge.value.add(doc.anchors.createAlias(doc.get(1, true)))
doc.toJSON() // [RangeError: Maximum call stack size exceeded]
doc.toJS() // [RangeError: Maximum call stack size exceeded]
String(doc)
// [
// &AA { a: A },
Expand Down
6 changes: 3 additions & 3 deletions docs/05_content_nodes.md
Expand Up @@ -14,7 +14,7 @@ class Node {
spaceBefore: ?boolean,
// a blank line before this node and its commentBefore
tag: ?string, // a fully qualified tag, if required
toJSON(): any // a plain JS representation of this node
toJSON(): any // a plain JS or JSON representation of this node
}
```

Expand Down Expand Up @@ -166,7 +166,7 @@ String(doc)

To create a new node, use the `createNode(value, options?)` document method. This will recursively wrap any input with appropriate `Node` containers. Generic JS `Object` values as well as `Map` and its descendants become mappings, while arrays and other iterable objects result in sequences. With `Object`, entries that have an `undefined` value are dropped.

To specify the collection type, set `options.tag` to its identifying string, e.g. `"!!omap"`. Note that this requires the corresponding tag to be available in the document's schema. If `options.wrapScalars` is undefined or `true`, plain values are wrapped in `Scalar` objects.
Use `options.replacer` to apply a replacer array or function, following the [JSON implementation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter). To specify the collection type, set `options.tag` to its identifying string, e.g. `"!!omap"`. Note that this requires the corresponding tag to be available in the document's schema. If `options.wrapScalars` is undefined or `true`, plain values are wrapped in `Scalar` objects.

As a possible side effect, this method may add entries to the document's [`anchors`](#working-with-anchors)

Expand Down Expand Up @@ -209,7 +209,7 @@ it has:
- of values
`)

doc.toJSON()
doc.toJS()
// { 'it has': [ 'an array', 'of values' ] }

doc.commentBefore
Expand Down
2 changes: 1 addition & 1 deletion docs/06_custom_tags.md
Expand Up @@ -132,7 +132,7 @@ import {
parseSeq, // (doc, cstNode) => new YAMLSeq
stringifyNumber, // (node) => string
stringifyString, // (node, ctx, ...) => string
toJSON, // (value, arg, ctx) => any -- Recursively convert to plain JS
toJS, // (value, arg, ctx) => any -- Recursively convert to plain JS
Type, // { [string]: string } -- Used as enum for node types
YAMLReferenceError, YAMLSemanticError, YAMLSyntaxError, YAMLWarning
} from 'yaml/util'
Expand Down

0 comments on commit f6a9f6f

Please sign in to comment.