fix: most of the template blocks

This commit is contained in:
Max Richter
2025-09-30 19:28:56 +02:00
parent d35f3e5e2e
commit 2a1572f99d
20 changed files with 210 additions and 187 deletions

View File

@@ -8,6 +8,23 @@ declare global {
// interface PageState {}
// interface Platform {}
}
class Go {
new(): {
run: (inst: WebAssembly.Instance) => Promise<void>;
importObject: WebAssembly.Imports;
};
}
const marka: {
matchBlocks(s: string, t: string): string;
detectType(markdown: string): string;
parseFile(input: string): string;
parseFileWithTemplate(markdown: string, template: string): string;
listTemplates(): string;
getTemplate(name: string): string;
compileTemplate(source: string): string;
};
}
export {};
export {};

View File

@@ -2,6 +2,7 @@
import { json } from '@codemirror/lang-json';
import { markdown } from '@codemirror/lang-markdown';
import {
compileTemplate,
getTemplate,
listTemplates,
parseMarkdown,
@@ -86,9 +87,12 @@ My favourite baguette recipe
return;
}
try {
compileTemplate(templateValue);
const result = templateValue
? parseMarkdownWithTemplate(markdownValue, templateValue)
: parseMarkdown(markdownValue);
console.log({ result });
if ('error' in result) {
jsonOutput = '';

View File

@@ -1,20 +1,6 @@
import { readable } from "svelte/store";
declare global {
interface Window {
Go: {
new(): {
run: (inst: WebAssembly.Instance) => Promise<void>;
importObject: WebAssembly.Imports;
};
};
markaMatchBlocks: (input: string) => unknown;
markaParseFile: (input: string) => string;
markaParseFileWithTemplate: (markdown: string, template: string) => string;
markaListTemplates: () => string;
markaGetTemplate: (name: string) => string;
}
}
export const wasmReady = readable(false, (set) => {
if (typeof window === "undefined") {
@@ -22,7 +8,7 @@ export const wasmReady = readable(false, (set) => {
}
const loadWasm = async () => {
const go = new window.Go();
const go = new globalThis.Go();
try {
const result = await WebAssembly.instantiateStreaming(
fetch("/main.wasm"),
@@ -38,7 +24,7 @@ export const wasmReady = readable(false, (set) => {
if (document.readyState === "complete") {
loadWasm();
} else {
window.addEventListener("load", loadWasm);
globalThis.addEventListener("load", loadWasm);
}
});
@@ -54,46 +40,75 @@ export type ParseResultError = {
export type ParseResult = ParseResultSuccess | ParseResultError;
export function parseMarkdown(markdown: string): ParseResult {
if (typeof window.markaParseFile !== "function") {
if (typeof globalThis.marka?.parseFile !== "function") {
throw new Error("Wasm module not ready");
}
const result = window.markaParseFile(markdown);
if (result.error) return result;
return JSON.parse(result);
const resultString = globalThis.marka.parseFile(markdown);
return JSON.parse(resultString);
}
export function matchBlocks(markdown: string): ParseResult {
if (typeof window.markaMatchBlocks !== "function") {
export function compileTemplate(templateSource: string) {
if (typeof globalThis.marka?.compileTemplate !== "function") {
throw new Error("Wasm module not ready");
}
const result = window.markaMatchBlocks(markdown) as ParseResult;
if (result.error) return result;
return JSON.parse(result);
const resultString = globalThis.marka.compileTemplate(templateSource);
const result = JSON.parse(resultString);
console.log({ result });
return result;
}
export function matchBlocks(markdown: string, template: string): ParseResult {
if (typeof globalThis.marka?.matchBlocks !== "function") {
throw new Error("Wasm module not ready");
}
const resultString = globalThis.marka.matchBlocks(markdown, template);
return JSON.parse(resultString);
}
export function parseMarkdownWithTemplate(
markdown: string,
template: string,
): ParseResult {
if (typeof window.markaParseFileWithTemplate !== "function") {
if (typeof globalThis.marka?.parseFileWithTemplate !== "function") {
throw new Error("Wasm module not ready");
}
const result = window.markaParseFileWithTemplate(markdown, template);
if (result.error) return result;
return JSON.parse(result);
const resultString = globalThis.marka.parseFileWithTemplate(
markdown,
template,
);
return JSON.parse(resultString);
}
export function listTemplates(): string[] {
if (typeof window.markaListTemplates !== "function") {
if (typeof globalThis.marka?.listTemplates !== "function") {
throw new Error("Wasm module not ready");
}
const result = window.markaListTemplates();
return JSON.parse(result);
const resultString = globalThis.marka.listTemplates();
return JSON.parse(resultString);
}
export function getTemplate(name: string): string {
if (typeof window.markaGetTemplate !== "function") {
if (typeof globalThis.marka?.getTemplate !== "function") {
throw new Error("Wasm module not ready");
}
return window.markaGetTemplate(name);
return globalThis.marka.getTemplate(name);
}
export function detectType(markdown: string): string | ParseResultError {
if (typeof globalThis.marka?.detectType !== "function") {
throw new Error("Wasm module not ready");
}
const result = globalThis.marka.detectType(markdown);
try {
// If the result is a JSON string with an error, parse and return it
const parsed = JSON.parse(result);
if (parsed.error) {
return parsed;
}
} catch (e) {
// Otherwise, it's a plain string for success
return result;
}
return result;
}

Binary file not shown.

View File

@@ -7,12 +7,13 @@ OUT_WASM="$OUT_DIR/main.wasm"
mkdir -p "$OUT_DIR"
tinygo build -target=wasm -opt=z -no-debug -panic=trap -gc=leaking \
tinygo build -target=wasm \
-opt=z -no-debug -panic=print -gc=leaking \
-o "$OUT_WASM" "$SCRIPT_DIR"
# Optional post-process (run only if tools exist)
# command -v wasm-opt >/dev/null && wasm-opt -Oz --strip-debug --strip-dwarf --strip-producers \
# -o "$OUT_WASM.tmp" "$OUT_WASM" && mv "$OUT_WASM.tmp" "$OUT_WASM"
command -v wasm-opt >/dev/null && wasm-opt -Oz --strip-debug --strip-dwarf --strip-producers \
-o "$OUT_WASM.tmp" "$OUT_WASM" && mv "$OUT_WASM.tmp" "$OUT_WASM"
# command -v wasm-strip >/dev/null && wasm-strip "$OUT_WASM"
# command -v brotli >/dev/null && brotli -f -q 11 "$OUT_WASM" -o "$OUT_WASM.br"
# command -v gzip >/dev/null && gzip -c -9 "$OUT_WASM" > "$OUT_WASM.gz"

View File

@@ -8,92 +8,108 @@ import (
p "git.max-richter.dev/max/marka/parser"
"git.max-richter.dev/max/marka/registry"
"git.max-richter.dev/max/marka/template"
)
func matchBlocks(_ js.Value, args []js.Value) any {
if len(args) == 0 {
return js.ValueOf(map[string]any{"error": "missing markdown"})
}
t, err := p.MatchBlocks(args[0].String(), args[1].String())
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
}
jsonString, _ := json.Marshal(t)
return js.ValueOf(string(jsonString)) // plain string
func wrapError(err error) string {
errMap := map[string]any{"error": err.Error()}
errJSON, _ := json.Marshal(errMap)
return string(errJSON)
}
func detectType(_ js.Value, args []js.Value) any {
if len(args) == 0 {
return js.ValueOf(map[string]any{"error": "missing markdown"})
}
t, err := p.DetectType(args[0].String())
func MatchBlocks(this js.Value, args []js.Value) any {
s := args[0].String()
t := args[1].String()
matched, err := p.MatchBlocks(s, t)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return js.ValueOf(t) // plain string
jsonString, _ := json.Marshal(matched)
return string(jsonString)
}
func parseFile(_ js.Value, args []js.Value) any {
if len(args) == 0 {
return js.ValueOf(map[string]any{"error": "missing markdown"})
}
res, err := p.ParseFile(args[0].String())
func DetectType(this js.Value, args []js.Value) any {
markdown := args[0].String()
t, err := p.DetectType(markdown)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return t
}
func ParseFile(this js.Value, args []js.Value) any {
markdown := args[0].String()
res, err := p.ParseFile(markdown)
if err != nil {
return wrapError(err)
}
b, err := json.Marshal(res)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return js.ValueOf(string(b))
return string(b)
}
func parseFileWithTemplate(_ js.Value, args []js.Value) any {
if len(args) < 2 {
return js.ValueOf(map[string]any{"error": "missing markdown or template"})
}
res, err := p.ParseFileWithTemplate(args[0].String(), args[1].String())
func ParseFileWithTemplate(this js.Value, args []js.Value) any {
markdown := args[0].String()
template := args[1].String()
res, err := p.ParseFileWithTemplate(markdown, template)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
b, err := json.Marshal(res)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return js.ValueOf(string(b))
return string(b)
}
func listTemplates(_ js.Value, args []js.Value) any {
func ListTemplates(this js.Value, args []js.Value) any {
templates, err := registry.ListTemplates()
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
b, err := json.Marshal(templates)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return js.ValueOf(string(b))
return string(b)
}
func getTemplate(_ js.Value, args []js.Value) any {
if len(args) == 0 {
return js.ValueOf(map[string]any{"error": "missing template name"})
}
template, err := registry.GetTemplate(args[0].String())
func GetTemplate(this js.Value, args []js.Value) any {
name := args[0].String()
template, err := registry.GetTemplate(name)
if err != nil {
return js.ValueOf(map[string]any{"error": err.Error()})
return wrapError(err)
}
return js.ValueOf(template)
return template
}
func CompileTemplate(this js.Value, args []js.Value) any {
source := args[0].String()
template, err := template.CompileTemplate(source)
if err != nil {
return wrapError(err)
}
b, err := json.Marshal(template)
if err != nil {
return wrapError(err)
}
return string(b)
}
func main() {
js.Global().Set("markaDetectType", js.FuncOf(detectType))
js.Global().Set("markaParseFile", js.FuncOf(parseFile))
js.Global().Set("markaParseFileWithTemplate", js.FuncOf(parseFileWithTemplate))
js.Global().Set("markaMatchBlocks", js.FuncOf(matchBlocks))
js.Global().Set("markaListTemplates", js.FuncOf(listTemplates))
js.Global().Set("markaGetTemplate", js.FuncOf(getTemplate))
marka := js.Global().Get("Object").New()
marka.Set("matchBlocks", js.FuncOf(MatchBlocks))
marka.Set("detectType", js.FuncOf(DetectType))
marka.Set("parseFile", js.FuncOf(ParseFile))
marka.Set("parseFileWithTemplate", js.FuncOf(ParseFileWithTemplate))
marka.Set("listTemplates", js.FuncOf(ListTemplates))
marka.Set("getTemplate", js.FuncOf(GetTemplate))
marka.Set("compileTemplate", js.FuncOf(CompileTemplate))
js.Global().Set("marka", marka)
select {}
}
}