Files
plainleaf/plugs/index/paragraph.ts
T
Zef HemelandGitHub dc2987a3f9 Sync engine rearchitecture (#1516)
* Don't require auth for .ping
* Finally introducing loggers
* Remove file list caching from disk_space_primitives
I don't think this is required anymore with the sync model
* Simplification of space primitives and more tests
* More reliable online status
* Add .zed settings
* Remove selfUpdate argument from `writeFile` no longer used
- Add `sync` config schema and document sync options
- Move sync config handling to client boot logic
- Move BootConfig type to ui_types.ts
- Remove sync env vars from server
- Update documentation for sync and architecture
* Improve sync logic and proxy routing for full sync state
* Add BoxProxy for late-bound client and improve Lua boot
- Add isMobile syscall for editor
* Add concurrency to sync process and log indexing duration
* Better service worker lifecycle management
2025-09-12 14:43:57 +02:00

93 lines
2.5 KiB
TypeScript

import type { IndexTreeEvent } from "../../type/event.ts";
import { indexObjects } from "./api.ts";
import {
collectNodesOfType,
findParentMatching,
renderToText,
traverseTreeAsync,
} from "../../plug-api/lib/tree.ts";
import { extractAttributes } from "@silverbulletmd/silverbullet/lib/attribute";
import { updateITags } from "@silverbulletmd/silverbullet/lib/tags";
import { extractFrontMatter } from "@silverbulletmd/silverbullet/lib/frontmatter";
import { extractHashtag } from "../../plug-api/lib/tags.ts";
import type { ObjectValue } from "../../type/index.ts";
import { system } from "@silverbulletmd/silverbullet/syscalls";
/** ParagraphObject An index object for the top level text nodes */
export type ParagraphObject = ObjectValue<
{
page: string;
pos: number;
text: string;
} & Record<string, any>
>;
export async function indexParagraphs({ name: page, tree }: IndexTreeEvent) {
const shouldIndexAll = await system.getConfig(
"index.paragraph.all",
true,
);
const objects: ParagraphObject[] = [];
const frontmatter = await extractFrontMatter(tree);
await traverseTreeAsync(tree, async (p) => {
if (p.type !== "Paragraph") {
return false;
}
if (findParentMatching(p, (n) => n.type === "ListItem")) {
// Not looking at paragraphs nested in a list
return false;
}
const fullText = renderToText(p);
// Collect tags and remove from the tree
const tags = new Set<string>();
collectNodesOfType(p, "Hashtag").forEach((tagNode) => {
tags.add(extractHashtag(tagNode.children![0].text!));
// Hacky way to remove the hashtag
tagNode.children = [];
});
if (tags.size === 0 && !shouldIndexAll) {
// Don't index paragraphs without a hashtag
return false;
}
// Extract attributes and remove from tree
const attrs = await extractAttributes(p);
const text = renderToText(p);
if (!text.trim()) {
// Empty paragraph, just tags and attributes maybe
return true;
}
const pos = p.from!;
const paragraph: ParagraphObject = {
tag: "paragraph",
ref: `${page}@${pos}`,
text: fullText,
page,
pos,
...attrs,
};
if (tags.size > 0) {
paragraph.tags = [...tags];
paragraph.itags = [...tags];
}
updateITags(paragraph, frontmatter);
objects.push(paragraph);
// stop on every element except document, including paragraphs
return true;
});
// console.log("Paragraph objects", objects);
await indexObjects<ParagraphObject>(page, objects);
}