Commit Graph

7 Commits

Author SHA1 Message Date
Tommy D. Rossi 5daea69581 test: add mdx-processor tests + use github-slugger for heading dedup
17 tests covering processMdx (frontmatter, headings, image srcs,
dedup, edge cases) and rewriteMdxImages (markdown→JSX conversion,
mixed paragraphs, JSX attr injection, code block safety, frontmatter
preservation).

Replaced hand-rolled slugify with github-slugger — duplicate headings
now get -1 postfix matching GitHub behavior (usage, usage-1).
2026-04-01 17:11:05 +02:00
Tommy D. Rossi c8f5c7b69f fix: AST-based image rewriting instead of unsafe replaceAll
Rewrites image nodes by mutating the mdast tree directly, then serializes
back to MDX with mdast-util-to-markdown + mdast-util-mdx.

Fixes from oracle review:
- Markdown images converted to JSX PixelatedImage with width/height/placeholder
- No more global string replaceAll that could corrupt code blocks/prose
- Each image node handled individually via AST traversal
- Old cache format guard: cached.mdx must be truthy
- Per-image try/catch: one bad image logs warning, doesn't fail build
- Paragraph containing single image → replaced with JSX block element

New deps: mdast-util-to-markdown, mdast-util-mdx, mdast-util-frontmatter
2026-04-01 16:34:30 +02:00
Tommy D. Rossi 66eb0097ff refactor: replace hand-rolled JSONC parser with tiny-jsonc regex approach
Ported from tiny-jsonc: regex captures strings as $1 and matches
comments as non-captured groups, so replacement keeps only strings
intact. Fast path tries JSON.parse first (zero overhead for valid JSON),
slow path strips comments + trailing commas.

Renamed strip-jsonc.ts → lib/jsonc.ts, exports parseJsonc().
2026-04-01 15:54:20 +02:00
Tommy D. Rossi 95c438c900 fix: address 7 oracle review findings
1. JSONC parser: character-by-character string-aware stripper — no longer
   corrupts URLs like https://... inside JSON string values
2. pagesDir: thread resolved prefix into virtual:holocron-config as
   pagesDirPrefix, used by loadMdxContent instead of hardcoded /pages
3. Stale images: re-resolve image SHAs on cached pages — if image content
   changed but MDX didn't, rewrites are refreshed and files recopied
4. configPath option: wired through readConfig + resolveConfigPath + HMR
5. Windows: use url.fileURLToPath(import.meta.url) instead of .pathname
6. Listener leak: process.once('beforeExit') instead of process.on
7. Normalizer guards: Array.isArray checks on tabs, groups, pages, anchors
   before casting — prevents crash on malformed configs
2026-04-01 15:48:15 +02:00
Tommy D. Rossi ad72046b22 feat: single-file image cache + relative image resolution
Image cache rewritten:
- Single dist/holocron-images.json instead of per-image JSON files
- Git blob SHA for invalidation (deterministic, works across CI)
- In-memory Record during build, flushed once on process exit
- Concurrent requests for same image deduplicated via inflight promises

Relative images in MDX:
- Images next to MDX files (./screenshot.png) are now supported
- During sync: detected, copied to public/_holocron/images/<hash>-<name>
- Content hash in filename for dedup + cache busting
- imageRewrites stored on NavPage, applied at render time via replaceAll
- Works like mintlify: images anywhere in repo, not just public/
2026-04-01 15:33:38 +02:00
Tommy D. Rossi 99519eb144 fix: normalize all config types to eliminate unions
readConfig() now collapses every docs.json variant into one canonical shape.
Consuming code (app-factory, sync) accesses fields directly with no type
discrimination.

- navigation: handle {tab,href} (→anchor), {tab,pages} (→group-wrapped),
  {tab,groups} (→kept), root {groups}, root {pages}, array formats
- anchors: merge from both global.anchors and root navigation.anchors
- navbar labels: TYPE_LABELS map (github→GitHub, discord→Discord) instead
  of broken capitalize()
- favicon: string|{light,dark} → always {light,dark}
- logo: string|{light,dark,href} → always {light,dark,href?}
- Navigation type: NavTab[] only (was NavTab[]|NavGroup[])
- findFirstPageInTab: typed with NavTab/NavPage/isNavPage (was ad-hoc)
- removed unused isConfigNavGroup import from sync.ts
- removed getTabs, isNavTabArray, normalizeNavigation exports
2026-04-01 15:04:23 +02:00
Tommy D. Rossi d1344f7d31 feat: add @holocron.so/vite package — drop-in Mintlify replacement as Vite plugin
Holocron is a documentation website framework that reads MDX files + a
holocron.jsonc (or docs.json) config file and generates a full docs site
via a single Vite plugin.

**Architecture:**
- Vite plugin wraps spiceflow, tailwind, tsconfig-paths
- Virtual modules for lazy MDX loading (import.meta.glob) and config
- SHA-based cache in dist/holocron-cache.json for instant rebuilds
- Editorial components copied from website/ (same design system)

**Config (docs.json compatible):**
- navigation with tabs, groups, pages, global.anchors
- navbar.links for header, anchors rendered as tab bar items
- Schema saved locally from https://mintlify.com/docs.json

**Core modules:**
- config.ts — JSONC reader, type normalization for 3 navigation formats
- navigation.ts — enriched tree types + getTabs/findPage/flattenForSidebar
- lib/sync.ts — MDX→cache with git blob SHA deduplication
- lib/mdx-processor.ts — frontmatter + heading extraction via safe-mdx
- app-factory.tsx — Spiceflow app with layout, catch-all page, search API
2026-04-01 14:34:37 +02:00