import { marked } from 'marked'; import { escapeAttribute, escapeHtml, highlightCode } from './highlight.js'; 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: 'Arithmetic', slug: 'language/expression/arithmetic' }, { 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' }, ]; const renderer = new marked.Renderer(); renderer.code = (code, language = '') => { const normalizedLanguage = language.split(/\s+/)[0] ?? ''; const className = normalizedLanguage ? ` class="language-${escapeAttribute(normalizedLanguage)}"` : ''; return `
${highlightCode(code, normalizedLanguage)}
`; }; renderer.codespan = (code) => `${escapeHtml(code)}`; marked.setOptions({ gfm: true, renderer }); export function allDocSlugs() { return Object.keys(docs).filter((slug) => slug !== 'index'); } 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'; }