Skip to content

Commit bac121e

Browse files
authored
Merge pull request #655 from eemeli/less-custom
Be more strict and less custom
2 parents 1dbf1c7 + 92f132b commit bac121e

63 files changed

Lines changed: 1367 additions & 1928 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,33 +97,24 @@ parse(file)
9797

9898
- [`Document`](https://eemeli.org/yaml/#documents)
9999
- [`constructor(value, replacer?, options?)`](https://eemeli.org/yaml/#creating-documents)
100-
- [`#contents`](https://eemeli.org/yaml/#content-nodes)
100+
- [`#value`](https://eemeli.org/yaml/#content-nodes)
101101
- [`#directives`](https://eemeli.org/yaml/#stream-directives)
102102
- [`#errors`](https://eemeli.org/yaml/#errors)
103103
- [`#warnings`](https://eemeli.org/yaml/#errors)
104-
- [`isDocument(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
105104
- [`parseAllDocuments(str, options?): Document[]`](https://eemeli.org/yaml/#parsing-documents)
106105
- [`parseDocument(str, options?): Document`](https://eemeli.org/yaml/#parsing-documents)
107106

108107
<!-- prettier-ignore -->
109108
```js
110109
import {
111110
Document,
112-
isDocument,
113111
parseAllDocuments,
114112
parseDocument
115113
} from 'yaml'
116114
```
117115

118116
### Content Nodes
119117

120-
- [`isAlias(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
121-
- [`isCollection(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
122-
- [`isMap(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
123-
- [`isNode(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
124-
- [`isPair(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
125-
- [`isScalar(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
126-
- [`isSeq(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
127118
- [`new Scalar(value)`](https://eemeli.org/yaml/#scalar-values)
128119
- [`new YAMLMap()`](https://eemeli.org/yaml/#collections)
129120
- [`new YAMLSeq()`](https://eemeli.org/yaml/#collections)
@@ -136,9 +127,11 @@ import {
136127
<!-- prettier-ignore -->
137128
```js
138129
import {
139-
isAlias, isCollection, isMap, isNode,
140-
isPair, isScalar, isSeq, Scalar,
141-
visit, visitAsync, YAMLMap, YAMLSeq
130+
Scalar,
131+
visit,
132+
visitAsync,
133+
YAMLMap,
134+
YAMLSeq
142135
} from 'yaml'
143136
```
144137

docs/01_intro.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,14 @@ import { parse, stringify } from 'yaml'
6262
```js
6363
import {
6464
Document,
65-
isDocument,
6665
parseAllDocuments,
6766
parseDocument
6867
} from 'yaml'
6968
```
7069

7170
- [`Document`](#documents)
7271
- [`constructor(value, replacer?, options?)`](#creating-documents)
73-
- [`#contents`](#content-nodes)
72+
- [`#value`](#content-nodes)
7473
- [`#directives`](#stream-directives)
7574
- [`#errors`](#errors)
7675
- [`#warnings`](#errors)
@@ -82,13 +81,14 @@ import {
8281
<!-- prettier-ignore -->
8382
```js
8483
import {
85-
isAlias, isCollection, isMap, isNode,
86-
isPair, isScalar, isSeq, Scalar,
87-
visit, visitAsync, YAMLMap, YAMLSeq
84+
Scalar,
85+
visit,
86+
visitAsync,
87+
YAMLMap,
88+
YAMLSeq
8889
} from 'yaml'
8990
```
9091

91-
- [`is*(foo): boolean`](#identifying-node-types)
9292
- [`new Scalar(value)`](#scalar-values)
9393
- [`new YAMLMap()`](#collections)
9494
- [`new YAMLSeq()`](#collections)

docs/04_documents.md

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { parseAllDocuments, parseDocument } from 'yaml'
1010

1111
const file = fs.readFileSync('./file.yml', 'utf8')
1212
const doc = parseDocument(file)
13-
doc.contents
13+
doc.value
1414
// YAMLMap {
1515
// items:
1616
// [ Pair {
@@ -44,9 +44,9 @@ These functions should never throw,
4444
provided that `str` is a string and the `options` are valid.
4545
Errors and warnings are included in the documents' `errors` and `warnings` arrays.
4646
In particular, if `errors` is not empty
47-
it's likely that the document's parsed `contents` are not entirely correct.
47+
it's likely that the document's parsed `value` are not entirely correct.
4848

49-
The `contents` of a parsed document will always consist of `Scalar`, `Map`, `Seq` or `null` values.
49+
The `value` of a parsed document will always consist of `Scalar`, `Map`, or `Seq` values.
5050

5151
#### `parseDocument(str, options = {}): Document`
5252

@@ -69,16 +69,15 @@ See [Options](#options) for more information on the second parameter.
6969
#### `new Document(value, replacer?, options = {})`
7070

7171
Creates a new document.
72-
If `value` is defined, the document `contents` are initialised with that value, wrapped recursively in appropriate [content nodes](#content-nodes).
73-
If `value` is `undefined`, the document's `contents` is initialised as `null`.
74-
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).
72+
The document `value` is initialised with `value`, wrapped recursively in appropriate [content nodes](#content-nodes).
73+
If defined, a `replacer` may filter or modify the initial document value, 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).
7574
See [Options](#options) for more information on the last argument.
7675

7776
| Member | Type | Description |
7877
| ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7978
| commentBefore | `string?` | A comment at the very beginning of the document. If not empty, separated from the rest of the document by a blank line or the doc-start indicator when stringified. |
8079
| comment | `string?` | A comment at the end of the document. If not empty, separated from the rest of the document by a blank line when stringified. |
81-
| contents | [`Node`](#content-nodes) `⎮ any` | The document contents. |
80+
| value | [`Node`](#content-nodes) `⎮ any` | The document value. |
8281
| directives | [`Directives`](#stream-directives) | Controls for the `%YAML` and `%TAG` directives, as well as the doc-start marker `---`. |
8382
| errors | [`Error[]`](#errors) | Errors encountered during parsing. |
8483
| schema | `Schema` | The schema used with the document. |
@@ -99,21 +98,21 @@ String(doc)
9998
```
10099

101100
The Document members are all modifiable, though it's unlikely that you'll have reason to change `errors`, `schema` or `warnings`.
102-
In particular you may be interested in both reading and writing **`contents`**.
103-
Although `parseDocument()` and `parseAllDocuments()` will leave it with `YAMLMap`, `YAMLSeq`, `Scalar` or `null` contents, it can be set to anything.
101+
In particular you may be interested in both reading and writing **`value`**,
102+
which is expected to always contain a `YAMLMap`, `YAMLSeq`, or `Scalar` value.
104103

105104
## Document Methods
106105

107-
| Method | Returns | Description |
108-
| ------------------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
109-
| clone() | `Document` | Create a deep copy of this Document and its contents. Custom Node values that inherit from `Object` still refer to their original instances. |
110-
| createAlias(node: Node, name?: string) | `Alias` | Create a new `Alias` node, adding the required anchor for `node`. If `name` is empty, a new anchor name will be generated. |
111-
| createNode(value,&nbsp;options?) | `Node` | Recursively wrap any input with appropriate `Node` containers. See [Creating Nodes](#creating-nodes) for more information. |
112-
| createPair(key,&nbsp;value,&nbsp;options?) | `Pair` | Recursively wrap `key` and `value` into a `Pair` object. See [Creating Nodes](#creating-nodes) for more information. |
113-
| setSchema(version,&nbsp;options?) | `void` | Change the YAML version and schema used by the document. `version` must be either `'1.1'` or `'1.2'`; accepts all Schema options. |
114-
| toJS(options?) | `any` | A plain JavaScript representation of the document `contents`. |
115-
| toJSON() | `any` | A JSON representation of the document `contents`. |
116-
| toString(options?) | `string` | A YAML representation of the document. |
106+
| Method | Returns | Description |
107+
| ------------------------------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
108+
| clone() | `Document` | Create a deep copy of this Document and its value. Custom Node values that inherit from `Object` still refer to their original instances. |
109+
| createAlias(node: Node, name?: string) | `Alias` | Create a new `Alias` node, adding the required anchor for `node`. If `name` is empty, a new anchor name will be generated. |
110+
| createNode(value,&nbsp;options?) | `Node` | Recursively wrap any input with appropriate `Node` containers. See [Creating Nodes](#creating-nodes) for more information. |
111+
| createPair(key,&nbsp;value,&nbsp;options?) | `Pair` | Recursively wrap `key` and `value` into a `Pair` object. See [Creating Nodes](#creating-nodes) for more information. |
112+
| setSchema(version,&nbsp;options?) | `void` | Change the YAML version and schema used by the document. `version` must be either `'1.1'` or `'1.2'`; accepts all Schema options. |
113+
| toJS(options?) | `any` | A plain JavaScript representation of the document `value`. |
114+
| toJSON() | `any` | A JSON representation of the document `value`. |
115+
| toString(options?) | `string` | A YAML representation of the document. |
117116

118117
```js
119118
const doc = parseDocument('a: 1\nb: [2, 3]\n')
@@ -127,7 +126,7 @@ doc.getIn(['b', 1]) // 4
127126

128127
In addition to the above, the document object also provides the same **accessor methods** as [collections](#collections), based on the top-level collection:
129128
`add`, `delete`, `get`, `has`, and `set`, along with their deeper variants `addIn`, `deleteIn`, `getIn`, `hasIn`, and `setIn`.
130-
For the `*In` methods using an empty `path` value (i.e. `null`, `undefined`, or `[]`) will refer to the document's top-level `contents`.
129+
For the `*In` methods using an empty `path` value (i.e. `[]`) will refer to the document's top-level `value`.
131130

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

@@ -177,5 +176,5 @@ The contents of `doc.directives.tags` are used both for the `%TAG` directives an
177176
Each of the handles must start and end with a `!` character; `!` is by default the local tag and `!!` is used for default tags.
178177
See the section on [custom tags](#writing-custom-tags) for more on this topic.
179178

180-
`doc.contents.yaml` determines if an explicit `%YAML` directive should be included in the output, and what version it should use.
179+
`doc.directives.yaml` determines if an explicit `%YAML` directive should be included in the output, and what version it should use.
181180
If changing the version after the document's creation, you'll probably want to use `doc.setSchema()` as it will also update the schema accordingly.

docs/05_content_nodes.md

Lines changed: 17 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Content Nodes
22

3-
After parsing, the `contents` value of each `YAML.Document` is the root of an [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of nodes representing the document (or `null` for an empty document).
3+
After parsing, the `value` value of each `YAML.Document` is the root of an [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of nodes representing the document.
44

55
Both scalar and collection values may have an `anchor` associated with them; this is rendered in the string representation with a `&` prefix, so e.g. in `foo: &aa bar`, the value `bar` has the anchor `aa`.
66
Anchors are used by [Alias nodes](#alias-nodes) to allow for the same value to be used in multiple places in the document.
@@ -41,7 +41,7 @@ class Scalar<T = unknown> extends NodeBase {
4141
}
4242
```
4343
44-
A parsed document's contents will have all of its non-object values wrapped in `Scalar` objects, which themselves may be in some hierarchy of `YAMLMap` and `YAMLSeq` collections.
44+
A parsed document's value will have all of its non-object values wrapped in `Scalar` objects, which themselves may be in some hierarchy of `YAMLMap` and `YAMLSeq` collections.
4545
However, this is not a requirement for the document's stringification, which is rather tolerant regarding its input values, and will use [`doc.createNode()`](#creating-nodes) when encountering an unwrapped value.
4646
4747
When stringifying, the node `type` will be taken into account by `!!str` and `!!binary` values, and ignored by other scalars.
@@ -50,21 +50,21 @@ On the other hand, `!!int` and `!!float` stringifiers will take `format` into ac
5050
## Collections
5151
5252
```js
53-
class Pair<K = unknown, V = unknown> {
54-
key: K // When parsed, key and value are always
55-
value: V // Node or null, but can be set to anything
53+
class Pair {
54+
key: Node
55+
value: Node | null
5656
}
5757

5858
class Collection extends NodeBase {
5959
anchor?: string // an anchor associated with this node
6060
flow?: boolean // use flow style when stringifying this
6161
schema?: Schema
62-
addIn(path: Iterable<unknown>, value: unknown): void
62+
addIn(path: unknown[], value: unknown): void
6363
clone(schema?: Schema): NodeBase // a deep copy of this collection
64-
deleteIn(path: Iterable<unknown>): boolean
65-
getIn(path: Iterable<unknown>, keepScalar?: boolean): unknown
66-
hasIn(path: Iterable<unknown>): boolean
67-
setIn(path: Iterable<unknown>, value: unknown): void
64+
deleteIn(path: unknown[]): boolean
65+
getIn(path: unknown[], keepScalar?: boolean): unknown
66+
hasIn(path: unknown[]): boolean
67+
setIn(path: unknown[], value: unknown): void
6868
}
6969

7070
class YAMLMap<K = unknown, V = unknown> extends Collection {
@@ -87,8 +87,8 @@ class YAMLSeq<T = unknown> extends Collection {
8787
```
8888
8989
Within all YAML documents, two forms of collections are supported: sequential `YAMLSeq` collections and key-value `YAMLMap` collections.
90-
The JavaScript representations of these collections both have an `items` array, which may (`YAMLSeq`) or must (`YAMLMap`) consist of `Pair` objects that contain a `key` and a `value` of any type, including `null`.
91-
The `items` array of a `YAMLSeq` object may contain values of any type.
90+
The JavaScript representations of these collections both have an `items` array, which may (`YAMLSeq`) or must (`YAMLMap`) consist of `Pair` objects that contain a `key` and a `value` of any node type, or `null` for `value`.
91+
The `items` array of a `YAMLSeq` object may contain any node values.
9292
9393
When stringifying collections, by default block notation will be used.
9494
Flow notation will be selected if `flow` is `true`, the collection is within a surrounding flow collection, or if the collection is in an implicit key.
@@ -169,7 +169,7 @@ When nodes are constructed from JS structures (e.g. during `YAML.stringify()`),
169169
```js
170170
const doc = new YAML.Document(['some', 'values'])
171171
// Document {
172-
// contents:
172+
// value:
173173
// YAMLSeq {
174174
// items:
175175
// [ Scalar { value: 'some' },
@@ -209,8 +209,7 @@ For all available options, see the [CreateNode Options](#createnode-options) sec
209209
[replacer]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter
210210
211211
The primary purpose of this method is to enable attaching comments or other metadata to a value, or to otherwise exert more fine-grained control over the stringified output.
212-
To that end, you'll need to assign its return value to the `contents` of a document (or somewhere within said contents), as the document's schema is required for YAML string output.
213-
If you're not interested in working with such metadata, document `contents` may also include non-`Node` values at any level.
212+
To that end, you'll need to assign its return value to the `value` of a document (or somewhere within said value), as the document's schema is required for YAML string output.
214213
215214
<h4 style="clear:both"><code>doc.createAlias(node, name?): Alias</code></h4>
216215
@@ -236,12 +235,11 @@ You should make sure to only add alias nodes to the document after the nodes to
236235
```js
237236
import { Document, YAMLSeq } from 'yaml'
238237

239-
const doc = new Document(new YAMLSeq())
240-
doc.contents.items = [
238+
const doc = new Document([
241239
'some values',
242240
42,
243241
{ including: 'objects', 3: 'a string' }
244-
]
242+
])
245243
doc.add(doc.createPair(1, 'a number'))
246244

247245
doc.toString()
@@ -320,7 +318,7 @@ The return value of the visitor may be used to control the traversal:
320318
- `number`: While iterating the items of a sequence or map, set the index of the next step.
321319
This is useful especially if the index of the current node has changed.
322320
323-
If `visitor` is a single function, it will be called with all values encountered in the tree, including e.g. `null` values.
321+
If `visitor` is a single function, it will be called with all values encountered in the tree, including `null` values.
324322
Alternatively, separate visitor functions may be defined for each `Map`, `Pair`, `Seq`, `Alias` and `Scalar` node.
325323
To define the same visitor function for more than one node type,
326324
use the `Collection` (map and seq), `Value` (map, seq & scalar) and `Node` (alias, map, seq & scalar) targets.
@@ -332,51 +330,6 @@ The same as `visit()`,
332330
but allows for visitor functions that return a promise
333331
which resolves to one of the above-defined control values.
334332
335-
## Identifying Node Types
336-
337-
```js
338-
import {
339-
isAlias,
340-
isCollection, // map or seq
341-
isDocument,
342-
isMap,
343-
isNode, // alias, scalar, map or seq
344-
isPair,
345-
isScalar,
346-
isSeq
347-
} from 'yaml'
348-
349-
const doc = new Document({ foo: [13, 42] })
350-
isDocument(doc) === true
351-
isNode(doc) === false
352-
isMap(doc.contents) === true
353-
isNode(doc.contents) === true
354-
isPair(doc.contents.items[0]) === true
355-
isCollection(doc.get('foo')) === true
356-
isScalar(doc.getIn(['foo', 1])) === true
357-
```
358-
359-
#### `isAlias(x: unknown): boolean`
360-
361-
#### `isCollection(x: unknown): boolean`
362-
363-
#### `isDocument(x: unknown): boolean`
364-
365-
#### `isMap(x: unknown): boolean`
366-
367-
#### `isNode(x: unknown): boolean`
368-
369-
#### `isPair(x: unknown): boolean`
370-
371-
#### `isScalar(x: unknown): boolean`
372-
373-
#### `isSeq(x: unknown): boolean`
374-
375-
To find out what you've got, a family of custom type guard functions is provided.
376-
These should be preferred over other methods such as `instanceof` checks, as they'll work even if the nodes have been created by a different instance of the library.
377-
378-
Internally, node identification uses property symbols that are set on instances during their construction.
379-
380333
## Comments and Blank Lines
381334
382335
```js

0 commit comments

Comments
 (0)