https://project.mdnd-it.cc/work_packages/94
This commit is contained in:
2025-08-23 04:25:28 +02:00
parent 725516ad6c
commit 19cfa031d0
25823 changed files with 1095587 additions and 2801760 deletions
+13
View File
@@ -0,0 +1,13 @@
Copyright 2018 Eemeli Aro <eemeli@gmail.com>
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.
+126
View File
@@ -0,0 +1,126 @@
# YAML <a href="https://www.npmjs.com/package/yaml"><img align="right" src="https://badge.fury.io/js/yaml.svg" title="npm package" /></a>
`yaml` is a JavaScript parser and stringifier for [YAML](http://yaml.org/), a human friendly data serialization standard. It supports both parsing and stringifying data using all versions of YAML, along with all common data schemas. As a particularly distinguishing feature, `yaml` fully supports reading and writing comments and blank lines in YAML documents.
The library is released under the ISC open source license, and the code is [available on GitHub](https://github.com/eemeli/yaml/). It has no external dependencies and runs on Node.js 6 and later, and in browsers from IE 11 upwards.
For the purposes of versioning, any changes that break any of the endpoints or APIs documented here will be considered semver-major breaking changes. Undocumented library internals may change between minor versions, and previous APIs may be deprecated (but not removed).
For more information, see the project's documentation site: [**eemeli.org/yaml**](https://eemeli.org/yaml/)
To install:
```sh
npm install yaml@next
```
**Note:** These docs are for `yaml@2`. For v1, see the [v1.10.0 tag](https://github.com/eemeli/yaml/tree/v1.10.0) for the source and [eemeli.org/yaml/v1](https://eemeli.org/yaml/v1/) for the documentation.
## API Overview
The API provided by `yaml` has three layers, depending on how deep you need to go: [Parse & Stringify](https://eemeli.org/yaml/#parse-amp-stringify), [Documents](https://eemeli.org/yaml/#documents), and the [CST Parser](https://eemeli.org/yaml/#cst-parser). The first has the simplest API and "just works", the second gets you all the bells and whistles supported by the library along with a decent [AST](https://eemeli.org/yaml/#content-nodes), and the third is the closest to YAML source, making it fast, raw, and crude.
```js
import YAML from 'yaml'
// or
const YAML = require('yaml')
```
### Parse & 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, replacer?, options?)`](https://eemeli.org/yaml/#creating-documents)
- [`defaults`](https://eemeli.org/yaml/#options)
- [`#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)
```js
import { Pair, YAMLMap, YAMLSeq } from 'yaml/types'
```
- [`new Pair(key, value)`](https://eemeli.org/yaml/#creating-nodes)
- [`new YAMLMap()`](https://eemeli.org/yaml/#creating-nodes)
- [`new YAMLSeq()`](https://eemeli.org/yaml/#creating-nodes)
### CST Parser
```js
import parseCST from 'yaml/parse-cst'
```
- [`parseCST(str): CSTDocument[]`](https://eemeli.org/yaml/#parsecst)
- [`YAML.parseCST(str): CSTDocument[]`](https://eemeli.org/yaml/#parsecst)
## YAML.parse
```yaml
# file.yml
YAML:
- A human-readable data serialization language
- https://en.wikipedia.org/wiki/YAML
yaml:
- A complete JavaScript implementation
- https://www.npmjs.com/package/yaml
```
```js
import fs from 'fs'
import YAML from 'yaml'
YAML.parse('3.14159')
// 3.14159
YAML.parse('[ true, false, maybe, null ]\n')
// [ true, false, 'maybe', null ]
const file = fs.readFileSync('./file.yml', 'utf8')
YAML.parse(file)
// { YAML:
// [ 'A human-readable data serialization language',
// 'https://en.wikipedia.org/wiki/YAML' ],
// yaml:
// [ 'A complete JavaScript implementation',
// 'https://www.npmjs.com/package/yaml' ] }
```
## YAML.stringify
```js
import YAML from 'yaml'
YAML.stringify(3.14159)
// '3.14159\n'
YAML.stringify([true, false, 'maybe', null])
// `- true
// - false
// - maybe
// - null
// `
YAML.stringify({ number: 3, plain: 'string', block: 'two\nlines\n' })
// `number: 3
// plain: string
// block: |
// two
// lines
// `
```
---
Browser testing provided by:
<a href="https://www.browserstack.com/open-source">
<img width=200 src="https://eemeli.org/yaml/images/browserstack.svg" />
</a>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
import './errors-2634d01a.js';
export { p as parse } from './parse-d1ba890f.js';
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
import './errors-2634d01a.js';
export { A as Alias, C as Collection, N as Node, P as Pair, S as Scalar, d as YAMLMap, Y as YAMLSeq, b as binaryOptions, a as boolOptions, i as intOptions, n as nullOptions, s as strOptions } from './stringifyNumber-d8af95b1.js';
export { M as Merge, S as Schema } from './Schema-ea978338.js';
+2
View File
@@ -0,0 +1,2 @@
export { T as Type, k as YAMLError, j as YAMLReferenceError, Y as YAMLSemanticError, i as YAMLSyntaxError, g as YAMLWarning } from './errors-2634d01a.js';
export { l as findPair, k as stringifyNumber, c as stringifyString, t as toJS } from './stringifyNumber-d8af95b1.js';
+1
View File
@@ -0,0 +1 @@
module.exports = require('./dist')
+1
View File
@@ -0,0 +1 @@
module.exports = require('./dist/parse-cst').parse
+1
View File
@@ -0,0 +1 @@
export * from './dist/types.js'
+1
View File
@@ -0,0 +1 @@
export * from './dist/util.js'
File diff suppressed because it is too large Load Diff
+934
View File
@@ -0,0 +1,934 @@
'use strict';
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-eed30217.js');
var stringifyNumber = require('./stringifyNumber-dea1120c.js');
const MERGE_KEY = '<<';
class Merge extends stringifyNumber.Pair {
constructor(pair) {
if (pair instanceof stringifyNumber.Pair) {
let seq = pair.value;
if (!(seq instanceof stringifyNumber.YAMLSeq)) {
seq = new stringifyNumber.YAMLSeq();
seq.items.push(pair.value);
seq.range = pair.value.range;
}
super(pair.key, seq);
this.range = pair.range;
} else {
super(new stringifyNumber.Scalar(MERGE_KEY), new stringifyNumber.YAMLSeq());
}
this.type = stringifyNumber.Pair.Type.MERGE_PAIR;
} // If the value associated with a merge key is a single mapping node, each of
// its key/value pairs is inserted into the current mapping, unless the key
// already exists in it. If the value associated with the merge key is a
// sequence, then this sequence is expected to contain mapping nodes and each
// of these nodes is merged in turn according to its order in the sequence.
// Keys in mapping nodes earlier in the sequence override keys specified in
// later mapping nodes. -- http://yaml.org/type/merge.html
addToJSMap(ctx, map) {
for (const {
source
} of this.value.items) {
if (!(source instanceof stringifyNumber.YAMLMap)) throw new Error('Merge sources must be maps');
const srcMap = source.toJSON(null, ctx, Map);
for (const [key, value] of srcMap) {
if (map instanceof Map) {
if (!map.has(key)) map.set(key, value);
} else if (map instanceof Set) {
map.add(key);
} else if (!Object.prototype.hasOwnProperty.call(map, key)) {
Object.defineProperty(map, key, {
value,
writable: true,
enumerable: true,
configurable: true
});
}
}
}
return map;
}
toString(ctx, onComment) {
const seq = this.value;
if (seq.items.length > 1) return super.toString(ctx, onComment);
this.value = seq.items[0];
const str = super.toString(ctx, onComment);
this.value = seq;
return str;
}
}
function createMap(schema, obj, ctx) {
const {
keepUndefined,
replacer
} = ctx;
const map = new stringifyNumber.YAMLMap(schema);
const add = (key, value) => {
if (typeof replacer === 'function') value = replacer.call(obj, key, value);else if (Array.isArray(replacer) && !replacer.includes(key)) return;
if (value !== undefined || keepUndefined) map.items.push(stringifyNumber.createPair(key, value, ctx));
};
if (obj instanceof Map) {
for (const [key, value] of obj) add(key, value);
} else if (obj && typeof obj === 'object') {
for (const key of Object.keys(obj)) add(key, obj[key]);
}
if (typeof schema.sortMapEntries === 'function') {
map.items.sort(schema.sortMapEntries);
}
return map;
}
const map = {
createNode: createMap,
default: true,
nodeClass: stringifyNumber.YAMLMap,
tag: 'tag:yaml.org,2002:map',
resolve: map => map
};
function createSeq(schema, obj, ctx) {
const {
replacer
} = ctx;
const seq = new stringifyNumber.YAMLSeq(schema);
if (obj && obj[Symbol.iterator]) {
let i = 0;
for (let it of obj) {
if (typeof replacer === 'function') {
const key = obj instanceof Set ? it : String(i++);
it = replacer.call(obj, key, it);
}
seq.items.push(stringifyNumber.createNode(it, null, ctx));
}
}
return seq;
}
const seq = {
createNode: createSeq,
default: true,
nodeClass: stringifyNumber.YAMLSeq,
tag: 'tag:yaml.org,2002:seq',
resolve: seq => seq
};
const string = {
identify: value => typeof value === 'string',
default: true,
tag: 'tag:yaml.org,2002:str',
resolve: str => str,
stringify(item, ctx, onComment, onChompKeep) {
ctx = Object.assign({
actualString: true
}, ctx);
return stringifyNumber.stringifyString(item, ctx, onComment, onChompKeep);
},
options: stringifyNumber.strOptions
};
const failsafe = [map, seq, string];
/* global BigInt */
const intIdentify = value => typeof value === 'bigint' || Number.isInteger(value);
const intResolve = (src, offset, radix) => stringifyNumber.intOptions.asBigInt ? BigInt(src) : parseInt(src.substring(offset), radix);
function intStringify(node, radix, prefix) {
const {
value
} = node;
if (intIdentify(value) && value >= 0) return prefix + value.toString(radix);
return stringifyNumber.stringifyNumber(node);
}
const nullObj = {
identify: value => value == null,
createNode: (schema, value, ctx) => ctx.wrapScalars ? new stringifyNumber.Scalar(null) : null,
default: true,
tag: 'tag:yaml.org,2002:null',
test: /^(?:~|[Nn]ull|NULL)?$/,
resolve: str => {
const node = new stringifyNumber.Scalar(null);
node.sourceStr = str;
return node;
},
options: stringifyNumber.nullOptions,
stringify: ({
sourceStr
}) => sourceStr !== null && sourceStr !== void 0 ? sourceStr : stringifyNumber.nullOptions.nullStr
};
const boolObj = {
identify: value => typeof value === 'boolean',
default: true,
tag: 'tag:yaml.org,2002:bool',
test: /^(?:[Tt]rue|TRUE|[Ff]alse|FALSE)$/,
resolve: str => str[0] === 't' || str[0] === 'T',
options: stringifyNumber.boolOptions,
stringify: ({
value
}) => value ? stringifyNumber.boolOptions.trueStr : stringifyNumber.boolOptions.falseStr
};
const octObj = {
identify: value => intIdentify(value) && value >= 0,
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'OCT',
test: /^0o[0-7]+$/,
resolve: str => intResolve(str, 2, 8),
options: stringifyNumber.intOptions,
stringify: node => intStringify(node, 8, '0o')
};
const intObj = {
identify: intIdentify,
default: true,
tag: 'tag:yaml.org,2002:int',
test: /^[-+]?[0-9]+$/,
resolve: str => intResolve(str, 0, 10),
options: stringifyNumber.intOptions,
stringify: stringifyNumber.stringifyNumber
};
const hexObj = {
identify: value => intIdentify(value) && value >= 0,
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'HEX',
test: /^0x[0-9a-fA-F]+$/,
resolve: str => intResolve(str, 2, 16),
options: stringifyNumber.intOptions,
stringify: node => intStringify(node, 16, '0x')
};
const nanObj = {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
test: /^(?:[-+]?\.(?:inf|Inf|INF|nan|NaN|NAN))$/,
resolve: str => str.slice(-3).toLowerCase() === 'nan' ? NaN : str[0] === '-' ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
stringify: stringifyNumber.stringifyNumber
};
const expObj = {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
format: 'EXP',
test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
resolve: str => parseFloat(str),
stringify: ({
value
}) => Number(value).toExponential()
};
const floatObj = {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
test: /^[-+]?(?:\.[0-9]+|[0-9]+\.[0-9]*)$/,
resolve(str) {
const node = new stringifyNumber.Scalar(parseFloat(str));
const dot = str.indexOf('.');
if (dot !== -1 && str[str.length - 1] === '0') node.minFractionDigits = str.length - dot - 1;
return node;
},
stringify: stringifyNumber.stringifyNumber
};
const core = failsafe.concat([nullObj, boolObj, octObj, intObj, hexObj, nanObj, expObj, floatObj]);
/* global BigInt */
const intIdentify$1 = value => typeof value === 'bigint' || Number.isInteger(value);
const stringifyJSON = ({
value
}) => JSON.stringify(value);
const json = [map, seq, {
identify: value => typeof value === 'string',
default: true,
tag: 'tag:yaml.org,2002:str',
resolve: str => str,
stringify: stringifyJSON
}, {
identify: value => value == null,
createNode: (schema, value, ctx) => ctx.wrapScalars ? new stringifyNumber.Scalar(null) : null,
default: true,
tag: 'tag:yaml.org,2002:null',
test: /^null$/,
resolve: () => null,
stringify: stringifyJSON
}, {
identify: value => typeof value === 'boolean',
default: true,
tag: 'tag:yaml.org,2002:bool',
test: /^true|false$/,
resolve: str => str === 'true',
stringify: stringifyJSON
}, {
identify: intIdentify$1,
default: true,
tag: 'tag:yaml.org,2002:int',
test: /^-?(?:0|[1-9][0-9]*)$/,
resolve: str => stringifyNumber.intOptions.asBigInt ? BigInt(str) : parseInt(str, 10),
stringify: ({
value
}) => intIdentify$1(value) ? value.toString() : JSON.stringify(value)
}, {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
test: /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][-+]?[0-9]+)?$/,
resolve: str => parseFloat(str),
stringify: stringifyJSON
}, {
default: true,
test: /^/,
resolve(str, onError) {
onError(`Unresolved plain scalar ${JSON.stringify(str)}`);
return str;
}
}];
/* global atob, btoa, Buffer */
const binary = {
identify: value => value instanceof Uint8Array,
// Buffer inherits from Uint8Array
default: false,
tag: 'tag:yaml.org,2002:binary',
/**
* Returns a Buffer in node and an Uint8Array in browsers
*
* To use the resulting buffer as an image, you'll want to do something like:
*
* const blob = new Blob([buffer], { type: 'image/jpeg' })
* document.querySelector('#photo').src = URL.createObjectURL(blob)
*/
resolve(src, onError) {
if (typeof Buffer === 'function') {
return Buffer.from(src, 'base64');
} else if (typeof atob === 'function') {
// On IE 11, atob() can't handle newlines
const str = atob(src.replace(/[\n\r]/g, ''));
const buffer = new Uint8Array(str.length);
for (let i = 0; i < str.length; ++i) buffer[i] = str.charCodeAt(i);
return buffer;
} else {
onError('This environment does not support reading binary tags; either Buffer or atob is required');
return src;
}
},
options: stringifyNumber.binaryOptions,
stringify: ({
comment,
type,
value
}, ctx, onComment, onChompKeep) => {
let src;
if (typeof Buffer === 'function') {
src = value instanceof Buffer ? value.toString('base64') : Buffer.from(value.buffer).toString('base64');
} else if (typeof btoa === 'function') {
let s = '';
for (let i = 0; i < value.length; ++i) s += String.fromCharCode(value[i]);
src = btoa(s);
} else {
throw new Error('This environment does not support writing binary tags; either Buffer or btoa is required');
}
if (!type) type = stringifyNumber.binaryOptions.defaultType;
if (type === _rollupPluginBabelHelpers.Type.QUOTE_DOUBLE) {
value = src;
} else {
const {
lineWidth
} = stringifyNumber.binaryOptions;
const n = Math.ceil(src.length / lineWidth);
const lines = new Array(n);
for (let i = 0, o = 0; i < n; ++i, o += lineWidth) {
lines[i] = src.substr(o, lineWidth);
}
value = lines.join(type === _rollupPluginBabelHelpers.Type.BLOCK_LITERAL ? '\n' : ' ');
}
return stringifyNumber.stringifyString({
comment,
type,
value
}, ctx, onComment, onChompKeep);
}
};
function parsePairs(seq, onError) {
if (seq instanceof stringifyNumber.YAMLSeq) {
for (let i = 0; i < seq.items.length; ++i) {
let item = seq.items[i];
if (item instanceof stringifyNumber.Pair) continue;else if (item instanceof stringifyNumber.YAMLMap) {
if (item.items.length > 1) onError('Each pair must have its own sequence indicator');
const pair = item.items[0] || new stringifyNumber.Pair();
if (item.commentBefore) pair.commentBefore = pair.commentBefore ? `${item.commentBefore}\n${pair.commentBefore}` : item.commentBefore;
if (item.comment) pair.comment = pair.comment ? `${item.comment}\n${pair.comment}` : item.comment;
item = pair;
}
seq.items[i] = item instanceof stringifyNumber.Pair ? item : new stringifyNumber.Pair(item);
}
} else onError('Expected a sequence for this tag');
return seq;
}
function createPairs(schema, iterable, ctx) {
const {
replacer
} = ctx;
const pairs = new stringifyNumber.YAMLSeq(schema);
pairs.tag = 'tag:yaml.org,2002:pairs';
let i = 0;
for (let it of iterable) {
if (typeof replacer === 'function') it = replacer.call(iterable, String(i++), it);
let key, value;
if (Array.isArray(it)) {
if (it.length === 2) {
key = it[0];
value = it[1];
} else throw new TypeError(`Expected [key, value] tuple: ${it}`);
} else if (it && it instanceof Object) {
const keys = Object.keys(it);
if (keys.length === 1) {
key = keys[0];
value = it[key];
} else throw new TypeError(`Expected { key: value } tuple: ${it}`);
} else {
key = it;
}
pairs.items.push(stringifyNumber.createPair(key, value, ctx));
}
return pairs;
}
const pairs = {
default: false,
tag: 'tag:yaml.org,2002:pairs',
resolve: parsePairs,
createNode: createPairs
};
class YAMLOMap extends stringifyNumber.YAMLSeq {
constructor() {
super();
_rollupPluginBabelHelpers._defineProperty(this, "add", stringifyNumber.YAMLMap.prototype.add.bind(this));
_rollupPluginBabelHelpers._defineProperty(this, "delete", stringifyNumber.YAMLMap.prototype.delete.bind(this));
_rollupPluginBabelHelpers._defineProperty(this, "get", stringifyNumber.YAMLMap.prototype.get.bind(this));
_rollupPluginBabelHelpers._defineProperty(this, "has", stringifyNumber.YAMLMap.prototype.has.bind(this));
_rollupPluginBabelHelpers._defineProperty(this, "set", stringifyNumber.YAMLMap.prototype.set.bind(this));
this.tag = YAMLOMap.tag;
}
toJSON(_, ctx) {
const map = new Map();
if (ctx && ctx.onCreate) ctx.onCreate(map);
for (const pair of this.items) {
let key, value;
if (pair instanceof stringifyNumber.Pair) {
key = stringifyNumber.toJS(pair.key, '', ctx);
value = stringifyNumber.toJS(pair.value, key, ctx);
} else {
key = stringifyNumber.toJS(pair, '', ctx);
}
if (map.has(key)) throw new Error('Ordered maps must not include duplicate keys');
map.set(key, value);
}
return map;
}
}
_rollupPluginBabelHelpers._defineProperty(YAMLOMap, "tag", 'tag:yaml.org,2002:omap');
function parseOMap(seq, onError) {
const pairs = parsePairs(seq, onError);
const seenKeys = [];
for (const {
key
} of pairs.items) {
if (key instanceof stringifyNumber.Scalar) {
if (seenKeys.includes(key.value)) {
onError(`Ordered maps must not include duplicate keys: ${key.value}`);
} else {
seenKeys.push(key.value);
}
}
}
return Object.assign(new YAMLOMap(), pairs);
}
function createOMap(schema, iterable, ctx) {
const pairs = createPairs(schema, iterable, ctx);
const omap = new YAMLOMap();
omap.items = pairs.items;
return omap;
}
const omap = {
identify: value => value instanceof Map,
nodeClass: YAMLOMap,
default: false,
tag: 'tag:yaml.org,2002:omap',
resolve: parseOMap,
createNode: createOMap
};
class YAMLSet extends stringifyNumber.YAMLMap {
constructor(schema) {
super(schema);
this.tag = YAMLSet.tag;
}
add(key) {
const pair = key instanceof stringifyNumber.Pair ? key : new stringifyNumber.Pair(key);
const prev = stringifyNumber.findPair(this.items, pair.key);
if (!prev) this.items.push(pair);
}
get(key, keepPair) {
const pair = stringifyNumber.findPair(this.items, key);
return !keepPair && pair instanceof stringifyNumber.Pair ? pair.key instanceof stringifyNumber.Scalar ? pair.key.value : pair.key : pair;
}
set(key, value) {
if (typeof value !== 'boolean') throw new Error(`Expected boolean value for set(key, value) in a YAML set, not ${typeof value}`);
const prev = stringifyNumber.findPair(this.items, key);
if (prev && !value) {
this.items.splice(this.items.indexOf(prev), 1);
} else if (!prev && value) {
this.items.push(new stringifyNumber.Pair(key));
}
}
toJSON(_, ctx) {
return super.toJSON(_, ctx, Set);
}
toString(ctx, onComment, onChompKeep) {
if (!ctx) return JSON.stringify(this);
if (this.hasAllNullValues()) return super.toString(ctx, onComment, onChompKeep);else throw new Error('Set items must all have null values');
}
}
_rollupPluginBabelHelpers._defineProperty(YAMLSet, "tag", 'tag:yaml.org,2002:set');
function parseSet(map, onError) {
if (map instanceof stringifyNumber.YAMLMap) {
if (map.hasAllNullValues()) return Object.assign(new YAMLSet(), map);else onError('Set items must all have null values');
} else onError('Expected a mapping for this tag');
return map;
}
function createSet(schema, iterable, ctx) {
const {
replacer
} = ctx;
const set = new YAMLSet(schema);
for (let value of iterable) {
if (typeof replacer === 'function') value = replacer.call(iterable, value, value);
set.items.push(stringifyNumber.createPair(value, null, ctx));
}
return set;
}
const set = {
identify: value => value instanceof Set,
nodeClass: YAMLSet,
default: false,
tag: 'tag:yaml.org,2002:set',
resolve: parseSet,
createNode: createSet
};
/* global BigInt */
const parseSexagesimal = (str, isInt) => {
const sign = str[0];
const parts = sign === '-' || sign === '+' ? str.substring(1) : str;
const num = n => isInt && stringifyNumber.intOptions.asBigInt ? BigInt(n) : Number(n);
const res = parts.replace(/_/g, '').split(':').reduce((res, p) => res * num(60) + num(p), num(0));
return sign === '-' ? num(-1) * res : res;
}; // hhhh:mm:ss.sss
const stringifySexagesimal = ({
value
}) => {
let num = n => n;
if (typeof value === 'bigint') num = n => BigInt(n);else if (isNaN(value) || !isFinite(value)) return stringifyNumber.stringifyNumber(value);
let sign = '';
if (value < 0) {
sign = '-';
value *= num(-1);
}
const _60 = num(60);
const parts = [value % _60]; // seconds, including ms
if (value < 60) {
parts.unshift(0); // at least one : is required
} else {
value = (value - parts[0]) / _60;
parts.unshift(value % _60); // minutes
if (value >= 60) {
value = (value - parts[0]) / _60;
parts.unshift(value); // hours
}
}
return sign + parts.map(n => n < 10 ? '0' + String(n) : String(n)).join(':').replace(/000000\d*$/, '') // % 60 may introduce error
;
};
const intTime = {
identify: value => typeof value === 'bigint' || Number.isInteger(value),
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'TIME',
test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+$/,
resolve: str => parseSexagesimal(str, true),
stringify: stringifySexagesimal
};
const floatTime = {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
format: 'TIME',
test: /^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*$/,
resolve: str => parseSexagesimal(str, false),
stringify: stringifySexagesimal
};
const timestamp = {
identify: value => value instanceof Date,
default: true,
tag: 'tag:yaml.org,2002:timestamp',
// If the time zone is omitted, the timestamp is assumed to be specified in UTC. The time part
// may be omitted altogether, resulting in a date format. In such a case, the time part is
// assumed to be 00:00:00Z (start of day, UTC).
test: RegExp('^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})' + // YYYY-Mm-Dd
'(?:' + // time is optional
'(?:t|T|[ \\t]+)' + // t | T | whitespace
'([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)' + // Hh:Mm:Ss(.ss)?
'(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?' + // Z | +5 | -03:30
')?$'),
resolve(str) {
let [, year, month, day, hour, minute, second, millisec, tz] = str.match(timestamp.test);
if (millisec) millisec = (millisec + '00').substr(1, 3);
let date = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec || 0);
if (tz && tz !== 'Z') {
let d = parseSexagesimal(tz, false);
if (Math.abs(d) < 30) d *= 60;
date -= 60000 * d;
}
return new Date(date);
},
stringify: ({
value
}) => value.toISOString().replace(/((T00:00)?:00)?\.000Z$/, '')
};
/* global BigInt */
const boolStringify = ({
value
}) => value ? stringifyNumber.boolOptions.trueStr : stringifyNumber.boolOptions.falseStr;
const intIdentify$2 = value => typeof value === 'bigint' || Number.isInteger(value);
function intResolve$1(str, offset, radix) {
const sign = str[0];
if (sign === '-' || sign === '+') offset += 1;
str = str.substring(offset).replace(/_/g, '');
if (stringifyNumber.intOptions.asBigInt) {
switch (radix) {
case 2:
str = `0b${str}`;
break;
case 8:
str = `0o${str}`;
break;
case 16:
str = `0x${str}`;
break;
}
const n = BigInt(str);
return sign === '-' ? BigInt(-1) * n : n;
}
const n = parseInt(str, radix);
return sign === '-' ? -1 * n : n;
}
function intStringify$1(node, radix, prefix) {
const {
value
} = node;
if (intIdentify$2(value)) {
const str = value.toString(radix);
return value < 0 ? '-' + prefix + str.substr(1) : prefix + str;
}
return stringifyNumber.stringifyNumber(node);
}
const yaml11 = failsafe.concat([{
identify: value => value == null,
createNode: (schema, value, ctx) => ctx.wrapScalars ? new stringifyNumber.Scalar(null) : null,
default: true,
tag: 'tag:yaml.org,2002:null',
test: /^(?:~|[Nn]ull|NULL)?$/,
resolve: str => {
const node = new stringifyNumber.Scalar(null);
node.sourceStr = str;
return node;
},
options: stringifyNumber.nullOptions,
stringify: ({
sourceStr
}) => sourceStr !== null && sourceStr !== void 0 ? sourceStr : stringifyNumber.nullOptions.nullStr
}, {
identify: value => typeof value === 'boolean',
default: true,
tag: 'tag:yaml.org,2002:bool',
test: /^(?:Y|y|[Yy]es|YES|[Tt]rue|TRUE|[Oo]n|ON)$/,
resolve: () => true,
options: stringifyNumber.boolOptions,
stringify: boolStringify
}, {
identify: value => typeof value === 'boolean',
default: true,
tag: 'tag:yaml.org,2002:bool',
test: /^(?:N|n|[Nn]o|NO|[Ff]alse|FALSE|[Oo]ff|OFF)$/,
resolve: () => false,
options: stringifyNumber.boolOptions,
stringify: boolStringify
}, {
identify: intIdentify$2,
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'BIN',
test: /^[-+]?0b[0-1_]+$/,
resolve: str => intResolve$1(str, 2, 2),
stringify: node => intStringify$1(node, 2, '0b')
}, {
identify: intIdentify$2,
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'OCT',
test: /^[-+]?0[0-7_]+$/,
resolve: str => intResolve$1(str, 1, 8),
stringify: node => intStringify$1(node, 8, '0')
}, {
identify: intIdentify$2,
default: true,
tag: 'tag:yaml.org,2002:int',
test: /^[-+]?[0-9][0-9_]*$/,
resolve: str => intResolve$1(str, 0, 10),
stringify: stringifyNumber.stringifyNumber
}, {
identify: intIdentify$2,
default: true,
tag: 'tag:yaml.org,2002:int',
format: 'HEX',
test: /^[-+]?0x[0-9a-fA-F_]+$/,
resolve: str => intResolve$1(str, 2, 16),
stringify: node => intStringify$1(node, 16, '0x')
}, {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
test: /^[-+]?\.(?:inf|Inf|INF|nan|NaN|NAN)$/,
resolve: str => str.slice(-3).toLowerCase() === 'nan' ? NaN : str[0] === '-' ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY,
stringify: stringifyNumber.stringifyNumber
}, {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
format: 'EXP',
test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
resolve: str => parseFloat(str.replace(/_/g, '')),
stringify: ({
value
}) => Number(value).toExponential()
}, {
identify: value => typeof value === 'number',
default: true,
tag: 'tag:yaml.org,2002:float',
test: /^[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*$/,
resolve(str) {
const node = new stringifyNumber.Scalar(parseFloat(str.replace(/_/g, '')));
const dot = str.indexOf('.');
if (dot !== -1) {
const f = str.substring(dot + 1).replace(/_/g, '');
if (f[f.length - 1] === '0') node.minFractionDigits = f.length;
}
return node;
},
stringify: stringifyNumber.stringifyNumber
}], binary, omap, pairs, set, intTime, floatTime, timestamp);
const schemas = {
core,
failsafe,
json,
yaml11
};
const tags = {
binary,
bool: boolObj,
float: floatObj,
floatExp: expObj,
floatNaN: nanObj,
floatTime,
int: intObj,
intHex: hexObj,
intOct: octObj,
intTime,
map,
null: nullObj,
omap,
pairs,
seq,
set,
timestamp
};
function getSchemaTags(schemas, knownTags, customTags, schemaId) {
let tags = schemas[schemaId.replace(/\W/g, '')]; // 'yaml-1.1' -> 'yaml11'
if (!tags) {
const keys = Object.keys(schemas).map(key => JSON.stringify(key)).join(', ');
throw new Error(`Unknown schema "${schemaId}"; use one of ${keys}`);
}
if (Array.isArray(customTags)) {
for (const tag of customTags) tags = tags.concat(tag);
} else if (typeof customTags === 'function') {
tags = customTags(tags.slice());
}
for (let i = 0; i < tags.length; ++i) {
const tag = tags[i];
if (typeof tag === 'string') {
const tagObj = knownTags[tag];
if (!tagObj) {
const keys = Object.keys(knownTags).map(key => JSON.stringify(key)).join(', ');
throw new Error(`Unknown custom tag "${tag}"; use one of ${keys}`);
}
tags[i] = tagObj;
}
}
return tags;
}
const sortMapEntriesByKey = (a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
const coreKnownTags = {
'tag:yaml.org,2002:binary': tags.binary,
'tag:yaml.org,2002:omap': tags.omap,
'tag:yaml.org,2002:pairs': tags.pairs,
'tag:yaml.org,2002:set': tags.set,
'tag:yaml.org,2002:timestamp': tags.timestamp
};
class Schema {
constructor({
customTags,
merge,
resolveKnownTags,
schema,
sortMapEntries
}) {
this.merge = !!merge;
this.name = schema;
this.knownTags = resolveKnownTags ? coreKnownTags : {};
this.tags = getSchemaTags(schemas, tags, customTags, schema); // Used by createNode(), to avoid circular dependencies
this.map = tags.map;
this.seq = tags.seq; // Used by createMap()
this.sortMapEntries = sortMapEntries === true ? sortMapEntriesByKey : sortMapEntries || null;
}
}
exports.MERGE_KEY = MERGE_KEY;
exports.Merge = Merge;
exports.Schema = Schema;
@@ -0,0 +1,709 @@
'use strict';
const Char = {
ANCHOR: '&',
COMMENT: '#',
TAG: '!',
DIRECTIVES_END: '-',
DOCUMENT_END: '.'
};
const Type = {
ALIAS: 'ALIAS',
BLANK_LINE: 'BLANK_LINE',
BLOCK_FOLDED: 'BLOCK_FOLDED',
BLOCK_LITERAL: 'BLOCK_LITERAL',
COMMENT: 'COMMENT',
DIRECTIVE: 'DIRECTIVE',
DOCUMENT: 'DOCUMENT',
FLOW_MAP: 'FLOW_MAP',
FLOW_SEQ: 'FLOW_SEQ',
MAP: 'MAP',
MAP_KEY: 'MAP_KEY',
MAP_VALUE: 'MAP_VALUE',
PLAIN: 'PLAIN',
QUOTE_DOUBLE: 'QUOTE_DOUBLE',
QUOTE_SINGLE: 'QUOTE_SINGLE',
SEQ: 'SEQ',
SEQ_ITEM: 'SEQ_ITEM'
};
const defaultTagPrefix = 'tag:yaml.org,2002:';
const defaultTags = {
MAP: 'tag:yaml.org,2002:map',
SEQ: 'tag:yaml.org,2002:seq',
STR: 'tag:yaml.org,2002:str'
};
function findLineStarts(src) {
const ls = [0];
let offset = src.indexOf('\n');
while (offset !== -1) {
offset += 1;
ls.push(offset);
offset = src.indexOf('\n', offset);
}
return ls;
}
function getSrcInfo(cst) {
let lineStarts, src;
if (typeof cst === 'string') {
lineStarts = findLineStarts(cst);
src = cst;
} else {
if (Array.isArray(cst)) cst = cst[0];
if (cst && cst.context) {
if (!cst.lineStarts) cst.lineStarts = findLineStarts(cst.context.src);
lineStarts = cst.lineStarts;
src = cst.context.src;
}
}
return {
lineStarts,
src
};
}
/**
* @typedef {Object} LinePos - One-indexed position in the source
* @property {number} line
* @property {number} col
*/
/**
* Determine the line/col position matching a character offset.
*
* Accepts a source string or a CST document as the second parameter. With
* the latter, starting indices for lines are cached in the document as
* `lineStarts: number[]`.
*
* Returns a one-indexed `{ line, col }` location if found, or
* `undefined` otherwise.
*
* @param {number} offset
* @param {string|Document|Document[]} cst
* @returns {?LinePos}
*/
function getLinePos(offset, cst) {
if (typeof offset !== 'number' || offset < 0) return null;
const {
lineStarts,
src
} = getSrcInfo(cst);
if (!lineStarts || !src || offset > src.length) return null;
for (let i = 0; i < lineStarts.length; ++i) {
const start = lineStarts[i];
if (offset < start) {
return {
line: i,
col: offset - lineStarts[i - 1] + 1
};
}
if (offset === start) return {
line: i + 1,
col: 1
};
}
const line = lineStarts.length;
return {
line,
col: offset - lineStarts[line - 1] + 1
};
}
/**
* Get a specified line from the source.
*
* Accepts a source string or a CST document as the second parameter. With
* the latter, starting indices for lines are cached in the document as
* `lineStarts: number[]`.
*
* Returns the line as a string if found, or `null` otherwise.
*
* @param {number} line One-indexed line number
* @param {string|Document|Document[]} cst
* @returns {?string}
*/
function getLine(line, cst) {
const {
lineStarts,
src
} = getSrcInfo(cst);
if (!lineStarts || !(line >= 1) || line > lineStarts.length) return null;
const start = lineStarts[line - 1];
let end = lineStarts[line]; // undefined for last line; that's ok for slice()
while (end && end > start && src[end - 1] === '\n') --end;
return src.slice(start, end);
}
/**
* Pretty-print the starting line from the source indicated by the range `pos`
*
* Trims output to `maxWidth` chars while keeping the starting column visible,
* using `…` at either end to indicate dropped characters.
*
* Returns a two-line string (or `null`) with `\n` as separator; the second line
* will hold appropriately indented `^` marks indicating the column range.
*
* @param {Object} pos
* @param {LinePos} pos.start
* @param {LinePos} [pos.end]
* @param {string|Document|Document[]*} cst
* @param {number} [maxWidth=80]
* @returns {?string}
*/
function getPrettyContext({
start,
end
}, cst, maxWidth = 80) {
let src = getLine(start.line, cst);
if (!src) return null;
let {
col
} = start;
if (src.length > maxWidth) {
if (col <= maxWidth - 10) {
src = src.substr(0, maxWidth - 1) + '…';
} else {
const halfWidth = Math.round(maxWidth / 2);
if (src.length > col + halfWidth) src = src.substr(0, col + halfWidth - 1) + '…';
col -= src.length - maxWidth;
src = '…' + src.substr(1 - maxWidth);
}
}
let errLen = 1;
let errEnd = '';
if (end) {
if (end.line === start.line && col + (end.col - start.col) <= maxWidth + 1) {
errLen = end.col - start.col;
} else {
errLen = Math.min(src.length + 1, maxWidth) - col;
errEnd = '…';
}
}
const offset = col > 1 ? ' '.repeat(col - 1) : '';
const err = '^'.repeat(errLen);
return `${src}\n${offset}${err}${errEnd}`;
}
class Range {
static copy(orig) {
return new Range(orig.start, orig.end);
}
constructor(start, end) {
this.start = start;
this.end = end || start;
}
isEmpty() {
return typeof this.start !== 'number' || !this.end || this.end <= this.start;
}
/**
* Set `origStart` and `origEnd` to point to the original source range for
* this node, which may differ due to dropped CR characters.
*
* @param {number[]} cr - Positions of dropped CR characters
* @param {number} offset - Starting index of `cr` from the last call
* @returns {number} - The next offset, matching the one found for `origStart`
*/
setOrigRange(cr, offset) {
const {
start,
end
} = this;
if (cr.length === 0 || end <= cr[0]) {
this.origStart = start;
this.origEnd = end;
return offset;
}
let i = offset;
while (i < cr.length) {
if (cr[i] > start) break;else ++i;
}
this.origStart = start + i;
const nextOffset = i;
while (i < cr.length) {
// if end was at \n, it should now be at \r
if (cr[i] >= end) break;else ++i;
}
this.origEnd = end + i;
return nextOffset;
}
}
/** Root class of all nodes */
class Node {
static addStringTerminator(src, offset, str) {
if (str[str.length - 1] === '\n') return str;
const next = Node.endOfWhiteSpace(src, offset);
return next >= src.length || src[next] === '\n' ? str + '\n' : str;
} // ^(---|...)
static atDocumentBoundary(src, offset, sep) {
const ch0 = src[offset];
if (!ch0) return true;
const prev = src[offset - 1];
if (prev && prev !== '\n') return false;
if (sep) {
if (ch0 !== sep) return false;
} else {
if (ch0 !== Char.DIRECTIVES_END && ch0 !== Char.DOCUMENT_END) return false;
}
const ch1 = src[offset + 1];
const ch2 = src[offset + 2];
if (ch1 !== ch0 || ch2 !== ch0) return false;
const ch3 = src[offset + 3];
return !ch3 || ch3 === '\n' || ch3 === '\t' || ch3 === ' ';
}
static endOfIdentifier(src, offset) {
let ch = src[offset];
const isVerbatim = ch === '<';
const notOk = isVerbatim ? ['\n', '\t', ' ', '>'] : ['\n', '\t', ' ', '[', ']', '{', '}', ','];
while (ch && notOk.indexOf(ch) === -1) ch = src[offset += 1];
if (isVerbatim && ch === '>') offset += 1;
return offset;
}
static endOfIndent(src, offset) {
let ch = src[offset];
while (ch === ' ') ch = src[offset += 1];
return offset;
}
static endOfLine(src, offset) {
let ch = src[offset];
while (ch && ch !== '\n') ch = src[offset += 1];
return offset;
}
static endOfWhiteSpace(src, offset) {
let ch = src[offset];
while (ch === '\t' || ch === ' ') ch = src[offset += 1];
return offset;
}
static startOfLine(src, offset) {
let ch = src[offset - 1];
if (ch === '\n') return offset;
while (ch && ch !== '\n') ch = src[offset -= 1];
return offset + 1;
}
/**
* End of indentation, or null if the line's indent level is not more
* than `indent`
*
* @param {string} src
* @param {number} indent
* @param {number} lineStart
* @returns {?number}
*/
static endOfBlockIndent(src, indent, lineStart) {
const inEnd = Node.endOfIndent(src, lineStart);
if (inEnd > lineStart + indent) {
return inEnd;
} else {
const wsEnd = Node.endOfWhiteSpace(src, inEnd);
const ch = src[wsEnd];
if (!ch || ch === '\n') return wsEnd;
}
return null;
}
static atBlank(src, offset, endAsBlank) {
const ch = src[offset];
return ch === '\n' || ch === '\t' || ch === ' ' || endAsBlank && !ch;
}
static nextNodeIsIndented(ch, indentDiff, indicatorAsIndent) {
if (!ch || indentDiff < 0) return false;
if (indentDiff > 0) return true;
return indicatorAsIndent && ch === '-';
} // should be at line or string end, or at next non-whitespace char
static normalizeOffset(src, offset) {
const ch = src[offset];
return !ch ? offset : ch !== '\n' && src[offset - 1] === '\n' ? offset - 1 : Node.endOfWhiteSpace(src, offset);
} // fold single newline into space, multiple newlines to N - 1 newlines
// presumes src[offset] === '\n'
static foldNewline(src, offset, indent) {
let inCount = 0;
let error = false;
let fold = '';
let ch = src[offset + 1];
while (ch === ' ' || ch === '\t' || ch === '\n') {
switch (ch) {
case '\n':
inCount = 0;
offset += 1;
fold += '\n';
break;
case '\t':
if (inCount <= indent) error = true;
offset = Node.endOfWhiteSpace(src, offset + 2) - 1;
break;
case ' ':
inCount += 1;
offset += 1;
break;
}
ch = src[offset + 1];
}
if (!fold) fold = ' ';
if (ch && inCount <= indent) error = true;
return {
fold,
offset,
error
};
}
constructor(type, props, context) {
Object.defineProperty(this, 'context', {
value: context || null,
writable: true
});
this.error = null;
this.range = null;
this.valueRange = null;
this.props = props || [];
this.type = type;
this.value = null;
}
getPropValue(idx, key, skipKey) {
if (!this.context) return null;
const {
src
} = this.context;
const prop = this.props[idx];
return prop && src[prop.start] === key ? src.slice(prop.start + (skipKey ? 1 : 0), prop.end) : null;
}
get anchor() {
for (let i = 0; i < this.props.length; ++i) {
const anchor = this.getPropValue(i, Char.ANCHOR, true);
if (anchor != null) return anchor;
}
return null;
}
get comment() {
const comments = [];
for (let i = 0; i < this.props.length; ++i) {
const comment = this.getPropValue(i, Char.COMMENT, true);
if (comment != null) comments.push(comment);
}
return comments.length > 0 ? comments.join('\n') : null;
}
commentHasRequiredWhitespace(start) {
const {
src
} = this.context;
if (this.header && start === this.header.end) return false;
if (!this.valueRange) return false;
const {
end
} = this.valueRange;
return start !== end || Node.atBlank(src, end - 1);
}
get hasComment() {
if (this.context) {
const {
src
} = this.context;
for (let i = 0; i < this.props.length; ++i) {
if (src[this.props[i].start] === Char.COMMENT) return true;
}
}
return false;
}
get hasProps() {
if (this.context) {
const {
src
} = this.context;
for (let i = 0; i < this.props.length; ++i) {
if (src[this.props[i].start] !== Char.COMMENT) return true;
}
}
return false;
}
get includesTrailingLines() {
return false;
}
get jsonLike() {
const jsonLikeTypes = [Type.FLOW_MAP, Type.FLOW_SEQ, Type.QUOTE_DOUBLE, Type.QUOTE_SINGLE];
return jsonLikeTypes.indexOf(this.type) !== -1;
}
get rangeAsLinePos() {
if (!this.range || !this.context) return undefined;
const start = getLinePos(this.range.start, this.context.root);
if (!start) return undefined;
const end = getLinePos(this.range.end, this.context.root);
return {
start,
end
};
}
get rawValue() {
if (!this.valueRange || !this.context) return null;
const {
start,
end
} = this.valueRange;
return this.context.src.slice(start, end);
}
get tag() {
for (let i = 0; i < this.props.length; ++i) {
const tag = this.getPropValue(i, Char.TAG, false);
if (tag != null) {
if (tag[1] === '<') {
return {
verbatim: tag.slice(2, -1)
};
} else {
// eslint-disable-next-line no-unused-vars
const [_, handle, suffix] = tag.match(/^(.*!)([^!]*)$/);
return {
handle,
suffix
};
}
}
}
return null;
}
get valueRangeContainsNewline() {
if (!this.valueRange || !this.context) return false;
const {
start,
end
} = this.valueRange;
const {
src
} = this.context;
for (let i = start; i < end; ++i) {
if (src[i] === '\n') return true;
}
return false;
}
parseComment(start) {
const {
src
} = this.context;
if (src[start] === Char.COMMENT) {
const end = Node.endOfLine(src, start + 1);
const commentRange = new Range(start, end);
this.props.push(commentRange);
return end;
}
return start;
}
/**
* Populates the `origStart` and `origEnd` values of all ranges for this
* node. Extended by child classes to handle descendant nodes.
*
* @param {number[]} cr - Positions of dropped CR characters
* @param {number} offset - Starting index of `cr` from the last call
* @returns {number} - The next offset, matching the one found for `origStart`
*/
setOrigRanges(cr, offset) {
if (this.range) offset = this.range.setOrigRange(cr, offset);
if (this.valueRange) this.valueRange.setOrigRange(cr, offset);
this.props.forEach(prop => prop.setOrigRange(cr, offset));
return offset;
}
toString() {
const {
context: {
src
},
range,
value
} = this;
if (value != null) return value;
const str = src.slice(range.start, range.end);
return Node.addStringTerminator(src, range.end, str);
}
}
class YAMLError extends Error {
constructor(name, source, message) {
if (!message || !(source instanceof Node)) throw new Error(`Invalid arguments for new ${name}`);
super();
this.name = name;
this.message = message;
this.source = source;
}
makePretty() {
if (!this.source) return;
this.nodeType = this.source.type;
const cst = this.source.context && this.source.context.root;
if (typeof this.offset === 'number') {
this.range = new Range(this.offset, this.offset + 1);
const start = cst && getLinePos(this.offset, cst);
if (start) {
const end = {
line: start.line,
col: start.col + 1
};
this.linePos = {
start,
end
};
}
delete this.offset;
} else {
this.range = this.source.range;
this.linePos = this.source.rangeAsLinePos;
}
if (this.linePos) {
const {
line,
col
} = this.linePos.start;
this.message += ` at line ${line}, column ${col}`;
const ctx = cst && getPrettyContext(this.linePos, cst);
if (ctx) this.message += `:\n\n${ctx}\n`;
}
delete this.source;
}
}
class YAMLReferenceError extends YAMLError {
constructor(source, message) {
super('YAMLReferenceError', source, message);
}
}
class YAMLSemanticError extends YAMLError {
constructor(source, message) {
super('YAMLSemanticError', source, message);
}
}
class YAMLSyntaxError extends YAMLError {
constructor(source, message) {
super('YAMLSyntaxError', source, message);
}
}
class YAMLWarning extends YAMLError {
constructor(source, message) {
super('YAMLWarning', source, message);
}
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
exports.Char = Char;
exports.Node = Node;
exports.Range = Range;
exports.Type = Type;
exports.YAMLError = YAMLError;
exports.YAMLReferenceError = YAMLReferenceError;
exports.YAMLSemanticError = YAMLSemanticError;
exports.YAMLSyntaxError = YAMLSyntaxError;
exports.YAMLWarning = YAMLWarning;
exports._defineProperty = _defineProperty;
exports.defaultTagPrefix = defaultTagPrefix;
exports.defaultTags = defaultTags;
+93
View File
@@ -0,0 +1,93 @@
'use strict';
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-eed30217.js');
var parseCst = require('./parse-3997f544.js');
require('./stringifyNumber-dea1120c.js');
require('./Schema-807430ba.js');
var Document = require('./Document-f89a2614.js');
/* global console, process, YAML_SILENCE_WARNINGS */
function warn(warning, type) {
if (typeof YAML_SILENCE_WARNINGS !== 'undefined' && YAML_SILENCE_WARNINGS) return;
if (typeof process !== 'undefined') {
if (process.env.YAML_SILENCE_WARNINGS) return; // This will throw in Jest if `warning` is an Error instance due to
// https://github.com/facebook/jest/issues/2549
if (process.emitWarning) {
process.emitWarning(warning, type);
return;
}
} // eslint-disable-next-line no-console
console.warn(type ? `${type}: ${warning}` : warning);
}
function parseAllDocuments(src, options) {
const stream = [];
let prev;
for (const cstDoc of parseCst.parse(src)) {
const doc = new Document.Document(undefined, null, options);
doc.parse(cstDoc, prev);
stream.push(doc);
prev = doc;
}
return stream;
}
function parseDocument(src, options) {
const cst = parseCst.parse(src);
const doc = new Document.Document(cst[0], null, options);
if (cst.length > 1) {
const errMsg = 'Source contains multiple documents; please use YAML.parseAllDocuments()';
doc.errors.unshift(new _rollupPluginBabelHelpers.YAMLSemanticError(cst[1], errMsg));
}
return doc;
}
function parse(src, reviver, options) {
if (options === undefined && reviver && typeof reviver === 'object') {
options = reviver;
reviver = undefined;
}
const doc = parseDocument(src, options);
doc.warnings.forEach(warning => warn(warning));
if (doc.errors.length > 0) throw doc.errors[0];
return doc.toJS({
reviver
});
}
function stringify(value, replacer, options) {
if (typeof options === 'string') options = options.length;
if (typeof options === 'number') {
const indent = Math.round(options);
options = indent < 1 ? undefined : indent > 8 ? {
indent: 8
} : {
indent
};
}
if (value === undefined) {
const {
keepUndefined
} = options || replacer || {};
if (!keepUndefined) return undefined;
}
return new Document.Document(value, replacer, options).toString();
}
exports.parseCST = parseCst.parse;
exports.Document = Document.Document;
exports.defaultOptions = Document.defaultOptions;
exports.scalarOptions = Document.scalarOptions;
exports.parse = parse;
exports.parseAllDocuments = parseAllDocuments;
exports.parseDocument = parseDocument;
exports.stringify = stringify;
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
'use strict';
require('./_rollupPluginBabelHelpers-eed30217.js');
var parseCst = require('./parse-3997f544.js');
exports.parse = parseCst.parse;
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
'use strict';
require('./_rollupPluginBabelHelpers-eed30217.js');
var parseCst = require('./parse-3997f544.js');
require('./stringifyNumber-dea1120c.js');
require('./Schema-807430ba.js');
var Document = require('./Document-f89a2614.js');
function testEvents(src, options) {
const opt = Object.assign({
keepCstNodes: true,
keepNodeTypes: true,
version: '1.2'
}, options);
const docs = parseCst.parse(src).map(cstDoc => new Document.Document(null, opt).parse(cstDoc));
const errDoc = docs.find(doc => doc.errors.length > 0);
const error = errDoc ? errDoc.errors[0].message : null;
const events = ['+STR'];
try {
for (let i = 0; i < docs.length; ++i) {
const doc = docs[i];
let root = doc.contents;
if (Array.isArray(root)) root = root[0];
const [rootStart, rootEnd] = doc.range || [0, 0];
let e = doc.errors[0] && doc.errors[0].source;
if (e && e.type === 'SEQ_ITEM') e = e.node;
if (e && (e.type === 'DOCUMENT' || e.range.start < rootStart)) throw new Error();
let docStart = '+DOC';
const pre = src.slice(0, rootStart);
const explicitDoc = /---\s*$/.test(pre);
if (explicitDoc) docStart += ' ---';else if (!doc.contents) continue;
events.push(docStart);
addEvents(events, doc, e, root);
if (doc.contents && doc.contents.length > 1) throw new Error();
let docEnd = '-DOC';
if (rootEnd) {
const post = src.slice(rootEnd);
if (/^\.\.\./.test(post)) docEnd += ' ...';
}
events.push(docEnd);
}
} catch (e) {
return {
events,
error: error || e
};
}
events.push('-STR');
return {
events,
error
};
}
function addEvents(events, doc, e, node) {
if (!node) {
events.push('=VAL :');
return;
}
if (e && node.cstNode === e) throw new Error();
let props = '';
let anchor = doc.anchors.getName(node);
if (anchor) {
if (/\d$/.test(anchor)) {
const alt = anchor.replace(/\d$/, '');
if (doc.anchors.getNode(alt)) anchor = alt;
}
props = ` &${anchor}`;
}
if (node.cstNode && node.cstNode.tag) {
const {
handle,
suffix
} = node.cstNode.tag;
props += handle === '!' && !suffix ? ' <!>' : ` <${node.tag}>`;
}
let scalar = null;
switch (node.type) {
case 'ALIAS':
{
let alias = doc.anchors.getName(node.source);
if (/\d$/.test(alias)) {
const alt = alias.replace(/\d$/, '');
if (doc.anchors.getNode(alt)) alias = alt;
}
events.push(`=ALI${props} *${alias}`);
}
break;
case 'BLOCK_FOLDED':
scalar = '>';
break;
case 'BLOCK_LITERAL':
scalar = '|';
break;
case 'PLAIN':
scalar = ':';
break;
case 'QUOTE_DOUBLE':
scalar = '"';
break;
case 'QUOTE_SINGLE':
scalar = "'";
break;
case 'PAIR':
events.push(`+MAP${props}`);
addEvents(events, doc, e, node.key);
addEvents(events, doc, e, node.value);
events.push('-MAP');
break;
case 'FLOW_SEQ':
case 'SEQ':
events.push(`+SEQ${props}`);
node.items.forEach(item => {
addEvents(events, doc, e, item);
});
events.push('-SEQ');
break;
case 'FLOW_MAP':
case 'MAP':
events.push(`+MAP${props}`);
node.items.forEach(({
key,
value
}) => {
addEvents(events, doc, e, key);
addEvents(events, doc, e, value);
});
events.push('-MAP');
break;
default:
throw new Error(`Unexpected node type ${node.type}`);
}
if (scalar) {
const value = node.cstNode.strValue.replace(/\\/g, '\\\\').replace(/\0/g, '\\0').replace(/\x07/g, '\\a').replace(/\x08/g, '\\b').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\v/g, '\\v').replace(/\f/g, '\\f').replace(/\r/g, '\\r').replace(/\x1b/g, '\\e');
events.push(`=VAL${props} ${scalar}${value}`);
}
}
exports.testEvents = testEvents;
+22
View File
@@ -0,0 +1,22 @@
'use strict';
require('./_rollupPluginBabelHelpers-eed30217.js');
var stringifyNumber = require('./stringifyNumber-dea1120c.js');
var Schema = require('./Schema-807430ba.js');
exports.Alias = stringifyNumber.Alias;
exports.Collection = stringifyNumber.Collection;
exports.Node = stringifyNumber.Node;
exports.Pair = stringifyNumber.Pair;
exports.Scalar = stringifyNumber.Scalar;
exports.YAMLMap = stringifyNumber.YAMLMap;
exports.YAMLSeq = stringifyNumber.YAMLSeq;
exports.binaryOptions = stringifyNumber.binaryOptions;
exports.boolOptions = stringifyNumber.boolOptions;
exports.intOptions = stringifyNumber.intOptions;
exports.nullOptions = stringifyNumber.nullOptions;
exports.strOptions = stringifyNumber.strOptions;
exports.Merge = Schema.Merge;
exports.Schema = Schema.Schema;
+17
View File
@@ -0,0 +1,17 @@
'use strict';
var _rollupPluginBabelHelpers = require('./_rollupPluginBabelHelpers-eed30217.js');
var stringifyNumber = require('./stringifyNumber-dea1120c.js');
exports.Type = _rollupPluginBabelHelpers.Type;
exports.YAMLError = _rollupPluginBabelHelpers.YAMLError;
exports.YAMLReferenceError = _rollupPluginBabelHelpers.YAMLReferenceError;
exports.YAMLSemanticError = _rollupPluginBabelHelpers.YAMLSemanticError;
exports.YAMLSyntaxError = _rollupPluginBabelHelpers.YAMLSyntaxError;
exports.YAMLWarning = _rollupPluginBabelHelpers.YAMLWarning;
exports.findPair = stringifyNumber.findPair;
exports.stringifyNumber = stringifyNumber.stringifyNumber;
exports.stringifyString = stringifyNumber.stringifyString;
exports.toJS = stringifyNumber.toJS;
+455
View File
@@ -0,0 +1,455 @@
import { CST } from './parse-cst'
import {
AST,
Alias,
Collection,
Merge,
Node,
Pair,
Scalar,
Schema,
YAMLMap,
YAMLSeq
} from './types'
import { Type, YAMLError, YAMLWarning } from './util'
export { AST, CST }
export { default as parseCST } from './parse-cst'
/**
* `yaml` defines document-specific options in three places: as an argument of
* parse, create and stringify calls, in the values of `YAML.defaultOptions`,
* and in the version-dependent `YAML.Document.defaults` object. Values set in
* `YAML.defaultOptions` override version-dependent defaults, and argument
* options override both.
*/
export const defaultOptions: Options
type Replacer = any[] | ((key: any, value: any) => boolean)
type Reviver = (key: any, value: any) => any
export interface Options extends Schema.Options {
/**
* Default prefix for anchors.
*
* Default: `'a'`, resulting in anchors `a1`, `a2`, etc.
*/
anchorPrefix?: string
/**
* The number of spaces to use when indenting code.
*
* Default: `2`
*/
indent?: number
/**
* Whether block sequences should be indented.
*
* Default: `true`
*/
indentSeq?: boolean
/**
* Include references in the AST to each node's corresponding CST node.
*
* Default: `false`
*/
keepCstNodes?: boolean
/**
* Store the original node type when parsing documents.
*
* Default: `true`
*/
keepNodeTypes?: boolean
/**
* Keep `undefined` object values when creating mappings and return a Scalar
* node when calling `YAML.stringify(undefined)`, rather than `undefined`.
*
* Default: `false`
*/
keepUndefined?: boolean
/**
* When outputting JS, use Map rather than Object to represent mappings.
*
* Default: `false`
*/
mapAsMap?: boolean
/**
* Prevent exponential entity expansion attacks by limiting data aliasing count;
* set to `-1` to disable checks; `0` disallows all alias nodes.
*
* Default: `100`
*/
maxAliasCount?: number
/**
* Include line position & node type directly in errors; drop their verbose source and context.
*
* Default: `true`
*/
prettyErrors?: boolean
/**
* When stringifying, require keys to be scalars and to use implicit rather than explicit notation.
*
* Default: `false`
*/
simpleKeys?: boolean
/**
* The YAML version used by documents without a `%YAML` directive.
*
* Default: `"1.2"`
*/
version?: '1.0' | '1.1' | '1.2'
}
/**
* Some customization options are availabe to control the parsing and
* stringification of scalars. Note that these values are used by all documents.
*/
export const scalarOptions: {
binary: scalarOptions.Binary
bool: scalarOptions.Bool
int: scalarOptions.Int
null: scalarOptions.Null
str: scalarOptions.Str
}
export namespace scalarOptions {
interface Binary {
/**
* The type of string literal used to stringify `!!binary` values.
*
* Default: `'BLOCK_LITERAL'`
*/
defaultType: Scalar.Type
/**
* Maximum line width for `!!binary`.
*
* Default: `76`
*/
lineWidth: number
}
interface Bool {
/**
* String representation for `true`. With the core schema, use `'true' | 'True' | 'TRUE'`.
*
* Default: `'true'`
*/
trueStr: string
/**
* String representation for `false`. With the core schema, use `'false' | 'False' | 'FALSE'`.
*
* Default: `'false'`
*/
falseStr: string
}
interface Int {
/**
* Whether integers should be parsed into BigInt values.
*
* Default: `false`
*/
asBigInt: boolean
}
interface Null {
/**
* String representation for `null`. With the core schema, use `'null' | 'Null' | 'NULL' | '~' | ''`.
*
* Default: `'null'`
*/
nullStr: string
}
interface Str {
/**
* The default type of string literal used to stringify values in general
*
* Default: `'PLAIN'`
*/
defaultType: Scalar.Type
/**
* The default type of string literal used to stringify implicit key values
*
* Default: `'PLAIN'`
*/
defaultKeyType: Scalar.Type
/**
* Use 'single quote' rather than "double quote" by default
*
* Default: `false`
*/
defaultQuoteSingle: boolean
doubleQuoted: {
/**
* Whether to restrict double-quoted strings to use JSON-compatible syntax.
*
* Default: `false`
*/
jsonEncoding: boolean
/**
* Minimum length to use multiple lines to represent the value.
*
* Default: `40`
*/
minMultiLineLength: number
}
fold: {
/**
* Maximum line width (set to `0` to disable folding).
*
* Default: `80`
*/
lineWidth: number
/**
* Minimum width for highly-indented content.
*
* Default: `20`
*/
minContentWidth: number
}
}
}
export interface CreateNodeOptions {
/**
* Filter or modify values while creating a node.
*
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter
*/
replacer?: Replacer
/**
* Specify the collection type, e.g. `"!!omap"`. Note that this requires the
* corresponding tag to be available in this document's schema.
*/
tag?: string
/**
* Wrap plain values in `Scalar` objects.
*
* Default: `true`
*/
wrapScalars?: boolean
}
export class Document extends Collection {
cstNode?: CST.Document
/**
* @param value - The initial value for the document, which will be wrapped
* in a Node container.
*/
constructor(value?: any, options?: Options)
constructor(value: any, replacer: null | Replacer, options?: Options)
tag: never
directivesEndMarker?: boolean
type: Type.DOCUMENT
/**
* Anchors associated with the document's nodes;
* also provides alias & merge node creators.
*/
anchors: Document.Anchors
/** The document contents. */
contents: any
/** Errors encountered during parsing. */
errors: YAMLError[]
/**
* The schema used with the document. Use `setSchema()` to change or
* initialise.
*/
schema?: Schema
/**
* Array of prefixes; each will have a string `handle` that
* starts and ends with `!` and a string `prefix` that the handle will be replaced by.
*/
tagPrefixes: Document.TagPrefix[]
/**
* The parsed version of the source document;
* if true-ish, stringified output will include a `%YAML` directive.
*/
version?: string
/** Warnings encountered during parsing. */
warnings: YAMLWarning[]
/**
* Convert any value into a `Node` using the current schema, recursively
* turning objects into collections.
*/
createNode(
value: any,
{ replacer, tag, wrapScalars }?: CreateNodeOptions
): Node
/**
* Convert a key and a value into a `Pair` using the current schema,
* recursively wrapping all values as `Scalar` or `Collection` nodes.
*
* @param options If `wrapScalars` is not `false`, wraps plain values in
* `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
* arguments to set it manually, or with arguments to change the schema used
* by the document.
*/
setSchema(
id?: Options['version'] | Schema.Name,
customTags?: (Schema.TagId | Schema.Tag)[]
): void
/** Set `handle` as a shorthand string for the `prefix` tag namespace. */
setTagPrefix(handle: string, prefix: string): void
/**
* A plain JavaScript representation of the document `contents`.
*
* @param mapAsMap - Use Map rather than Object to represent mappings.
* Overrides values set in Document or global options.
* @param onAnchor - If defined, called with the resolved `value` and
* reference `count` for each anchor in the document.
* @param reviver - A function that may filter or modify the output JS value
*/
toJS(opt?: {
mapAsMap?: boolean
onAnchor?: (value: any, count: number) => void
reviver?: Reviver
}): any
/**
* A JSON representation of the document `contents`.
*
* @param arg Used by `JSON.stringify` to indicate the array index or property
* name.
*/
toJSON(arg?: string): any
/** A YAML representation of the document. */
toString(): string
}
export namespace Document {
interface Parsed extends Document {
contents: Node | null
/** The schema used with the document. */
schema: Schema
}
interface Anchors {
/**
* Create a new `Alias` node, adding the required anchor for `node`.
* If `name` is empty, a new anchor name will be generated.
*/
createAlias(node: Node, name?: string): Alias
/**
* Create a new `Merge` node with the given source nodes.
* Non-`Alias` sources will be automatically wrapped.
*/
createMergePair(...nodes: Node[]): Merge
/** The anchor name associated with `node`, if set. */
getName(node: Node): undefined | string
/** List of all defined anchor names. */
getNames(): string[]
/** The node associated with the anchor `name`, if set. */
getNode(name: string): undefined | Node
/**
* Find an available anchor name with the given `prefix` and a
* numerical suffix.
*/
newName(prefix: string): string
/**
* Associate an anchor with `node`. If `name` is empty, a new name will be generated.
* To remove an anchor, use `setAnchor(null, name)`.
*/
setAnchor(node: Node | null, name?: string): void | string
}
interface TagPrefix {
handle: string
prefix: string
}
}
/**
* Recursively turns objects into collections. Generic objects as well as `Map`
* and its descendants become mappings, while arrays and other iterable objects
* result in sequences.
*
* The primary purpose of this function is to enable attaching comments or other
* metadata to a value, or to otherwise exert more fine-grained control over the
* stringified output. 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.
*
* @param wrapScalars If undefined or `true`, also wraps plain values in
* `Scalar` objects; if `false` and `value` is not an object, it will be
* returned directly.
* @param tag Use to specify the collection type, e.g. `"!!omap"`. Note that
* this requires the corresponding tag to be available based on the default
* options. To use a specific document's schema, use `doc.schema.createNode`.
*/
export function createNode(
value: any,
wrapScalars?: true,
tag?: string
): YAMLMap | YAMLSeq | Scalar
/**
* YAML.createNode recursively turns objects into Map and arrays to Seq collections.
* Its primary use is to enable attaching comments or other metadata to a value,
* or to otherwise exert more fine-grained control over the stringified output.
*
* Doesn't wrap plain values in Scalar objects.
*/
export function createNode(
value: any,
wrapScalars: false,
tag?: string
): YAMLMap | YAMLSeq | string | number | boolean | null
/**
* Parse an input string into a single YAML.Document.
*/
export function parseDocument(str: string, options?: Options): Document.Parsed
/**
* Parse the input as a stream of YAML documents.
*
* Documents should be separated from each other by `...` or `---` marker lines.
*/
export function parseAllDocuments(
str: string,
options?: Options
): Document.Parsed[]
/**
* Parse an input string into JavaScript.
*
* Only supports input consisting of a single YAML document; for multi-document
* support you should use `YAML.parseAllDocuments`. May throw on error, and may
* log warnings using `console.warn`.
*
* @param str - A string with YAML formatting.
* @param reviver - A reviver function, as in `JSON.parse()`
* @returns The 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.
*/
export function parse(str: string, options?: Options): any
export function parse(
str: string,
reviver: null | Reviver,
options?: Options
): any
/**
* Stringify a value as a YAML document.
*
* @param replacer - A replacer array or function, as in `JSON.stringify()`
* @returns Will always include `\n` as the last character, as is expected of YAML documents.
*/
export function stringify(value: any, options?: Options): string
export function stringify(
value: any,
replacer: null | Replacer,
options?: number | string | Options
): string
+1
View File
@@ -0,0 +1 @@
module.exports = require('./dist')
+96
View File
@@ -0,0 +1,96 @@
{
"name": "yaml",
"version": "2.0.0-1",
"license": "ISC",
"author": "Eemeli Aro <eemeli@gmail.com>",
"repository": "github:eemeli/yaml",
"description": "JavaScript parser and stringifier for YAML",
"keywords": [
"YAML",
"parser",
"stringifier"
],
"homepage": "https://eemeli.org/yaml/",
"files": [
"browser/",
"dist/",
"types/",
"*.d.ts",
"*.js",
"*.mjs",
"!*config.js"
],
"type": "commonjs",
"main": "./index.js",
"browser": {
"./index.js": "./browser/index.js",
"./parse-cst.js": "./browser/parse-cst.js",
"./types.js": "./browser/types.js",
"./types.mjs": "./browser/types.js",
"./util.js": "./browser/util.js",
"./util.mjs": "./browser/util.js"
},
"exports": {
".": "./index.js",
"./package.json": "./package.json",
"./parse-cst": "./parse-cst.js",
"./types": [
{
"import": "./types.mjs"
},
"./types.js"
],
"./util": [
{
"import": "./util.mjs"
},
"./util.js"
]
},
"scripts": {
"build": "npm run build:node && npm run build:browser",
"build:browser": "rollup -c rollup.browser-config.js",
"build:node": "rollup -c rollup.node-config.js",
"clean": "git clean -fdxe node_modules",
"lint": "eslint src/",
"prettier": "prettier --write .",
"start": "cross-env TRACE_LEVEL=log npm run build:node && node -i -e 'YAML=require(\".\")'",
"test": "jest",
"test:browsers": "cd playground && npm test",
"test:dist": "npm run build:node && jest",
"test:types": "tsc --lib ES2017 --noEmit tests/typings.ts",
"docs:install": "cd docs-slate && bundle install",
"docs:deploy": "cd docs-slate && ./deploy.sh",
"docs": "cd docs-slate && bundle exec middleman server",
"preversion": "npm test && npm run build",
"prepublishOnly": "npm run clean && npm test && npm run build"
},
"browserslist": "> 0.5%, not dead",
"prettier": {
"arrowParens": "avoid",
"semi": false,
"singleQuote": true,
"trailingComma": "none"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.11.5",
"@rollup/plugin-babel": "^5.2.1",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.5.0",
"babel-plugin-trace": "^1.1.0",
"common-tags": "^1.8.0",
"cross-env": "^7.0.2",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"fast-check": "^2.4.0",
"jest": "^26.5.0",
"prettier": "^2.1.2",
"rollup": "^2.28.2",
"typescript": "^4.0.3"
},
"engines": {
"node": ">= 6"
}
}
+187
View File
@@ -0,0 +1,187 @@
import { Type, YAMLSyntaxError } from './util'
export default function parseCST(str: string): ParsedCST
export interface ParsedCST extends Array<CST.Document> {
setOrigRanges(): boolean
}
export namespace CST {
interface Range {
start: number
end: number
origStart?: number
origEnd?: number
isEmpty(): boolean
}
interface ParseContext {
/** Node starts at beginning of line */
atLineStart: boolean
/** true if currently in a collection context */
inCollection: boolean
/** true if currently in a flow context */
inFlow: boolean
/** Current level of indentation */
indent: number
/** Start of the current line */
lineStart: number
/** The parent of the node */
parent: Node
/** Source of the YAML document */
src: string
}
interface Node {
context: ParseContext | null
/** if not null, indicates a parser failure */
error: YAMLSyntaxError | null
/** span of context.src parsed into this node */
range: Range | null
valueRange: Range | null
/** anchors, tags and comments */
props: Range[]
/** specific node type */
type: Type
/** if non-null, overrides source value */
value: string | null
readonly anchor: string | null
readonly comment: string | null
readonly hasComment: boolean
readonly hasProps: boolean
readonly jsonLike: boolean
readonly rawValue: string | null
readonly tag:
| null
| { verbatim: string }
| { handle: string; suffix: string }
readonly valueRangeContainsNewline: boolean
}
interface Alias extends Node {
type: Type.ALIAS
/** contain the anchor without the * prefix */
readonly rawValue: string
}
type Scalar = BlockValue | PlainValue | QuoteValue
interface BlockValue extends Node {
type: Type.BLOCK_FOLDED | Type.BLOCK_LITERAL
chomping: 'CLIP' | 'KEEP' | 'STRIP'
blockIndent: number | null
header: Range
readonly strValue: string | null
}
interface BlockFolded extends BlockValue {
type: Type.BLOCK_FOLDED
}
interface BlockLiteral extends BlockValue {
type: Type.BLOCK_LITERAL
}
interface PlainValue extends Node {
type: Type.PLAIN
readonly strValue: string | null
}
interface QuoteValue extends Node {
type: Type.QUOTE_DOUBLE | Type.QUOTE_SINGLE
readonly strValue:
| null
| string
| { str: string; errors: YAMLSyntaxError[] }
}
interface QuoteDouble extends QuoteValue {
type: Type.QUOTE_DOUBLE
}
interface QuoteSingle extends QuoteValue {
type: Type.QUOTE_SINGLE
}
interface Comment extends Node {
type: Type.COMMENT
readonly anchor: null
readonly comment: string
readonly rawValue: null
readonly tag: null
}
interface BlankLine extends Node {
type: Type.BLANK_LINE
}
interface MapItem extends Node {
type: Type.MAP_KEY | Type.MAP_VALUE
node: ContentNode | null
}
interface MapKey extends MapItem {
type: Type.MAP_KEY
}
interface MapValue extends MapItem {
type: Type.MAP_VALUE
}
interface Map extends Node {
type: Type.MAP
/** implicit keys are not wrapped */
items: Array<BlankLine | Comment | Alias | Scalar | MapItem>
}
interface SeqItem extends Node {
type: Type.SEQ_ITEM
node: ContentNode | null
}
interface Seq extends Node {
type: Type.SEQ
items: Array<BlankLine | Comment | SeqItem>
}
interface FlowChar {
char: '{' | '}' | '[' | ']' | ',' | '?' | ':'
offset: number
origOffset?: number
}
interface FlowCollection extends Node {
type: Type.FLOW_MAP | Type.FLOW_SEQ
items: Array<
FlowChar | BlankLine | Comment | Alias | Scalar | FlowCollection
>
}
interface FlowMap extends FlowCollection {
type: Type.FLOW_MAP
}
interface FlowSeq extends FlowCollection {
type: Type.FLOW_SEQ
}
type ContentNode = Alias | Scalar | Map | Seq | FlowCollection
interface Directive extends Node {
type: Type.DIRECTIVE
name: string
readonly anchor: null
readonly parameters: string[]
readonly tag: null
}
interface Document extends Node {
type: Type.DOCUMENT
directives: Array<BlankLine | Comment | Directive>
contents: Array<BlankLine | Comment | ContentNode>
readonly anchor: null
readonly comment: null
readonly tag: null
}
}
+1
View File
@@ -0,0 +1 @@
module.exports = require('./dist/parse-cst').parse
+379
View File
@@ -0,0 +1,379 @@
import { Document, scalarOptions } from './index'
import { CST } from './parse-cst'
import { Type } from './util'
export const binaryOptions: scalarOptions.Binary
export const boolOptions: scalarOptions.Bool
export const intOptions: scalarOptions.Int
export const nullOptions: scalarOptions.Null
export const strOptions: scalarOptions.Str
export class Schema {
constructor(options: Schema.Options)
knownTags: { [key: string]: Schema.CustomTag }
merge: boolean
name: Schema.Name
sortMapEntries: ((a: Pair, b: Pair) => number) | null
tags: Schema.Tag[]
}
export namespace Schema {
type Name = 'core' | 'failsafe' | 'json' | 'yaml-1.1'
interface Options {
/**
* Array of additional tags to include in the schema, or a function that may
* modify the schema's base tag array.
*/
customTags?: (TagId | Tag)[] | ((tags: Tag[]) => Tag[])
/**
* Enable support for `<<` merge keys.
*
* Default: `false` for YAML 1.2, `true` for earlier versions
*/
merge?: boolean
/**
* When using the `'core'` schema, support parsing values with these
* explicit YAML 1.1 tags:
*
* `!!binary`, `!!omap`, `!!pairs`, `!!set`, `!!timestamp`.
*
* Default `true`
*/
resolveKnownTags?: boolean
/**
* The base schema to use.
*
* Default: `"core"` for YAML 1.2, `"yaml-1.1"` for earlier versions
*/
schema?: Name
/**
* When stringifying, sort map entries. If `true`, sort by comparing key values with `<`.
*
* Default: `false`
*/
sortMapEntries?: boolean | ((a: Pair, b: Pair) => number)
/**
* @deprecated Use `customTags` instead.
*/
tags?: Options['customTags']
}
interface CreateNodeContext {
wrapScalars?: boolean
[key: string]: any
}
interface StringifyContext {
forceBlockIndent?: boolean
implicitKey?: boolean
indent?: string
indentAtStart?: number
inFlow?: boolean
[key: string]: any
}
type TagId =
| 'binary'
| 'bool'
| 'float'
| 'floatExp'
| 'floatNaN'
| 'floatTime'
| 'int'
| 'intHex'
| 'intOct'
| 'intTime'
| 'null'
| 'omap'
| 'pairs'
| 'set'
| 'timestamp'
type Tag = CustomTag | DefaultTag
interface BaseTag {
/**
* An optional factory function, used e.g. by collections when wrapping JS objects as AST nodes.
*/
createNode?: (
schema: Schema,
value: any,
ctx: Schema.CreateNodeContext
) => YAMLMap | YAMLSeq | Scalar
/**
* If a tag has multiple forms that should be parsed and/or stringified differently, use `format` to identify them.
*/
format?: string
/**
* Used by `YAML.createNode` to detect your data type, e.g. using `typeof` or
* `instanceof`.
*/
identify(value: any): boolean
/**
* The `Node` child class that implements this tag. Required for collections and tags that have overlapping JS representations.
*/
nodeClass?: new () => any
/**
* Used by some tags to configure their stringification, where applicable.
*/
options?: object
/**
* Turns a value into an AST node.
* If returning a non-`Node` value, the output will be wrapped as a `Scalar`.
*/
resolve(
value: string | YAMLMap | YAMLSeq,
onError: (message: string) => void
): Node | any
/**
* Optional function stringifying the AST node in the current context. If your
* data includes a suitable `.toString()` method, you can probably leave this
* undefined and use the default stringifier.
*
* @param item The node being stringified.
* @param ctx Contains the stringifying context variables.
* @param onComment Callback to signal that the stringifier includes the
* item's comment in its output.
* @param onChompKeep Callback to signal that the output uses a block scalar
* type with the `+` chomping indicator.
*/
stringify?: (
item: Node,
ctx: Schema.StringifyContext,
onComment?: () => void,
onChompKeep?: () => void
) => string
/**
* The identifier for your data type, with which its stringified form will be
* prefixed. Should either be a !-prefixed local `!tag`, or a fully qualified
* `tag:domain,date:foo`.
*/
tag: string
}
interface CustomTag extends BaseTag {
default?: false
}
interface DefaultTag extends BaseTag {
/**
* If `true`, together with `test` allows for values to be stringified without
* an explicit tag. For most cases, it's unlikely that you'll actually want to
* use this, even if you first think you do.
*/
default: true
/**
* Together with `default` allows for values to be stringified without an
* explicit tag and detected using a regular expression. For most cases, it's
* unlikely that you'll actually want to use these, even if you first think
* you do.
*/
test: RegExp
}
}
export class Node {
/** A comment on or immediately after this */
comment?: string | null
/** A comment before this */
commentBefore?: string | null
/** Only available when `keepCstNodes` is set to `true` */
cstNode?: CST.Node
/**
* The [start, end] range of characters of the source parsed
* into this node (undefined for pairs or if not parsed)
*/
range?: [number, number] | null
/** A blank line before this node and its commentBefore */
spaceBefore?: boolean
/** A fully qualified tag, if required */
tag?: string
/** A plain JS representation of this node */
toJSON(arg?: any): any
/** The type of this node */
type?: Type | Pair.Type
}
export class Scalar extends Node {
constructor(value: any)
type?: Scalar.Type
/**
* By default (undefined), numbers use decimal notation.
* The YAML 1.2 core schema only supports 'HEX' and 'OCT'.
*/
format?: 'BIN' | 'HEX' | 'OCT' | 'TIME'
value: any
toJSON(arg?: any, ctx?: AST.NodeToJsonContext): any
toString(): string
}
export namespace Scalar {
type Type =
| Type.BLOCK_FOLDED
| Type.BLOCK_LITERAL
| Type.PLAIN
| Type.QUOTE_DOUBLE
| Type.QUOTE_SINGLE
}
export class Alias extends Node {
type: Type.ALIAS
source: Node
cstNode?: CST.Alias
toString(ctx: Schema.StringifyContext): string
}
export class Pair extends Node {
constructor(key: any, value?: any)
type: Pair.Type.PAIR | Pair.Type.MERGE_PAIR
/** Always Node or null when parsed, but can be set to anything. */
key: any
/** Always Node or null when parsed, but can be set to anything. */
value: any
cstNode?: never // no corresponding cstNode
toJSON(arg?: any, ctx?: AST.NodeToJsonContext): object | Map<any, any>
toString(
ctx?: Schema.StringifyContext,
onComment?: () => void,
onChompKeep?: () => void
): string
}
export namespace Pair {
enum Type {
PAIR = 'PAIR',
MERGE_PAIR = 'MERGE_PAIR'
}
}
export class Merge extends Pair {
type: Pair.Type.MERGE_PAIR
/** Always Scalar('<<'), defined by the type specification */
key: AST.PlainValue
/** Always YAMLSeq<Alias(Map)>, stringified as *A if length = 1 */
value: YAMLSeq
toString(ctx?: Schema.StringifyContext, onComment?: () => void): string
}
export class Collection extends Node {
type?: Type.MAP | Type.FLOW_MAP | Type.SEQ | Type.FLOW_SEQ | Type.DOCUMENT
items: any[]
schema?: Schema
/**
* 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.
*/
add(value: any): void
addIn(path: Iterable<any>, value: any): void
/**
* Removes a value from the collection.
* @returns `true` if the item was found and removed.
*/
delete(key: any): boolean
deleteIn(path: Iterable<any>): boolean
/**
* 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).
*/
get(key: any, keepScalar?: boolean): any
getIn(path: Iterable<any>, keepScalar?: boolean): any
/**
* Checks if the collection includes a value with the key `key`.
*/
has(key: any): boolean
hasIn(path: Iterable<any>): boolean
/**
* Sets a value in this collection. For `!!set`, `value` needs to be a
* boolean to add/remove the item from the set.
*/
set(key: any, value: any): void
setIn(path: Iterable<any>, value: any): void
}
export class YAMLMap extends Collection {
type?: Type.FLOW_MAP | Type.MAP
items: Array<Pair>
hasAllNullValues(): boolean
toJSON(arg?: any, ctx?: AST.NodeToJsonContext): object | Map<any, any>
toString(
ctx?: Schema.StringifyContext,
onComment?: () => void,
onChompKeep?: () => void
): string
}
export class YAMLSeq extends Collection {
type?: Type.FLOW_SEQ | Type.SEQ
delete(key: number | string | Scalar): boolean
get(key: number | string | Scalar, keepScalar?: boolean): any
has(key: number | string | Scalar): boolean
set(key: number | string | Scalar, value: any): void
hasAllNullValues(): boolean
toJSON(arg?: any, ctx?: AST.NodeToJsonContext): any[]
toString(
ctx?: Schema.StringifyContext,
onComment?: () => void,
onChompKeep?: () => void
): string
}
export namespace AST {
interface NodeToJsonContext {
anchors?: any[]
doc: Document
keep?: boolean
mapAsMap?: boolean
maxAliasCount?: number
onCreate?: (node: Node) => void
[key: string]: any
}
interface BlockFolded extends Scalar {
type: Type.BLOCK_FOLDED
cstNode?: CST.BlockFolded
}
interface BlockLiteral extends Scalar {
type: Type.BLOCK_LITERAL
cstNode?: CST.BlockLiteral
}
interface PlainValue extends Scalar {
type: Type.PLAIN
cstNode?: CST.PlainValue
}
interface QuoteDouble extends Scalar {
type: Type.QUOTE_DOUBLE
cstNode?: CST.QuoteDouble
}
interface QuoteSingle extends Scalar {
type: Type.QUOTE_SINGLE
cstNode?: CST.QuoteSingle
}
interface FlowMap extends YAMLMap {
type: Type.FLOW_MAP
cstNode?: CST.FlowMap
}
interface BlockMap extends YAMLMap {
type: Type.MAP
cstNode?: CST.Map
}
interface FlowSeq extends YAMLSeq {
type: Type.FLOW_SEQ
items: Array<Node>
cstNode?: CST.FlowSeq
}
interface BlockSeq extends YAMLSeq {
type: Type.SEQ
items: Array<Node | null>
cstNode?: CST.Seq
}
}
+17
View File
@@ -0,0 +1,17 @@
const types = require('./dist/types')
exports.binaryOptions = types.binaryOptions
exports.boolOptions = types.boolOptions
exports.intOptions = types.intOptions
exports.nullOptions = types.nullOptions
exports.strOptions = types.strOptions
exports.Schema = types.Schema
exports.Alias = types.Alias
exports.Collection = types.Collection
exports.Merge = types.Merge
exports.Node = types.Node
exports.Pair = types.Pair
exports.Scalar = types.Scalar
exports.YAMLMap = types.YAMLMap
exports.YAMLSeq = types.YAMLSeq
+17
View File
@@ -0,0 +1,17 @@
import types from './dist/types.js'
export const binaryOptions = types.binaryOptions
export const boolOptions = types.boolOptions
export const intOptions = types.intOptions
export const nullOptions = types.nullOptions
export const strOptions = types.strOptions
export const Schema = types.Schema
export const Alias = types.Alias
export const Collection = types.Collection
export const Merge = types.Merge
export const Node = types.Node
export const Pair = types.Pair
export const Scalar = types.Scalar
export const YAMLMap = types.YAMLMap
export const YAMLSeq = types.YAMLSeq
+76
View File
@@ -0,0 +1,76 @@
import { CST } from './parse-cst'
import { Pair, Scalar, Schema } from './types'
export function findPair(items: any[], key: Scalar | any): Pair | undefined
export function stringifyNumber(item: Scalar): string
export function stringifyString(
item: Scalar,
ctx: Schema.StringifyContext,
onComment?: () => void,
onChompKeep?: () => void
): string
export function toJS(value: any, arg?: any, ctx?: Schema.CreateNodeContext): any
export enum Type {
ALIAS = 'ALIAS',
BLANK_LINE = 'BLANK_LINE',
BLOCK_FOLDED = 'BLOCK_FOLDED',
BLOCK_LITERAL = 'BLOCK_LITERAL',
COMMENT = 'COMMENT',
DIRECTIVE = 'DIRECTIVE',
DOCUMENT = 'DOCUMENT',
FLOW_MAP = 'FLOW_MAP',
FLOW_SEQ = 'FLOW_SEQ',
MAP = 'MAP',
MAP_KEY = 'MAP_KEY',
MAP_VALUE = 'MAP_VALUE',
PLAIN = 'PLAIN',
QUOTE_DOUBLE = 'QUOTE_DOUBLE',
QUOTE_SINGLE = 'QUOTE_SINGLE',
SEQ = 'SEQ',
SEQ_ITEM = 'SEQ_ITEM'
}
interface LinePos {
line: number
col: number
}
export class YAMLError extends Error {
name:
| 'YAMLReferenceError'
| 'YAMLSemanticError'
| 'YAMLSyntaxError'
| 'YAMLWarning'
message: string
source?: CST.Node
nodeType?: Type
range?: CST.Range
linePos?: { start: LinePos; end: LinePos }
/**
* Drops `source` and adds `nodeType`, `range` and `linePos`, as well as
* adding details to `message`. Run automatically for document errors if
* the `prettyErrors` option is set.
*/
makePretty(): void
}
export class YAMLReferenceError extends YAMLError {
name: 'YAMLReferenceError'
}
export class YAMLSemanticError extends YAMLError {
name: 'YAMLSemanticError'
}
export class YAMLSyntaxError extends YAMLError {
name: 'YAMLSyntaxError'
}
export class YAMLWarning extends YAMLError {
name: 'YAMLWarning'
}
+14
View File
@@ -0,0 +1,14 @@
const util = require('./dist/util')
exports.findPair = util.findPair
exports.toJSON = util.toJSON
exports.stringifyNumber = util.stringifyNumber
exports.stringifyString = util.stringifyString
exports.Type = util.Type
exports.YAMLError = util.YAMLError
exports.YAMLReferenceError = util.YAMLReferenceError
exports.YAMLSemanticError = util.YAMLSemanticError
exports.YAMLSyntaxError = util.YAMLSyntaxError
exports.YAMLWarning = util.YAMLWarning
+15
View File
@@ -0,0 +1,15 @@
import util from './dist/util.js'
export const findPair = util.findPair
export const toJSON = util.toJSON
export const stringifyNumber = util.stringifyNumber
export const stringifyString = util.stringifyString
export const Type = util.Type
export const YAMLError = util.YAMLError
export const YAMLReferenceError = util.YAMLReferenceError
export const YAMLSemanticError = util.YAMLSemanticError
export const YAMLSyntaxError = util.YAMLSyntaxError
export const YAMLWarning = util.YAMLWarning