From b69cd3d846e85d720e360c8c67c0a41efeca6a85 Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Tue, 1 Jul 2025 10:16:32 +1000 Subject: [PATCH] chore: add JS formatting with biome --- Makefile | 4 ++ bin/.biome-1.9.4.pkg | 1 + bin/biome | 1 + biome.json | 6 ++ cmd/chromad/static/chroma.js | 120 ++++++++++++++++--------------- cmd/chromad/static/index.js | 135 ++++++++++++++++++++--------------- 6 files changed, 152 insertions(+), 115 deletions(-) create mode 120000 bin/.biome-1.9.4.pkg create mode 120000 bin/biome create mode 100644 biome.json diff --git a/Makefile b/Makefile index 3fc57db..5fd4992 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,10 @@ README.md: lexers/*/*.go tokentype_string.go: types.go go generate +.PHONY: format-js +format-js: + biome format --write cmd/chromad/static/{index.js,chroma.js} + .PHONY: chromad chromad: build/chromad diff --git a/bin/.biome-1.9.4.pkg b/bin/.biome-1.9.4.pkg new file mode 120000 index 0000000..383f451 --- /dev/null +++ b/bin/.biome-1.9.4.pkg @@ -0,0 +1 @@ +hermit \ No newline at end of file diff --git a/bin/biome b/bin/biome new file mode 120000 index 0000000..7a5028c --- /dev/null +++ b/bin/biome @@ -0,0 +1 @@ +.biome-1.9.4.pkg \ No newline at end of file diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..a5bec2e --- /dev/null +++ b/biome.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", + "formatter": { + "indentStyle": "space" + } +} diff --git a/cmd/chromad/static/chroma.js b/cmd/chromad/static/chroma.js index 60758ca..3e0e41f 100644 --- a/cmd/chromad/static/chroma.js +++ b/cmd/chromad/static/chroma.js @@ -1,72 +1,79 @@ // chroma.js - TinyGo WASM runtime initialization for Chroma syntax highlighter // Import wasm_exec.js so that it initialises the Go WASM runtime. -import './wasm_exec.js'; +import "./wasm_exec.js"; class ChromaWASM { - constructor() { - this.go = null; - this.wasm = null; - this.ready = false; - this.readyPromise = this.init(); + constructor() { + this.go = null; + this.wasm = null; + this.ready = false; + this.readyPromise = this.init(); + } + + async init() { + try { + // Create a new Go instance + this.go = new Go(); + + // Load the WASM module + const wasmResponse = await fetch("./static/chroma.wasm"); + if (!wasmResponse.ok) { + throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`); + } + + const wasmBytes = await wasmResponse.arrayBuffer(); + const wasmModule = await WebAssembly.instantiate( + wasmBytes, + this.go.importObject, + ); + + this.wasm = wasmModule.instance; + + // Run the Go program + this.go.run(this.wasm); + + this.ready = true; + console.log("Chroma WASM module initialized successfully"); + } catch (error) { + console.error("Failed to initialize Chroma WASM module:", error); + throw error; + } + } + + async waitForReady() { + await this.readyPromise; + if (!this.ready) { + throw new Error("Chroma WASM module failed to initialize"); + } + } + + async highlight(source, lexer, formatter, withClasses) { + await this.waitForReady(); + + if (typeof window.highlight !== "function") { + throw new Error("highlight function not available from WASM module"); } - async init() { - try { - // Create a new Go instance - this.go = new Go(); - - // Load the WASM module - const wasmResponse = await fetch('./static/chroma.wasm'); - if (!wasmResponse.ok) { - throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`); - } - - const wasmBytes = await wasmResponse.arrayBuffer(); - const wasmModule = await WebAssembly.instantiate(wasmBytes, this.go.importObject); - - this.wasm = wasmModule.instance; - - // Run the Go program - this.go.run(this.wasm); - - this.ready = true; - console.log('Chroma WASM module initialized successfully'); - } catch (error) { - console.error('Failed to initialize Chroma WASM module:', error); - throw error; - } - } - - async waitForReady() { - await this.readyPromise; - if (!this.ready) { - throw new Error('Chroma WASM module failed to initialize'); - } - } - - async highlight(source, lexer, formatter, withClasses) { - await this.waitForReady(); - - if (typeof window.highlight !== 'function') { - throw new Error('highlight function not available from WASM module'); - } - - try { - return window.highlight(source, lexer, formatter, withClasses); - } catch (error) { - console.error('Error calling highlight function:', error); - throw error; - } + try { + return window.highlight(source, lexer, formatter, withClasses); + } catch (error) { + console.error("Error calling highlight function:", error); + throw error; } + } } - export function isWasmSupported() { try { - if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { + if ( + typeof WebAssembly === "object" && + typeof WebAssembly.instantiate === "function" + ) { // The smallest possible WebAssembly module (magic number + version) - const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); + const module = new WebAssembly.Module( + Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00), + ); if (module instanceof WebAssembly.Module) { // Try to instantiate the module to ensure it's truly runnable return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; @@ -78,6 +85,5 @@ export function isWasmSupported() { return false; } - // Create global instance, null if WASM is not supported. export const chroma = isWasmSupported() ? new ChromaWASM() : null; diff --git a/cmd/chromad/static/index.js b/cmd/chromad/static/index.js index ba33941..f2ecf82 100644 --- a/cmd/chromad/static/index.js +++ b/cmd/chromad/static/index.js @@ -2,12 +2,14 @@ import * as Base64 from "./base64.js"; import { chroma } from "./chroma.js"; document.addEventListener("DOMContentLoaded", function () { - var darkMode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); - var style = document.createElement('style'); - var ref = document.querySelector('script'); + var darkMode = + window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches; + var style = document.createElement("style"); + var ref = document.querySelector("script"); ref.parentNode.insertBefore(style, ref); - var form = document.getElementById('chroma'); + var form = document.getElementById("chroma"); var textArea = form.elements["text"]; var styleSelect = form.elements["style"]; var languageSelect = form.elements["language"]; @@ -16,49 +18,62 @@ document.addEventListener("DOMContentLoaded", function () { var output = document.getElementById("output"); var htmlCheckbox = document.getElementById("html"); - (document.querySelectorAll('.notification .delete') || []).forEach((el) => { + (document.querySelectorAll(".notification .delete") || []).forEach((el) => { const notification = el.parentNode; - el.addEventListener('click', () => { + el.addEventListener("click", () => { notification.parentNode.removeChild(notification); }); }); async function renderServer(formData) { - return (await fetch("api/render", { - method: 'POST', - mode: 'cors', - cache: 'no-cache', - credentials: 'same-origin', - headers: { - 'X-CSRF-Token': csrfToken, - 'Content-Type': 'application/json', - }, - redirect: 'follow', - referrer: 'no-referrer', - body: JSON.stringify(formData), - })).json(); + return ( + await fetch("api/render", { + method: "POST", + mode: "cors", + cache: "no-cache", + credentials: "same-origin", + headers: { + "X-CSRF-Token": csrfToken, + "Content-Type": "application/json", + }, + redirect: "follow", + referrer: "no-referrer", + body: JSON.stringify(formData), + }) + ).json(); } async function renderWasm(formData) { - return await chroma.highlight( - formData.text, - formData.language, - formData.style, - formData.classes, - ); + return await chroma.highlight( + formData.text, + formData.language, + formData.style, + formData.classes, + ); } async function render(formData) { - return chroma !== null - ? renderWasm(formData) - : renderServer(formData); + return chroma !== null ? renderWasm(formData) : renderServer(formData); } - // https://stackoverflow.com/a/37697925/7980 function handleTab(e) { - var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val; - if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey) { + var after, + before, + end, + lastNewLine, + changeLength, + re, + replace, + selection, + start, + val; + if ( + (e.charCode === 9 || e.keyCode === 9) && + !e.altKey && + !e.ctrlKey && + !e.metaKey + ) { e.preventDefault(); start = this.selectionStart; end = this.selectionEnd; @@ -68,14 +83,14 @@ document.addEventListener("DOMContentLoaded", function () { replace = true; if (start !== end) { selection = val.substring(start, end); - if (~selection.indexOf('\n')) { + if (~selection.indexOf("\n")) { replace = false; changeLength = 0; - lastNewLine = before.lastIndexOf('\n'); + lastNewLine = before.lastIndexOf("\n"); if (!~lastNewLine) { selection = before + selection; changeLength = before.length; - before = ''; + before = ""; } else { selection = before.substring(lastNewLine) + selection; changeLength = before.length - lastNewLine; @@ -87,9 +102,9 @@ document.addEventListener("DOMContentLoaded", function () { start--; changeLength--; } - selection = selection.replace(re, '$1'); + selection = selection.replace(re, "$1"); } else { - selection = selection.replace(/(\n|^)/g, '$1\t'); + selection = selection.replace(/(\n|^)/g, "$1\t"); start++; changeLength++; } @@ -99,7 +114,7 @@ document.addEventListener("DOMContentLoaded", function () { } } if (replace && !e.shiftKey) { - this.value = before + '\t' + after; + this.value = before + "\t" + after; this.selectionStart = this.selectionEnd = start + 1; } } @@ -109,7 +124,8 @@ document.addEventListener("DOMContentLoaded", function () { function debounce(func, wait, immediate) { var timeout; return function () { - var context = this, args = arguments; + var context = this; + var args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); @@ -123,11 +139,11 @@ document.addEventListener("DOMContentLoaded", function () { function getFormJSON() { return { - "language": languageSelect.value, - "style": styleSelect.value, - "text": textArea.value, - "classes": htmlCheckbox.checked, - } + language: languageSelect.value, + style: styleSelect.value, + text: textArea.value, + classes: htmlCheckbox.checked, + }; } async function update(event) { @@ -145,12 +161,12 @@ document.addEventListener("DOMContentLoaded", function () { output.innerHTML = value.html; } } catch (error) { - console.error('Error highlighting code:', error); + console.error("Error highlighting code:", error); // Fallback: display plain text if (htmlCheckbox.checked) { output.innerText = textArea.value; } else { - output.innerHTML = '
' + textArea.value + '
'; + output.innerHTML = "
" + textArea.value + "
"; } } @@ -160,7 +176,7 @@ document.addEventListener("DOMContentLoaded", function () { } function share(event) { - let data = JSON.stringify(getFormJSON()) + let data = JSON.stringify(getFormJSON()); data = Base64.encodeURI(data); location.hash = "#" + data; try { @@ -172,26 +188,29 @@ document.addEventListener("DOMContentLoaded", function () { } if (location.hash) { - let json = Base64.decode(location.hash.substring(1)) + let json = Base64.decode(location.hash.substring(1)); json = JSON.parse(json); textArea.value = json.text; languageSelect.value = json.language; styleSelect.value = json.style; htmlCheckbox.checked = json.classes; - update(new Event('change')); - } else if (darkMode) { - styleSelect.value = "monokai"; - update(new Event("change")); + update(new Event("change")); + } else if (darkMode) { + styleSelect.value = "monokai"; + update(new Event("change")); } var eventHandler = (event) => update(event); - var debouncedEventHandler = debounce(eventHandler, chroma === null ? 250 : 100); + var debouncedEventHandler = debounce( + eventHandler, + chroma === null ? 250 : 100, + ); - languageSelect.addEventListener('change', eventHandler); - styleSelect.addEventListener('change', eventHandler); - htmlCheckbox.addEventListener('change', eventHandler); - copyButton.addEventListener('click', share); + languageSelect.addEventListener("change", eventHandler); + styleSelect.addEventListener("change", eventHandler); + htmlCheckbox.addEventListener("change", eventHandler); + copyButton.addEventListener("click", share); - textArea.addEventListener('keydown', handleTab); - textArea.addEventListener('change', debouncedEventHandler); + textArea.addEventListener("keydown", handleTab); + textArea.addEventListener("change", debouncedEventHandler); });