Monorepo with yarn workspaces requires yarn 3.2

This commit is contained in:
Zef Hemel
2022-04-21 13:57:45 +02:00
parent 32f3501773
commit 1f842ec1d6
167 changed files with 10424 additions and 8263 deletions
-105
View File
@@ -1,105 +0,0 @@
syntax:
HashTag:
firstCharacters:
- "#"
regex: "#[A-Za-z\\.]+"
styles:
color: blue
AtMention:
firstCharacters:
- "@"
regex: "@[A-Za-z\\.]+"
styles:
color: blue
NakedURL:
firstCharacters:
- "h"
regex: "https?:\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}([-a-zA-Z0-9()@:%_\\+.~#?&=\\/]*)"
styles:
color: "#0330cb"
textDecoration: underline
functions:
clearPageIndex:
path: "./page.ts:clearPageIndex"
env: server
events:
- page:saved
- page:deleted
pageQueryProvider:
path: ./page.ts:pageQueryProvider
events:
- query:page
parseIndexTextRepublish:
path: "./page.ts:parseIndexTextRepublish"
events:
- page:index_text
indexLinks:
path: "./page.ts:indexLinks"
events:
- page:index
linkQueryProvider:
path: ./page.ts:linkQueryProvider
events:
- query:link
indexItems:
path: "./item.ts:indexItems"
events:
- page:index
itemQueryProvider:
path: ./item.ts:queryProvider
events:
- query:item
deletePage:
path: "./page.ts:deletePage"
command:
name: "Page: Delete"
reindexSpaceCommand:
path: "./page.ts:reindexCommand"
command:
name: "Space: Reindex"
reindexSpace:
path: "./page.ts:reindexSpace"
env: server
renamePage:
path: "./page.ts:renamePage"
command:
name: "Page: Rename"
mac: Cmd-Alt-r
key: Ctrl-Alt-r
pageComplete:
path: "./page.ts:pageComplete"
events:
- page:complete
linkNavigate:
path: "./navigate.ts:linkNavigate"
command:
name: Navigate To page
key: Ctrl-Enter
mac: Cmd-Enter
clickNavigate:
path: "./navigate.ts:clickNavigate"
events:
- page:click
insertToday:
path: "./dates.ts:insertToday"
slashCommand:
name: today
insertTomorrow:
path: "./dates.ts:insertTomorrow"
slashCommand:
name: tomorrow
parseServerCommand:
path: ./page.ts:parseServerPageCommand
command:
name: "Debug: Parse Document on Server"
parsePage:
path: ./page.ts:parsePage
parseCommand:
path: ./page.ts:parsePageCommand
command:
name: "Debug: Parse Document"
instantiateTemplateCommand:
path: ./template.ts:instantiateTemplateCommand
command:
name: "Template: Instantiate for Page"
-17
View File
@@ -1,17 +0,0 @@
import { insertAtCursor } from "plugos-silverbullet-syscall/editor";
const dateMatchRegex = /(\d{4}\-\d{2}\-\d{2})/g;
export function niceDate(d: Date): string {
return d.toISOString().split("T")[0];
}
export async function insertToday() {
await insertAtCursor(niceDate(new Date()));
}
export async function insertTomorrow() {
let d = new Date();
d.setDate(d.getDate() + 1);
await insertAtCursor(niceDate(d));
}
-71
View File
@@ -1,71 +0,0 @@
import { IndexTreeEvent } from "../../webapp/app_event";
import { batchSet, scanPrefixGlobal } from "plugos-silverbullet-syscall/index";
import { collectNodesOfType, ParseTree, renderToText } from "../../common/tree";
import { removeQueries } from "../query/util";
import { applyQuery, QueryProviderEvent } from "../query/engine";
export type Item = {
name: string;
nested?: string;
// Not stored in DB
page?: string;
pos?: number;
};
export async function indexItems({ name, tree }: IndexTreeEvent) {
let items: { key: string; value: Item }[] = [];
removeQueries(tree);
console.log("Indexing items", name);
let coll = collectNodesOfType(tree, "ListItem");
coll.forEach((n) => {
if (!n.children) {
return;
}
let textNodes: ParseTree[] = [];
let nested: string | undefined;
for (let child of n.children!.slice(1)) {
if (child.type === "OrderedList" || child.type === "BulletList") {
nested = renderToText(child);
break;
}
textNodes.push(child);
}
let item = textNodes.map(renderToText).join("").trim();
let value: Item = {
name: item,
};
if (nested) {
value.nested = nested;
}
items.push({
key: `it:${n.from}`,
value,
});
});
console.log("Found", items.length, "item(s)");
await batchSet(name, items);
}
export async function queryProvider({
query,
}: QueryProviderEvent): Promise<string> {
let allItems: Item[] = [];
for (let { key, page, value } of await scanPrefixGlobal("it:")) {
let [, pos] = key.split(":");
allItems.push({
...value,
page: page,
pos: +pos,
});
}
let markdownItems = applyQuery(query, allItems).map(
(item) =>
`* [[${item.page}@${item.pos}]] ${item.name}` +
(item.nested ? "\n " + item.nested : "")
);
return markdownItems.join("\n");
}
-38
View File
@@ -1,38 +0,0 @@
import {
getCursor,
getText,
insertAtPos,
replaceRange,
} from "plugos-silverbullet-syscall/editor";
export async function toggleH1() {
await togglePrefix("# ");
}
export async function toggleH2() {
await togglePrefix("## ");
}
function lookBack(s: string, pos: number, backString: string): boolean {
return s.substring(pos - backString.length, pos) === backString;
}
async function togglePrefix(prefix: string) {
let text = await getText();
let pos = await getCursor();
if (text[pos] === "\n") {
pos--;
}
while (pos > 0 && text[pos] !== "\n") {
if (lookBack(text, pos, prefix)) {
// Already has this prefix, let's flip it
await replaceRange(pos - prefix.length, pos, "");
return;
}
pos--;
}
if (pos) {
pos++;
}
await insertAtPos(prefix, pos);
}
-46
View File
@@ -1,46 +0,0 @@
import { ClickEvent } from "../../webapp/app_event";
import { getCursor, getText, navigate as navigateTo, openUrl } from "plugos-silverbullet-syscall/editor";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { nodeAtPos, ParseTree } from "../../common/tree";
const materializedQueryPrefix = /<!--\s*#query\s+/;
async function actionClickOrActionEnter(mdTree: ParseTree | null) {
if (!mdTree) {
return;
}
console.log("Attempting to navigate based on syntax node", mdTree);
switch (mdTree.type) {
case "WikiLinkPage":
let pageLink = mdTree.children![0].text!;
let pos = "0";
if (pageLink.includes("@")) {
[pageLink, pos] = pageLink.split("@");
}
await navigateTo(pageLink, +pos);
break;
case "URL":
case "NakedURL":
await openUrl(mdTree.children![0].text!);
break;
case "Link":
await openUrl(mdTree.children![4].children![0].text!);
break;
}
}
export async function linkNavigate() {
let mdTree = await parseMarkdown(await getText());
let newNode = nodeAtPos(mdTree, await getCursor());
await actionClickOrActionEnter(newNode);
}
export async function clickNavigate(event: ClickEvent) {
// Navigate by default, don't navigate when Ctrl or Cmd is held
if (event.ctrlKey || event.metaKey) {
return;
}
let mdTree = await parseMarkdown(await getText());
let newNode = nodeAtPos(mdTree, event.pos);
await actionClickOrActionEnter(newNode);
}
-253
View File
@@ -1,253 +0,0 @@
import { IndexEvent, IndexTreeEvent } from "../../webapp/app_event";
import {
batchSet,
clearPageIndex as clearPageIndexSyscall,
clearPageIndexForPage,
scanPrefixGlobal,
set
} from "plugos-silverbullet-syscall/index";
import {
flashNotification,
getCurrentPage,
getText,
matchBefore,
navigate,
prompt
} from "plugos-silverbullet-syscall/editor";
import { dispatch } from "plugos-syscall/event";
import { deletePage as deletePageSyscall, listPages, readPage, writePage } from "plugos-silverbullet-syscall/space";
import { invokeFunction } from "plugos-silverbullet-syscall/system";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import {
addParentPointers,
collectNodesMatching,
ParseTree,
renderToText,
replaceNodesMatching
} from "../../common/tree";
import { applyQuery, QueryProviderEvent } from "../query/engine";
import { PageMeta } from "../../common/types";
import { extractMeta } from "../query/data";
import { jsonToMDTable } from "../query/util";
// Key space:
// pl:toPage:pos => pageName
// meta => metaJson
export async function indexLinks({ name, tree }: IndexTreeEvent) {
let backLinks: { key: string; value: string }[] = [];
// [[Style Links]]
console.log("Now indexing", name);
let pageMeta = extractMeta(tree);
if (Object.keys(pageMeta).length > 0) {
await set(name, "meta:", pageMeta);
}
collectNodesMatching(tree, (n) => n.type === "WikiLinkPage").forEach((n) => {
let toPage = n.children![0].text!;
if (toPage.includes("@")) {
toPage = toPage.split("@")[0];
}
backLinks.push({
key: `pl:${toPage}:${n.from}`,
value: name,
});
});
console.log("Found", backLinks.length, "wiki link(s)");
await batchSet(name, backLinks);
}
export async function pageQueryProvider({
query,
}: QueryProviderEvent): Promise<string> {
let allPages = await listPages();
if (query.select) {
let allPageMap: Map<string, any> = new Map(
allPages.map((pm) => [pm.name, pm])
);
for (let { page, value } of await scanPrefixGlobal("meta:")) {
let p = allPageMap.get(page);
if (p) {
for (let [k, v] of Object.entries(value)) {
p[k] = v;
}
}
}
allPages = [...allPageMap.values()];
return jsonToMDTable(applyQuery(query, allPages), (k, v) =>
k === "name" ? `[[${v}]]` : v
);
} else {
return applyQuery(query, allPages)
.map((pageMeta: PageMeta) => `* [[${pageMeta.name}]]`)
.join("\n");
}
}
export async function linkQueryProvider({
query,
pageName,
}: QueryProviderEvent): Promise<string> {
let uniqueLinks = new Set<string>();
for (let { value: name } of await scanPrefixGlobal(`pl:${pageName}:`)) {
uniqueLinks.add(name);
}
let markdownLinks = applyQuery(
query,
[...uniqueLinks].map((l) => ({ name: l }))
).map((pageMeta) => `* [[${pageMeta.name}]]`);
return markdownLinks.join("\n");
}
export async function deletePage() {
let pageName = await getCurrentPage();
console.log("Navigating to start page");
await navigate("start");
console.log("Deleting page from space");
await deletePageSyscall(pageName);
}
export async function renamePage() {
const oldName = await getCurrentPage();
console.log("Old name is", oldName);
const newName = await prompt(`Rename ${oldName} to:`, oldName);
if (!newName) {
return;
}
console.log("New name", newName);
let pagesToUpdate = await getBackLinks(oldName);
console.log("All pages containing backlinks", pagesToUpdate);
let text = await getText();
console.log("Writing new page to space");
await writePage(newName, text);
console.log("Navigating to new page");
await navigate(newName);
console.log("Deleting page from space");
await deletePageSyscall(oldName);
let pageToUpdateSet = new Set<string>();
for (let pageToUpdate of pagesToUpdate) {
pageToUpdateSet.add(pageToUpdate.page);
}
for (let pageToUpdate of pageToUpdateSet) {
if (pageToUpdate === oldName) {
continue;
}
console.log("Now going to update links in", pageToUpdate);
let { text } = await readPage(pageToUpdate);
// console.log("Received text", text);
if (!text) {
// Page likely does not exist, but at least we can skip it
continue;
}
let mdTree = await parseMarkdown(text);
addParentPointers(mdTree);
replaceNodesMatching(mdTree, (n): ParseTree | undefined | null => {
if (n.type === "WikiLinkPage") {
let pageName = n.children![0].text!;
if (pageName === oldName) {
n.children![0].text = newName;
return n;
}
// page name with @pos position
if (pageName.startsWith(`${oldName}@`)) {
let [, pos] = pageName.split("@");
n.children![0].text = `${newName}@${pos}`;
return n;
}
}
return;
});
// let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);
let newText = renderToText(mdTree);
if (text !== newText) {
console.log("Changes made, saving...");
await writePage(pageToUpdate, newText);
}
}
}
type BackLink = {
page: string;
pos: number;
};
async function getBackLinks(pageName: string): Promise<BackLink[]> {
let allBackLinks = await scanPrefixGlobal(`pl:${pageName}:`);
let pagesToUpdate: BackLink[] = [];
for (let { key, value } of allBackLinks) {
let keyParts = key.split(":");
pagesToUpdate.push({
page: value,
pos: +keyParts[keyParts.length - 1],
});
}
return pagesToUpdate;
}
export async function reindexCommand() {
await flashNotification("Reindexing...");
await invokeFunction("server", "reindexSpace");
await flashNotification("Reindexing done");
}
// Completion
export async function pageComplete() {
let prefix = await matchBefore("\\[\\[[\\w\\s]*");
if (!prefix) {
return null;
}
let allPages = await listPages();
return {
from: prefix.from + 2,
options: allPages.map((pageMeta) => ({
label: pageMeta.name,
type: "page",
})),
};
}
// Server functions
export async function reindexSpace() {
console.log("Clearing page index...");
await clearPageIndexSyscall();
console.log("Listing all pages");
let pages = await listPages();
for (let { name } of pages) {
console.log("Indexing", name);
const { text } = await readPage(name);
let parsed = await parseMarkdown(text);
await dispatch("page:index", {
name,
tree: parsed,
});
}
}
export async function clearPageIndex(page: string) {
console.log("Clearing page index for page", page);
await clearPageIndexForPage(page);
}
export async function parseIndexTextRepublish({ name, text }: IndexEvent) {
await dispatch("page:index", {
name,
tree: await parseMarkdown(text),
});
}
export async function parseServerPageCommand() {
console.log(await invokeFunction("server", "parsePage", await getText()));
}
export async function parsePageCommand() {
parsePage(await getText());
}
export async function parsePage(text: string) {
console.log("AST", JSON.stringify(await parseMarkdown(text), null, 2));
}
-9
View File
@@ -1,9 +0,0 @@
import { EndpointRequest, EndpointResponse } from "../../plugos/hooks/endpoint";
export function endpointTest(req: EndpointRequest): EndpointResponse {
console.log("I'm running on the server!", req);
return {
status: 200,
body: "Hello world!",
};
}
-58
View File
@@ -1,58 +0,0 @@
import { listPages, readPage, writePage } from "plugos-silverbullet-syscall/space";
import { filterBox, navigate, prompt } from "plugos-silverbullet-syscall/editor";
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
import { extractMeta } from "../query/data";
import { renderToText } from "../../common/tree";
import { niceDate } from "./dates";
const pageTemplatePrefix = `template/page/`;
export async function instantiateTemplateCommand() {
let allPages = await listPages();
let allPageTemplates = allPages.filter((pageMeta) =>
pageMeta.name.startsWith(pageTemplatePrefix)
);
let selectedTemplate = await filterBox(
"Template",
allPageTemplates,
"Select the template to create a new page from"
);
if (!selectedTemplate) {
return;
}
console.log("Selected template", selectedTemplate);
let { text } = await readPage(selectedTemplate.name);
let parseTree = await parseMarkdown(text);
let additionalPageMeta = extractMeta(parseTree, true);
console.log("Page meta", additionalPageMeta);
let pageName = await prompt("Name of new page", additionalPageMeta.name);
if (!pageName) {
return;
}
let pageText = replaceTemplateVars(renderToText(parseTree), pageName);
await writePage(pageName, pageText);
await navigate(pageName);
}
export function replaceTemplateVars(s: string, pageName: string): string {
return s.replaceAll(/\{\{([^\}]+)\}\}/g, (match, v) => {
switch (v) {
case "today":
return niceDate(new Date());
case "yesterday":
let yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
return niceDate(yesterday);
case "lastWeek":
let lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);
return niceDate(lastWeek);
}
return match;
});
}
-9
View File
@@ -1,9 +0,0 @@
function countWords(str: string): number {
const matches = str.match(/[\w\d\'-]+/gi);
return matches ? matches.length : 0;
}
function readingTime(wordCount: number): number {
// 225 is average word reading speed for adults
return Math.ceil(wordCount / 225);
}