UNPKG

3.95 kBJavaScriptView Raw
1'use strict';
2
3var log = require('../log.js');
4var stringify = require('../stringify/stringify.js');
5var identity = require('./identity.js');
6var Scalar = require('./Scalar.js');
7var toJS = require('./toJS.js');
8
9const MERGE_KEY = '<<';
10function addPairToJSMap(ctx, map, { key, value }) {
11 if (ctx?.doc.schema.merge && isMergeKey(key)) {
12 value = identity.isAlias(value) ? value.resolve(ctx.doc) : value;
13 if (identity.isSeq(value))
14 for (const it of value.items)
15 mergeToJSMap(ctx, map, it);
16 else if (Array.isArray(value))
17 for (const it of value)
18 mergeToJSMap(ctx, map, it);
19 else
20 mergeToJSMap(ctx, map, value);
21 }
22 else {
23 const jsKey = toJS.toJS(key, '', ctx);
24 if (map instanceof Map) {
25 map.set(jsKey, toJS.toJS(value, jsKey, ctx));
26 }
27 else if (map instanceof Set) {
28 map.add(jsKey);
29 }
30 else {
31 const stringKey = stringifyKey(key, jsKey, ctx);
32 const jsValue = toJS.toJS(value, stringKey, ctx);
33 if (stringKey in map)
34 Object.defineProperty(map, stringKey, {
35 value: jsValue,
36 writable: true,
37 enumerable: true,
38 configurable: true
39 });
40 else
41 map[stringKey] = jsValue;
42 }
43 }
44 return map;
45}
46const isMergeKey = (key) => key === MERGE_KEY ||
47 (identity.isScalar(key) &&
48 key.value === MERGE_KEY &&
49 (!key.type || key.type === Scalar.Scalar.PLAIN));
50// If the value associated with a merge key is a single mapping node, each of
51// its key/value pairs is inserted into the current mapping, unless the key
52// already exists in it. If the value associated with the merge key is a
53// sequence, then this sequence is expected to contain mapping nodes and each
54// of these nodes is merged in turn according to its order in the sequence.
55// Keys in mapping nodes earlier in the sequence override keys specified in
56// later mapping nodes. -- http://yaml.org/type/merge.html
57function mergeToJSMap(ctx, map, value) {
58 const source = ctx && identity.isAlias(value) ? value.resolve(ctx.doc) : value;
59 if (!identity.isMap(source))
60 throw new Error('Merge sources must be maps or map aliases');
61 const srcMap = source.toJSON(null, ctx, Map);
62 for (const [key, value] of srcMap) {
63 if (map instanceof Map) {
64 if (!map.has(key))
65 map.set(key, value);
66 }
67 else if (map instanceof Set) {
68 map.add(key);
69 }
70 else if (!Object.prototype.hasOwnProperty.call(map, key)) {
71 Object.defineProperty(map, key, {
72 value,
73 writable: true,
74 enumerable: true,
75 configurable: true
76 });
77 }
78 }
79 return map;
80}
81function stringifyKey(key, jsKey, ctx) {
82 if (jsKey === null)
83 return '';
84 if (typeof jsKey !== 'object')
85 return String(jsKey);
86 if (identity.isNode(key) && ctx?.doc) {
87 const strCtx = stringify.createStringifyContext(ctx.doc, {});
88 strCtx.anchors = new Set();
89 for (const node of ctx.anchors.keys())
90 strCtx.anchors.add(node.anchor);
91 strCtx.inFlow = true;
92 strCtx.inStringifyKey = true;
93 const strKey = key.toString(strCtx);
94 if (!ctx.mapKeyWarned) {
95 let jsonStr = JSON.stringify(strKey);
96 if (jsonStr.length > 40)
97 jsonStr = jsonStr.substring(0, 36) + '..."';
98 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.`);
99 ctx.mapKeyWarned = true;
100 }
101 return strKey;
102 }
103 return JSON.stringify(jsKey);
104}
105
106exports.addPairToJSMap = addPairToJSMap;