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.
116 lines
3.8 KiB
116 lines
3.8 KiB
import { stringifyCollection } from '../stringify/stringifyCollection.js'; |
|
import { addPairToJSMap } from './addPairToJSMap.js'; |
|
import { Collection } from './Collection.js'; |
|
import { isPair, isScalar, MAP } from './Node.js'; |
|
import { Pair } from './Pair.js'; |
|
import { isScalarValue } from './Scalar.js'; |
|
|
|
function findPair(items, key) { |
|
const k = isScalar(key) ? key.value : key; |
|
for (const it of items) { |
|
if (isPair(it)) { |
|
if (it.key === key || it.key === k) |
|
return it; |
|
if (isScalar(it.key) && it.key.value === k) |
|
return it; |
|
} |
|
} |
|
return undefined; |
|
} |
|
class YAMLMap extends Collection { |
|
constructor(schema) { |
|
super(MAP, schema); |
|
this.items = []; |
|
} |
|
static get tagName() { |
|
return 'tag:yaml.org,2002:map'; |
|
} |
|
/** |
|
* Adds a value to the collection. |
|
* |
|
* @param overwrite - If not set `true`, using a key that is already in the |
|
* collection will throw. Otherwise, overwrites the previous value. |
|
*/ |
|
add(pair, overwrite) { |
|
let _pair; |
|
if (isPair(pair)) |
|
_pair = pair; |
|
else if (!pair || typeof pair !== 'object' || !('key' in pair)) { |
|
// In TypeScript, this never happens. |
|
_pair = new Pair(pair, pair?.value); |
|
} |
|
else |
|
_pair = new Pair(pair.key, pair.value); |
|
const prev = findPair(this.items, _pair.key); |
|
const sortEntries = this.schema?.sortMapEntries; |
|
if (prev) { |
|
if (!overwrite) |
|
throw new Error(`Key ${_pair.key} already set`); |
|
// For scalars, keep the old node & its comments and anchors |
|
if (isScalar(prev.value) && isScalarValue(_pair.value)) |
|
prev.value.value = _pair.value; |
|
else |
|
prev.value = _pair.value; |
|
} |
|
else if (sortEntries) { |
|
const i = this.items.findIndex(item => sortEntries(_pair, item) < 0); |
|
if (i === -1) |
|
this.items.push(_pair); |
|
else |
|
this.items.splice(i, 0, _pair); |
|
} |
|
else { |
|
this.items.push(_pair); |
|
} |
|
} |
|
delete(key) { |
|
const it = findPair(this.items, key); |
|
if (!it) |
|
return false; |
|
const del = this.items.splice(this.items.indexOf(it), 1); |
|
return del.length > 0; |
|
} |
|
get(key, keepScalar) { |
|
const it = findPair(this.items, key); |
|
const node = it?.value; |
|
return (!keepScalar && isScalar(node) ? node.value : node) ?? undefined; |
|
} |
|
has(key) { |
|
return !!findPair(this.items, key); |
|
} |
|
set(key, value) { |
|
this.add(new Pair(key, value), true); |
|
} |
|
/** |
|
* @param ctx - Conversion context, originally set in Document#toJS() |
|
* @param {Class} Type - If set, forces the returned collection type |
|
* @returns Instance of Type, Map, or Object |
|
*/ |
|
toJSON(_, ctx, Type) { |
|
const map = Type ? new Type() : ctx?.mapAsMap ? new Map() : {}; |
|
if (ctx?.onCreate) |
|
ctx.onCreate(map); |
|
for (const item of this.items) |
|
addPairToJSMap(ctx, map, item); |
|
return map; |
|
} |
|
toString(ctx, onComment, onChompKeep) { |
|
if (!ctx) |
|
return JSON.stringify(this); |
|
for (const item of this.items) { |
|
if (!isPair(item)) |
|
throw new Error(`Map items must all be pairs; found ${JSON.stringify(item)} instead`); |
|
} |
|
if (!ctx.allNullValues && this.hasAllNullValues(false)) |
|
ctx = Object.assign({}, ctx, { allNullValues: true }); |
|
return stringifyCollection(this, ctx, { |
|
blockItemPrefix: '', |
|
flowChars: { start: '{', end: '}' }, |
|
itemIndent: ctx.indent || '', |
|
onChompKeep, |
|
onComment |
|
}); |
|
} |
|
} |
|
|
|
export { YAMLMap, findPair };
|
|
|