diff --git a/.gitignore b/.gitignore index 2949f09b..57538075 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ doc benchmark/implementations/* !/benchmark/implementations/current/ dist/ +.claude/ +.codex/ +.agents/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e59030d..abf30a46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [4.0.0] - 2021-01-03 ### Changed -- Check [migration guide](migrate_v3_to_v4.md) to see details for all breaking changes. +- Check migration guide in [docs](docs/) for details of all breaking changes. - Breaking: "unsafe" tags `!!js/function`, `!!js/regexp`, `!!js/undefined` are moved to [js-yaml-js-types](https://github.com/nodeca/js-yaml-js-types) package. - Breaking: removed `safe*` functions. Use `load`, `loadAll`, `dump` diff --git a/bin/js-yaml.js b/bin/js-yaml.js index 583e2999..abcd7e00 100755 --- a/bin/js-yaml.js +++ b/bin/js-yaml.js @@ -9,8 +9,8 @@ const yaml = require('..') /// ///////////////////////////////////////////////////////////////////////////// const cli = new argparse.ArgumentParser({ - prog: 'js-yaml', - add_help: true + prog: 'js-yaml', + add_help: true }) cli.add_argument('-v', '--version', { @@ -19,26 +19,26 @@ cli.add_argument('-v', '--version', { }) cli.add_argument('-c', '--compact', { - help: 'Display errors in compact mode', + help: 'Display errors in compact mode', action: 'store_true' }) // deprecated (not needed after we removed output colors) // option suppressed, but not completely removed for compatibility cli.add_argument('-j', '--to-json', { - help: argparse.SUPPRESS, - dest: 'json', + help: argparse.SUPPRESS, + dest: 'json', action: 'store_true' }) cli.add_argument('-t', '--trace', { - help: 'Show stack trace on error', + help: 'Show stack trace on error', action: 'store_true' }) cli.add_argument('file', { - help: 'File to read, utf-8 encoded without BOM', - nargs: '?', + help: 'File to read, utf-8 encoded without BOM', + nargs: '?', default: '-' }) diff --git a/migrate_v3_to_v4.md b/docs/migrate_v3_to_v4.md similarity index 100% rename from migrate_v3_to_v4.md rename to docs/migrate_v3_to_v4.md diff --git a/docs/safety.md b/docs/safety.md new file mode 100644 index 00000000..d7771218 --- /dev/null +++ b/docs/safety.md @@ -0,0 +1,57 @@ +# Safety notes for untrusted input + +The YAML spec by design allows compact documents that produce objects which are +expensive to materialize. Guard against this when the input is untrusted. + +### 1. Limit input size + +Limit the input size to the smallest acceptable value. + +### 2. Catch all exceptions + +`load()` throws on malformed input. Always wrap it in `try/catch` and treat any +error as a rejected document. + +### 3. Traverse with a node limit before materializing + +Aliases let a tiny document expand into a huge object graph (the "billion +laughs" pattern) and can even create circular references. It stays cheap until +you fully walk it (`JSON.stringify`, deep clone, recursive validation), so do a +cheap pass first that counts every element and bails out past a limit. + +The walk is a flat loop over a manual stack — no recursion, so deep documents +can't overflow the call stack. Counting happens as each element is discovered, +so the stack never grows past the limit: + +```js +// plain `{}` or `Object.create(null)`, but not Date / Uint8Array / etc. +function isContainer(o) { + if (Array.isArray(o)) return true + if (!o || typeof o !== 'object') return false + const proto = Object.getPrototypeOf(o) + return proto === Object.prototype || proto === null +} + +function guardNodeCount(root, limit) { + let count = 0 + const stack = [ root ] + + while (stack.length) { + const node = stack.pop() + + for (const key in node) { + if (++count > limit) throw new Error('Too many nodes') + const value = node[key] + if (isContainer(value)) stack.push(value) + } + } +} + +const data = yaml.load(input) +guardNodeCount(data, 100000) +const json = JSON.stringify(data) +``` + +Note: aliases that point to the same node are counted every time they appear +(matching the real materialization cost), and a cyclic document keeps producing +elements until it hits the limit — both are rejected as intended. diff --git a/eslint.config.mjs b/eslint.config.mjs index 0af9359d..cb5f9824 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,9 +12,6 @@ export default [ { rules: { - camelcase: 'off', - '@stylistic/key-spacing': 'off', - 'no-useless-escape': 'off', 'object-shorthand': 'off', } } diff --git a/examples/dumper.js b/examples/dumper.js index d3fa3af6..337d99c9 100644 --- a/examples/dumper.js +++ b/examples/dumper.js @@ -6,8 +6,8 @@ const object = require('./dumper.json') console.log(yaml.dump(object, { flowLevel: 3, styles: { - '!!int' : 'hexadecimal', - '!!null' : 'camelcase' + '!!int': 'hexadecimal', + '!!null': 'camelcase' } })) diff --git a/index.js b/index.js index 3d5d4142..0b66b8f2 100644 --- a/index.js +++ b/index.js @@ -23,19 +23,19 @@ module.exports.YAMLException = require('./lib/exception') // Re-export all types in case user wants to create custom schema module.exports.types = { - binary: require('./lib/type/binary'), - float: require('./lib/type/float'), - map: require('./lib/type/map'), - null: require('./lib/type/null'), - pairs: require('./lib/type/pairs'), - set: require('./lib/type/set'), + binary: require('./lib/type/binary'), + float: require('./lib/type/float'), + map: require('./lib/type/map'), + null: require('./lib/type/null'), + pairs: require('./lib/type/pairs'), + set: require('./lib/type/set'), timestamp: require('./lib/type/timestamp'), - bool: require('./lib/type/bool'), - int: require('./lib/type/int'), - merge: require('./lib/type/merge'), - omap: require('./lib/type/omap'), - seq: require('./lib/type/seq'), - str: require('./lib/type/str') + bool: require('./lib/type/bool'), + int: require('./lib/type/int'), + merge: require('./lib/type/merge'), + omap: require('./lib/type/omap'), + seq: require('./lib/type/seq'), + str: require('./lib/type/str') } // Removed functions from JS-YAML 3.0.x diff --git a/lib/loader.js b/lib/loader.js index 8256c2d4..fb1bd53b 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -19,28 +19,31 @@ const CHOMPING_KEEP = 3 // eslint-disable-next-line no-control-regex const PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/ const PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/ -const PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/ +// eslint-disable-next-line no-useless-escape +const PATTERN_FLOW_INDICATORS = /[,\[\]{}]/ +// eslint-disable-next-line no-useless-escape const PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i -const PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i +// eslint-disable-next-line no-useless-escape +const PATTERN_TAG_URI = /^(?:!|[^,\[\]{}])(?:%[0-9a-f]{2}|[0-9a-z\-#;/?:@&=+$,_.!~*'()\[\]])*$/i function _class (obj) { return Object.prototype.toString.call(obj) } -function is_EOL (c) { +function isEol (c) { return (c === 0x0A/* LF */) || (c === 0x0D/* CR */) } -function is_WHITE_SPACE (c) { +function isWhiteSpace (c) { return (c === 0x09/* Tab */) || (c === 0x20/* Space */) } -function is_WS_OR_EOL (c) { +function isWsOrEol (c) { return (c === 0x09/* Tab */) || (c === 0x20/* Space */) || (c === 0x0A/* LF */) || (c === 0x0D/* CR */) } -function is_FLOW_INDICATOR (c) { +function isFlowIndicator (c) { return c === 0x2C/* , */ || c === 0x5B/* [ */ || c === 0x5D/* ] */ || @@ -177,11 +180,11 @@ function State (input, options) { function generateError (state, message) { const mark = { - name: state.filename, - buffer: state.input.slice(0, -1), // omit trailing \0 + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 position: state.position, - line: state.line, - column: state.position - state.lineStart + line: state.line, + column: state.position - state.lineStart } mark.snippet = makeSnippet(mark) @@ -381,7 +384,7 @@ function skipSeparationSpace (state, allowComments, checkIndent) { let ch = state.input.charCodeAt(state.position) while (ch !== 0) { - while (is_WHITE_SPACE(ch)) { + while (isWhiteSpace(ch)) { if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { state.firstTabInLine = state.position } @@ -394,7 +397,7 @@ function skipSeparationSpace (state, allowComments, checkIndent) { } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0) } - if (is_EOL(ch)) { + if (isEol(ch)) { readLineBreak(state) ch = state.input.charCodeAt(state.position) @@ -430,7 +433,7 @@ function testDocumentSeparator (state) { ch = state.input.charCodeAt(_position) - if (ch === 0 || is_WS_OR_EOL(ch)) { + if (ch === 0 || isWsOrEol(ch)) { return true } } @@ -458,8 +461,8 @@ function readPlainScalar (state, nodeIndent, withinFlowCollection) { let ch = state.input.charCodeAt(state.position) - if (is_WS_OR_EOL(ch) || - is_FLOW_INDICATOR(ch) || + if (isWsOrEol(ch) || + isFlowIndicator(ch) || ch === 0x23/* # */ || ch === 0x26/* & */ || ch === 0x2A/* * */ || @@ -477,8 +480,8 @@ function readPlainScalar (state, nodeIndent, withinFlowCollection) { if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { const following = state.input.charCodeAt(state.position + 1) - if (is_WS_OR_EOL(following) || - (withinFlowCollection && is_FLOW_INDICATOR(following))) { + if (isWsOrEol(following) || + (withinFlowCollection && isFlowIndicator(following))) { return false } } @@ -492,20 +495,20 @@ function readPlainScalar (state, nodeIndent, withinFlowCollection) { if (ch === 0x3A/* : */) { const following = state.input.charCodeAt(state.position + 1) - if (is_WS_OR_EOL(following) || - (withinFlowCollection && is_FLOW_INDICATOR(following))) { + if (isWsOrEol(following) || + (withinFlowCollection && isFlowIndicator(following))) { break } } else if (ch === 0x23/* # */) { const preceding = state.input.charCodeAt(state.position - 1) - if (is_WS_OR_EOL(preceding)) { + if (isWsOrEol(preceding)) { break } } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || - (withinFlowCollection && is_FLOW_INDICATOR(ch))) { + (withinFlowCollection && isFlowIndicator(ch))) { break - } else if (is_EOL(ch)) { + } else if (isEol(ch)) { _line = state.line _lineStart = state.lineStart _lineIndent = state.lineIndent @@ -531,7 +534,7 @@ function readPlainScalar (state, nodeIndent, withinFlowCollection) { hasPendingContent = false } - if (!is_WHITE_SPACE(ch)) { + if (!isWhiteSpace(ch)) { captureEnd = state.position + 1 } @@ -576,7 +579,7 @@ function readSingleQuotedScalar (state, nodeIndent) { } else { return true } - } else if (is_EOL(ch)) { + } else if (isEol(ch)) { captureSegment(state, captureStart, captureEnd, true) writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)) captureStart = captureEnd = state.position @@ -616,7 +619,7 @@ function readDoubleQuotedScalar (state, nodeIndent) { captureSegment(state, captureStart, state.position, true) ch = state.input.charCodeAt(++state.position) - if (is_EOL(ch)) { + if (isEol(ch)) { skipSeparationSpace(state, false, nodeIndent) // TODO: rework to inline fn with no type cast? @@ -645,7 +648,7 @@ function readDoubleQuotedScalar (state, nodeIndent) { } captureStart = captureEnd = state.position - } else if (is_EOL(ch)) { + } else if (isEol(ch)) { captureSegment(state, captureStart, captureEnd, true) writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)) captureStart = captureEnd = state.position @@ -722,7 +725,7 @@ function readFlowCollection (state, nodeIndent) { if (ch === 0x3F/* ? */) { const following = state.input.charCodeAt(state.position + 1) - if (is_WS_OR_EOL(following)) { + if (isWsOrEol(following)) { isPair = isExplicitPair = true state.position++ skipSeparationSpace(state, true, nodeIndent) @@ -816,13 +819,13 @@ function readBlockScalar (state, nodeIndent) { } } - if (is_WHITE_SPACE(ch)) { + if (isWhiteSpace(ch)) { do { ch = state.input.charCodeAt(++state.position) } - while (is_WHITE_SPACE(ch)) + while (isWhiteSpace(ch)) if (ch === 0x23/* # */) { do { ch = state.input.charCodeAt(++state.position) } - while (!is_EOL(ch) && (ch !== 0)) + while (!isEol(ch) && (ch !== 0)) } } @@ -843,7 +846,7 @@ function readBlockScalar (state, nodeIndent) { textIndent = state.lineIndent } - if (is_EOL(ch)) { + if (isEol(ch)) { emptyLines++ continue } @@ -866,7 +869,7 @@ function readBlockScalar (state, nodeIndent) { // Folded style: use fancy rules to handle line breaks. if (folding) { // Lines starting with white space characters (more-indented lines) are not folded. - if (is_WHITE_SPACE(ch)) { + if (isWhiteSpace(ch)) { atMoreIndented = true // except for the first content line (cf. Example 8.1) state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines) @@ -898,7 +901,7 @@ function readBlockScalar (state, nodeIndent) { emptyLines = 0 const captureStart = state.position - while (!is_EOL(ch) && (ch !== 0)) { + while (!isEol(ch) && (ch !== 0)) { ch = state.input.charCodeAt(++state.position) } @@ -936,7 +939,7 @@ function readBlockSequence (state, nodeIndent) { const following = state.input.charCodeAt(state.position + 1) - if (!is_WS_OR_EOL(following)) { + if (!isWsOrEol(following)) { break } @@ -1013,7 +1016,7 @@ function readBlockMapping (state, nodeIndent, flowIndent) { // Explicit notation case. There are two separate blocks: // first for the key (denoted by "?") and second for the value (denoted by ":") // - if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && isWsOrEol(following)) { if (ch === 0x3F/* ? */) { if (atExplicitKey) { storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos) @@ -1051,14 +1054,14 @@ function readBlockMapping (state, nodeIndent, flowIndent) { if (state.line === _line) { ch = state.input.charCodeAt(state.position) - while (is_WHITE_SPACE(ch)) { + while (isWhiteSpace(ch)) { ch = state.input.charCodeAt(++state.position) } if (ch === 0x3A/* : */) { ch = state.input.charCodeAt(++state.position) - if (!is_WS_OR_EOL(ch)) { + if (!isWsOrEol(ch)) { throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping') } @@ -1182,7 +1185,7 @@ function readTagProperty (state) { throwError(state, 'unexpected end of the stream within a verbatim tag') } } else { - while (ch !== 0 && !is_WS_OR_EOL(ch)) { + while (ch !== 0 && !isWsOrEol(ch)) { if (ch === 0x21/* ! */) { if (!isNamed) { tagHandle = state.input.slice(_position - 1, state.position + 1) @@ -1245,7 +1248,7 @@ function readAnchorProperty (state) { ch = state.input.charCodeAt(++state.position) const _position = state.position - while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { ch = state.input.charCodeAt(++state.position) } @@ -1265,7 +1268,7 @@ function readAlias (state) { ch = state.input.charCodeAt(++state.position) const _position = state.position - while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + while (ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)) { ch = state.input.charCodeAt(++state.position) } @@ -1478,7 +1481,7 @@ function readDocument (state) { ch = state.input.charCodeAt(++state.position) let _position = state.position - while (ch !== 0 && !is_WS_OR_EOL(ch)) { + while (ch !== 0 && !isWsOrEol(ch)) { ch = state.input.charCodeAt(++state.position) } @@ -1490,21 +1493,21 @@ function readDocument (state) { } while (ch !== 0) { - while (is_WHITE_SPACE(ch)) { + while (isWhiteSpace(ch)) { ch = state.input.charCodeAt(++state.position) } if (ch === 0x23/* # */) { do { ch = state.input.charCodeAt(++state.position) } - while (ch !== 0 && !is_EOL(ch)) + while (ch !== 0 && !isEol(ch)) break } - if (is_EOL(ch)) break + if (isEol(ch)) break _position = state.position - while (ch !== 0 && !is_WS_OR_EOL(ch)) { + while (ch !== 0 && !isWsOrEol(ch)) { ch = state.input.charCodeAt(++state.position) } diff --git a/lib/type/int.js b/lib/type/int.js index c4670b0f..b21bfea7 100644 --- a/lib/type/int.js +++ b/lib/type/int.js @@ -138,16 +138,16 @@ module.exports = new Type('tag:yaml.org,2002:int', { construct: constructYamlInteger, predicate: isInteger, represent: { - binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) }, - octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) }, - decimal: function (obj) { return obj.toString(10) }, + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1) }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1) }, + decimal: function (obj) { return obj.toString(10) }, hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1) } }, defaultStyle: 'decimal', styleAliases: { - binary: [2, 'bin'], - octal: [8, 'oct'], - decimal: [10, 'dec'], + binary: [2, 'bin'], + octal: [8, 'oct'], + decimal: [10, 'dec'], hexadecimal: [16, 'hex'] } }) diff --git a/lib/type/null.js b/lib/type/null.js index cbae3bdc..0a9d7e56 100644 --- a/lib/type/null.js +++ b/lib/type/null.js @@ -29,7 +29,7 @@ module.exports = new Type('tag:yaml.org,2002:null', { lowercase: function () { return 'null' }, uppercase: function () { return 'NULL' }, camelcase: function () { return 'Null' }, - empty: function () { return '' } + empty: function () { return '' } }, defaultStyle: 'lowercase' }) diff --git a/lib/type/timestamp.js b/lib/type/timestamp.js index 771474ea..05f323b6 100644 --- a/lib/type/timestamp.js +++ b/lib/type/timestamp.js @@ -16,8 +16,8 @@ const YAML_TIMESTAMP_REGEXP = new RegExp( ':([0-9][0-9])' + // [5] minute ':([0-9][0-9])' + // [6] second '(?:\\.([0-9]*))?' + // [7] fraction - '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour - '(?::([0-9][0-9]))?))?$') // [11] tz_minute + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tzHour + '(?::([0-9][0-9]))?))?$') // [11] tzMinute function resolveYamlTimestamp (data) { if (data === null) return false @@ -59,12 +59,12 @@ function constructYamlTimestamp (data) { fraction = +fraction } - // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + // match: [8] tz [9] tz_sign [10] tzHour [11] tzMinute if (match[9]) { - const tz_hour = +(match[10]) - const tz_minute = +(match[11] || 0) - delta = (tz_hour * 60 + tz_minute) * 60000 // delta in mili-seconds + const tzHour = +(match[10]) + const tzMinute = +(match[11] || 0) + delta = (tzHour * 60 + tzMinute) * 60000 // delta in mili-seconds if (match[9] === '-') delta = -delta } diff --git a/package.json b/package.json index 5b289fb5..914e3f35 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ }, "scripts": { "lint": "eslint .", + "lint-fix": "eslint . --fix", "test": "npm run lint && npm run test:core && npm run test:build", "test:core": "node --test test/core/*.test.*", "test:build": "npm run build && node --test test/build/*.test.*", diff --git a/support/demo_template/index.mjs b/support/demo_template/index.mjs index 7ccb5a90..857d557c 100644 --- a/support/demo_template/index.mjs +++ b/support/demo_template/index.mjs @@ -1,7 +1,7 @@ import jsyaml from '../../lib/index_vite_proxy.tmp.mjs' import codemirror from 'codemirror' import { inspect } from 'util' -import default_text from './sample.mjs' +import defaultText from './sample.mjs' import 'codemirror/lib/codemirror.css' import 'codemirror/mode/yaml/yaml.js' @@ -56,7 +56,7 @@ function updateSource () { yaml = decodeBase64(location.hash.slice(6)) } - source.setValue(yaml || default_text) + source.setValue(yaml || defaultText) parse() } diff --git a/test/core/issues/0303.js b/test/core/issues/0303.js index ef0ffaab..9bc41272 100644 --- a/test/core/issues/0303.js +++ b/test/core/issues/0303.js @@ -6,8 +6,8 @@ const assert = require('assert') const yaml = require('js-yaml') it('Loader should not strip quotes before newlines', function () { - const with_space = yaml.load("'''foo'' '") - const with_newline = yaml.load("'''foo''\n'") - assert.strictEqual(with_space, "'foo' ") - assert.strictEqual(with_newline, "'foo' ") + const withSpace = yaml.load("'''foo'' '") + const withNewline = yaml.load("'''foo''\n'") + assert.strictEqual(withSpace, "'foo' ") + assert.strictEqual(withNewline, "'foo' ") }) diff --git a/test/core/issues/0529.js b/test/core/issues/0529.js index bc913fd4..6060fbae 100644 --- a/test/core/issues/0529.js +++ b/test/core/issues/0529.js @@ -94,7 +94,7 @@ empty: '' assert.strictEqual(yaml.dump(sample, { quotingType: "'", forceQuotes: false }), expected) }) - it('quotingType=\", forceQuotes=false', function () { + it('quotingType=", forceQuotes=false', function () { const expected = ` simple_key: value foo'bar"baz: 1 @@ -159,7 +159,7 @@ empty: '' assert.strictEqual(yaml.dump(sample, { quotingType: "'", forceQuotes: true }), expected) }) - it('quotingType=\", forceQuotes=true', function () { + it('quotingType=", forceQuotes=true', function () { const expected = ` simple_key: "value" foo'bar"baz: 1 diff --git a/test/core/issues/0571.js b/test/core/issues/0571.js index bbd06e58..a2513d1a 100644 --- a/test/core/issues/0571.js +++ b/test/core/issues/0571.js @@ -14,7 +14,7 @@ describe('Undefined', function () { represent: () => '' }) - const undef_schema = yaml.DEFAULT_SCHEMA.extend(undef) + const undefSchema = yaml.DEFAULT_SCHEMA.extend(undef) it('Should replace undefined with null in collections', function () { let str @@ -59,16 +59,16 @@ describe('Undefined', function () { it('Should serialize undefined if schema is available', function () { assert.deepStrictEqual( yaml.load( - yaml.dump([1, undefined, null, 2], { schema: undef_schema }), - { schema: undef_schema } + yaml.dump([1, undefined, null, 2], { schema: undefSchema }), + { schema: undefSchema } ), [1, undefined, null, 2] ) assert.deepStrictEqual( yaml.load( - yaml.dump({ foo: 1, bar: undefined, baz: null }, { schema: undef_schema }), - { schema: undef_schema } + yaml.dump({ foo: 1, bar: undefined, baz: null }, { schema: undefSchema }), + { schema: undefSchema } ), { foo: 1, bar: undefined, baz: null } ) diff --git a/test/core/issues/0576.js b/test/core/issues/0576.js index 3137f4fb..f8a2dbf2 100644 --- a/test/core/issues/0576.js +++ b/test/core/issues/0576.js @@ -6,11 +6,11 @@ const assert = require('assert') const yaml = require('js-yaml') describe('Custom tags', function () { - const tag_names = ['tag', '!tag', '!!tag', '!', 'tag*-!< >{\n}', '!tagαβγ'] + const tagNames = ['tag', '!tag', '!!tag', '!', 'tag*-!< >{\n}', '!tagαβγ'] const encoded = ['!', '!tag', '!%21tag', '!%3C%21tag%3E', '!', '!tag%CE%B1%CE%B2%CE%B3'] - const tags = tag_names.map(tag => + const tags = tagNames.map(tag => new yaml.Type(tag, { kind: 'scalar', resolve: () => true, @@ -23,14 +23,14 @@ describe('Custom tags', function () { const schema = yaml.DEFAULT_SCHEMA.extend(tags) it('Should dump tags with proper encoding', function () { - tag_names.forEach(function (tag, idx) { + tagNames.forEach(function (tag, idx) { assert.strictEqual(yaml.dump({ tag }, { schema }), encoded[idx] + ' value\n') }) }) it('Should decode tags when loading', function () { encoded.forEach(function (tag, idx) { - assert.deepStrictEqual(yaml.load(tag + ' value', { schema }), [tag_names[idx], 'value']) + assert.deepStrictEqual(yaml.load(tag + ' value', { schema }), [tagNames[idx], 'value']) }) }) diff --git a/test/core/issues/0586.js b/test/core/issues/0586.js index 12fb3ca4..f5dc4a25 100644 --- a/test/core/issues/0586.js +++ b/test/core/issues/0586.js @@ -35,7 +35,7 @@ it('Should allow custom formatting through implicit custom tags', function () { return value // default } - const result = CustomDump({ flow_choices : [1, 2], block_choices: [4, 5] }).represent().trim() + const result = CustomDump({ flow_choices: [1, 2], block_choices: [4, 5] }).represent().trim() assert.strictEqual(result, ` flow_choices: [1, 2] diff --git a/test/core/samples-common/construct-omap.js b/test/core/samples-common/construct-omap.js index 8c41dcf5..bb06b5e6 100644 --- a/test/core/samples-common/construct-omap.js +++ b/test/core/samples-common/construct-omap.js @@ -2,13 +2,13 @@ module.exports = { Bestiary: [ - { aardvark : 'African pig-like ant eater. Ugly.' }, - { anteater : 'South-American ant eater. Two species.' }, - { anaconda : 'South-American constrictor snake. Scaly.' } + { aardvark: 'African pig-like ant eater. Ugly.' }, + { anteater: 'South-American ant eater. Two species.' }, + { anaconda: 'South-American constrictor snake. Scaly.' } ], Numbers: [ - { one : 1 }, - { two : 2 }, - { three : 3 } + { one: 1 }, + { two: 2 }, + { three: 3 } ] } diff --git a/test/core/samples-common/construct-timestamp.js b/test/core/samples-common/construct-timestamp.js index d82b88c1..3b3f99b0 100644 --- a/test/core/samples-common/construct-timestamp.js +++ b/test/core/samples-common/construct-timestamp.js @@ -1,9 +1,9 @@ 'use strict' module.exports = { - canonical: new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), - 'valid iso8601': new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), - 'space separated': new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), + canonical: new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), + 'valid iso8601': new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), + 'space separated': new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), 'no time zone (Z)': new Date(Date.UTC(2001, 11, 15, 2, 59, 43, 100)), 'date (00:00:00Z)': new Date(Date.UTC(2002, 11, 14)), 'not a date': '2002-1-1' diff --git a/test/core/samples-common/dump-empty-collections.js b/test/core/samples-common/dump-empty-collections.js index 0591ac63..bea5772c 100644 --- a/test/core/samples-common/dump-empty-collections.js +++ b/test/core/samples-common/dump-empty-collections.js @@ -1,6 +1,6 @@ 'use strict' module.exports = { - emptyArray: [], + emptyArray: [], emptyObject: {} } diff --git a/test/core/support/schema.js b/test/core/support/schema.js index f4bcf84f..11e0f701 100644 --- a/test/core/support/schema.js +++ b/test/core/support/schema.js @@ -86,14 +86,14 @@ const TEST_SCHEMA = yaml.DEFAULT_SCHEMA.extend([ }, construct: function (data) { return new Foo({ - myParameter: data['my-parameter'], + myParameter: data['my-parameter'], myAnotherParameter: data['my-another-parameter'] }) }, instanceOf: Foo, represent: function (object) { return { - 'my-parameter': object.myParameter, + 'my-parameter': object.myParameter, 'my-another-parameter': object.myAnotherParameter } } diff --git a/test/core/units/replacer.js b/test/core/units/replacer.js index 9298ace8..49737f00 100644 --- a/test/core/units/replacer.js +++ b/test/core/units/replacer.js @@ -14,7 +14,7 @@ describe('replacer', function () { represent: () => '' }) - const undef_schema = yaml.DEFAULT_SCHEMA.extend(undef) + const undefSchema = yaml.DEFAULT_SCHEMA.extend(undef) it('should be called on the root of the document', function () { let called = 0 @@ -127,9 +127,9 @@ describe('replacer', function () { if (key === 'b') return undefined return value }, - schema: undef_schema + schema: undefSchema }) - result = yaml.load(str, { schema: undef_schema }) + result = yaml.load(str, { schema: undefSchema }) assert.deepStrictEqual(result, { a: 1, b: undefined, c: 3 }) }) @@ -148,9 +148,9 @@ describe('replacer', function () { if (key === '1') return undefined return value }, - schema: undef_schema + schema: undefSchema }) - result = yaml.load(str, { schema: undef_schema }) + result = yaml.load(str, { schema: undefSchema }) assert.deepStrictEqual(result, [1, undefined, 3]) }) diff --git a/test/core/units/skip-invalid.js b/test/core/units/skip-invalid.js index 2bb05ac2..c9d0a3a9 100644 --- a/test/core/units/skip-invalid.js +++ b/test/core/units/skip-invalid.js @@ -8,15 +8,15 @@ const yaml = require('js-yaml') const sample = { number: 42, string: 'hello', - func: function (a, b) { return a + b }, + func: function (a, b) { return a + b }, regexp: /^hel+o/, - array: [1, 2, 3] + array: [1, 2, 3] } const expected = { number: 42, string: 'hello', - array: [1, 2, 3] + array: [1, 2, 3] } it('Dumper must throw an exception on invalid type when option `skipInvalid` is false.', function () {