Federation: rewrite page references in federated content
This commit is contained in:
parent
b584e2ef7e
commit
6929a7beb5
@ -30,14 +30,14 @@ export function isFederationPath(path: string) {
|
|||||||
return path.startsWith("!");
|
return path.startsWith("!");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rewritePageRefs(tree: ParseTree, templatePath: string) {
|
export function rewritePageRefs(tree: ParseTree, containerPageName: string) {
|
||||||
traverseTree(tree, (n): boolean => {
|
traverseTree(tree, (n): boolean => {
|
||||||
if (n.type === "DirectiveStart") {
|
if (n.type === "DirectiveStart") {
|
||||||
const pageRef = findNodeOfType(n, "PageRef")!;
|
const pageRef = findNodeOfType(n, "PageRef")!;
|
||||||
if (pageRef) {
|
if (pageRef) {
|
||||||
const pageRefName = pageRef.children![0].text!.slice(2, -2);
|
const pageRefName = pageRef.children![0].text!.slice(2, -2);
|
||||||
pageRef.children![0].text = `[[${
|
pageRef.children![0].text = `[[${
|
||||||
resolvePath(templatePath, pageRefName)
|
resolvePath(containerPageName, pageRefName)
|
||||||
}]]`;
|
}]]`;
|
||||||
}
|
}
|
||||||
const directiveText = n.children![0].text;
|
const directiveText = n.children![0].text;
|
||||||
@ -48,7 +48,7 @@ export function rewritePageRefs(tree: ParseTree, templatePath: string) {
|
|||||||
const pageRefName = match[1];
|
const pageRefName = match[1];
|
||||||
n.children![0].text = directiveText.replace(
|
n.children![0].text = directiveText.replace(
|
||||||
match[0],
|
match[0],
|
||||||
`[[${resolvePath(templatePath, pageRefName)}]]`,
|
`[[${resolvePath(containerPageName, pageRefName)}]]`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,7 +56,10 @@ export function rewritePageRefs(tree: ParseTree, templatePath: string) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (n.type === "WikiLinkPage") {
|
if (n.type === "WikiLinkPage") {
|
||||||
n.children![0].text = resolvePath(templatePath, n.children![0].text!);
|
n.children![0].text = resolvePath(
|
||||||
|
containerPageName,
|
||||||
|
n.children![0].text!,
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { index } from "$sb/silverbullet-syscall/mod.ts";
|
|||||||
import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
|
import { collectNodesOfType, ParseTree, renderToText } from "$sb/lib/tree.ts";
|
||||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
|
import { rewritePageRefs } from "$sb/lib/resolve.ts";
|
||||||
|
|
||||||
export type Item = {
|
export type Item = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -38,6 +39,7 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
|
|||||||
const textNodes: ParseTree[] = [];
|
const textNodes: ParseTree[] = [];
|
||||||
let nested: string | undefined;
|
let nested: string | undefined;
|
||||||
for (const child of n.children!.slice(1)) {
|
for (const child of n.children!.slice(1)) {
|
||||||
|
rewritePageRefs(child, name);
|
||||||
if (child.type === "OrderedList" || child.type === "BulletList") {
|
if (child.type === "OrderedList" || child.type === "BulletList") {
|
||||||
nested = renderToText(child);
|
nested = renderToText(child);
|
||||||
break;
|
break;
|
||||||
@ -67,7 +69,7 @@ export async function indexItems({ name, tree }: IndexTreeEvent) {
|
|||||||
value: item,
|
value: item,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// console.log("Found", items.length, "item(s)");
|
// console.log("Found", items, "item(s)");
|
||||||
await index.batchSet(name, items);
|
await index.batchSet(name, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import { events } from "$sb/plugos-syscall/mod.ts";
|
|||||||
|
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
import { invokeFunction } from "$sb/silverbullet-syscall/system.ts";
|
import { invokeFunction } from "$sb/silverbullet-syscall/system.ts";
|
||||||
import { backlinkPrefix } from "./page_links.ts";
|
|
||||||
|
|
||||||
// Key space:
|
// Key space:
|
||||||
// meta: => metaJson
|
// meta: => metaJson
|
||||||
|
@ -4,6 +4,7 @@ import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
|||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
import { IndexTreeEvent, QueryProviderEvent } from "$sb/app_event.ts";
|
||||||
import { applyQuery } from "$sb/lib/query.ts";
|
import { applyQuery } from "$sb/lib/query.ts";
|
||||||
|
import { resolvePath } from "$sb/lib/resolve.ts";
|
||||||
|
|
||||||
// Key space:
|
// Key space:
|
||||||
// l:toPage:pos => {name: pageName, inDirective: true, asTemplate: true}
|
// l:toPage:pos => {name: pageName, inDirective: true, asTemplate: true}
|
||||||
@ -46,7 +47,10 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
|||||||
directiveDepth++;
|
directiveDepth++;
|
||||||
const pageRef = findNodeOfType(n, "PageRef")!;
|
const pageRef = findNodeOfType(n, "PageRef")!;
|
||||||
if (pageRef) {
|
if (pageRef) {
|
||||||
const pageRefName = pageRef.children![0].text!.slice(2, -2);
|
const pageRefName = resolvePath(
|
||||||
|
name,
|
||||||
|
pageRef.children![0].text!.slice(2, -2),
|
||||||
|
);
|
||||||
backLinks.push({
|
backLinks.push({
|
||||||
key: `${backlinkPrefix}${pageRefName}:${pageRef.from! + 2}`,
|
key: `${backlinkPrefix}${pageRefName}:${pageRef.from! + 2}`,
|
||||||
value: { name, asTemplate: true },
|
value: { name, asTemplate: true },
|
||||||
@ -57,7 +61,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
|||||||
if (directiveText) {
|
if (directiveText) {
|
||||||
const match = /\[\[(.+)\]\]/.exec(directiveText);
|
const match = /\[\[(.+)\]\]/.exec(directiveText);
|
||||||
if (match) {
|
if (match) {
|
||||||
const pageRefName = match[1];
|
const pageRefName = resolvePath(name, match[1]);
|
||||||
backLinks.push({
|
backLinks.push({
|
||||||
key: `${backlinkPrefix}${pageRefName}:${
|
key: `${backlinkPrefix}${pageRefName}:${
|
||||||
n.from! + match.index! + 2
|
n.from! + match.index! + 2
|
||||||
@ -77,7 +81,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
|||||||
if (n.type === "WikiLink") {
|
if (n.type === "WikiLink") {
|
||||||
const wikiLinkPage = findNodeOfType(n, "WikiLinkPage")!;
|
const wikiLinkPage = findNodeOfType(n, "WikiLinkPage")!;
|
||||||
const wikiLinkAlias = findNodeOfType(n, "WikiLinkAlias");
|
const wikiLinkAlias = findNodeOfType(n, "WikiLinkAlias");
|
||||||
let toPage = wikiLinkPage.children![0].text!;
|
let toPage = resolvePath(name, wikiLinkPage.children![0].text!);
|
||||||
if (toPage.includes("@")) {
|
if (toPage.includes("@")) {
|
||||||
toPage = toPage.split("@")[0];
|
toPage = toPage.split("@")[0];
|
||||||
}
|
}
|
||||||
@ -96,7 +100,7 @@ export async function indexLinks({ name, tree }: IndexTreeEvent) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
// console.log("Found", backLinks.length, "page link(s)");
|
// console.log("Found", backLinks, "page link(s)");
|
||||||
await index.batchSet(name, backLinks);
|
await index.batchSet(name, backLinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
import { applyQuery, removeQueries } from "$sb/lib/query.ts";
|
||||||
import { niceDate } from "$sb/lib/dates.ts";
|
import { niceDate } from "$sb/lib/dates.ts";
|
||||||
import { extractAttributes } from "$sb/lib/attribute.ts";
|
import { extractAttributes } from "$sb/lib/attribute.ts";
|
||||||
|
import { rewritePageRefs } from "$sb/lib/resolve.ts";
|
||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -54,6 +55,8 @@ export async function indexTasks({ name, tree }: IndexTreeEvent) {
|
|||||||
done: complete,
|
done: complete,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rewritePageRefs(n, name);
|
||||||
|
|
||||||
replaceNodesMatching(n, (tree) => {
|
replaceNodesMatching(n, (tree) => {
|
||||||
if (tree.type === "DeadlineDate") {
|
if (tree.type === "DeadlineDate") {
|
||||||
task.deadline = getDeadline(tree);
|
task.deadline = getDeadline(tree);
|
||||||
@ -91,7 +94,7 @@ export async function indexTasks({ name, tree }: IndexTreeEvent) {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log("Found", tasks.length, "task(s)");
|
// console.log("Found", tasks, "task(s)");
|
||||||
await index.batchSet(name, tasks);
|
await index.batchSet(name, tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
website/Federation.md
Normal file
28
website/Federation.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Federation enables _browsing_, and _synchronizing_ (parts of) spaces outside of the user’s space into your SilverBullet client.
|
||||||
|
|
||||||
|
This enables a few things:
|
||||||
|
|
||||||
|
* Linking and browsing publicly hosted SilverBullet spaces (or website adhering to its [[API]]). For instance the [[!silverbullet.md/CHANGELOG|SilverBullet CHANGELOG]] without leaving the comfort of your own SilverBullet client.
|
||||||
|
* Reusing content from externally hosted sources, such as:
|
||||||
|
* _Templates_, e.g. by federating with `silverbullet.md/template` will give you access to the example templates hosted there without manually copying and pasting them, and automatically pull in the latest version. So you can for instance use `render [[!silverbullet.md/template/page]]` to use the [[template/page]] template.
|
||||||
|
* _Data_: such as tasks, item, data hosted elsewhere that you want to query from your own space.
|
||||||
|
|
||||||
|
**Note:** Federation does not support authentication yet, so all federated spaces need to be unauthenticated and will be _read only_.
|
||||||
|
|
||||||
|
## Browsing
|
||||||
|
Browsing other publicly hosted spaces is as simple as navigating to a page starting with `!` such as [[!silverbullet.md/CHANGELOG]].
|
||||||
|
|
||||||
|
## Federating
|
||||||
|
To synchronize federated content into your client, you need to list these URIs in your [[SETTINGS]] under the `federate` key. For instance:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
federate:
|
||||||
|
- uri: silverbullet.md/template
|
||||||
|
```
|
||||||
|
|
||||||
|
This will synchronize all content under `!silverbullet.md` with a `template` prefix (so all templates hosted there) locally.
|
||||||
|
|
||||||
|
Currently content can only be synchronized in read-only mode, so you can not edit the synchronized files. This will likely change in the future.
|
||||||
|
|
||||||
|
## Hosting
|
||||||
|
Tooling to make hosting public spaces is still work in progress.
|
Loading…
Reference in New Issue
Block a user