Skip to content

Commit

Permalink
Create intermediates for set() & setIn() on doc with empty contents (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed Aug 23, 2020
1 parent f4f1919 commit fac33b1
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 14 deletions.
16 changes: 8 additions & 8 deletions docs/05_content_nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ The `yaml-1.1` schema includes [additional collections](https://yaml.org/type/in

All of the collections provide the following accessor methods:

| Method | Returns | Description |
| --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| add(value) | `void` | Adds a value to the collection. For `!!map` and `!!omap` the value must be a Pair instance or a `{ key, value }` object, which may not have a key that already exists in the map. |
| delete(key) | `boolean` | Removes a value from the collection. Returns `true` if the item was found and removed. |
| get(key, [keepScalar]) | `any` | Returns item at `key`, or `undefined` if not found. By default unwraps scalar values from their surrounding node; to disable set `keepScalar` to `true` (collections are always returned intact). |
| has(key) | `boolean` | Checks if the collection includes a value with the key `key`. |
| set(key, value) | `any` | Sets a value in this collection. For `!!set`, `value` needs to be a boolean to add/remove the item from the set. When overwriting a `Scalar` value with a scalar, the original node is retained. |
| Method | Returns | Description |
| ----------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| add(value), addIn(path, value) | `void` | Adds a value to the collection. For `!!map` and `!!omap` the value must be a Pair instance or a `{ key, value }` object, which may not have a key that already exists in the map. |
| delete(key), deleteIn(path) | `boolean` | Removes a value from the collection. Returns `true` if the item was found and removed. |
| get(key, [keep]), getIn(path, [keep]) | `any` | Returns value at `key`, or `undefined` if not found. By default unwraps scalar values from their surrounding node; to disable set `keep` to `true` (collections are always returned intact). |
| has(key), hasIn(path) | `boolean` | Checks if the collection includes a value with the key `key`. |
| set(key, value), setIn(path, value) | `any` | Sets a value in this collection. For `!!set`, `value` needs to be a boolean to add/remove the item from the set. When overwriting a `Scalar` value with a scalar, the original node is retained. |

<!-- prettier-ignore -->
```js
Expand All @@ -92,7 +92,7 @@ doc.hasIn(['b', '0']) // true

For all of these methods, the keys may be nodes or their wrapped scalar values (i.e. `42` will match `Scalar { value: 42 }`) . Keys for `!!seq` should be positive integers, or their string representations. `add()` and `set()` do not automatically call `doc.createNode()` to wrap the value.

Each of the methods also has a variant that requires an iterable as the first parameter, and allows fetching or modifying deeper collections: `addIn(path, value)`, `deleteIn(path)`, `getIn(path, keepScalar)`, `hasIn(path)`, `setIn(path, value)`. If any intermediate node in `path` is a scalar rather than a collection, an error will be thrown. If any of the intermediate collections is not found:
Each of the methods also has a variant that requires an iterable as the first parameter, and allows fetching or modifying deeper collections. If any intermediate node in `path` is a scalar rather than a collection, an error will be thrown. If any of the intermediate collections is not found:

- `getIn` and `hasIn` will return `undefined` or `false` (respectively)
- `addIn` and `setIn` will create missing collections; non-negative integer keys will create sequences, all other keys create maps
Expand Down
2 changes: 1 addition & 1 deletion src/ast/Collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createNode } from '../doc/createNode.js'
import { Node } from './Node.js'
import { Scalar } from './Scalar.js'

function collectionFromPath(schema, path, value) {
export function collectionFromPath(schema, path, value) {
let v = value
for (let i = path.length - 1; i >= 0; --i) {
const k = path[i]
Expand Down
2 changes: 1 addition & 1 deletion src/ast/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { Alias } from './Alias.js'
export { Collection, isEmptyPath } from './Collection.js'
export { Collection, collectionFromPath, isEmptyPath } from './Collection.js'
export { Merge } from './Merge.js'
export { Node } from './Node.js'
export { Pair } from './Pair.js'
Expand Down
15 changes: 12 additions & 3 deletions src/doc/Document.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Node,
Pair,
Scalar,
collectionFromPath,
isEmptyPath,
toJSON
} from '../ast/index.js'
Expand Down Expand Up @@ -147,13 +148,21 @@ export class Document {
}

set(key, value) {
assertCollection(this.contents)
this.contents.set(key, value)
if (this.contents == null) {
this.setSchema()
this.contents = collectionFromPath(this.schema, [key], value)
} else {
assertCollection(this.contents)
this.contents.set(key, value)
}
}

setIn(path, value) {
if (isEmptyPath(path)) this.contents = value
else {
else if (this.contents == null) {
this.setSchema()
this.contents = collectionFromPath(this.schema, path, value)
} else {
assertCollection(this.contents)
this.contents.setIn(path, value)
}
Expand Down
10 changes: 9 additions & 1 deletion tests/doc/collection-access.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('Map', () => {
test('set scalar node with anchor', () => {
doc = YAML.parseDocument('a: &A value\nb: *A\n')
doc.set('a', 'foo')
expect(doc.get('a',true)).toMatchObject({ value: 'foo' })
expect(doc.get('a', true)).toMatchObject({ value: 'foo' })
expect(String(doc)).toBe('a: &A foo\nb: *A\n')
})
})
Expand Down Expand Up @@ -464,6 +464,10 @@ describe('Document', () => {

doc.contents = doc.createNode('s')
expect(() => doc.set('a', 1)).toThrow(/document contents/)

doc.contents = null
doc.set('a', 1)
expect(doc.get('a')).toBe(1)
})

test('setIn', () => {
Expand All @@ -485,5 +489,9 @@ describe('Document', () => {

doc.contents = doc.createNode('s')
expect(() => doc.setIn(['a'], 1)).toThrow(/document contents/)

doc.contents = null
doc.setIn(['a', 2], 1)
expect(doc.get('a')).toMatchObject({ items: [null, null, 1] })
})
})

0 comments on commit fac33b1

Please sign in to comment.