SilverBullet pivot to become an offline-first PWA (#403)
This commit is contained in:
+15
-15
@@ -1,24 +1,24 @@
|
||||
import * as YAML from "yaml";
|
||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
||||
|
||||
import {
|
||||
addParentPointers,
|
||||
findNodeOfType,
|
||||
ParseTree,
|
||||
renderToText,
|
||||
replaceNodesMatching,
|
||||
traverseTree,
|
||||
replaceNodesMatchingAsync,
|
||||
traverseTreeAsync,
|
||||
} from "$sb/lib/tree.ts";
|
||||
|
||||
// Extracts front matter (or legacy "meta" code blocks) from a markdown document
|
||||
// optionally removes certain keys from the front matter
|
||||
export function extractFrontmatter(
|
||||
export async function extractFrontmatter(
|
||||
tree: ParseTree,
|
||||
removeKeys: string[] = [],
|
||||
): any {
|
||||
): Promise<any> {
|
||||
let data: any = {};
|
||||
addParentPointers(tree);
|
||||
|
||||
replaceNodesMatching(tree, (t) => {
|
||||
await replaceNodesMatchingAsync(tree, async (t) => {
|
||||
// Find top-level hash tags
|
||||
if (t.type === "Hashtag") {
|
||||
// Check if if nested directly into a Paragraph
|
||||
@@ -38,7 +38,7 @@ export function extractFrontmatter(
|
||||
const yamlNode = t.children![1].children![0];
|
||||
const yamlText = renderToText(yamlNode);
|
||||
try {
|
||||
const parsedData: any = YAML.parse(yamlText);
|
||||
const parsedData: any = await YAML.parse(yamlText);
|
||||
const newData = { ...parsedData };
|
||||
data = { ...data, ...parsedData };
|
||||
if (removeKeys.length > 0) {
|
||||
@@ -51,7 +51,7 @@ export function extractFrontmatter(
|
||||
}
|
||||
}
|
||||
if (removedOne) {
|
||||
yamlNode.text = YAML.stringify(newData);
|
||||
yamlNode.text = await YAML.stringify(newData);
|
||||
}
|
||||
}
|
||||
// If nothing is left, let's just delete this whole block
|
||||
@@ -92,7 +92,7 @@ export function extractFrontmatter(
|
||||
}
|
||||
}
|
||||
if (removedOne) {
|
||||
codeTextNode.children![0].text = YAML.stringify(newData).trim();
|
||||
codeTextNode.children![0].text = (await YAML.stringify(newData)).trim();
|
||||
}
|
||||
}
|
||||
// If nothing is left, let's just delete this whole block
|
||||
@@ -112,26 +112,26 @@ export function extractFrontmatter(
|
||||
}
|
||||
|
||||
// Updates the front matter of a markdown document and returns the text as a rendered string
|
||||
export function prepareFrontmatterDispatch(
|
||||
export async function prepareFrontmatterDispatch(
|
||||
tree: ParseTree,
|
||||
data: Record<string, any>,
|
||||
): any {
|
||||
): Promise<any> {
|
||||
let dispatchData: any = null;
|
||||
traverseTree(tree, (t) => {
|
||||
await traverseTreeAsync(tree, async (t) => {
|
||||
// Find FrontMatter and parse it
|
||||
if (t.type === "FrontMatter") {
|
||||
const bodyNode = t.children![1].children![0];
|
||||
const yamlText = renderToText(bodyNode);
|
||||
|
||||
try {
|
||||
const parsedYaml = YAML.parse(yamlText) as any;
|
||||
const parsedYaml = await YAML.parse(yamlText) as any;
|
||||
const newData = { ...parsedYaml, ...data };
|
||||
// Patch inline
|
||||
dispatchData = {
|
||||
changes: {
|
||||
from: bodyNode.from,
|
||||
to: bodyNode.to,
|
||||
insert: YAML.stringify(newData, { noArrayIndent: true }),
|
||||
insert: await YAML.stringify(newData),
|
||||
},
|
||||
};
|
||||
} catch (e: any) {
|
||||
@@ -147,7 +147,7 @@ export function prepareFrontmatterDispatch(
|
||||
changes: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
insert: "---\n" + YAML.stringify(data, { noArrayIndent: true }) +
|
||||
insert: "---\n" + await YAML.stringify(data) +
|
||||
"---\n",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ export async function readSecrets(keys: string[]): Promise<any[]> {
|
||||
}
|
||||
return collectedSecrets;
|
||||
} catch (e: any) {
|
||||
if (e.message === "Page not found") {
|
||||
if (e.message === "Not found") {
|
||||
throw new Error(`No such secret: ${keys[0]}`);
|
||||
}
|
||||
throw e;
|
||||
@@ -34,7 +34,7 @@ export async function readSecret(key: string): Promise<any> {
|
||||
}
|
||||
return val;
|
||||
} catch (e: any) {
|
||||
if (e.message === "Page not found") {
|
||||
if (e.message === "Not found") {
|
||||
throw new Error(`No such secret: ${key}`);
|
||||
}
|
||||
throw e;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readYamlPage } from "./yaml_page.ts";
|
||||
import { notifyUser } from "./util.ts";
|
||||
import * as YAML from "yaml";
|
||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
||||
|
||||
import { space } from "$sb/silverbullet-syscall/mod.ts";
|
||||
|
||||
@@ -30,7 +30,7 @@ export async function readSettings<T extends object>(settings: T): Promise<T> {
|
||||
}
|
||||
return collectedSettings as T;
|
||||
} catch (e: any) {
|
||||
if (e.message === "Page not found") {
|
||||
if (e.message === "Not found") {
|
||||
// No settings yet, return default values for all
|
||||
return settings;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export async function readSetting(
|
||||
const val = allSettings[key];
|
||||
return val === undefined ? defaultValue : val;
|
||||
} catch (e: any) {
|
||||
if (e.message === "Page not found") {
|
||||
if (e.message === "Not found") {
|
||||
// No settings yet, return default values for all
|
||||
return defaultValue;
|
||||
}
|
||||
@@ -71,10 +71,9 @@ export async function writeSettings<T extends object>(settings: T) {
|
||||
// const doc = new YAML.Document();
|
||||
// doc.contents = writeSettings;
|
||||
const contents =
|
||||
`This page contains settings for configuring SilverBullet and its Plugs.\nAny changes outside of the yaml block will be overwritten.\n\`\`\`yaml\n${
|
||||
YAML.stringify(
|
||||
`This page contains settings for configuring SilverBullet and its Plugs.\nAny changes outside of the yaml block will be overwritten.\n\`\`\`yaml\n${await YAML
|
||||
.stringify(
|
||||
writeSettings,
|
||||
)
|
||||
}\n\`\`\``; // might need \r\n for windows?
|
||||
)}\n\`\`\``; // might need \r\n for windows?
|
||||
await space.writePage(SETTINGS_PAGE, contents);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ Deno.test("Test parsing", () => {
|
||||
};
|
||||
}
|
||||
});
|
||||
console.log(JSON.stringify(mdTree, null, 2));
|
||||
// console.log(JSON.stringify(mdTree, null, 2));
|
||||
let mdTree3 = parse(lang, mdTest3);
|
||||
console.log(JSON.stringify(mdTree3, null, 2));
|
||||
// console.log(JSON.stringify(mdTree3, null, 2));
|
||||
});
|
||||
|
||||
@@ -69,6 +69,25 @@ export function collectNodesMatching(
|
||||
return results;
|
||||
}
|
||||
|
||||
export async function collectNodesMatchingAsync(
|
||||
tree: ParseTree,
|
||||
matchFn: (tree: ParseTree) => Promise<boolean>,
|
||||
): Promise<ParseTree[]> {
|
||||
if (await matchFn(tree)) {
|
||||
return [tree];
|
||||
}
|
||||
let results: ParseTree[] = [];
|
||||
if (tree.children) {
|
||||
for (const child of tree.children) {
|
||||
results = [
|
||||
...results,
|
||||
...await collectNodesMatchingAsync(child, matchFn),
|
||||
];
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// return value: returning undefined = not matched, continue, null = delete, new node = replace
|
||||
export function replaceNodesMatching(
|
||||
tree: ParseTree,
|
||||
@@ -93,6 +112,29 @@ export function replaceNodesMatching(
|
||||
}
|
||||
}
|
||||
|
||||
export async function replaceNodesMatchingAsync(
|
||||
tree: ParseTree,
|
||||
substituteFn: (tree: ParseTree) => Promise<ParseTree | null | undefined>,
|
||||
) {
|
||||
if (tree.children) {
|
||||
const children = tree.children.slice();
|
||||
for (const child of children) {
|
||||
const subst = await substituteFn(child);
|
||||
if (subst !== undefined) {
|
||||
const pos = tree.children.indexOf(child);
|
||||
if (subst) {
|
||||
tree.children.splice(pos, 1, subst);
|
||||
} else {
|
||||
// null = delete
|
||||
tree.children.splice(pos, 1);
|
||||
}
|
||||
} else {
|
||||
replaceNodesMatchingAsync(child, substituteFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function findNodeMatching(
|
||||
tree: ParseTree,
|
||||
matchFn: (tree: ParseTree) => boolean,
|
||||
@@ -116,6 +158,15 @@ export function traverseTree(
|
||||
collectNodesMatching(tree, matchFn);
|
||||
}
|
||||
|
||||
export async function traverseTreeAsync(
|
||||
tree: ParseTree,
|
||||
// Return value = should stop traversal?
|
||||
matchFn: (tree: ParseTree) => Promise<boolean>,
|
||||
): Promise<void> {
|
||||
// Do a collect, but ignore the result
|
||||
await collectNodesMatchingAsync(tree, matchFn);
|
||||
}
|
||||
|
||||
// Finds non-text node at position
|
||||
export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null {
|
||||
if (pos < tree.from! || pos >= tree.to!) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { findNodeOfType, traverseTree } from "$sb/lib/tree.ts";
|
||||
import { markdown, space } from "$sb/silverbullet-syscall/mod.ts";
|
||||
import * as YAML from "yaml";
|
||||
import { YAML } from "$sb/plugos-syscall/mod.ts";
|
||||
|
||||
export async function readCodeBlockPage(
|
||||
pageName: string,
|
||||
@@ -58,8 +58,6 @@ export async function writeYamlPage(
|
||||
data: any,
|
||||
prelude = "",
|
||||
): Promise<void> {
|
||||
const text = YAML.stringify(data, {
|
||||
noCompatMode: true,
|
||||
});
|
||||
const text = await YAML.stringify(data);
|
||||
await space.writePage(pageName, prelude + "```yaml\n" + text + "\n```");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user