Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor parsing completely #203

Merged
merged 90 commits into from Feb 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
6c8eee2
Add TokenStream
eemeli Sep 20, 2020
c36150b
Add token type identifier
eemeli Sep 26, 2020
0e19aa2
Add DocStream
eemeli Sep 26, 2020
3846ac8
Refactor: Lexer -> Parser -> ParseStream
eemeli Sep 27, 2020
d258b35
Push rather than throw errors
eemeli Sep 27, 2020
17c9b4b
lexer: Harmonise scalar unindent/doc-end detection
eemeli Sep 27, 2020
eebbe89
lexer: Fix indent handling for maps in sequences
eemeli Sep 27, 2020
69ca08d
Add some d.ts files next to their js sources, for now copying content…
eemeli Sep 28, 2020
b270dfb
Refactor & fix type declarations
eemeli Oct 3, 2020
fdd0971
Add initial dev-only build for mixed JS+TS sources
eemeli Oct 3, 2020
6fc22cb
Add StreamDirectives
eemeli Oct 3, 2020
9d09709
Add composeScalar() + scalar value folding
eemeli Oct 3, 2020
c409eee
Split src/stream/ into src/{parse,compose}/
eemeli Oct 4, 2020
b59e930
Add optional onNewLine(offset) callback to parser
eemeli Oct 4, 2020
3041d04
lexer: Require more indent in top-level mapping values
eemeli Oct 4, 2020
e4d2de3
Add starting offset to all block & flow tokens
eemeli Oct 4, 2020
b2ca63f
Refactor scalar composition to also determine node [start, end) range
eemeli Oct 4, 2020
54e9d2e
Refactor compose error callback to always use offset from beginning o…
eemeli Oct 4, 2020
3e61321
Start on supporting collection composition, with block sequences
eemeli Oct 4, 2020
37004ce
Add initial block mapping composition, refactoring around it
eemeli Oct 4, 2020
ba7ef7b
lexer: Fix for lines without value
eemeli Oct 5, 2020
94942b5
parser: Start new document on doc-start after content
eemeli Oct 5, 2020
153f816
Add document composition, with test wrapper at compose/parse-docs
eemeli Oct 5, 2020
99f27ce
Overload token arg of composeNode() for empty node support
eemeli Oct 24, 2020
4a1d99b
Prop resolution fixes
eemeli Dec 5, 2020
217f9fe
Add initial flow collection composition
eemeli Dec 5, 2020
f3a51f8
Fix config to allow TS sources in tests
eemeli Dec 9, 2020
1b037f0
Add minimal scaffold for using stream parser via old API
eemeli Dec 9, 2020
c21b375
Add directives to Document, use for proper tag names
eemeli Dec 14, 2020
ac36361
Refactor index.js as index.ts & adjust scripts accordingly
eemeli Dec 14, 2020
7cff090
Use LOG_TOKENS and LOG_STREAM env vars to control debug prints
eemeli Dec 14, 2020
3443d08
Add & use a new Node.Parsed interface when range is known
eemeli Dec 14, 2020
138087c
Make Collection schema not enumerable to hide it from logging
eemeli Dec 14, 2020
2fc9e65
Handle composition of all supported collections, not just map & seq
eemeli Dec 14, 2020
88ca375
Return null from parse() & parseDocument() for empty input
eemeli Dec 15, 2020
a8fe00f
Fix various bugs
eemeli Dec 15, 2020
264c1c5
Adjust tests
eemeli Dec 15, 2020
d5d3542
Fix some map parsing cases
eemeli Dec 20, 2020
f7a89a9
Allow flow collections to grab line-end comments & act as implicit ma…
eemeli Dec 20, 2020
51f9615
Drop YAML 1.0 tests
eemeli Dec 21, 2020
2401304
Resolve merge pairs
eemeli Dec 28, 2020
4fce392
Fix alias parsing
eemeli Dec 28, 2020
4ae6927
Ensure Anchors#setAnchor() follows its documented behaviour
eemeli Dec 28, 2020
f68fc4f
Fix top-level block scalar parsing
eemeli Dec 28, 2020
ec6835d
Lexer fixes: Empty scalars, tabs, cr-lf after plain, colon after plai…
eemeli Dec 30, 2020
93975fa
Add strict option (default true), to allow being less pedantic
eemeli Jan 1, 2021
182a2de
Loads of debugging for various tests
eemeli Jan 1, 2021
b3a9783
Assign map & first-key props correctly
eemeli Jan 1, 2021
0f84d86
Include offset in error tokens where possible
eemeli Jan 2, 2021
3f0d5ec
Fix block-scalar indentation control
eemeli Jan 2, 2021
26c3a52
Require space before comment
eemeli Jan 2, 2021
1472244
Allow skipping some yaml-test-suite tests
eemeli Jan 2, 2021
5ff783d
Drop Document method listNonDefaultTags()
eemeli Jan 2, 2021
afe6ac6
Use doc.directives.tags rather than doc.tagPrefixes
eemeli Jan 2, 2021
05f5c75
Loads more debugging for various tests
eemeli Jan 3, 2021
dbe74f1
Refactor doc-end parsing
eemeli Jan 3, 2021
d4b3276
Miscellaneous debugging
eemeli Jan 3, 2021
14585f5
Check for outer block indent when parsing flow collections
eemeli Jan 6, 2021
8e722ff
Fix tests to expect new error message strings
eemeli Jan 6, 2021
2be7e80
Refactor directives to support version-specific behaviour
eemeli Jan 9, 2021
816db58
Allow for byte-order-mark in stream
eemeli Jan 9, 2021
fb1a65a
Refactor parseDocs() into composeStream(), adding empty-stream handling
eemeli Jan 9, 2021
f16333d
Fix bugs, mostly with tag parsing and error reporting
eemeli Jan 9, 2021
70bb49c
Check implicit key lengths, refactoring also contains-newline check
eemeli Jan 9, 2021
2d63b15
Improve null value printing
eemeli Jan 9, 2021
0f5bf20
Bugfixes, mostly for comment & whitespace handling
eemeli Jan 9, 2021
5e8ad7e
Fix document comment parsing; add directives to EmptyStream
eemeli Jan 10, 2021
8587841
Assign collection comments separated by empty line to preceding node
eemeli Jan 24, 2021
eebde3c
Do not include trailing lines for strip & clip chomped block scalars
eemeli Jan 24, 2021
20f4220
Grab trailing less-indented comments from inner block map/seq to parent
eemeli Jan 24, 2021
bb211fc
ci: Tweak GitHub Action workflow, for now skipping browser & dist tests
eemeli Jan 24, 2021
88b6cbd
Rename files in src/parse/, mark class private members as such
eemeli Jan 30, 2021
20ced9c
Merge branch 'master' into stream
eemeli Jan 31, 2021
2bfb11c
Refactor visit() as TypeScript
eemeli Jan 31, 2021
87e0e23
Include source string value for all scalars
eemeli Jan 31, 2021
db96f63
Use new parser for test-events; fix bugs as needed
eemeli Jan 31, 2021
fec3ca0
Drop Document#parse(cst) method
eemeli Jan 31, 2021
15f8871
Only test for default tag matches when stringifying a string
eemeli Feb 1, 2021
dd0198e
Drop all code in src/resolve/ as unused
eemeli Feb 1, 2021
f9451ef
Drop all code in & references to src/cst/ as obsolete
eemeli Feb 7, 2021
beb8d8b
Drop YAMLReferenceError, YAMLSemanticError & YAMLSyntaxError in favou…
eemeli Feb 7, 2021
0e7ea1c
Refactor errors.js as TypeScript
eemeli Feb 7, 2021
5bc1066
Refactor composeStream function into Composer class
eemeli Feb 8, 2021
bcc0420
Add lineCounter option to parse methods & LineCounter class
eemeli Feb 8, 2021
a6d9bcf
Re-rename CSTParser as just Parser
eemeli Feb 12, 2021
9dd0cb1
Add exports & API docs for Lexer, Parser & Composer
eemeli Feb 12, 2021
cef8489
Refactor options & tags/options as TypeScript
eemeli Feb 13, 2021
ff8bdca
Include TS support in Node.js & browser builds; drop separate dev build
eemeli Feb 13, 2021
3ac4a33
ci: Re-enable browser & dist tests
eemeli Feb 13, 2021
d1e59c5
Drop example/test files from src/parse/
eemeli Feb 13, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
@@ -1,6 +1,7 @@
/browser/
/dist/
/docs-slate/
/lib/
/package-lock.json
/playground/dist/
/tests/yaml-test-suite/
8 changes: 5 additions & 3 deletions .github/workflows/nodejs.yml
@@ -1,9 +1,11 @@
name: Node.js

on:
- pull_request
- push
- workflow_dispatch
pull_request:
branches: [master]
push:
branches: [master]
workflow_dispatch:

jobs:
test:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
.*
coverage/
dist/
lib/
node_modules/
5 changes: 4 additions & 1 deletion babel.config.js
Expand Up @@ -7,4 +7,7 @@ module.exports = {
}

if (process.env.NODE_ENV === 'test')
module.exports.presets = [['@babel/env', { targets: { node: 'current' } }]]
module.exports.presets = [
['@babel/env', { targets: { node: 'current' } }],
'@babel/preset-typescript'
]
185 changes: 0 additions & 185 deletions cst.d.ts

This file was deleted.

1 change: 1 addition & 0 deletions docs/03_options.md
Expand Up @@ -39,6 +39,7 @@ The `version` option value (`'1.2'` by default) may be overridden by any documen
| schema | `'core' ⎮ 'failsafe' ⎮` `'json' ⎮ 'yaml-1.1'` | The base schema to use. By default `'core'` for YAML 1.2 and `'yaml-1.1'` for earlier versions. |
| simpleKeys | `boolean` | When stringifying, require keys to be scalars and to use implicit rather than explicit notation. By default `false`. |
| sortMapEntries | `boolean ⎮` `(a, b: Pair) => number` | When stringifying, sort map entries. If `true`, sort by comparing key values with `<`. By default `false`. |
| strict | `boolean` | When parsing, do not ignore errors required by the YAML 1.2 spec, but caused by unambiguous content. By default `true`. |
| version | `'1.0' ⎮ '1.1' ⎮ '1.2'` | The YAML version used by documents without a `%YAML` directive. By default `'1.2'`. |

[exponential entity expansion attacks]: https://en.wikipedia.org/wiki/Billion_laughs_attack
Expand Down
13 changes: 9 additions & 4 deletions docs/04_documents.md
Expand Up @@ -102,7 +102,6 @@ During stringification, a document with a true-ish `version` value will include
| ------------------------------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| createNode(value,&nbsp;options?) | `Node` | Recursively wrap any input with appropriate `Node` containers. See [Creating Nodes](#creating-nodes) for more information. |
| createPair(key,&nbsp;value,&nbsp;options?) | `Pair` | Recursively wrap `key` and `value` into a `Pair` object. See [Creating Nodes](#creating-nodes) for more information. |
| listNonDefaultTags() | `string[]` | List the tags used in the document that are not in the default `tag:yaml.org,2002:` namespace. |
| 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. |
Expand Down Expand Up @@ -162,7 +161,7 @@ A description of [alias and merge nodes](#alias-nodes) is included in the next s
| getNames() | `string[]` | List of all defined anchor names. |
| getNode(name: string) | `Node?` | The node associated with the anchor `name`, if set. |
| newName(prefix: string) | `string` | Find an available anchor name with the given `prefix` and a numerical suffix. |
| setAnchor(node: Node, name?: string) | `string?` | Associate an anchor with `node`. If `name` is empty, a new name will be generated. |
| setAnchor(node?: Node, name?: string) | `string?` | Associate an anchor with `node`. If `name` is empty, a new name will be generated. |

```js
const src = '[{ a: A }, { b: B }]'
Expand Down Expand Up @@ -208,8 +207,14 @@ String(doc)
// ]
```

The constructors for `Alias` and `Merge` are not directly exported by the library, as they depend on the document's anchors; instead you'll need to use **`createAlias(node, name)`** and **`createMergePair(...sources)`**. You should make sure to only add alias and merge nodes to the document after the nodes to which they refer, or the document's YAML stringification will fail.
The constructors for `Alias` and `Merge` are not directly exported by the library, as they depend on the document's anchors; instead you'll need to use **`createAlias(node, name)`** and **`createMergePair(...sources)`**.
You should make sure to only add alias and merge nodes to the document after the nodes to which they refer, or the document's YAML stringification will fail.

It is valid to have an anchor associated with a node even if it has no aliases. `yaml` will not allow you to associate the same name with more than one node, even though this is allowed by the YAML spec (all but the last instance will have numerical suffixes added). To add or reassign an anchor, use **`setAnchor(node, name)`**. The second parameter is optional, and if left out either the pre-existing anchor name of the node will be used, or a new one generated. To remove an anchor, use `setAnchor(null, name)`. The function will return the new anchor's name, or `null` if both of its arguments are `null`.
It is valid to have an anchor associated with a node even if it has no aliases.
`yaml` will not allow you to associate the same name with more than one node, even though this is allowed by the YAML spec (all but the last instance will have numerical suffixes added).
To add or reassign an anchor, use **`setAnchor(node, name)`**.
The second parameter is optional, and if left out either the pre-existing anchor name of the node will be used, or a new one generated.
To remove an anchor, use `setAnchor(null, name)`.
The function will return the new anchor's name, or `null` if both of its arguments are `null`.

While the `merge` option needs to be true to parse `Merge` nodes as such, this is not required during stringification.
2 changes: 1 addition & 1 deletion docs/06_custom_tags.md
Expand Up @@ -132,7 +132,7 @@ import {
stringifyString, // (node, ctx, ...) => string
toJS, // (value, arg, ctx) => any -- Recursively convert to plain JS
Type, // { [string]: string } -- Used as enum for node types
YAMLReferenceError, YAMLSemanticError, YAMLSyntaxError, YAMLWarning
YAMLError, YAMLParseError, YAMLWarning
} from 'yaml/util'
```

Expand Down
24 changes: 8 additions & 16 deletions docs/08_errors.md
Expand Up @@ -2,13 +2,13 @@

Nearly all errors and warnings produced by the `yaml` parser functions contain the following fields:

| Member | Type | Description |
| ------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | `string` | One of `YAMLReferenceError`, `YAMLSemanticError`, `YAMLSyntaxError`, or `YAMLWarning` |
| message | `string` | A human-readable description of the error |
| source | `CST Node` | The CST node at which this error or warning was encountered. Note that in particular `source.context` is likely to be a complex object and include some circular references. |
| Member | Type | Description |
| ------- | -------- | ------------------------------------------------------------------------ |
| name | `string` | Either `YAMLParseError` or `YAMLWarning` |
| message | `string` | A human-readable description of the error |
| offset | `number` | The offset in the source at which this error or warning was encountered. |

If the `prettyErrors` option is enabled, `source` is dropped from the errors and the following fields are added with summary information regarding the error's source node, if available:
If the `prettyErrors` option is enabled, the following fields are added with summary information regarding the error's source node, if available:

| Member | Type | Description |
| -------- | ----------------------------------- | --------------------------------------------------------------------------------------------- |
Expand All @@ -18,17 +18,9 @@ If the `prettyErrors` option is enabled, `source` is dropped from the errors and

In rare cases, the library may produce a more generic error. In particular, `TypeError` may occur when parsing invalid input using the `json` schema, and `ReferenceError` when the `maxAliasCount` limit is enountered.

## YAMLReferenceError
## YAMLParseError

An error resolving a tag or an anchor that is referred to in the source. It is likely that the contents of the `source` node have not been completely parsed into the document. Not used by the CST parser.

## YAMLSemanticError

An error related to the metadata of the document, or an error with limitations imposed by the YAML spec. The data contents of the document should be valid, but the metadata may be broken.

## YAMLSyntaxError

A serious parsing error; the document contents will not be complete, and the CST is likely to be rather broken.
An error encountered while parsing a source as YAML.

## YAMLWarning

Expand Down
22 changes: 5 additions & 17 deletions index.d.ts
@@ -1,4 +1,3 @@
import { CST } from './cst'
import {
AST,
Alias,
Expand All @@ -13,13 +12,7 @@ import {
} from './types'
import { Type, YAMLError, YAMLWarning } from './util'

export { AST, CST }

export function parseCST(str: string): ParsedCST

export interface ParsedCST extends Array<CST.Document> {
setOrigRanges(): boolean
}
export { AST }

/**
* Apply a visitor to an AST node or document.
Expand Down Expand Up @@ -160,7 +153,7 @@ export interface Options extends Schema.Options {
*
* Default: `"1.2"`
*/
version?: '1.0' | '1.1' | '1.2'
version?: '1.1' | '1.2'
}

/**
Expand Down Expand Up @@ -294,7 +287,7 @@ export interface CreateNodeOptions {
}

export class Document extends Collection {
cstNode?: CST.Document
// cstNode?: CST.Document
/**
* @param value - The initial value for the document, which will be wrapped
* in a Node container.
Expand Down Expand Up @@ -347,13 +340,7 @@ export class Document extends Collection {
* `Scalar` objects.
*/
createPair(key: any, value: any, options?: { wrapScalars?: boolean }): Pair
/**
* List the tags used in the document that are not in the default
* `tag:yaml.org,2002:` namespace.
*/
listNonDefaultTags(): string[]
/** Parse a CST into this document */
parse(cst: CST.Document): this

/**
* When a document is created with `new YAML.Document()`, the schema object is
* not set as it may be influenced by parsed directives; call this with no
Expand Down Expand Up @@ -394,6 +381,7 @@ export class Document extends Collection {
export namespace Document {
interface Parsed extends Document {
contents: Scalar | YAMLMap | YAMLSeq | null
range: [number, number]
/** The schema used with the document. */
schema: Schema
}
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Expand Up @@ -31,8 +31,9 @@ switch (process.env.npm_lifecycle_event) {
module.exports = {
collectCoverageFrom: ['src/**/*.js'],
moduleNameMapper,
resolver: 'jest-ts-webcompat-resolver',
testEnvironment: 'node',
testMatch: ['**/tests/**/*.js'],
testPathIgnorePatterns,
transform: { '/(src|tests)/.*\\.js$': 'babel-jest' }
transform: { '/(src|tests)/.*\\.(js|ts)$': 'babel-jest' }
}