silphius/app/astride/evaluators/object.js
2024-06-22 10:47:17 -05:00

84 lines
2.2 KiB
JavaScript

import {
isIdentifier,
isLiteral,
isProperty,
isSpreadElement,
} from '@/astride/types.js';
export default function(node, {evaluate, scope}) {
const {properties} = node;
let isAsync = false;
const entries = [];
for (let i = 0; i < properties.length; i++) {
if (isProperty(properties[i])) {
const {computed, key, value} = properties[i];
let k;
if (computed) {
k = evaluate(key, {scope});
}
else if (isIdentifier(key)) {
k = {value: key.name};
}
else if (isLiteral(key)) {
k = {value: key.value};
}
/* v8 ignore next 3 */
else {
throw new Error(`property key type ${key.type} not implemented`);
}
const v = evaluate(value, {scope});
isAsync ||= k.async || v.async;
if (k.async || v.async) {
entries.push(Promise.all([k.value, v.value]));
}
else {
entries.push([k.value, v.value]);
}
}
if (isSpreadElement(properties[i])) {
const {argument} = properties[i];
const spreading = evaluate(argument, {scope});
isAsync ||= spreading.async;
if (spreading.async) {
entries.push(Promise.resolve(spreading.value).then((spreading) => {
const entries = [];
const keys = Object.keys(spreading);
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
entries.push([key, spreading[key]]);
}
return entries;
}));
}
else {
const keys = Object.keys(spreading.value);
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
entries.push([key, spreading.value[key]]);
}
}
}
}
return {
async: !!isAsync,
value: isAsync
? Promise.all(entries)
.then((entries) => {
const flat = [];
for (let i = 0; i < entries.length; ++i) {
const entry = entries[i];
if (Array.isArray(entry[0])) {
for (let j = 0; j < entry.length; j++) {
flat.push(entry[j]);
}
}
else {
flat.push(entry);
}
}
return Object.fromEntries(flat);
})
: Object.fromEntries(entries),
};
}