Materialized query parser redo
parent
d649009dd2
commit
b3c3302970
|
@ -13,4 +13,14 @@ export type SilverBulletHooks = CommandHookT &
|
|||
CronHookT &
|
||||
EventHookT;
|
||||
|
||||
export type Manifest = plugos.Manifest<SilverBulletHooks>;
|
||||
export type SyntaxExtensions = {
|
||||
syntax?: { [key: string]: NodeDef };
|
||||
};
|
||||
|
||||
export type NodeDef = {
|
||||
firstCharacters: string[];
|
||||
regex: string;
|
||||
styles: { [key: string]: string };
|
||||
};
|
||||
|
||||
export type Manifest = plugos.Manifest<SilverBulletHooks> & SyntaxExtensions;
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import type { SyntaxNode } from "@lezer/common";
|
||||
import type { Language } from "@codemirror/language";
|
||||
import { ParseTree } from "./tree";
|
||||
|
||||
export function lezerToParseTree(
|
||||
text: string,
|
||||
n: SyntaxNode,
|
||||
offset = 0
|
||||
): ParseTree {
|
||||
let children: ParseTree[] = [];
|
||||
let nodeText: string | undefined;
|
||||
let child = n.firstChild;
|
||||
while (child) {
|
||||
children.push(lezerToParseTree(text, child));
|
||||
child = child.nextSibling;
|
||||
}
|
||||
|
||||
if (children.length === 0) {
|
||||
children = [
|
||||
{
|
||||
from: n.from + offset,
|
||||
to: n.to + offset,
|
||||
text: text.substring(n.from, n.to),
|
||||
},
|
||||
];
|
||||
} else {
|
||||
let newChildren: ParseTree[] = [];
|
||||
let index = n.from;
|
||||
for (let child of children) {
|
||||
let s = text.substring(index, child.from);
|
||||
if (s) {
|
||||
newChildren.push({
|
||||
from: index + offset,
|
||||
to: child.from! + offset,
|
||||
text: s,
|
||||
});
|
||||
}
|
||||
newChildren.push(child);
|
||||
index = child.to!;
|
||||
}
|
||||
let s = text.substring(index, n.to);
|
||||
if (s) {
|
||||
newChildren.push({ from: index + offset, to: n.to + offset, text: s });
|
||||
}
|
||||
children = newChildren;
|
||||
}
|
||||
|
||||
let result: ParseTree = {
|
||||
type: n.name,
|
||||
from: n.from + offset,
|
||||
to: n.to + offset,
|
||||
};
|
||||
if (children.length > 0) {
|
||||
result.children = children;
|
||||
}
|
||||
if (nodeText) {
|
||||
result.text = nodeText;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function parse(language: Language, text: string): ParseTree {
|
||||
let tree = lezerToParseTree(text, language.parser.parse(text).topNode);
|
||||
// replaceNodesMatching(tree, (n): MarkdownTree | undefined | null => {
|
||||
// if (n.type === "FencedCode") {
|
||||
// let infoN = findNodeMatching(n, (n) => n.type === "CodeInfo");
|
||||
// let language = infoN!.children![0].text;
|
||||
// let textN = findNodeMatching(n, (n) => n.type === "CodeText");
|
||||
// let text = textN!.children![0].text!;
|
||||
//
|
||||
// console.log(language, text);
|
||||
// switch (language) {
|
||||
// case "yaml":
|
||||
// let parsed = StreamLanguage.define(yaml).parser.parse(text);
|
||||
// let subTree = treeToAST(text, parsed.topNode, n.from);
|
||||
// // console.log(JSON.stringify(subTree, null, 2));
|
||||
// subTree.type = "yaml";
|
||||
// return subTree;
|
||||
// }
|
||||
// }
|
||||
// return;
|
||||
// });
|
||||
return tree;
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
import { SysCallMapping } from "../../plugos/system";
|
||||
import { MarkdownTree, parse } from "../tree";
|
||||
import { parse } from "../parse_tree";
|
||||
import { Language } from "@codemirror/language";
|
||||
import type { ParseTree } from "../tree";
|
||||
|
||||
export function markdownSyscalls(): SysCallMapping {
|
||||
export function markdownSyscalls(lang: Language): SysCallMapping {
|
||||
return {
|
||||
"markdown.parseMarkdown": (ctx, text: string): MarkdownTree => {
|
||||
return parse(text);
|
||||
"markdown.parseMarkdown": (ctx, text: string): ParseTree => {
|
||||
return parse(lang, text);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { expect, test } from "@jest/globals";
|
||||
import { parse } from "../../common/tree";
|
||||
import { parse } from "./parse_tree";
|
||||
import {
|
||||
addParentPointers,
|
||||
collectNodesMatching,
|
||||
findParentMatching,
|
||||
nodeAtPos,
|
||||
removeParentPointers,
|
||||
renderMarkdown,
|
||||
renderToText,
|
||||
replaceNodesMatching
|
||||
} from "./tree";
|
||||
import wikiMarkdownLang from "../webapp/parser";
|
||||
|
||||
const mdTest1 = `
|
||||
# Heading
|
||||
|
@ -46,7 +47,8 @@ name: something
|
|||
`;
|
||||
|
||||
test("Run a Node sandbox", async () => {
|
||||
let mdTree = parse(mdTest1);
|
||||
const lang = wikiMarkdownLang([]);
|
||||
let mdTree = parse(lang, mdTest1);
|
||||
addParentPointers(mdTree);
|
||||
// console.log(JSON.stringify(mdTree, null, 2));
|
||||
let wikiLink = nodeAtPos(mdTree, mdTest1.indexOf("Wiki Page"))!;
|
||||
|
@ -59,7 +61,7 @@ test("Run a Node sandbox", async () => {
|
|||
expect(allTodos.length).toBe(2);
|
||||
|
||||
// Render back into markdown should be equivalent
|
||||
expect(renderMarkdown(mdTree)).toBe(mdTest1);
|
||||
expect(renderToText(mdTree)).toBe(mdTest1);
|
||||
|
||||
removeParentPointers(mdTree);
|
||||
replaceNodesMatching(mdTree, (n) => {
|
||||
|
@ -70,6 +72,6 @@ test("Run a Node sandbox", async () => {
|
|||
}
|
||||
});
|
||||
console.log(JSON.stringify(mdTree, null, 2));
|
||||
let mdTree3 = parse(mdTest3);
|
||||
let mdTree3 = parse(lang, mdTest3);
|
||||
console.log(JSON.stringify(mdTree3, null, 2));
|
||||
});
|
194
common/tree.ts
194
common/tree.ts
|
@ -1,87 +1,137 @@
|
|||
import { SyntaxNode } from "@lezer/common";
|
||||
import wikiMarkdownLang from "../webapp/parser";
|
||||
|
||||
export type MarkdownTree = {
|
||||
export type ParseTree = {
|
||||
type?: string; // undefined === text node
|
||||
from?: number;
|
||||
to?: number;
|
||||
text?: string;
|
||||
children?: MarkdownTree[];
|
||||
children?: ParseTree[];
|
||||
// Only present after running addParentPointers
|
||||
parent?: ParseTree;
|
||||
};
|
||||
|
||||
function treeToAST(text: string, n: SyntaxNode, offset = 0): MarkdownTree {
|
||||
let children: MarkdownTree[] = [];
|
||||
let nodeText: string | undefined;
|
||||
let child = n.firstChild;
|
||||
while (child) {
|
||||
children.push(treeToAST(text, child));
|
||||
child = child.nextSibling;
|
||||
export function addParentPointers(tree: ParseTree) {
|
||||
if (!tree.children) {
|
||||
return;
|
||||
}
|
||||
for (let child of tree.children) {
|
||||
child.parent = tree;
|
||||
addParentPointers(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (children.length === 0) {
|
||||
children = [
|
||||
{
|
||||
from: n.from + offset,
|
||||
to: n.to + offset,
|
||||
text: text.substring(n.from, n.to),
|
||||
},
|
||||
];
|
||||
} else {
|
||||
let newChildren: MarkdownTree[] | string = [];
|
||||
let index = n.from;
|
||||
export function removeParentPointers(tree: ParseTree) {
|
||||
delete tree.parent;
|
||||
if (!tree.children) {
|
||||
return;
|
||||
}
|
||||
for (let child of tree.children) {
|
||||
removeParentPointers(child);
|
||||
}
|
||||
}
|
||||
|
||||
export function findParentMatching(
|
||||
tree: ParseTree,
|
||||
matchFn: (tree: ParseTree) => boolean
|
||||
): ParseTree | null {
|
||||
let node = tree.parent;
|
||||
while (node) {
|
||||
if (matchFn(node)) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function collectNodesOfType(
|
||||
tree: ParseTree,
|
||||
nodeType: string
|
||||
): ParseTree[] {
|
||||
return collectNodesMatching(tree, (n) => n.type === nodeType);
|
||||
}
|
||||
|
||||
export function collectNodesMatching(
|
||||
tree: ParseTree,
|
||||
matchFn: (tree: ParseTree) => boolean
|
||||
): ParseTree[] {
|
||||
if (matchFn(tree)) {
|
||||
return [tree];
|
||||
}
|
||||
let results: ParseTree[] = [];
|
||||
if (tree.children) {
|
||||
for (let child of tree.children) {
|
||||
results = [...results, ...collectNodesMatching(child, matchFn)];
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// return value: returning undefined = not matched, continue, null = delete, new node = replace
|
||||
export function replaceNodesMatching(
|
||||
tree: ParseTree,
|
||||
substituteFn: (tree: ParseTree) => ParseTree | null | undefined
|
||||
) {
|
||||
if (tree.children) {
|
||||
let children = tree.children.slice();
|
||||
for (let child of children) {
|
||||
let s = text.substring(index, child.from);
|
||||
if (s) {
|
||||
newChildren.push({
|
||||
from: index + offset,
|
||||
to: child.from! + offset,
|
||||
text: s,
|
||||
});
|
||||
let subst = substituteFn(child);
|
||||
if (subst !== undefined) {
|
||||
let pos = tree.children.indexOf(child);
|
||||
if (subst) {
|
||||
tree.children.splice(pos, 1, subst);
|
||||
} else {
|
||||
// null = delete
|
||||
tree.children.splice(pos, 1);
|
||||
}
|
||||
} else {
|
||||
replaceNodesMatching(child, substituteFn);
|
||||
}
|
||||
newChildren.push(child);
|
||||
index = child.to!;
|
||||
}
|
||||
let s = text.substring(index, n.to);
|
||||
if (s) {
|
||||
newChildren.push({ from: index + offset, to: n.to + offset, text: s });
|
||||
}
|
||||
children = newChildren;
|
||||
}
|
||||
|
||||
let result: MarkdownTree = {
|
||||
type: n.name,
|
||||
from: n.from + offset,
|
||||
to: n.to + offset,
|
||||
};
|
||||
if (children.length > 0) {
|
||||
result.children = children;
|
||||
}
|
||||
if (nodeText) {
|
||||
result.text = nodeText;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function parse(text: string): MarkdownTree {
|
||||
let tree = treeToAST(text, wikiMarkdownLang.parser.parse(text).topNode);
|
||||
// replaceNodesMatching(tree, (n): MarkdownTree | undefined | null => {
|
||||
// if (n.type === "FencedCode") {
|
||||
// let infoN = findNodeMatching(n, (n) => n.type === "CodeInfo");
|
||||
// let language = infoN!.children![0].text;
|
||||
// let textN = findNodeMatching(n, (n) => n.type === "CodeText");
|
||||
// let text = textN!.children![0].text!;
|
||||
//
|
||||
// console.log(language, text);
|
||||
// switch (language) {
|
||||
// case "yaml":
|
||||
// let parsed = StreamLanguage.define(yaml).parser.parse(text);
|
||||
// let subTree = treeToAST(text, parsed.topNode, n.from);
|
||||
// // console.log(JSON.stringify(subTree, null, 2));
|
||||
// subTree.type = "yaml";
|
||||
// return subTree;
|
||||
// }
|
||||
// }
|
||||
// return;
|
||||
// });
|
||||
return tree;
|
||||
export function findNodeMatching(
|
||||
tree: ParseTree,
|
||||
matchFn: (tree: ParseTree) => boolean
|
||||
): ParseTree | null {
|
||||
return collectNodesMatching(tree, matchFn)[0];
|
||||
}
|
||||
|
||||
export function findNodeOfType(
|
||||
tree: ParseTree,
|
||||
nodeType: string
|
||||
): ParseTree | null {
|
||||
return collectNodesMatching(tree, (n) => n.type === nodeType)[0];
|
||||
}
|
||||
|
||||
// Finds non-text node at position
|
||||
export function nodeAtPos(tree: ParseTree, pos: number): ParseTree | null {
|
||||
if (pos < tree.from! || pos > tree.to!) {
|
||||
return null;
|
||||
}
|
||||
if (!tree.children) {
|
||||
return tree;
|
||||
}
|
||||
for (let child of tree.children) {
|
||||
let n = nodeAtPos(child, pos);
|
||||
if (n && n.text !== undefined) {
|
||||
// Got a text node, let's return its parent
|
||||
return tree;
|
||||
} else if (n) {
|
||||
// Got it
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Turn ParseTree back into text
|
||||
export function renderToText(tree: ParseTree): string {
|
||||
let pieces: string[] = [];
|
||||
if (tree.text !== undefined) {
|
||||
return tree.text;
|
||||
}
|
||||
for (let child of tree.children!) {
|
||||
pieces.push(renderToText(child));
|
||||
}
|
||||
return pieces.join("");
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
},
|
||||
"test": {
|
||||
"source": [
|
||||
"plugs/lib/tree.test.ts",
|
||||
"common/tree.test.ts",
|
||||
"plugs/query/engine.test.ts",
|
||||
"common/spaces/sync.test.ts"
|
||||
],
|
||||
"includeNodeModules": ["@codemirror/legacy-modes"],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { syscall } from "./syscall";
|
||||
import type { MarkdownTree } from "../common/tree";
|
||||
|
||||
export async function parseMarkdown(text: string): Promise<MarkdownTree> {
|
||||
import type { ParseTree } from "../common/tree";
|
||||
|
||||
export async function parseMarkdown(text: string): Promise<ParseTree> {
|
||||
return syscall("markdown.parseMarkdown", text);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
syntax:
|
||||
HashTag:
|
||||
firstCharacters:
|
||||
- "#"
|
||||
regex: "#[A-Za-z\\.]+"
|
||||
styles:
|
||||
color: blue
|
||||
AtMention:
|
||||
firstCharacters:
|
||||
- "@"
|
||||
regex: "@[A-Za-z\\.]+"
|
||||
styles:
|
||||
color: blue
|
||||
URL:
|
||||
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"
|
||||
|
@ -55,13 +75,13 @@ functions:
|
|||
path: "./dates.ts:indexDates"
|
||||
events:
|
||||
- page:index
|
||||
updateMaterializedQueriesOnPage:
|
||||
path: ./materialized_queries.ts:updateMaterializedQueriesOnPage
|
||||
updateMaterializedQueriesCommand:
|
||||
path: ./materialized_queries.ts:updateMaterializedQueriesCommand
|
||||
parseServerCommand:
|
||||
path: ./page.ts:parseServerPageCommand
|
||||
command:
|
||||
name: "Materialized Queries: Update"
|
||||
parseCommand:
|
||||
name: "Debug: Parse Document on Server"
|
||||
parsePage:
|
||||
path: ./page.ts:parsePage
|
||||
parseCommand:
|
||||
path: ./page.ts:parsePageCommand
|
||||
command:
|
||||
name: Parse Document
|
||||
name: "Debug: Parse Document"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { insertAtCursor } from "plugos-silverbullet-syscall/editor";
|
||||
import { IndexEvent } from "../../webapp/app_event";
|
||||
import { batchSet } from "plugos-silverbullet-syscall";
|
||||
import { whiteOutQueries } from "./materialized_queries";
|
||||
import { whiteOutQueries } from "../query/materialized_queries";
|
||||
|
||||
const dateMatchRegex = /(\d{4}\-\d{2}\-\d{2})/g;
|
||||
|
||||
|
@ -23,12 +23,16 @@ export async function indexDates({ name, text }: IndexEvent) {
|
|||
await batchSet(name, dates);
|
||||
}
|
||||
|
||||
export function niceDate(d: Date): string {
|
||||
return new Date().toISOString().split("T")[0];
|
||||
}
|
||||
|
||||
export async function insertToday() {
|
||||
await insertAtCursor(new Date().toISOString().split("T")[0]);
|
||||
await insertAtCursor(niceDate(new Date()));
|
||||
}
|
||||
|
||||
export async function insertTomorrow() {
|
||||
let d = new Date();
|
||||
d.setDate(d.getDate() + 1);
|
||||
await insertAtCursor(d.toISOString().split("T")[0]);
|
||||
await insertAtCursor(niceDate(d));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { IndexEvent } from "../../webapp/app_event";
|
||||
import { whiteOutQueries } from "./materialized_queries";
|
||||
import { whiteOutQueries } from "../query/materialized_queries";
|
||||
|
||||
import { batchSet } from "plugos-silverbullet-syscall/index";
|
||||
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
|
||||
import { collectNodesMatching, MarkdownTree, renderMarkdown } from "../lib/tree";
|
||||
import { collectNodesMatching, ParseTree, renderToText } from "../../common/tree";
|
||||
|
||||
type Item = {
|
||||
item: string;
|
||||
|
@ -23,16 +23,16 @@ export async function indexItems({ name, text }: IndexEvent) {
|
|||
if (!n.children) {
|
||||
return;
|
||||
}
|
||||
let textNodes: MarkdownTree[] = [];
|
||||
let textNodes: ParseTree[] = [];
|
||||
let nested: string | undefined;
|
||||
for (let child of n.children!.slice(1)) {
|
||||
if (child.type === "OrderedList" || child.type === "BulletList") {
|
||||
nested = renderMarkdown(child);
|
||||
nested = renderToText(child);
|
||||
break;
|
||||
}
|
||||
textNodes.push(child);
|
||||
}
|
||||
let item = textNodes.map(renderMarkdown).join("").trim();
|
||||
let item = textNodes.map(renderToText).join("").trim();
|
||||
let value: Item = {
|
||||
item,
|
||||
};
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import { ClickEvent } from "../../webapp/app_event";
|
||||
import { updateMaterializedQueriesCommand } from "./materialized_queries";
|
||||
import { getCursor, getText, navigate as navigateTo, openUrl } from "plugos-silverbullet-syscall/editor";
|
||||
import { taskToggleAtPos } from "../tasks/task";
|
||||
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
|
||||
import { MarkdownTree, nodeAtPos } from "../lib/tree";
|
||||
import { nodeAtPos, ParseTree } from "../../common/tree";
|
||||
|
||||
const materializedQueryPrefix = /<!--\s*#query\s+/;
|
||||
|
||||
async function actionClickOrActionEnter(mdTree: MarkdownTree | null) {
|
||||
async function actionClickOrActionEnter(mdTree: ParseTree | null) {
|
||||
if (!mdTree) {
|
||||
return;
|
||||
}
|
||||
|
@ -24,17 +22,9 @@ async function actionClickOrActionEnter(mdTree: MarkdownTree | null) {
|
|||
case "URL":
|
||||
await openUrl(mdTree.children![0].text!);
|
||||
break;
|
||||
case "CommentBlock":
|
||||
if (mdTree.children![0].text!.match(materializedQueryPrefix)) {
|
||||
await updateMaterializedQueriesCommand();
|
||||
}
|
||||
break;
|
||||
case "Link":
|
||||
await openUrl(mdTree.children![4].children![0].text!);
|
||||
break;
|
||||
case "TaskMarker":
|
||||
await taskToggleAtPos(mdTree.from! + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,9 +35,11 @@ export async function linkNavigate() {
|
|||
}
|
||||
|
||||
export async function clickNavigate(event: ClickEvent) {
|
||||
// Navigate by default, don't navigate when Ctrl or Cmd is held
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
let mdTree = await parseMarkdown(await getText());
|
||||
let newNode = nodeAtPos(mdTree, event.pos);
|
||||
await actionClickOrActionEnter(newNode);
|
||||
return;
|
||||
}
|
||||
let mdTree = await parseMarkdown(await getText());
|
||||
let newNode = nodeAtPos(mdTree, event.pos);
|
||||
await actionClickOrActionEnter(newNode);
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@ import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
|
|||
import {
|
||||
addParentPointers,
|
||||
collectNodesMatching,
|
||||
MarkdownTree,
|
||||
renderMarkdown,
|
||||
ParseTree,
|
||||
renderToText,
|
||||
replaceNodesMatching
|
||||
} from "../lib/tree";
|
||||
} from "../../common/tree";
|
||||
|
||||
export async function indexLinks({ name, text }: IndexEvent) {
|
||||
let backLinks: { key: string; value: string }[] = [];
|
||||
|
@ -93,7 +93,7 @@ export async function renamePage() {
|
|||
}
|
||||
let mdTree = await parseMarkdown(text);
|
||||
addParentPointers(mdTree);
|
||||
replaceNodesMatching(mdTree, (n): MarkdownTree | undefined | null => {
|
||||
replaceNodesMatching(mdTree, (n): ParseTree | undefined | null => {
|
||||
if (n.type === "WikiLinkPage") {
|
||||
let pageName = n.children![0].text!;
|
||||
if (pageName === oldName) {
|
||||
|
@ -110,7 +110,7 @@ export async function renamePage() {
|
|||
return;
|
||||
});
|
||||
// let newText = text.replaceAll(`[[${oldName}]]`, `[[${newName}]]`);
|
||||
let newText = renderMarkdown(mdTree);
|
||||
let newText = renderToText(mdTree);
|
||||
if (text !== newText) {
|
||||
console.log("Changes made, saving...");
|
||||
await writePage(pageToUpdate, newText);
|
||||
|
@ -179,6 +179,14 @@ export async function clearPageIndex(page: string) {
|
|||
await clearPageIndexForPage(page);
|
||||
}
|
||||
|
||||
export async function parsePage() {
|
||||
console.log(await parseMarkdown(await getText()));
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
export type MarkdownTree = {
|
||||
type?: string; // undefined === text node
|
||||
from?: number;
|
||||
to?: number;
|
||||
text?: string;
|
||||
children?: MarkdownTree[];
|
||||
parent?: MarkdownTree;
|
||||
};
|
||||
|
||||
export function addParentPointers(mdTree: MarkdownTree) {
|
||||
if (!mdTree.children) {
|
||||
return;
|
||||
}
|
||||
for (let child of mdTree.children) {
|
||||
child.parent = mdTree;
|
||||
addParentPointers(child);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeParentPointers(mdTree: MarkdownTree) {
|
||||
delete mdTree.parent;
|
||||
if (!mdTree.children) {
|
||||
return;
|
||||
}
|
||||
for (let child of mdTree.children) {
|
||||
removeParentPointers(child);
|
||||
}
|
||||
}
|
||||
|
||||
export function findParentMatching(
|
||||
mdTree: MarkdownTree,
|
||||
matchFn: (mdTree: MarkdownTree) => boolean
|
||||
): MarkdownTree | null {
|
||||
let node = mdTree.parent;
|
||||
while (node) {
|
||||
if (matchFn(node)) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function collectNodesMatching(
|
||||
mdTree: MarkdownTree,
|
||||
matchFn: (mdTree: MarkdownTree) => boolean
|
||||
): MarkdownTree[] {
|
||||
if (matchFn(mdTree)) {
|
||||
return [mdTree];
|
||||
}
|
||||
let results: MarkdownTree[] = [];
|
||||
if (mdTree.children) {
|
||||
for (let child of mdTree.children) {
|
||||
results = [...results, ...collectNodesMatching(child, matchFn)];
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// return value: returning undefined = not matched, continue, null = delete, new node = replace
|
||||
export function replaceNodesMatching(
|
||||
mdTree: MarkdownTree,
|
||||
substituteFn: (mdTree: MarkdownTree) => MarkdownTree | null | undefined
|
||||
) {
|
||||
if (mdTree.children) {
|
||||
for (let child of mdTree.children) {
|
||||
let subst = substituteFn(child);
|
||||
if (subst !== undefined) {
|
||||
let pos = mdTree.children.indexOf(child);
|
||||
if (subst) {
|
||||
mdTree.children.splice(pos, 1, subst);
|
||||
} else {
|
||||
// null = delete
|
||||
mdTree.children.splice(pos, 1);
|
||||
}
|
||||
} else {
|
||||
replaceNodesMatching(child, substituteFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function findNodeMatching(
|
||||
mdTree: MarkdownTree,
|
||||
matchFn: (mdTree: MarkdownTree) => boolean
|
||||
): MarkdownTree | null {
|
||||
return collectNodesMatching(mdTree, matchFn)[0];
|
||||
}
|
||||
|
||||
// Finds non-text node at position
|
||||
export function nodeAtPos(
|
||||
mdTree: MarkdownTree,
|
||||
pos: number
|
||||
): MarkdownTree | null {
|
||||
if (pos < mdTree.from! || pos > mdTree.to!) {
|
||||
return null;
|
||||
}
|
||||
if (!mdTree.children) {
|
||||
return mdTree;
|
||||
}
|
||||
for (let child of mdTree.children) {
|
||||
let n = nodeAtPos(child, pos);
|
||||
if (n && n.text !== undefined) {
|
||||
// Got a text node, let's return its parent
|
||||
return mdTree;
|
||||
} else if (n) {
|
||||
// Got it
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Turn MarkdownTree back into regular markdown text
|
||||
export function renderMarkdown(mdTree: MarkdownTree): string {
|
||||
let pieces: string[] = [];
|
||||
if (mdTree.text !== undefined) {
|
||||
return mdTree.text;
|
||||
}
|
||||
for (let child of mdTree.children!) {
|
||||
pieces.push(renderMarkdown(child));
|
||||
}
|
||||
return pieces.join("");
|
||||
}
|
|
@ -2,7 +2,7 @@ import MarkdownIt from "markdown-it";
|
|||
import { getText, hideRhs, showRhs } from "plugos-silverbullet-syscall/editor";
|
||||
import * as clientStore from "plugos-silverbullet-syscall/clientStore";
|
||||
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
|
||||
import { renderMarkdown, replaceNodesMatching } from "../lib/tree";
|
||||
import { renderToText, replaceNodesMatching } from "../../common/tree";
|
||||
|
||||
const css = `
|
||||
<style>
|
||||
|
@ -79,7 +79,7 @@ export async function cleanMarkdown(text: string) {
|
|||
return null;
|
||||
}
|
||||
});
|
||||
let html = md.render(renderMarkdown(mdTree));
|
||||
let html = md.render(renderToText(mdTree));
|
||||
return html;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@jest/globals": "^27.5.1",
|
||||
"@lezer/generator": "^0.15.4",
|
||||
"@lezer/lr": "^0.15.8",
|
||||
"@types/yaml": "^1.9.7",
|
||||
"plugos-silverbullet-syscall": "file:../plugos-silverbullet-syscall",
|
||||
"plugos-syscall": "file:../plugos-syscall"
|
||||
"plugos-syscall": "file:../plugos-syscall",
|
||||
"yaml": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"../plugos-silverbullet-syscall": {
|
||||
|
@ -173,6 +177,31 @@
|
|||
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/common": {
|
||||
"version": "0.15.12",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz",
|
||||
"integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig=="
|
||||
},
|
||||
"node_modules/@lezer/generator": {
|
||||
"version": "0.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-0.15.4.tgz",
|
||||
"integrity": "sha512-9bBwU2TzKMBQ6OCEDevuMNWGOBKlkq5YIGEhjrz9pb3MLb+oYYR4dVFZ7ehwLcDoSecsSA7PdlAy0thJO5pt2w==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^0.15.0",
|
||||
"@lezer/lr": "^0.15.0"
|
||||
},
|
||||
"bin": {
|
||||
"lezer-generator": "dist/lezer-generator.cjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/lr": {
|
||||
"version": "0.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz",
|
||||
"integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^0.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinonjs/commons": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
|
||||
|
@ -220,6 +249,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
|
||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
||||
},
|
||||
"node_modules/@types/yaml": {
|
||||
"version": "1.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
|
||||
"integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
|
||||
"deprecated": "This is a stub types definition. yaml provides its own type definitions, so you do not need this installed.",
|
||||
"dependencies": {
|
||||
"yaml": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "16.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
||||
|
@ -560,6 +598,14 @@
|
|||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0.tgz",
|
||||
"integrity": "sha512-JbfdlHKGP2Ik9IHylzWlGd4pPK++EU46/IxMykphS2ZKw7a7h+dHNmcXObLgpRDriBY+rpWslldikckX8oruWQ==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -683,6 +729,28 @@
|
|||
"chalk": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@lezer/common": {
|
||||
"version": "0.15.12",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz",
|
||||
"integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig=="
|
||||
},
|
||||
"@lezer/generator": {
|
||||
"version": "0.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-0.15.4.tgz",
|
||||
"integrity": "sha512-9bBwU2TzKMBQ6OCEDevuMNWGOBKlkq5YIGEhjrz9pb3MLb+oYYR4dVFZ7ehwLcDoSecsSA7PdlAy0thJO5pt2w==",
|
||||
"requires": {
|
||||
"@lezer/common": "^0.15.0",
|
||||
"@lezer/lr": "^0.15.0"
|
||||
}
|
||||
},
|
||||
"@lezer/lr": {
|
||||
"version": "0.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz",
|
||||
"integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==",
|
||||
"requires": {
|
||||
"@lezer/common": "^0.15.0"
|
||||
}
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
|
||||
|
@ -730,6 +798,14 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
|
||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
||||
},
|
||||
"@types/yaml": {
|
||||
"version": "1.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
|
||||
"integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
|
||||
"requires": {
|
||||
"yaml": "*"
|
||||
}
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "16.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
|
||||
|
@ -980,6 +1056,11 @@
|
|||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0.tgz",
|
||||
"integrity": "sha512-JbfdlHKGP2Ik9IHylzWlGd4pPK++EU46/IxMykphS2ZKw7a7h+dHNmcXObLgpRDriBY+rpWslldikckX8oruWQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
{
|
||||
"name": "plugs",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"generate": "lezer-generator query/query.grammar -o query/parse-query.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/globals": "^27.5.1",
|
||||
"@lezer/generator": "^0.15.4",
|
||||
"@lezer/lr": "^0.15.8",
|
||||
"@types/yaml": "^1.9.7",
|
||||
"plugos-silverbullet-syscall": "file:../plugos-silverbullet-syscall",
|
||||
"plugos-syscall": "file:../plugos-syscall",
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import { expect, test } from "@jest/globals";
|
||||
import { applyQuery, parseQuery } from "./engine";
|
||||
|
||||
test("Test parser", () => {
|
||||
let parsedBasicQuery = parseQuery(`page`);
|
||||
expect(parsedBasicQuery.table).toBe("page");
|
||||
|
||||
let parsedQuery1 = parseQuery(
|
||||
`task where completed = false and dueDate <= "{{today}}" order by dueDate desc limit 5`
|
||||
);
|
||||
expect(parsedQuery1.table).toBe("task");
|
||||
expect(parsedQuery1.orderBy).toBe("dueDate");
|
||||
expect(parsedQuery1.orderDesc).toBe(true);
|
||||
expect(parsedQuery1.limit).toBe(5);
|
||||
expect(parsedQuery1.filter.length).toBe(2);
|
||||
expect(parsedQuery1.filter[0]).toStrictEqual({
|
||||
op: "=",
|
||||
prop: "completed",
|
||||
value: false,
|
||||
});
|
||||
expect(parsedQuery1.filter[1]).toStrictEqual({
|
||||
op: "<=",
|
||||
prop: "dueDate",
|
||||
value: "{{today}}",
|
||||
});
|
||||
|
||||
let parsedQuery2 = parseQuery(`page where name like "interview/%"`);
|
||||
expect(parsedQuery2.table).toBe("page");
|
||||
expect(parsedQuery2.filter.length).toBe(1);
|
||||
expect(parsedQuery2.filter[0]).toStrictEqual({
|
||||
op: "like",
|
||||
prop: "name",
|
||||
value: "interview/%",
|
||||
});
|
||||
});
|
||||
|
||||
test("Test performing the queries", () => {
|
||||
let data: any[] = [
|
||||
{ name: "interview/My Interview", lastModified: 1 },
|
||||
{ name: "interview/My Interview 2", lastModified: 2 },
|
||||
{ name: "Pete", age: 38 },
|
||||
{ name: "Angie", age: 28 },
|
||||
];
|
||||
|
||||
expect(applyQuery(`page where name like "interview/%"`, data)).toStrictEqual([
|
||||
{ name: "interview/My Interview", lastModified: 1 },
|
||||
{ name: "interview/My Interview 2", lastModified: 2 },
|
||||
]);
|
||||
expect(
|
||||
applyQuery(`page where name like "interview/%" order by lastModified`, data)
|
||||
).toStrictEqual([
|
||||
{ name: "interview/My Interview", lastModified: 1 },
|
||||
{ name: "interview/My Interview 2", lastModified: 2 },
|
||||
]);
|
||||
expect(
|
||||
applyQuery(
|
||||
`page where name like "interview/%" order by lastModified desc`,
|
||||
data
|
||||
)
|
||||
).toStrictEqual([
|
||||
{ name: "interview/My Interview 2", lastModified: 2 },
|
||||
{ name: "interview/My Interview", lastModified: 1 },
|
||||
]);
|
||||
expect(applyQuery(`page where age > 30`, data)).toStrictEqual([
|
||||
{ name: "Pete", age: 38 },
|
||||
]);
|
||||
expect(applyQuery(`page where age > 28 and age < 38`, data)).toStrictEqual(
|
||||
[]
|
||||
);
|
||||
});
|
|
@ -0,0 +1,154 @@
|
|||
import { collectNodesOfType, findNodeOfType, replaceNodesMatching } from "../../common/tree";
|
||||
import { lezerToParseTree } from "../../common/parse_tree";
|
||||
|
||||
// @ts-ignore
|
||||
import { parser } from "./parse-query";
|
||||
|
||||
type Filter = {
|
||||
op: string;
|
||||
prop: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
type ParsedQuery = {
|
||||
table: string;
|
||||
orderBy?: string;
|
||||
orderDesc?: boolean;
|
||||
limit?: number;
|
||||
filter: Filter[];
|
||||
};
|
||||
|
||||
export function parseQuery(query: string): ParsedQuery {
|
||||
let n = lezerToParseTree(query, parser.parse(query).topNode);
|
||||
// Clean the tree a bit
|
||||
replaceNodesMatching(n, (n) => {
|
||||
if (!n.type) {
|
||||
let trimmed = n.text!.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
n.text = trimmed;
|
||||
}
|
||||
});
|
||||
|
||||
let queryNode = n.children![0];
|
||||
let parsedQuery: ParsedQuery = {
|
||||
table: queryNode.children![0].children![0].text!,
|
||||
filter: [],
|
||||
};
|
||||
let orderByNode = findNodeOfType(queryNode, "OrderClause");
|
||||
if (orderByNode) {
|
||||
let nameNode = findNodeOfType(orderByNode, "Name");
|
||||
parsedQuery.orderBy = nameNode!.children![0].text!;
|
||||
let orderNode = findNodeOfType(orderByNode, "Order");
|
||||
parsedQuery.orderDesc = orderNode
|
||||
? orderNode.children![0].text! === "desc"
|
||||
: false;
|
||||
}
|
||||
let limitNode = findNodeOfType(queryNode, "LimitClause");
|
||||
if (limitNode) {
|
||||
let nameNode = findNodeOfType(limitNode, "Number");
|
||||
parsedQuery.limit = +nameNode!.children![0].text!;
|
||||
}
|
||||
let filterNodes = collectNodesOfType(queryNode, "FilterExpr");
|
||||
for (let filterNode of filterNodes) {
|
||||
let val: any = undefined;
|
||||
let valNode = filterNode.children![2].children![0];
|
||||
switch (valNode.type) {
|
||||
case "Number":
|
||||
val = valNode.children![0].text!;
|
||||
break;
|
||||
case "Bool":
|
||||
val = valNode.children![0].text! === "true";
|
||||
break;
|
||||
case "Name":
|
||||
val = valNode.children![0].text!;
|
||||
break;
|
||||
case "String":
|
||||
val = valNode.children![0].text!;
|
||||
val = val.substring(1, val.length - 1);
|
||||
break;
|
||||
}
|
||||
let f: Filter = {
|
||||
prop: filterNode.children![0].children![0].text!,
|
||||
op: filterNode.children![1].text!,
|
||||
value: val,
|
||||
};
|
||||
parsedQuery.filter.push(f);
|
||||
}
|
||||
// console.log(JSON.stringify(queryNode, null, 2));
|
||||
return parsedQuery;
|
||||
}
|
||||
|
||||
export function applyQuery(query: string, records: any[]): any {
|
||||
const parsedQuery = parseQuery(query);
|
||||
|
||||
let resultRecords: any[] = [];
|
||||
if (parsedQuery.filter.length === 0) {
|
||||
resultRecords = records.slice();
|
||||
} else {
|
||||
recordLoop: for (let record of records) {
|
||||
for (let { op, prop, value } of parsedQuery.filter) {
|
||||
switch (op) {
|
||||
case "=":
|
||||
if (!(record[prop] === value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case "!=":
|
||||
if (!(record[prop] !== value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case "<":
|
||||
if (!(record[prop] < value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case "<=":
|
||||
if (!(record[prop] <= value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case ">":
|
||||
if (!(record[prop] > value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case ">=":
|
||||
if (!(record[prop] >= value)) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
case "like":
|
||||
let re = new RegExp(value.replaceAll("%", ".*"));
|
||||
if (!re.exec(record[prop])) {
|
||||
continue recordLoop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
resultRecords.push(record);
|
||||
}
|
||||
}
|
||||
// Now the sorting
|
||||
if (parsedQuery.orderBy) {
|
||||
resultRecords = resultRecords.sort((a: any, b: any) => {
|
||||
const orderBy = parsedQuery.orderBy!;
|
||||
const orderDesc = parsedQuery.orderDesc!;
|
||||
if (a[orderBy] === b[orderBy]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a[orderBy] < b[orderBy]) {
|
||||
return orderDesc ? 1 : -1;
|
||||
} else {
|
||||
return orderDesc ? -1 : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (parsedQuery.limit) {
|
||||
resultRecords = resultRecords.slice(0, parsedQuery.limit);
|
||||
}
|
||||
return resultRecords;
|
||||
}
|
|
@ -3,12 +3,16 @@ import { flashNotification, getCurrentPage, reloadPage, save } from "plugos-silv
|
|||
import { listPages, readPage, writePage } from "plugos-silverbullet-syscall/space";
|
||||
import { invokeFunction } from "plugos-silverbullet-syscall/system";
|
||||
import { scanPrefixGlobal } from "plugos-silverbullet-syscall";
|
||||
import { niceDate } from "../core/dates";
|
||||
|
||||
export const queryRegex =
|
||||
/(<!--\s*#query\s+(?<table>\w+)\s*(filter\s+["'“”‘’](?<filter>[^"'“”‘’]+)["'“”‘’])?\s*\s*(order by\s+(?<orderBy>\w+)(?<orderDesc>\s+desc)?)?(group by\s+(?<groupBy>\w+))?\s*(limit\s+(?<limit>\d+))?\s*-->)(.+?)(<!--\s*#end\s*-->)/gs;
|
||||
|
||||
export const newQueryRegex =
|
||||
/<!--\s*#query\s+(.+?)(?=\s*-->)-->(.+?)<!--\s*#end\s*-->/gs;
|
||||
|
||||
export function whiteOutQueries(text: string): string {
|
||||
return text.replaceAll(queryRegex, (match) =>
|
||||
return text.replaceAll(newQueryRegex, (match) =>
|
||||
new Array(match.length + 1).join(" ")
|
||||
);
|
||||
}
|
||||
|
@ -40,6 +44,17 @@ export async function updateMaterializedQueriesCommand() {
|
|||
await flashNotification("Updated materialized queries");
|
||||
}
|
||||
|
||||
function replaceTemplateVars(s: string): string {
|
||||
return s.replaceAll(/\{\{(\w+)\}\}/g, (match, v) => {
|
||||
switch (v) {
|
||||
case "today":
|
||||
return niceDate(new Date());
|
||||
break;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
}
|
||||
|
||||
// Called from client, running on server
|
||||
export async function updateMaterializedQueriesOnPage(pageName: string) {
|
||||
let { text } = await readPage(pageName);
|
||||
|
@ -50,6 +65,7 @@ export async function updateMaterializedQueriesOnPage(pageName: string) {
|
|||
const startQuery = args[0];
|
||||
const endQuery = args[args.length - 4];
|
||||
let results = [];
|
||||
filter = filter && replaceTemplateVars(filter);
|
||||
switch (table) {
|
||||
case "page":
|
||||
let pages = await listPages();
|
||||
|
@ -94,21 +110,17 @@ export async function updateMaterializedQueriesOnPage(pageName: string) {
|
|||
return `${startQuery}\n${results.sort().join("\n")}\n${endQuery}`;
|
||||
case "link":
|
||||
let uniqueLinks = new Set<string>();
|
||||
console.log("Here!!");
|
||||
for (let { key, page, value: name } of await scanPrefixGlobal(
|
||||
`pl:${pageName}:`
|
||||
)) {
|
||||
console.log("Here!!");
|
||||
let [, pos] = key.split(":");
|
||||
if (!filter || (filter && name.includes(filter))) {
|
||||
uniqueLinks.add(name);
|
||||
}
|
||||
}
|
||||
console.log("Here!!");
|
||||
for (const uniqueResult of uniqueLinks) {
|
||||
results.push(`* [[${uniqueResult}]]`);
|
||||
}
|
||||
console.log("Here!!");
|
||||
return `${startQuery}\n${results.sort().join("\n")}\n${endQuery}`;
|
||||
case "item":
|
||||
for (let {
|
|
@ -0,0 +1,44 @@
|
|||
@precedence { logic @left }
|
||||
|
||||
@top Program { Query }
|
||||
|
||||
Query {
|
||||
Name (WhereClause | OrderClause | LimitClause)*
|
||||
}
|
||||
|
||||
WhereClause { "where" LogicalExpr }
|
||||
OrderClause { "order" "by" Name Order? }
|
||||
LimitClause { "limit" Number }
|
||||
|
||||
Order {
|
||||
"desc" | "asc"
|
||||
}
|
||||
|
||||
Value { Number | String | Bool }
|
||||
|
||||
LogicalExpr { AndExpr | FilterExpr }
|
||||
|
||||
AndExpr { FilterExpr !logic "and" FilterExpr }
|
||||
|
||||
FilterExpr {
|
||||
Name "<" Value
|
||||
| Name "<=" Value
|
||||
| Name "=" Value
|
||||
| Name "!=" Value
|
||||
| Name ">=" Value
|
||||
| Name ">" Value
|
||||
| Name "like" Value
|
||||
}
|
||||
|
||||
@skip { space }
|
||||
|
||||
Bool {
|
||||
"true" | "false"
|
||||
}
|
||||
|
||||
@tokens {
|
||||
space { std.whitespace+ }
|
||||
Name { std.asciiLetter+ }
|
||||
String { "\"" ![\"]* "\"" }
|
||||
Number { std.digit+ }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
functions:
|
||||
updateMaterializedQueriesOnPage:
|
||||
path: ./materialized_queries.ts:updateMaterializedQueriesOnPage
|
||||
updateMaterializedQueriesCommand:
|
||||
path: ./materialized_queries.ts:updateMaterializedQueriesCommand
|
||||
command:
|
||||
name: "Materialized Queries: Update"
|
|
@ -1,16 +1,23 @@
|
|||
import type { ClickEvent } from "../../webapp/app_event";
|
||||
import { IndexEvent } from "../../webapp/app_event";
|
||||
|
||||
import { whiteOutQueries } from "../core/materialized_queries";
|
||||
import { whiteOutQueries } from "../query/materialized_queries";
|
||||
import { batchSet } from "plugos-silverbullet-syscall/index";
|
||||
import { readPage, writePage } from "plugos-silverbullet-syscall/space";
|
||||
import { parseMarkdown } from "plugos-silverbullet-syscall/markdown";
|
||||
import { dispatch, getText } from "plugos-silverbullet-syscall/editor";
|
||||
import { addParentPointers, collectNodesMatching, nodeAtPos, renderMarkdown } from "../lib/tree";
|
||||
import {
|
||||
addParentPointers,
|
||||
collectNodesMatching,
|
||||
collectNodesOfType,
|
||||
nodeAtPos,
|
||||
renderToText
|
||||
} from "../../common/tree";
|
||||
|
||||
type Task = {
|
||||
task: string;
|
||||
complete: boolean;
|
||||
deadline?: string;
|
||||
pos?: number;
|
||||
nested?: string;
|
||||
};
|
||||
|
@ -21,23 +28,29 @@ export async function indexTasks({ name, text }: IndexEvent) {
|
|||
text = whiteOutQueries(text);
|
||||
let mdTree = await parseMarkdown(text);
|
||||
addParentPointers(mdTree);
|
||||
collectNodesMatching(mdTree, (n) => n.type === "Task").forEach((n) => {
|
||||
let task = n.children!.slice(1).map(renderMarkdown).join("").trim();
|
||||
collectNodesOfType(mdTree, "Task").forEach((n) => {
|
||||
let task = n.children!.slice(1).map(renderToText).join("").trim();
|
||||
let complete = n.children![0].children![0].text! !== "[ ]";
|
||||
|
||||
let value: Task = {
|
||||
task,
|
||||
complete,
|
||||
};
|
||||
|
||||
let deadlineNodes = collectNodesOfType(n, "DeadlineDate");
|
||||
if (deadlineNodes.length > 0) {
|
||||
value.deadline = deadlineNodes[0].children![0].text!.replace(/📅\s*/, "");
|
||||
}
|
||||
|
||||
let taskIndex = n.parent!.children!.indexOf(n);
|
||||
let nestedItems = n.parent!.children!.slice(taskIndex + 1);
|
||||
if (nestedItems.length > 0) {
|
||||
value.nested = nestedItems.map(renderMarkdown).join("").trim();
|
||||
value.nested = nestedItems.map(renderToText).join("").trim();
|
||||
}
|
||||
tasks.push({
|
||||
key: `task:${n.from}`,
|
||||
value,
|
||||
});
|
||||
// console.log("Task", value);
|
||||
});
|
||||
|
||||
console.log("Found", tasks.length, "task(s)");
|
||||
|
@ -95,9 +108,9 @@ export async function taskToggleAtPos(pos: number) {
|
|||
taskMarkerNode.children![0].text = changeTo;
|
||||
console.log(
|
||||
"This will be the new marker",
|
||||
renderMarkdown(taskMarkerNode)
|
||||
renderToText(taskMarkerNode)
|
||||
);
|
||||
text = renderMarkdown(referenceMdTree);
|
||||
text = renderToText(referenceMdTree);
|
||||
console.log("Updated reference paged text", text);
|
||||
await writePage(page, text);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
syntax:
|
||||
DeadlineDate:
|
||||
firstCharacters:
|
||||
- "📅"
|
||||
regex: "📅\\s*\\d{4}\\-\\d{2}\\-\\d{2}"
|
||||
styles:
|
||||
backgroundColor: "rgba(22,22,22,0.07)"
|
||||
CompletedDate:
|
||||
firstCharacters:
|
||||
- "✅"
|
||||
regex: "✅\\s*\\d{4}\\-\\d{2}\\-\\d{2}"
|
||||
styles:
|
||||
backgroundColor: "rgba(22,22,22,0.07)"
|
||||
RepeatInterval:
|
||||
firstCharacters:
|
||||
- "🔁"
|
||||
regex: "🔁\\s*every\\s+\\w+"
|
||||
styles:
|
||||
backgroundColor: "rgba(22,22,22,0.07)"
|
||||
functions:
|
||||
indexTasks:
|
||||
path: "./task.ts:indexTasks"
|
||||
|
|
542
plugs/yarn.lock
542
plugs/yarn.lock
|
@ -3,396 +3,418 @@
|
|||
|
||||
|
||||
"@babel/code-frame@^7.12.13":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
||||
integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
|
||||
"integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
||||
"version" "7.16.7"
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.16.7"
|
||||
|
||||
"@babel/helper-validator-identifier@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
|
||||
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
|
||||
"integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
|
||||
"version" "7.16.7"
|
||||
|
||||
"@babel/highlight@^7.16.7":
|
||||
version "7.16.10"
|
||||
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
|
||||
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
|
||||
"integrity" "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
|
||||
"version" "7.16.10"
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.16.7"
|
||||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
"chalk" "^2.0.0"
|
||||
"js-tokens" "^4.0.0"
|
||||
|
||||
"@jest/environment@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz"
|
||||
integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==
|
||||
"integrity" "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA=="
|
||||
"resolved" "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/fake-timers" "^27.5.1"
|
||||
"@jest/types" "^27.5.1"
|
||||
"@types/node" "*"
|
||||
jest-mock "^27.5.1"
|
||||
"jest-mock" "^27.5.1"
|
||||
|
||||
"@jest/fake-timers@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz"
|
||||
integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==
|
||||
"integrity" "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ=="
|
||||
"resolved" "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/types" "^27.5.1"
|
||||
"@sinonjs/fake-timers" "^8.0.1"
|
||||
"@types/node" "*"
|
||||
jest-message-util "^27.5.1"
|
||||
jest-mock "^27.5.1"
|
||||
jest-util "^27.5.1"
|
||||
"jest-message-util" "^27.5.1"
|
||||
"jest-mock" "^27.5.1"
|
||||
"jest-util" "^27.5.1"
|
||||
|
||||
"@jest/globals@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz"
|
||||
integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==
|
||||
"integrity" "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q=="
|
||||
"resolved" "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/environment" "^27.5.1"
|
||||
"@jest/types" "^27.5.1"
|
||||
expect "^27.5.1"
|
||||
"expect" "^27.5.1"
|
||||
|
||||
"@jest/types@^27.5.1":
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz"
|
||||
integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
|
||||
"integrity" "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw=="
|
||||
"resolved" "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||
"@types/istanbul-reports" "^3.0.0"
|
||||
"@types/node" "*"
|
||||
"@types/yargs" "^16.0.0"
|
||||
chalk "^4.0.0"
|
||||
"chalk" "^4.0.0"
|
||||
|
||||
"@lezer/common@^0.15.0":
|
||||
"integrity" "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig=="
|
||||
"resolved" "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz"
|
||||
"version" "0.15.12"
|
||||
|
||||
"@lezer/generator@^0.15.4":
|
||||
"integrity" "sha512-9bBwU2TzKMBQ6OCEDevuMNWGOBKlkq5YIGEhjrz9pb3MLb+oYYR4dVFZ7ehwLcDoSecsSA7PdlAy0thJO5pt2w=="
|
||||
"resolved" "https://registry.npmjs.org/@lezer/generator/-/generator-0.15.4.tgz"
|
||||
"version" "0.15.4"
|
||||
dependencies:
|
||||
"@lezer/common" "^0.15.0"
|
||||
"@lezer/lr" "^0.15.0"
|
||||
|
||||
"@lezer/lr@^0.15.0", "@lezer/lr@^0.15.8":
|
||||
"integrity" "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg=="
|
||||
"resolved" "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz"
|
||||
"version" "0.15.8"
|
||||
dependencies:
|
||||
"@lezer/common" "^0.15.0"
|
||||
|
||||
"@sinonjs/commons@^1.7.0":
|
||||
version "1.8.3"
|
||||
resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"
|
||||
integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==
|
||||
"integrity" "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ=="
|
||||
"resolved" "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"
|
||||
"version" "1.8.3"
|
||||
dependencies:
|
||||
type-detect "4.0.8"
|
||||
"type-detect" "4.0.8"
|
||||
|
||||
"@sinonjs/fake-timers@^8.0.1":
|
||||
version "8.1.0"
|
||||
resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz"
|
||||
integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==
|
||||
"integrity" "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg=="
|
||||
"resolved" "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz"
|
||||
"version" "8.1.0"
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz"
|
||||
integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
|
||||
"integrity" "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g=="
|
||||
"resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz"
|
||||
"version" "2.0.4"
|
||||
|
||||
"@types/istanbul-lib-report@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
|
||||
integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==
|
||||
"integrity" "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg=="
|
||||
"resolved" "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
|
||||
"version" "3.0.0"
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "*"
|
||||
|
||||
"@types/istanbul-reports@^3.0.0":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz"
|
||||
integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==
|
||||
"integrity" "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw=="
|
||||
"resolved" "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz"
|
||||
"version" "3.0.1"
|
||||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/node@*":
|
||||
version "17.0.23"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz"
|
||||
integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==
|
||||
"integrity" "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw=="
|
||||
"resolved" "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz"
|
||||
"version" "17.0.23"
|
||||
|
||||
"@types/stack-utils@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz"
|
||||
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
|
||||
"integrity" "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
||||
"resolved" "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz"
|
||||
"version" "2.0.1"
|
||||
|
||||
"@types/yaml@^1.9.7":
|
||||
version "1.9.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/yaml/-/yaml-1.9.7.tgz#2331f36e0aac91311a63d33eb026c21687729679"
|
||||
integrity sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==
|
||||
"integrity" "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA=="
|
||||
"resolved" "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz"
|
||||
"version" "1.9.7"
|
||||
dependencies:
|
||||
yaml "*"
|
||||
"yaml" "*"
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "21.0.0"
|
||||
resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz"
|
||||
integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==
|
||||
"integrity" "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
|
||||
"resolved" "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz"
|
||||
"version" "21.0.0"
|
||||
|
||||
"@types/yargs@^16.0.0":
|
||||
version "16.0.4"
|
||||
resolved "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz"
|
||||
integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==
|
||||
"integrity" "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw=="
|
||||
"resolved" "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz"
|
||||
"version" "16.0.4"
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
"ansi-regex@^5.0.1":
|
||||
"integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
"resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
||||
"version" "5.0.1"
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
"ansi-styles@^3.2.1":
|
||||
"integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="
|
||||
"resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
|
||||
"version" "3.2.1"
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
"color-convert" "^1.9.0"
|
||||
|
||||
ansi-styles@^4.1.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
|
||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
|
||||
"ansi-styles@^4.1.0":
|
||||
"integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
|
||||
"resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
|
||||
"version" "4.3.0"
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
"color-convert" "^2.0.1"
|
||||
|
||||
ansi-styles@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
|
||||
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
|
||||
"ansi-styles@^5.0.0":
|
||||
"integrity" "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
||||
"resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
|
||||
"version" "5.2.0"
|
||||
|
||||
braces@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
"braces@^3.0.2":
|
||||
"integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="
|
||||
"resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
|
||||
"version" "3.0.2"
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
"fill-range" "^7.0.1"
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
"chalk@^2.0.0":
|
||||
"integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
|
||||
"resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||
"version" "2.4.2"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
"ansi-styles" "^3.2.1"
|
||||
"escape-string-regexp" "^1.0.5"
|
||||
"supports-color" "^5.3.0"
|
||||
|
||||
chalk@^4.0.0:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
"chalk@^4.0.0":
|
||||
"integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="
|
||||
"resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||
"version" "4.1.2"
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
"ansi-styles" "^4.1.0"
|
||||
"supports-color" "^7.1.0"
|
||||
|
||||
ci-info@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz"
|
||||
integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==
|
||||
"ci-info@^3.2.0":
|
||||
"integrity" "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw=="
|
||||
"resolved" "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz"
|
||||
"version" "3.3.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
"color-convert@^1.9.0":
|
||||
"integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="
|
||||
"resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||
"version" "1.9.3"
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
"color-name" "1.1.3"
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
|
||||
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
|
||||
"color-convert@^2.0.1":
|
||||
"integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="
|
||||
"resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
|
||||
"version" "2.0.1"
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
"color-name" "~1.1.4"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
"color-name@~1.1.4":
|
||||
"integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
"resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
"version" "1.1.4"
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
"color-name@1.1.3":
|
||||
"integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
"resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
"version" "1.1.3"
|
||||
|
||||
diff-sequences@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz"
|
||||
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
|
||||
"diff-sequences@^27.5.1":
|
||||
"integrity" "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
|
||||
"resolved" "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
"escape-string-regexp@^1.0.5":
|
||||
"integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
"resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
|
||||
"version" "1.0.5"
|
||||
|
||||
escape-string-regexp@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
|
||||
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
|
||||
"escape-string-regexp@^2.0.0":
|
||||
"integrity" "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
|
||||
"resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
|
||||
"version" "2.0.0"
|
||||
|
||||
expect@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz"
|
||||
integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==
|
||||
"expect@^27.5.1":
|
||||
"integrity" "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw=="
|
||||
"resolved" "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/types" "^27.5.1"
|
||||
jest-get-type "^27.5.1"
|
||||
jest-matcher-utils "^27.5.1"
|
||||
jest-message-util "^27.5.1"
|
||||
"jest-get-type" "^27.5.1"
|
||||
"jest-matcher-utils" "^27.5.1"
|
||||
"jest-message-util" "^27.5.1"
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
"fill-range@^7.0.1":
|
||||
"integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="
|
||||
"resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
|
||||
"version" "7.0.1"
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
"to-regex-range" "^5.0.1"
|
||||
|
||||
graceful-fs@^4.2.9:
|
||||
version "4.2.9"
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
|
||||
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
||||
"graceful-fs@^4.2.9":
|
||||
"integrity" "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
|
||||
"resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
|
||||
"version" "4.2.9"
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
"has-flag@^3.0.0":
|
||||
"integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
"resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
|
||||
"version" "3.0.0"
|
||||
|
||||
has-flag@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
"has-flag@^4.0.0":
|
||||
"integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
"resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
||||
"version" "4.0.0"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
"is-number@^7.0.0":
|
||||
"integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
"resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
"version" "7.0.0"
|
||||
|
||||
jest-diff@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz"
|
||||
integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
|
||||
"jest-diff@^27.5.1":
|
||||
"integrity" "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw=="
|
||||
"resolved" "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
diff-sequences "^27.5.1"
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
"chalk" "^4.0.0"
|
||||
"diff-sequences" "^27.5.1"
|
||||
"jest-get-type" "^27.5.1"
|
||||
"pretty-format" "^27.5.1"
|
||||
|
||||
jest-get-type@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz"
|
||||
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
|
||||
"jest-get-type@^27.5.1":
|
||||
"integrity" "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
|
||||
"resolved" "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
|
||||
jest-matcher-utils@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz"
|
||||
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
|
||||
"jest-matcher-utils@^27.5.1":
|
||||
"integrity" "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw=="
|
||||
"resolved" "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
jest-diff "^27.5.1"
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
"chalk" "^4.0.0"
|
||||
"jest-diff" "^27.5.1"
|
||||
"jest-get-type" "^27.5.1"
|
||||
"pretty-format" "^27.5.1"
|
||||
|
||||
jest-message-util@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz"
|
||||
integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==
|
||||
"jest-message-util@^27.5.1":
|
||||
"integrity" "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g=="
|
||||
"resolved" "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.12.13"
|
||||
"@jest/types" "^27.5.1"
|
||||
"@types/stack-utils" "^2.0.0"
|
||||
chalk "^4.0.0"
|
||||
graceful-fs "^4.2.9"
|
||||
micromatch "^4.0.4"
|
||||
pretty-format "^27.5.1"
|
||||
slash "^3.0.0"
|
||||
stack-utils "^2.0.3"
|
||||
"chalk" "^4.0.0"
|
||||
"graceful-fs" "^4.2.9"
|
||||
"micromatch" "^4.0.4"
|
||||
"pretty-format" "^27.5.1"
|
||||
"slash" "^3.0.0"
|
||||
"stack-utils" "^2.0.3"
|
||||
|
||||
jest-mock@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz"
|
||||
integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==
|
||||
"jest-mock@^27.5.1":
|
||||
"integrity" "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og=="
|
||||
"resolved" "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/types" "^27.5.1"
|
||||
"@types/node" "*"
|
||||
|
||||
jest-util@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz"
|
||||
integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==
|
||||
"jest-util@^27.5.1":
|
||||
"integrity" "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw=="
|
||||
"resolved" "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
"@jest/types" "^27.5.1"
|
||||
"@types/node" "*"
|
||||
chalk "^4.0.0"
|
||||
ci-info "^3.2.0"
|
||||
graceful-fs "^4.2.9"
|
||||
picomatch "^2.2.3"
|
||||
"chalk" "^4.0.0"
|
||||
"ci-info" "^3.2.0"
|
||||
"graceful-fs" "^4.2.9"
|
||||
"picomatch" "^2.2.3"
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
"js-tokens@^4.0.0":
|
||||
"integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
"resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||
"version" "4.0.0"
|
||||
|
||||
micromatch@^4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
|
||||
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
|
||||
"micromatch@^4.0.4":
|
||||
"integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA=="
|
||||
"resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
|
||||
"version" "4.0.5"
|
||||
dependencies:
|
||||
braces "^3.0.2"
|
||||
picomatch "^2.3.1"
|
||||
"braces" "^3.0.2"
|
||||
"picomatch" "^2.3.1"
|
||||
|
||||
picomatch@^2.2.3, picomatch@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
"picomatch@^2.2.3", "picomatch@^2.3.1":
|
||||
"integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
|
||||
"resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
"version" "2.3.1"
|
||||
|
||||
"plugos-silverbullet-syscall@file:../plugos-silverbullet-syscall":
|
||||
version "1.0.0"
|
||||
"resolved" "file:../plugos-silverbullet-syscall"
|
||||
"version" "1.0.0"
|
||||
|
||||
"plugos-syscall@file:../plugos-syscall":
|
||||
version "1.0.0"
|
||||
"resolved" "file:../plugos-syscall"
|
||||
"version" "1.0.0"
|
||||
|
||||
pretty-format@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz"
|
||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
||||
"pretty-format@^27.5.1":
|
||||
"integrity" "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="
|
||||
"resolved" "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz"
|
||||
"version" "27.5.1"
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
"ansi-regex" "^5.0.1"
|
||||
"ansi-styles" "^5.0.0"
|
||||
"react-is" "^17.0.1"
|
||||
|
||||
react-is@^17.0.1:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
"react-is@^17.0.1":
|
||||
"integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
"resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||
"version" "17.0.2"
|
||||
|
||||
slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
"slash@^3.0.0":
|
||||
"integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
"resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
||||
"version" "3.0.0"
|
||||
|
||||
stack-utils@^2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz"
|
||||
integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==
|
||||
"stack-utils@^2.0.3":
|
||||
"integrity" "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA=="
|
||||
"resolved" "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz"
|
||||
"version" "2.0.5"
|
||||
dependencies:
|
||||
escape-string-regexp "^2.0.0"
|
||||
"escape-string-regexp" "^2.0.0"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
"supports-color@^5.3.0":
|
||||
"integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="
|
||||
"resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
|
||||
"version" "5.5.0"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
"has-flag" "^3.0.0"
|
||||
|
||||
supports-color@^7.1.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
||||
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||
"supports-color@^7.1.0":
|
||||
"integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="
|
||||
"resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
||||
"version" "7.2.0"
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
"has-flag" "^4.0.0"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
"to-regex-range@^5.0.1":
|
||||
"integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="
|
||||
"resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
|
||||
"version" "5.0.1"
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
"is-number" "^7.0.0"
|
||||
|
||||
type-detect@4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
|
||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||
"type-detect@4.0.8":
|
||||
"integrity" "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
|
||||
"resolved" "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
|
||||
"version" "4.0.8"
|
||||
|
||||
yaml@*, yaml@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0.tgz#cbc588ad58e0cd924cd3f5f2b1a9485103048e25"
|
||||
integrity sha512-JbfdlHKGP2Ik9IHylzWlGd4pPK++EU46/IxMykphS2ZKw7a7h+dHNmcXObLgpRDriBY+rpWslldikckX8oruWQ==
|
||||
"yaml@*", "yaml@^2.0.0":
|
||||
"integrity" "sha512-JbfdlHKGP2Ik9IHylzWlGd4pPK++EU46/IxMykphS2ZKw7a7h+dHNmcXObLgpRDriBY+rpWslldikckX8oruWQ=="
|
||||
"resolved" "https://registry.npmjs.org/yaml/-/yaml-2.0.0.tgz"
|
||||
"version" "2.0.0"
|
||||
|
|
|
@ -17,10 +17,12 @@ import { NodeCronHook } from "../plugos/hooks/node_cron";
|
|||
import { markdownSyscalls } from "../common/syscalls/markdown";
|
||||
import { EventedSpacePrimitives } from "../common/spaces/evented_space_primitives";
|
||||
import { Space } from "../common/spaces/space";
|
||||
import { safeRun } from "../webapp/util";
|
||||
import { safeRun, throttle } from "../webapp/util";
|
||||
import { createSandbox } from "../plugos/environments/node_sandbox";
|
||||
import { jwtSyscalls } from "../plugos/syscalls/jwt";
|
||||
import { fetchSyscalls } from "../plugos/syscalls/fetch.node";
|
||||
import buildMarkdown from "../webapp/parser";
|
||||
import { loadMarkdownExtensions } from "../webapp/markdown_ext";
|
||||
|
||||
export class ExpressServer {
|
||||
app: Express;
|
||||
|
@ -66,23 +68,29 @@ export class ExpressServer {
|
|||
system.registerSyscalls([], pageIndexSyscalls(this.db));
|
||||
system.registerSyscalls([], spaceSyscalls(this.space));
|
||||
system.registerSyscalls([], eventSyscalls(this.eventHook));
|
||||
system.registerSyscalls([], markdownSyscalls());
|
||||
system.registerSyscalls([], markdownSyscalls(buildMarkdown([])));
|
||||
system.registerSyscalls([], fetchSyscalls());
|
||||
system.registerSyscalls([], jwtSyscalls());
|
||||
system.addHook(new EndpointHook(app, "/_/"));
|
||||
|
||||
let throttledRebuildMdExtensions = throttle(() => {
|
||||
this.rebuildMdExtensions();
|
||||
}, 100);
|
||||
|
||||
this.space.on({
|
||||
plugLoaded: (plugName, plug) => {
|
||||
safeRun(async () => {
|
||||
console.log("Plug load", plugName);
|
||||
await system.load(plugName, plug, createSandbox);
|
||||
});
|
||||
throttledRebuildMdExtensions();
|
||||
},
|
||||
plugUnloaded: (plugName) => {
|
||||
safeRun(async () => {
|
||||
console.log("Plug unload", plugName);
|
||||
await system.unload(plugName);
|
||||
});
|
||||
throttledRebuildMdExtensions();
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -92,6 +100,13 @@ export class ExpressServer {
|
|||
this.space.updatePageListAsync();
|
||||
}
|
||||
|
||||
rebuildMdExtensions() {
|
||||
this.system.registerSyscalls(
|
||||
[],
|
||||
markdownSyscalls(buildMarkdown(loadMarkdownExtensions(this.system)))
|
||||
);
|
||||
}
|
||||
|
||||
async init() {
|
||||
console.log("Setting up router");
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import { lineWrapper } from "./line_wrapper";
|
|||
import { markdown } from "./markdown";
|
||||
import { PathPageNavigator } from "./navigator";
|
||||
import customMarkDown from "./parser";
|
||||
import buildMarkdown from "./parser";
|
||||
import reducer from "./reducer";
|
||||
import { smartQuoteKeymap } from "./smart_quotes";
|
||||
import { Space } from "../common/spaces/space";
|
||||
|
@ -48,6 +49,7 @@ import { pasteLinkExtension } from "./editor_paste";
|
|||
import { markdownSyscalls } from "../common/syscalls/markdown";
|
||||
import { clientStoreSyscalls } from "./syscalls/clientStore";
|
||||
import { StatusBar } from "./components/status_bar";
|
||||
import { loadMarkdownExtensions, MDExt } from "./markdown_ext";
|
||||
|
||||
class PageState {
|
||||
scrollTop: number;
|
||||
|
@ -77,6 +79,7 @@ export class Editor implements AppEventDispatcher {
|
|||
this.eventHook.dispatchEvent("editor:updated");
|
||||
}, 1000);
|
||||
private system = new System<SilverBulletHooks>("client");
|
||||
private mdExtensions: MDExt[] = [];
|
||||
|
||||
constructor(space: Space, parent: Element) {
|
||||
this.space = space;
|
||||
|
@ -118,7 +121,10 @@ export class Editor implements AppEventDispatcher {
|
|||
this.system.registerSyscalls([], spaceSyscalls(this));
|
||||
this.system.registerSyscalls([], indexerSyscalls(this.space));
|
||||
this.system.registerSyscalls([], systemSyscalls(this.space));
|
||||
this.system.registerSyscalls([], markdownSyscalls());
|
||||
this.system.registerSyscalls(
|
||||
[],
|
||||
markdownSyscalls(buildMarkdown(this.mdExtensions))
|
||||
);
|
||||
this.system.registerSyscalls([], clientStoreSyscalls());
|
||||
}
|
||||
|
||||
|
@ -270,7 +276,7 @@ export class Editor implements AppEventDispatcher {
|
|||
history(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
customMarkdownStyle,
|
||||
customMarkdownStyle(this.mdExtensions),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion({
|
||||
|
@ -387,7 +393,7 @@ export class Editor implements AppEventDispatcher {
|
|||
),
|
||||
pasteLinkExtension,
|
||||
markdown({
|
||||
base: customMarkDown,
|
||||
base: customMarkDown(this.mdExtensions),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
@ -396,6 +402,14 @@ export class Editor implements AppEventDispatcher {
|
|||
rebuildEditorState() {
|
||||
const editorView = this.editorView;
|
||||
if (editorView && this.currentPage) {
|
||||
this.mdExtensions = loadMarkdownExtensions(this.system);
|
||||
|
||||
// And reload the syscalls to use the new syntax extensions
|
||||
this.system.registerSyscalls(
|
||||
[],
|
||||
markdownSyscalls(buildMarkdown(this.mdExtensions))
|
||||
);
|
||||
|
||||
editorView.setState(
|
||||
this.createEditorState(this.currentPage, editorView.state.sliceDoc())
|
||||
);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { ViewPlugin, ViewUpdate } from "@codemirror/view";
|
||||
import { urlRegexp } from "./parser";
|
||||
|
||||
const urlRegexp =
|
||||
/^https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{1,256}([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
||||
|
||||
export const pasteLinkExtension = ViewPlugin.fromClass(
|
||||
class {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { Tag } from "@codemirror/highlight";
|
||||
import type { MarkdownConfig } from "@lezer/markdown";
|
||||
import { System } from "../plugos/system";
|
||||
import { Manifest } from "../common/manifest";
|
||||
|
||||
export type MDExt = {
|
||||
// unicode char code for efficiency .charCodeAt(0)
|
||||
firstCharCodes: number[];
|
||||
regex: RegExp;
|
||||
nodeType: string;
|
||||
tag: Tag;
|
||||
styles: { [key: string]: string };
|
||||
};
|
||||
|
||||
export function mdExtensionSyntaxConfig({
|
||||
regex,
|
||||
firstCharCodes,
|
||||
nodeType,
|
||||
}: MDExt): MarkdownConfig {
|
||||
return {
|
||||
defineNodes: [nodeType],
|
||||
parseInline: [
|
||||
{
|
||||
name: nodeType,
|
||||
parse(cx, next, pos) {
|
||||
if (!firstCharCodes.includes(next)) {
|
||||
return -1;
|
||||
}
|
||||
let match = regex.exec(cx.slice(pos, cx.end));
|
||||
if (!match) {
|
||||
return -1;
|
||||
}
|
||||
return cx.addElement(cx.elt(nodeType, pos, pos + match[0].length));
|
||||
},
|
||||
after: "Emphasis",
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function mdExtensionStyleTags({ nodeType, tag }: MDExt): {
|
||||
[selector: string]: Tag | readonly Tag[];
|
||||
} {
|
||||
return {
|
||||
[nodeType]: tag,
|
||||
};
|
||||
}
|
||||
|
||||
export function loadMarkdownExtensions(system: System<any>): MDExt[] {
|
||||
let mdExtensions: MDExt[] = [];
|
||||
for (let plug of system.loadedPlugs.values()) {
|
||||
let manifest = plug.manifest as Manifest;
|
||||
if (manifest.syntax) {
|
||||
for (let [nodeType, def] of Object.entries(manifest.syntax)) {
|
||||
mdExtensions.push({
|
||||
nodeType,
|
||||
tag: Tag.define(),
|
||||
firstCharCodes: def.firstCharacters.map((ch) => ch.charCodeAt(0)),
|
||||
regex: new RegExp("^" + def.regex),
|
||||
styles: def.styles,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return mdExtensions;
|
||||
}
|
142
webapp/parser.ts
142
webapp/parser.ts
|
@ -1,11 +1,12 @@
|
|||
import { styleTags, tags as t } from "@codemirror/highlight";
|
||||
import { styleTags } from "@codemirror/highlight";
|
||||
import { BlockContext, LeafBlock, LeafBlockParser, MarkdownConfig, parseCode, TaskList } from "@lezer/markdown";
|
||||
import { commonmark, getCodeParser, mkLang } from "./markdown/markdown";
|
||||
import * as ct from "./customtags";
|
||||
import { LanguageDescription, LanguageSupport } from "@codemirror/language";
|
||||
import { Language, LanguageDescription, LanguageSupport } from "@codemirror/language";
|
||||
import { StreamLanguage } from "@codemirror/stream-parser";
|
||||
import { yaml } from "@codemirror/legacy-modes/mode/yaml";
|
||||
import { javascriptLanguage } from "@codemirror/lang-javascript";
|
||||
import { MDExt, mdExtensionStyleTags, mdExtensionSyntaxConfig } from "./markdown_ext";
|
||||
|
||||
export const pageLinkRegex = /^\[\[([^\]]+)\]\]/;
|
||||
|
||||
|
@ -37,51 +38,6 @@ const WikiLink: MarkdownConfig = {
|
|||
],
|
||||
};
|
||||
|
||||
const AtMention: MarkdownConfig = {
|
||||
defineNodes: ["AtMention"],
|
||||
parseInline: [
|
||||
{
|
||||
name: "AtMention",
|
||||
parse(cx, next, pos) {
|
||||
let match: RegExpMatchArray | null;
|
||||
if (
|
||||
next != 64 /* '@' */ ||
|
||||
!(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
return cx.addElement(
|
||||
cx.elt("AtMention", pos, pos + 1 + match[0].length)
|
||||
);
|
||||
},
|
||||
after: "Emphasis",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const urlRegexp =
|
||||
/^https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{1,256}([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
||||
|
||||
const UnmarkedUrl: MarkdownConfig = {
|
||||
defineNodes: ["URL"],
|
||||
parseInline: [
|
||||
{
|
||||
name: "URL",
|
||||
parse(cx, next, pos) {
|
||||
let match: RegExpMatchArray | null;
|
||||
if (
|
||||
next != 104 /* 'h' */ ||
|
||||
!(match = urlRegexp.exec(cx.slice(pos, cx.end)))
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
return cx.addElement(cx.elt("URL", pos, pos + match[0].length));
|
||||
},
|
||||
after: "Emphasis",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
class CommentParser implements LeafBlockParser {
|
||||
nextLine() {
|
||||
return false;
|
||||
|
@ -111,60 +67,40 @@ export const Comment: MarkdownConfig = {
|
|||
],
|
||||
};
|
||||
|
||||
const TagLink: MarkdownConfig = {
|
||||
defineNodes: ["TagLink"],
|
||||
parseInline: [
|
||||
{
|
||||
name: "TagLink",
|
||||
parse(cx, next, pos) {
|
||||
let match: RegExpMatchArray | null;
|
||||
if (
|
||||
next != 35 /* '#' */ ||
|
||||
!(match = /^[A-Za-z\.]+/.exec(cx.slice(pos + 1, cx.end)))
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
return cx.addElement(cx.elt("TagLink", pos, pos + 1 + match[0].length));
|
||||
export default function buildMarkdown(mdExtensions: MDExt[]): Language {
|
||||
return mkLang(
|
||||
commonmark.configure([
|
||||
WikiLink,
|
||||
TaskList,
|
||||
Comment,
|
||||
...mdExtensions.map(mdExtensionSyntaxConfig),
|
||||
parseCode({
|
||||
codeParser: getCodeParser([
|
||||
LanguageDescription.of({
|
||||
name: "yaml",
|
||||
support: new LanguageSupport(StreamLanguage.define(yaml)),
|
||||
}),
|
||||
LanguageDescription.of({
|
||||
name: "javascript",
|
||||
alias: ["js"],
|
||||
support: new LanguageSupport(javascriptLanguage),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
{
|
||||
props: [
|
||||
styleTags({
|
||||
WikiLink: ct.WikiLinkTag,
|
||||
WikiLinkPage: ct.WikiLinkPageTag,
|
||||
Task: ct.TaskTag,
|
||||
TaskMarker: ct.TaskMarkerTag,
|
||||
Comment: ct.CommentTag,
|
||||
}),
|
||||
...mdExtensions.map((mdExt) =>
|
||||
styleTags(mdExtensionStyleTags(mdExt))
|
||||
),
|
||||
],
|
||||
},
|
||||
after: "Emphasis",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const WikiMarkdown = commonmark.configure([
|
||||
WikiLink,
|
||||
AtMention,
|
||||
// TagLink,
|
||||
TaskList,
|
||||
UnmarkedUrl,
|
||||
Comment,
|
||||
parseCode({
|
||||
codeParser: getCodeParser([
|
||||
LanguageDescription.of({
|
||||
name: "yaml",
|
||||
support: new LanguageSupport(StreamLanguage.define(yaml)),
|
||||
}),
|
||||
LanguageDescription.of({
|
||||
name: "javascript",
|
||||
alias: ["js"],
|
||||
support: new LanguageSupport(javascriptLanguage),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
{
|
||||
props: [
|
||||
styleTags({
|
||||
WikiLink: ct.WikiLinkTag,
|
||||
WikiLinkPage: ct.WikiLinkPageTag,
|
||||
AtMention: ct.MentionTag,
|
||||
TagLink: ct.TagTag,
|
||||
Task: ct.TaskTag,
|
||||
TaskMarker: ct.TaskMarkerTag,
|
||||
Url: t.url,
|
||||
Comment: ct.CommentTag,
|
||||
}),
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
export default mkLang(WikiMarkdown);
|
||||
])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ async function activate() {
|
|||
self.addEventListener("activate", (e) => e.waitUntil(activate()));
|
||||
|
||||
self.addEventListener("fetch", (event: any) => {
|
||||
return;
|
||||
event.respondWith(
|
||||
caches.open(version).then(async (cache) => {
|
||||
let parsedUrl = new URL(event.request.url);
|
||||
|
|
|
@ -1,38 +1,44 @@
|
|||
import { HighlightStyle, tags as t } from "@codemirror/highlight";
|
||||
import * as ct from "./customtags";
|
||||
import { MDExt } from "./markdown_ext";
|
||||
|
||||
export default HighlightStyle.define([
|
||||
{ tag: t.heading1, class: "h1" },
|
||||
{ tag: t.heading2, class: "h2" },
|
||||
{ tag: t.heading3, class: "h3" },
|
||||
{ tag: t.link, class: "link" },
|
||||
{ tag: t.meta, class: "meta" },
|
||||
{ tag: t.quote, class: "quote" },
|
||||
{ tag: t.monospace, class: "code" },
|
||||
{ tag: t.url, class: "url" },
|
||||
{ tag: ct.WikiLinkTag, class: "wiki-link" },
|
||||
{ tag: ct.WikiLinkPageTag, class: "wiki-link-page" },
|
||||
{ tag: ct.TagTag, class: "tag" },
|
||||
{ tag: ct.MentionTag, class: "mention" },
|
||||
{ tag: ct.TaskTag, class: "task" },
|
||||
{ tag: ct.TaskMarkerTag, class: "task-marker" },
|
||||
{ tag: ct.CommentTag, class: "comment" },
|
||||
{ tag: ct.CommentMarkerTag, class: "comment-marker" },
|
||||
{ tag: t.emphasis, class: "emphasis" },
|
||||
{ tag: t.strong, class: "strong" },
|
||||
{ tag: t.atom, class: "atom" },
|
||||
{ tag: t.bool, class: "bool" },
|
||||
{ tag: t.url, class: "url" },
|
||||
{ tag: t.inserted, class: "inserted" },
|
||||
{ tag: t.deleted, class: "deleted" },
|
||||
{ tag: t.literal, class: "literal" },
|
||||
{ tag: t.list, class: "list" },
|
||||
{ tag: t.definition, class: "li" },
|
||||
{ tag: t.string, class: "string" },
|
||||
{ tag: t.number, class: "number" },
|
||||
{ tag: [t.regexp, t.escape, t.special(t.string)], class: "string2" },
|
||||
{ tag: t.variableName, class: "variableName" },
|
||||
{ tag: t.comment, class: "comment" },
|
||||
{ tag: t.invalid, class: "invalid" },
|
||||
{ tag: t.punctuation, class: "punctuation" },
|
||||
]);
|
||||
export default function highlightStyles(mdExtension: MDExt[]) {
|
||||
return HighlightStyle.define([
|
||||
{ tag: t.heading1, class: "h1" },
|
||||
{ tag: t.heading2, class: "h2" },
|
||||
{ tag: t.heading3, class: "h3" },
|
||||
{ tag: t.link, class: "link" },
|
||||
{ tag: t.meta, class: "meta" },
|
||||
{ tag: t.quote, class: "quote" },
|
||||
{ tag: t.monospace, class: "code" },
|
||||
{ tag: t.url, class: "url" },
|
||||
{ tag: ct.WikiLinkTag, class: "wiki-link" },
|
||||
{ tag: ct.WikiLinkPageTag, class: "wiki-link-page" },
|
||||
{ tag: ct.TagTag, class: "tag" },
|
||||
{ tag: ct.MentionTag, class: "mention" },
|
||||
{ tag: ct.TaskTag, class: "task" },
|
||||
{ tag: ct.TaskMarkerTag, class: "task-marker" },
|
||||
{ tag: ct.CommentTag, class: "comment" },
|
||||
{ tag: ct.CommentMarkerTag, class: "comment-marker" },
|
||||
{ tag: t.emphasis, class: "emphasis" },
|
||||
{ tag: t.strong, class: "strong" },
|
||||
{ tag: t.atom, class: "atom" },
|
||||
{ tag: t.bool, class: "bool" },
|
||||
{ tag: t.url, class: "url" },
|
||||
{ tag: t.inserted, class: "inserted" },
|
||||
{ tag: t.deleted, class: "deleted" },
|
||||
{ tag: t.literal, class: "literal" },
|
||||
{ tag: t.list, class: "list" },
|
||||
{ tag: t.definition, class: "li" },
|
||||
{ tag: t.string, class: "string" },
|
||||
{ tag: t.number, class: "number" },
|
||||
{ tag: [t.regexp, t.escape, t.special(t.string)], class: "string2" },
|
||||
{ tag: t.variableName, class: "variableName" },
|
||||
{ tag: t.comment, class: "comment" },
|
||||
{ tag: t.invalid, class: "invalid" },
|
||||
{ tag: t.punctuation, class: "punctuation" },
|
||||
...mdExtension.map((mdExt) => {
|
||||
return { tag: mdExt.tag, ...mdExt.styles };
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue