Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fiery-loops-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@fuzdev/fuz_ui': minor
---

deps: upgrade mdz
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ re-strip drops the extras. See the `vite_plugin_pkg_json` tome for the pattern.

- `vite_plugin_pkg_json.ts` - Vite plugin serving `virtual:pkg.json` (curated
`PkgJson` from `@fuzdev/fuz_util/pkg_json.ts`)
- `vite_plugin_docs_mdz.ts` - Vite plugin that pre-parses svelte-docinfo's
markdown fields to `MdzNode` trees (`*Nodes` siblings on `virtual:svelte-docinfo`),
so API-docs pages render pre-parsed instead of parsing per `<Mdz>` mount (see
[mdz rendering](#mdz-rendering))
- `library.svelte.ts` - `Library` class wrapping library data
- `declaration.svelte.ts` - `Declaration` class for code declarations (uses
`generateImport`, `getDisplayName` from `svelte-docinfo/declaration-helpers.js`)
Expand Down Expand Up @@ -252,6 +256,14 @@ preprocessor (it precompiles any static `<Mdz>` content to plain markup); fuz_ui
authors no static mdz, so it's effectively a pass-through and needs no injection
options.

The markdown **parsing** (not rendering) is moved to build time by
`vite_plugin_docs_mdz`: it pre-parses svelte-docinfo's markdown fields
(`docComment`, `description`, `returnDescription`, `moduleComment`, `examples`,
`seeAlso`) to `MdzNode` trees and adds them as `*Nodes` siblings, which the
`DocMdz` wrapper prefers (`<Mdz nodes={…}>`), falling back to parsing the raw
string when the plugin didn't run. Rendering and the injection seam above stay
at runtime; only the parse moves. Requires the `nodes` prop from `@fuzdev/mdz`.

## Context system

All contexts use the standardized pattern via `context_helpers.ts`:
Expand Down
9 changes: 6 additions & 3 deletions src/lib/ApiModule.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts">
import Code from '@fuzdev/fuz_code/Code.svelte';
import Mdz from '@fuzdev/mdz/Mdz.svelte';
import {
mdz_code_context,
mdz_codeblock_context,
mdz_set_context_with_fallback,
} from '@fuzdev/mdz/mdz_contexts.ts';

import DocMdz from './DocMdz.svelte';
import {set_library_context_with_fallback, type Library} from './library.svelte.ts';
import {tome_get_by_slug, type Tome} from './tome.ts';
import TomeContent from './TomeContent.svelte';
Expand Down Expand Up @@ -93,7 +93,10 @@
<li>
<h3><ModuleLink module_path={child_module.path} /></h3>
{#if child_module.module_comment}
<Mdz content={child_module.module_comment} />
<DocMdz
content={child_module.module_comment}
nodes={child_module.module_comment_nodes}
/>
{/if}
</li>
{/each}
Expand All @@ -103,7 +106,7 @@
{:else}
{#if module.module_comment}
<section>
<Mdz content={module.module_comment} />
<DocMdz content={module.module_comment} nodes={module.module_comment_nodes} />
</section>
{/if}
{#if source_url}
Expand Down
46 changes: 28 additions & 18 deletions src/lib/DeclarationDetail.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ including parameters, props, members, overloads, intersects, and more.
-->
<script lang="ts">
import Code from '@fuzdev/fuz_code/Code.svelte';
import Mdz from '@fuzdev/mdz/Mdz.svelte';
import {mdz_from_tsdoc} from '@fuzdev/mdz/tsdoc_mdz.ts';

import DocMdz from './DocMdz.svelte';
import {field_nodes, list_nodes, type Declaration} from './declaration.svelte.ts';
import {
mdz_code_context,
mdz_codeblock_context,
mdz_set_context_with_fallback,
} from '@fuzdev/mdz/mdz_contexts.ts';
import type {ParameterJsonInput} from 'svelte-docinfo/types.js';

import type {Declaration} from './declaration.svelte.ts';
import TypeLink from './TypeLink.svelte';
import ModuleLink from './ModuleLink.svelte';
import DocsLink from './DocsLink.svelte';
Expand Down Expand Up @@ -53,7 +54,7 @@ including parameters, props, members, overloads, intersects, and more.
>
</h4>
{#if param.description}
<Mdz content={param.description} />
<DocMdz content={param.description} nodes={field_nodes(param, 'description')} />
{/if}
<div class="row gap_md mb_sm">
<strong>type</strong>
Expand Down Expand Up @@ -97,15 +98,15 @@ including parameters, props, members, overloads, intersects, and more.
<p><strong>since</strong> {item.since}</p>
{/if}
{#if item.examples?.length}
{#each item.examples as example (example)}
<Mdz content={example} />
{#each item.examples as example, i (example)}
<DocMdz content={example} nodes={list_nodes(item, 'examples')?.[i]} />
{/each}
{/if}
{#if item.seeAlso?.length}
<p><strong>see also</strong></p>
<ul>
{#each item.seeAlso as ref (ref)}
<li><Mdz content={mdz_from_tsdoc(ref)} /></li>
{#each item.seeAlso as ref, i (ref)}
<li><DocMdz content={mdz_from_tsdoc(ref)} nodes={list_nodes(item, 'seeAlso')?.[i]} /></li>
{/each}
</ul>
{/if}
Expand Down Expand Up @@ -194,7 +195,7 @@ including parameters, props, members, overloads, intersects, and more.

<!-- documentation -->
{#if declaration.has_documentation}
<Mdz content={declaration.doc_comment!} />
<DocMdz content={declaration.doc_comment} nodes={declaration.doc_comment_nodes} />
{/if}

<!-- parameters -->
Expand All @@ -217,7 +218,7 @@ including parameters, props, members, overloads, intersects, and more.
>
</h4>
{#if prop.description}
<Mdz content={prop.description} />
<DocMdz content={prop.description} nodes={field_nodes(prop, 'description')} />
{/if}
<div class="row gap_md mb_sm">
<strong>type</strong>
Expand Down Expand Up @@ -259,7 +260,7 @@ including parameters, props, members, overloads, intersects, and more.
<section>
<Code lang="ts" content={overload.typeSignature} />
{#if overload.docComment}
<Mdz content={overload.docComment} />
<DocMdz content={overload.docComment} nodes={field_nodes(overload, 'docComment')} />
{/if}
{#if overload.parameters?.length}
{#each overload.parameters as param (param)}
Expand All @@ -272,7 +273,10 @@ including parameters, props, members, overloads, intersects, and more.
<TypeLink type={overload.returnType} />
</div>
{#if overload.returnDescription}
<Mdz content={overload.returnDescription} />
<DocMdz
content={overload.returnDescription}
nodes={field_nodes(overload, 'returnDescription')}
/>
{/if}
{/if}
</section>
Expand All @@ -296,7 +300,10 @@ including parameters, props, members, overloads, intersects, and more.
<h4>returns</h4>
<Code lang="ts" content={declaration.return_type} />
{#if declaration.return_description}
<Mdz content={declaration.return_description} />
<DocMdz
content={declaration.return_description}
nodes={declaration.return_description_nodes}
/>
{/if}
</section>
{/if}
Expand Down Expand Up @@ -393,8 +400,8 @@ including parameters, props, members, overloads, intersects, and more.
{#if declaration.examples.length}
<section>
<h4>examples</h4>
{#each declaration.examples as example (example)}
<Mdz content={example} />
{#each declaration.examples as example, i (example)}
<DocMdz content={example} nodes={declaration.examples_nodes?.[i]} />
{/each}
</section>
{/if}
Expand All @@ -404,9 +411,9 @@ including parameters, props, members, overloads, intersects, and more.
<section>
<h4>see also</h4>
<ul>
{#each declaration.see_also as ref (ref)}
{#each declaration.see_also as ref, i (ref)}
<li>
<Mdz content={mdz_from_tsdoc(ref)} />
<DocMdz content={mdz_from_tsdoc(ref)} nodes={declaration.see_also_nodes?.[i]} />
</li>
{/each}
</ul>
Expand All @@ -425,7 +432,7 @@ including parameters, props, members, overloads, intersects, and more.
>
</h4>
{#if member.docComment}
<Mdz content={member.docComment} />
<DocMdz content={member.docComment} nodes={field_nodes(member, 'docComment')} />
{/if}
{#if member.typeSignature}
<p class="row gap_md">
Expand Down Expand Up @@ -471,7 +478,10 @@ including parameters, props, members, overloads, intersects, and more.
<TypeLink type={member.returnType} />
</div>
{#if member.returnDescription}
<Mdz content={member.returnDescription} />
<DocMdz
content={member.returnDescription}
nodes={field_nodes(member, 'returnDescription')}
/>
{/if}
{/if}
{@render doc_extras(member)}
Expand Down
20 changes: 20 additions & 0 deletions src/lib/DocMdz.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!--
Renders a docs markdown field, preferring the build-time pre-parsed tree
(`nodes`, from `vite_plugin_docs_mdz`) over parsing the raw string at render.
Falls back to `content` when the pre-parse didn't run (a plain `vite dev`
without the plugin) so the docs always render either way. Isolates the
`<Mdz nodes={…}>` usage — which needs `@fuzdev/mdz` with the `nodes` prop — to
one component.
-->
<script lang="ts">
import Mdz from '@fuzdev/mdz/Mdz.svelte';
import type {MdzNode} from '@fuzdev/mdz/mdz.js';

const {content, nodes}: {content?: string; nodes?: Array<MdzNode>} = $props();
</script>

{#if nodes}
<Mdz {nodes} />
{:else if content}
<Mdz {content} />
{/if}
23 changes: 23 additions & 0 deletions src/lib/declaration.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type {
} from 'svelte-docinfo/types.js';
import {generateImport, getDisplayName} from 'svelte-docinfo/declaration-helpers.js';

import type {MdzNode} from '@fuzdev/mdz/mdz.js';

import type {Module} from './module.svelte.ts';
import {url_github_file} from '@fuzdev/fuz_util/package_helpers.ts';

Expand All @@ -23,6 +25,21 @@ import {url_github_file} from '@fuzdev/fuz_util/package_helpers.ts';
const field = <T>(decl: DeclarationJsonInput, key: string): T | undefined =>
(decl as Record<string, unknown>)[key] as T | undefined;

// Pre-parsed markdown trees. `vite_plugin_docs_mdz` adds a `${key}Nodes` sibling
// next to each markdown string field (e.g. `descriptionNodes` for `description`,
// `examplesNodes` for `examples`) so the docs render `<Mdz nodes={…}>` instead
// of parsing on the client. `undefined` when the build step didn't run (a plain
// `vite dev` without the plugin) or the source field was empty — callers fall
// back to the raw string via `DocMdz`.

/** Read the `*Nodes` sibling of a single markdown string field. */
export const field_nodes = (obj: unknown, key: string): Array<MdzNode> | undefined =>
(obj as Record<string, Array<MdzNode> | undefined> | null | undefined)?.[`${key}Nodes`];

/** Read the `*Nodes` sibling of a string-array field (`examples`/`seeAlso`). */
export const list_nodes = (obj: unknown, key: string): Array<Array<MdzNode>> | undefined =>
(obj as Record<string, Array<Array<MdzNode>> | undefined> | null | undefined)?.[`${key}Nodes`];

/**
* Rich runtime representation of an exported declaration.
*
Expand Down Expand Up @@ -114,6 +131,12 @@ export class Declaration {
since = $derived(this.declaration_json.since);
examples = $derived(this.declaration_json.examples ?? []);
see_also = $derived(this.declaration_json.seeAlso ?? []);

// Build-time pre-parsed trees for the markdown getters above (see `field_nodes`).
doc_comment_nodes = $derived(field_nodes(this.declaration_json, 'docComment'));
return_description_nodes = $derived(field_nodes(this.declaration_json, 'returnDescription'));
examples_nodes = $derived(list_nodes(this.declaration_json, 'examples'));
see_also_nodes = $derived(list_nodes(this.declaration_json, 'seeAlso'));
/**
* Nested members for classes, interfaces, types, and enums.
*/
Expand Down
7 changes: 6 additions & 1 deletion src/lib/module.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
ExternalReExportJsonInput,
} from 'svelte-docinfo/types.js';

import {Declaration} from './declaration.svelte.ts';
import {Declaration, field_nodes} from './declaration.svelte.ts';
import type {Library} from './library.svelte.ts';
import {url_github_file} from '@fuzdev/fuz_util/package_helpers.ts';

Expand Down Expand Up @@ -66,6 +66,11 @@ export class Module {

module_comment = $derived(this.module_json.moduleComment);

// Build-time pre-parsed tree for `module_comment` (the `moduleCommentNodes`
// sibling from `vite_plugin_docs_mdz`); `undefined` when the plugin didn't run
// or the comment was empty, so `DocMdz` falls back to the raw string.
module_comment_nodes = $derived(field_nodes(this.module_json, 'moduleComment'));

/**
* Array of `Declaration` instances. Filters out default exports.
*/
Expand Down
Loading
Loading