You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.8 KiB
106 lines
3.8 KiB
'use strict'; |
|
|
|
var log = require('../log.js'); |
|
var stringify = require('../stringify/stringify.js'); |
|
var Node = require('./Node.js'); |
|
var Scalar = require('./Scalar.js'); |
|
var toJS = require('./toJS.js'); |
|
|
|
const MERGE_KEY = '<<'; |
|
function addPairToJSMap(ctx, map, { key, value }) { |
|
if (ctx?.doc.schema.merge && isMergeKey(key)) { |
|
value = Node.isAlias(value) ? value.resolve(ctx.doc) : value; |
|
if (Node.isSeq(value)) |
|
for (const it of value.items) |
|
mergeToJSMap(ctx, map, it); |
|
else if (Array.isArray(value)) |
|
for (const it of value) |
|
mergeToJSMap(ctx, map, it); |
|
else |
|
mergeToJSMap(ctx, map, value); |
|
} |
|
else { |
|
const jsKey = toJS.toJS(key, '', ctx); |
|
if (map instanceof Map) { |
|
map.set(jsKey, toJS.toJS(value, jsKey, ctx)); |
|
} |
|
else if (map instanceof Set) { |
|
map.add(jsKey); |
|
} |
|
else { |
|
const stringKey = stringifyKey(key, jsKey, ctx); |
|
const jsValue = toJS.toJS(value, stringKey, ctx); |
|
if (stringKey in map) |
|
Object.defineProperty(map, stringKey, { |
|
value: jsValue, |
|
writable: true, |
|
enumerable: true, |
|
configurable: true |
|
}); |
|
else |
|
map[stringKey] = jsValue; |
|
} |
|
} |
|
return map; |
|
} |
|
const isMergeKey = (key) => key === MERGE_KEY || |
|
(Node.isScalar(key) && |
|
key.value === MERGE_KEY && |
|
(!key.type || key.type === Scalar.Scalar.PLAIN)); |
|
// 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 |
|
function mergeToJSMap(ctx, map, value) { |
|
const source = ctx && Node.isAlias(value) ? value.resolve(ctx.doc) : value; |
|
if (!Node.isMap(source)) |
|
throw new Error('Merge sources must be maps or map aliases'); |
|
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; |
|
} |
|
function stringifyKey(key, jsKey, ctx) { |
|
if (jsKey === null) |
|
return ''; |
|
if (typeof jsKey !== 'object') |
|
return String(jsKey); |
|
if (Node.isNode(key) && ctx && ctx.doc) { |
|
const strCtx = stringify.createStringifyContext(ctx.doc, {}); |
|
strCtx.anchors = new Set(); |
|
for (const node of ctx.anchors.keys()) |
|
strCtx.anchors.add(node.anchor); |
|
strCtx.inFlow = true; |
|
strCtx.inStringifyKey = true; |
|
const strKey = key.toString(strCtx); |
|
if (!ctx.mapKeyWarned) { |
|
let jsonStr = JSON.stringify(strKey); |
|
if (jsonStr.length > 40) |
|
jsonStr = jsonStr.substring(0, 36) + '..."'; |
|
log.warn(ctx.doc.options.logLevel, `Keys with collection values will be stringified due to JS Object restrictions: ${jsonStr}. Set mapAsMap: true to use object keys.`); |
|
ctx.mapKeyWarned = true; |
|
} |
|
return strKey; |
|
} |
|
return JSON.stringify(jsKey); |
|
} |
|
|
|
exports.addPairToJSMap = addPairToJSMap;
|
|
|