Add Svelte docs site and WASM playground

This commit is contained in:
Keisuke Hirata 2026-06-17 00:07:11 +09:00
parent 58d2c9b423
commit 4020b7c2d5
No known key found for this signature in database
23 changed files with 2359 additions and 1 deletions

3
.gitignore vendored
View File

@ -3,3 +3,6 @@
/.env /.env
/.yoi /.yoi
/result /result
node_modules
/dist
site/decodal-site/dist

112
Cargo.lock generated
View File

@ -11,6 +11,18 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]] [[package]]
name = "decodal" name = "decodal"
version = "0.1.0" version = "0.1.0"
@ -25,12 +37,44 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "decodal-wasm"
version = "0.1.0"
dependencies = [
"decodal-core",
"wasm-bindgen",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.2" version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.12.4" version = "1.12.4"
@ -59,3 +103,71 @@ name = "regex-syntax"
version = "0.8.11" version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasm-bindgen"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
dependencies = [
"unicode-ident",
]

View File

@ -2,6 +2,7 @@
members = [ members = [
"crates/decodal-core", "crates/decodal-core",
"crates/decodal-cli", "crates/decodal-cli",
"crates/decodal-wasm",
] ]
resolver = "3" resolver = "3"

View File

@ -0,0 +1,14 @@
[package]
name = "decodal-wasm"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
decodal-core = { path = "../decodal-core" }
wasm-bindgen = "0.2"
[package.metadata.wasm-pack.profile.release]
wasm-opt = false

View File

@ -0,0 +1,96 @@
use decodal_core::{Data, EmptyLoader, Engine};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn evaluate(source: &str) -> String {
match evaluate_inner(source) {
Ok(output) => format!("{{\"ok\":true,\"output\":{}}}", json_string(&output)),
Err(error) => format!("{{\"ok\":false,\"error\":{}}}", json_string(&error)),
}
}
fn evaluate_inner(source: &str) -> Result<String, String> {
let mut engine = Engine::new(EmptyLoader);
let module = engine
.add_root_source("playground", "playground", source)
.map_err(format_diagnostic)?;
let value = engine.eval_module(module).map_err(format_diagnostic)?;
let data = engine.materialize(&value).map_err(format_diagnostic)?;
Ok(format_data(&data, 0))
}
fn format_diagnostic(diagnostic: decodal_core::Diagnostic) -> String {
format!(
"{:?} at {}:{}..{}: {}",
diagnostic.kind,
diagnostic.span.source.0,
diagnostic.span.start,
diagnostic.span.end,
diagnostic.message,
)
}
fn format_data(data: &Data, indent: usize) -> String {
match data {
Data::String(value) => json_string(value),
Data::Int(value) => value.to_string(),
Data::Float(value) => value.to_string(),
Data::Bool(value) => value.to_string(),
Data::Array(items) => {
if items.is_empty() {
return String::from("[]");
}
let mut out = String::from("[\n");
for (index, item) in items.iter().enumerate() {
out.push_str(&" ".repeat(indent + 2));
out.push_str(&format_data(item, indent + 2));
if index + 1 != items.len() {
out.push(',');
}
out.push('\n');
}
out.push_str(&" ".repeat(indent));
out.push(']');
out
}
Data::Object(fields) => {
if fields.is_empty() {
return String::from("{}");
}
let mut out = String::from("{\n");
for (index, field) in fields.iter().enumerate() {
out.push_str(&" ".repeat(indent + 2));
out.push_str(&json_string(&field.name));
out.push_str(": ");
out.push_str(&format_data(&field.value, indent + 2));
if index + 1 != fields.len() {
out.push(',');
}
out.push('\n');
}
out.push_str(&" ".repeat(indent));
out.push('}');
out
}
}
}
fn json_string(value: &str) -> String {
let mut out = String::from("\"");
for ch in value.chars() {
match ch {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
ch if ch.is_control() => {
use core::fmt::Write;
let _ = write!(out, "\\u{:04x}", ch as u32);
}
ch => out.push(ch),
}
}
out.push('"');
out
}

View File

@ -4,11 +4,13 @@ pkgs.mkShell {
cargo cargo
clippy clippy
git git
lld
nodejs nodejs
nixfmt nixfmt
rustc rustc
rustfmt rustfmt
tree-sitter tree-sitter
wasm-pack
]; ];
shellHook = '' shellHook = ''

View File

@ -20,6 +20,50 @@ cargo test -p decodal-core --features regex
cargo run -q -p decodal --features regex -- examples/regex/main.dcdl cargo run -q -p decodal --features regex -- examples/regex/main.dcdl
``` ```
## Web site and playground
The Svelte documentation site and browser playground are kept in:
```text
site/decodal-site/
```
The site imports Markdown files from `doc/manual/souce/` and renders them as mdBook-style pages.
The playground loads `decodal-wasm` and evaluates DCDL entirely in the browser.
Important files:
```text
site/decodal-site/src/App.svelte
site/decodal-site/src/Playground.svelte
site/decodal-site/src/lib/docs.js
crates/decodal-wasm/src/lib.rs
```
Build the WebAssembly package before building the site:
```sh
cd site/decodal-site
npm install
npm run build:wasm
npm run build
```
`npm run build:wasm` writes generated files into:
```text
site/decodal-site/src/wasm/
```
These generated files are committed so the site can be built without requiring every consumer to regenerate the wasm package first.
To run the site locally:
```sh
cd site/decodal-site
npm run dev
```
## Tree-sitter grammar ## Tree-sitter grammar
The Tree-sitter grammar is kept in: The Tree-sitter grammar is kept in:
@ -73,7 +117,7 @@ When the Decodal syntax changes:
## Development shell ## Development shell
The Nix development shell includes Rust tooling, Node.js, and Tree-sitter CLI tooling. The Nix development shell includes Rust tooling, Node.js, Tree-sitter CLI tooling, and wasm-pack tooling.
```sh ```sh
nix develop nix develop
@ -87,5 +131,7 @@ The shell provides:
- `clippy` - `clippy`
- `node` - `node`
- `npm` - `npm`
- `wasm-pack`
- `lld`
- `tree-sitter` - `tree-sitter`
- `nixfmt` - `nixfmt`

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Decodal</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

1270
site/decodal-site/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
{
"name": "decodal-site",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0",
"build": "vite build",
"preview": "vite preview --host 0.0.0.0",
"build:wasm": "wasm-pack build ../../crates/decodal-wasm --target web --out-dir ../../site/decodal-site/src/wasm --release"
},
"dependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
"marked": "^12.0.2",
"svelte": "^4.2.18",
"vite": "^5.3.5"
},
"devDependencies": {}
}

View File

@ -0,0 +1,52 @@
<script>
import { onMount } from 'svelte';
import NavTree from './NavTree.svelte';
import Playground from './Playground.svelte';
import { nav, renderMarkdown } from './lib/docs.js';
let route = parseRoute(location.hash);
onMount(() => {
const onHashChange = () => (route = parseRoute(location.hash));
addEventListener('hashchange', onHashChange);
return () => removeEventListener('hashchange', onHashChange);
});
$: isPlayground = route.kind === 'playground';
$: currentSlug = route.slug ?? 'introduction';
$: html = isPlayground ? '' : renderMarkdown(currentSlug);
function parseRoute(hash) {
const raw = hash.replace(/^#\/?/, '');
if (raw === 'playground') return { kind: 'playground' };
if (raw.startsWith('docs/')) {
return { kind: 'docs', slug: raw.slice('docs/'.length) || 'introduction' };
}
return { kind: 'docs', slug: 'introduction' };
}
</script>
<header class="topbar">
<a class="brand" href="#/docs/introduction">Decodal</a>
<nav class="topnav">
<a href="#/docs/introduction">Docs</a>
<a href="#/playground">Playground</a>
</nav>
</header>
<div class="layout">
<aside class="sidebar">
<a class="sidebar-title" href="#/docs/index">Manual</a>
<NavTree items={nav} active={currentSlug} />
</aside>
<main class:playground={isPlayground}>
{#if isPlayground}
<Playground />
{:else}
<article class="markdown">
{@html html}
</article>
{/if}
</main>
</div>

View File

@ -0,0 +1,15 @@
<script>
export let items = [];
export let active = '';
</script>
<ul class="nav-tree">
{#each items as item}
<li>
<a class:active={active === item.slug} href={`#/docs/${item.slug}`}>{item.title}</a>
{#if item.children}
<svelte:self items={item.children} {active} />
{/if}
</li>
{/each}
</ul>

View File

@ -0,0 +1,81 @@
<script>
import { onMount } from 'svelte';
const starter = `let
Service = {
name = String;
port = Int & > 443 default 8443;
feature.enable = Bool default true;
};
in
Service & {
name = "api";
port = 9443;
}
`;
let source = starter;
let output = '';
let error = '';
let ready = false;
let loading = true;
let evaluate;
onMount(async () => {
try {
const wasm = await import('./wasm/decodal_wasm.js');
await wasm.default();
evaluate = wasm.evaluate;
ready = true;
run();
} catch (err) {
error = `Failed to load WASM playground: ${err.message ?? err}`;
} finally {
loading = false;
}
});
function run() {
if (!evaluate) return;
const result = JSON.parse(evaluate(source));
if (result.ok) {
output = result.output;
error = '';
} else {
output = '';
error = result.error;
}
}
</script>
<section class="playground-page">
<div class="playground-header">
<div>
<h1>Playground</h1>
<p>Evaluate Decodal directly in your browser through WebAssembly.</p>
</div>
<button on:click={run} disabled={!ready}>Run</button>
</div>
{#if loading}
<p class="status">Loading WASM...</p>
{/if}
<div class="playground-grid">
<label class="pane">
<span>Input</span>
<textarea bind:value={source} spellcheck="false" on:keydown={(event) => {
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') run();
}} />
</label>
<section class="pane output-pane">
<span>Output</span>
{#if error}
<pre class="error">{error}</pre>
{:else}
<pre>{output}</pre>
{/if}
</section>
</div>
</section>

View File

@ -0,0 +1,108 @@
import { marked } from 'marked';
const modules = import.meta.glob('../../../../doc/manual/souce/**/*.md', {
query: '?raw',
import: 'default',
eager: true,
});
export const docs = Object.fromEntries(
Object.entries(modules).map(([path, content]) => {
const slug = path
.replace(/^\.\.\/\.\.\/\.\.\/\.\.\/doc\/manual\/souce\//, '')
.replace(/\.md$/, '')
.replace(/\/index$/, '');
return [slug || 'index', content];
}),
);
export const nav = [
{ title: 'Introduction', slug: 'introduction' },
{
title: 'Language Specification',
slug: 'language',
children: [
{ title: 'Syntax', slug: 'language/syntax' },
{
title: 'Value',
slug: 'language/value',
children: [
{ title: 'String', slug: 'language/value/string' },
{ title: 'Int', slug: 'language/value/int' },
{ title: 'Float', slug: 'language/value/float' },
{ title: 'Bool', slug: 'language/value/bool' },
],
},
{
title: 'Expression',
slug: 'language/expression',
children: [
{ title: 'Literal', slug: 'language/expression/literal' },
{ title: 'Identifier', slug: 'language/expression/identifier' },
{ title: 'Path Reference', slug: 'language/expression/path-reference' },
{ title: 'Object', slug: 'language/expression/object' },
{ title: 'Array', slug: 'language/expression/array' },
{ title: 'Function', slug: 'language/expression/function' },
{ title: 'Function Call', slug: 'language/expression/function-call' },
{ title: 'Let', slug: 'language/expression/let' },
{ title: 'Match', slug: 'language/expression/match' },
{ title: 'Import', slug: 'language/expression/import' },
{ title: 'Composition', slug: 'language/expression/composition' },
{ title: 'Default', slug: 'language/expression/default' },
{ title: 'String Interpolation', slug: 'language/expression/string-interpolation' },
],
},
{ title: 'Constraints and Defaults', slug: 'language/constraints-and-defaults' },
{ title: 'Composition Operators', slug: 'language/operators' },
{ title: 'Functions', slug: 'language/functions' },
{ title: 'Modules and Imports', slug: 'language/modules-and-imports' },
{ title: 'Evaluation Semantics', slug: 'language/evaluation' },
{ title: 'Materialization and Errors', slug: 'language/materialization-and-errors' },
{ title: 'Naming', slug: 'language/naming' },
{ title: 'Examples', slug: 'language/examples' },
],
},
{
title: 'Implementation Design',
slug: 'design',
children: [
{ title: 'Execution Pipeline', slug: 'design/execution-pipeline' },
{ title: 'Runtime Model', slug: 'design/runtime-model' },
{ title: 'Thunk and Lazy Evaluation', slug: 'design/thunk-and-lazy-evaluation' },
{ title: 'Composition and Materialization', slug: 'design/composition-and-materialization' },
{ title: 'Diagnostics and Fallback', slug: 'design/diagnostics-and-fallback' },
{ title: 'Embedding API', slug: 'design/embedding-api' },
{ title: 'Features', slug: 'design/features' },
],
},
{ title: 'Development', slug: 'development' },
{ title: 'Open Issues', slug: 'open-issues' },
];
marked.setOptions({
gfm: true,
mangle: false,
headerIds: true,
});
export function renderMarkdown(slug) {
const source = docs[slug] ?? docs.index;
const html = marked.parse(source ?? '# Not found\n');
return html.replace(/href="([^"#][^"]*)\.md(#[^"]*)?"/g, (_all, href, hash = '') => {
const target = normalizeDocLink(slug, href);
return `href="#/docs/${target}${hash}"`;
});
}
function normalizeDocLink(currentSlug, href) {
const base = currentSlug.includes('/') ? currentSlug.split('/').slice(0, -1) : [];
const parts = [...base, ...href.split('/')];
const out = [];
for (const part of parts) {
if (!part || part === '.') continue;
if (part === '..') out.pop();
else out.push(part);
}
if (out[out.length - 1] === 'index') out.pop();
return out.join('/') || 'index';
}

View File

@ -0,0 +1,8 @@
import App from './App.svelte';
import './style.css';
const app = new App({
target: document.getElementById('app'),
});
export default app;

View File

@ -0,0 +1,232 @@
:root {
color-scheme: light dark;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #f7f7f8;
color: #1f2328;
}
body {
margin: 0;
}
a {
color: #2563eb;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.topbar {
align-items: center;
background: #111827;
color: white;
display: flex;
height: 56px;
justify-content: space-between;
padding: 0 24px;
}
.brand {
color: white;
font-size: 20px;
font-weight: 700;
}
.topnav {
display: flex;
gap: 18px;
}
.topnav a {
color: #dbeafe;
}
.layout {
display: grid;
grid-template-columns: 300px minmax(0, 1fr);
min-height: calc(100vh - 56px);
}
.sidebar {
background: #ffffff;
border-right: 1px solid #e5e7eb;
overflow: auto;
padding: 22px 18px;
}
.sidebar-title {
color: #111827;
display: block;
font-weight: 700;
margin-bottom: 12px;
}
.nav-tree {
list-style: none;
margin: 0;
padding-left: 0;
}
.nav-tree .nav-tree {
margin: 4px 0 6px 12px;
}
.nav-tree a {
border-radius: 6px;
color: #374151;
display: block;
font-size: 14px;
line-height: 1.35;
padding: 4px 8px;
}
.nav-tree a.active {
background: #dbeafe;
color: #1d4ed8;
font-weight: 600;
}
main {
min-width: 0;
padding: 36px;
}
main.playground {
padding: 24px;
}
.markdown {
background: white;
border: 1px solid #e5e7eb;
border-radius: 12px;
box-shadow: 0 8px 24px rgb(15 23 42 / 0.05);
margin: 0 auto;
max-width: 920px;
padding: 24px 36px 42px;
}
.markdown h1,
.markdown h2,
.markdown h3 {
color: #111827;
}
.markdown pre,
.pane pre {
background: #0f172a;
border-radius: 10px;
color: #e5e7eb;
overflow: auto;
padding: 14px;
}
.markdown code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}
.markdown :not(pre) > code {
background: #eef2ff;
border-radius: 4px;
color: #3730a3;
padding: 1px 4px;
}
.playground-page {
height: calc(100vh - 104px);
}
.playground-header {
align-items: center;
display: flex;
justify-content: space-between;
margin-bottom: 18px;
}
.playground-header h1 {
margin: 0 0 4px;
}
.playground-header p {
color: #4b5563;
margin: 0;
}
button {
background: #2563eb;
border: 0;
border-radius: 8px;
color: white;
cursor: pointer;
font-weight: 700;
padding: 10px 18px;
}
button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.playground-grid {
display: grid;
gap: 16px;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
height: calc(100% - 82px);
}
.pane {
background: white;
border: 1px solid #e5e7eb;
border-radius: 12px;
display: flex;
flex-direction: column;
min-height: 0;
overflow: hidden;
}
.pane > span {
border-bottom: 1px solid #e5e7eb;
color: #374151;
font-size: 13px;
font-weight: 700;
padding: 10px 12px;
text-transform: uppercase;
}
textarea {
border: 0;
flex: 1;
font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
outline: none;
padding: 14px;
resize: none;
}
.output-pane pre {
border-radius: 0;
flex: 1;
margin: 0;
}
.output-pane pre.error {
color: #fecaca;
}
.status {
color: #4b5563;
}
@media (max-width: 900px) {
.layout {
grid-template-columns: 1fr;
}
.sidebar {
border-bottom: 1px solid #e5e7eb;
border-right: 0;
max-height: 260px;
}
.playground-grid {
grid-template-columns: 1fr;
}
}

1
site/decodal-site/src/wasm/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
# wasm-pack output is committed for the playground build.

View File

@ -0,0 +1,37 @@
/* tslint:disable */
/* eslint-disable */
export function evaluate(source: string): string;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly evaluate: (a: number, b: number, c: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_export: (a: number, b: number) => number;
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_export3: (a: number, b: number, c: number) => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;
/**
* Instantiates the given `module`, which can either be bytes or
* a precompiled `WebAssembly.Module`.
*
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
*
* @returns {InitOutput}
*/
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
/**
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
* for everything else, calls `WebAssembly.instantiate` directly.
*
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
*
* @returns {Promise<InitOutput>}
*/
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@ -0,0 +1,212 @@
/* @ts-self-types="./decodal_wasm.d.ts" */
/**
* @param {string} source
* @returns {string}
*/
export function evaluate(source) {
let deferred2_0;
let deferred2_1;
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
const ptr0 = passStringToWasm0(source, wasm.__wbindgen_export, wasm.__wbindgen_export2);
const len0 = WASM_VECTOR_LEN;
wasm.evaluate(retptr, ptr0, len0);
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
deferred2_0 = r0;
deferred2_1 = r1;
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_export3(deferred2_0, deferred2_1, 1);
}
}
function __wbg_get_imports() {
const import0 = {
__proto__: null,
};
return {
__proto__: null,
"./decodal_wasm_bg.js": import0,
};
}
let cachedDataViewMemory0 = null;
function getDataViewMemory0() {
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
}
return cachedDataViewMemory0;
}
function getStringFromWasm0(ptr, len) {
return decodeText(ptr >>> 0, len);
}
let cachedUint8ArrayMemory0 = null;
function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8ArrayMemory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
const ret = cachedTextEncoder.encodeInto(arg, view);
offset += ret.written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
const MAX_SAFARI_DECODE_BYTES = 2146435072;
let numBytesDecoded = 0;
function decodeText(ptr, len) {
numBytesDecoded += len;
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
numBytesDecoded = len;
}
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}
const cachedTextEncoder = new TextEncoder();
if (!('encodeInto' in cachedTextEncoder)) {
cachedTextEncoder.encodeInto = function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
};
}
let WASM_VECTOR_LEN = 0;
let wasmModule, wasmInstance, wasm;
function __wbg_finalize_init(instance, module) {
wasmInstance = instance;
wasm = instance.exports;
wasmModule = module;
cachedDataViewMemory0 = null;
cachedUint8ArrayMemory0 = null;
return wasm;
}
async function __wbg_load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
const validResponse = module.ok && expectedResponseType(module.type);
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else { throw e; }
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
function expectedResponseType(type) {
switch (type) {
case 'basic': case 'cors': case 'default': return true;
}
return false;
}
}
function initSync(module) {
if (wasm !== undefined) return wasm;
if (module !== undefined) {
if (Object.getPrototypeOf(module) === Object.prototype) {
({module} = module)
} else {
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
}
}
const imports = __wbg_get_imports();
if (!(module instanceof WebAssembly.Module)) {
module = new WebAssembly.Module(module);
}
const instance = new WebAssembly.Instance(module, imports);
return __wbg_finalize_init(instance, module);
}
async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;
if (module_or_path !== undefined) {
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
({module_or_path} = module_or_path)
} else {
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
}
}
if (module_or_path === undefined) {
module_or_path = new URL('decodal_wasm_bg.wasm', import.meta.url);
}
const imports = __wbg_get_imports();
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
module_or_path = fetch(module_or_path);
}
const { instance, module } = await __wbg_load(await module_or_path, imports);
return __wbg_finalize_init(instance, module);
}
export { initSync, __wbg_init as default };

Binary file not shown.

View File

@ -0,0 +1,8 @@
/* tslint:disable */
/* eslint-disable */
export const memory: WebAssembly.Memory;
export const evaluate: (a: number, b: number, c: number) => void;
export const __wbindgen_add_to_stack_pointer: (a: number) => number;
export const __wbindgen_export: (a: number, b: number) => number;
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
export const __wbindgen_export3: (a: number, b: number, c: number) => void;

View File

@ -0,0 +1,15 @@
{
"name": "decodal-wasm",
"type": "module",
"version": "0.1.0",
"files": [
"decodal_wasm_bg.wasm",
"decodal_wasm.js",
"decodal_wasm.d.ts"
],
"main": "decodal_wasm.js",
"types": "decodal_wasm.d.ts",
"sideEffects": [
"./snippets/*"
]
}

View File

@ -0,0 +1,14 @@
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
import { fileURLToPath, URL } from 'node:url';
const repoRoot = fileURLToPath(new URL('../..', import.meta.url));
export default defineConfig({
plugins: [svelte()],
server: {
fs: {
allow: [repoRoot],
},
},
});