2022-10-21 14:44:44 +00:00
'use strict' ;
var log = require ( '../log.js' ) ;
var stringify = require ( '../stringify/stringify.js' ) ;
2024-01-17 09:08:10 +00:00
var identity = require ( './identity.js' ) ;
2022-10-21 14:44:44 +00:00
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 ) ) {
2024-01-17 09:08:10 +00:00
value = identity . isAlias ( value ) ? value . resolve ( ctx . doc ) : value ;
if ( identity . isSeq ( value ) )
2022-10-21 14:44:44 +00:00
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 ||
2024-01-17 09:08:10 +00:00
( identity . isScalar ( key ) &&
2022-10-21 14:44:44 +00:00
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 ) {
2024-01-17 09:08:10 +00:00
const source = ctx && identity . isAlias ( value ) ? value . resolve ( ctx . doc ) : value ;
if ( ! identity . isMap ( source ) )
2022-10-21 14:44:44 +00:00
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 ) ;
2024-01-17 09:08:10 +00:00
if ( identity . isNode ( key ) && ctx ? . doc ) {
2022-10-21 14:44:44 +00:00
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 ;