2023-07-25 01:54:31 +08:00
|
|
|
import {
|
|
|
|
findNodeOfType,
|
2024-07-30 23:33:33 +08:00
|
|
|
type ParseTree,
|
2024-02-28 03:05:12 +08:00
|
|
|
renderToText,
|
2024-08-22 02:13:40 +08:00
|
|
|
replaceNodesMatching,
|
|
|
|
traverseTreeAsync,
|
2024-02-29 22:23:05 +08:00
|
|
|
} from "./tree.ts";
|
2023-07-25 01:54:31 +08:00
|
|
|
|
2024-08-07 02:11:38 +08:00
|
|
|
import { cleanupJSON } from "@silverbulletmd/silverbullet/lib/json";
|
2024-07-09 15:32:57 +08:00
|
|
|
|
2024-03-16 22:29:24 +08:00
|
|
|
import { system, YAML } from "../syscalls.ts";
|
2023-07-26 23:12:56 +08:00
|
|
|
|
2023-07-25 01:54:31 +08:00
|
|
|
/**
|
2024-08-22 02:13:40 +08:00
|
|
|
* Extracts attributes from a tree
|
2023-07-25 01:54:31 +08:00
|
|
|
* @param tree tree to extract attributes from
|
|
|
|
* @returns mapping from attribute name to attribute value
|
|
|
|
*/
|
2023-07-26 23:12:56 +08:00
|
|
|
export async function extractAttributes(
|
2024-02-28 03:05:12 +08:00
|
|
|
tags: string[],
|
2023-07-25 01:54:31 +08:00
|
|
|
tree: ParseTree,
|
2023-07-26 23:12:56 +08:00
|
|
|
): Promise<Record<string, any>> {
|
2024-02-28 03:05:12 +08:00
|
|
|
let attributes: Record<string, any> = {};
|
2024-08-22 02:13:40 +08:00
|
|
|
await traverseTreeAsync(tree, async (n) => {
|
|
|
|
if (tree !== n && n.type === "ListItem") {
|
2023-07-25 01:54:31 +08:00
|
|
|
// Find top-level only, no nested lists
|
2024-08-22 02:13:40 +08:00
|
|
|
return true;
|
2023-07-25 01:54:31 +08:00
|
|
|
}
|
|
|
|
if (n.type === "Attribute") {
|
|
|
|
const nameNode = findNodeOfType(n, "AttributeName");
|
|
|
|
const valueNode = findNodeOfType(n, "AttributeValue");
|
|
|
|
if (nameNode && valueNode) {
|
2023-07-26 23:12:56 +08:00
|
|
|
const name = nameNode.children![0].text!;
|
|
|
|
const val = valueNode.children![0].text!;
|
|
|
|
try {
|
2024-07-09 15:32:57 +08:00
|
|
|
attributes[name] = cleanupJSON(await YAML.parse(val));
|
2023-07-26 23:12:56 +08:00
|
|
|
} catch (e: any) {
|
|
|
|
console.error("Error parsing attribute value as YAML", val, e);
|
2023-07-25 01:54:31 +08:00
|
|
|
}
|
|
|
|
}
|
2024-08-22 02:13:40 +08:00
|
|
|
return true;
|
2023-07-25 01:54:31 +08:00
|
|
|
}
|
|
|
|
// Go on...
|
2024-08-22 02:13:40 +08:00
|
|
|
return false;
|
2023-07-25 01:54:31 +08:00
|
|
|
});
|
2024-02-28 03:05:12 +08:00
|
|
|
const text = renderToText(tree);
|
|
|
|
const spaceScriptAttributes = await system.applyAttributeExtractors(
|
|
|
|
tags,
|
|
|
|
text,
|
|
|
|
tree,
|
|
|
|
);
|
|
|
|
attributes = {
|
|
|
|
...attributes,
|
|
|
|
...spaceScriptAttributes,
|
|
|
|
};
|
2023-07-25 01:54:31 +08:00
|
|
|
return attributes;
|
|
|
|
}
|
2024-08-22 02:13:40 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Cleans attributes from a tree (as a side effect)
|
|
|
|
* @param tree to clean attributes from
|
|
|
|
*/
|
|
|
|
export function cleanAttributes(tree: ParseTree) {
|
|
|
|
replaceNodesMatching(tree, (n) => {
|
|
|
|
if (n.type === "Attribute") {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
});
|
|
|
|
}
|