@veluai/velu 0.1.8 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -80
- package/dist/cli.js +91 -9
- package/package.json +2 -1
- package/runtime/velu-ui/components/ErrorCard.jsx +138 -0
- package/runtime/velu-ui/index.js +46 -45
- package/runtime/velu-ui/lib/component-schemas.js +100 -0
- package/runtime/velu-ui/lib/copyText.js +64 -64
- package/runtime/velu-ui/mdx-components.jsx +105 -85
- package/src/runtime/App.jsx +1476 -1473
- package/src/runtime/ErrorBoundary.jsx +54 -0
package/README.md
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
# Velu
|
|
2
|
-
|
|
3
|
-
A documentation-site generator with live preview. Scaffold a docs project
|
|
4
|
-
and run it locally with two commands — author your pages in Markdown +
|
|
5
|
-
components, configure the site with a single `velu.json`.
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install -g @veluai/velu
|
|
9
|
-
velu init my-docs
|
|
10
|
-
velu dev my-docs
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Then open <http://localhost:
|
|
14
|
-
reloads the browser automatically.
|
|
15
|
-
|
|
16
|
-
> Requires **Node.js 18+**. Prefer not to install globally? Use
|
|
17
|
-
> `npx @veluai/velu init my-docs` and `npx @veluai/velu dev my-docs`.
|
|
18
|
-
|
|
19
|
-
## Commands
|
|
20
|
-
|
|
21
|
-
| Command | What it does |
|
|
22
|
-
| --- | --- |
|
|
23
|
-
| `velu init <dir>` | Scaffold a new docs project into `<dir>` (creates `velu.json`, a favicon, and a set of starter `.mdx` pages). |
|
|
24
|
-
| `velu dev [dir]` | Start the live-preview dev server for the project in `<dir>` (defaults to the current directory). |
|
|
25
|
-
|
|
26
|
-
Set a custom port with the `PORT` env var:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
PORT=5180 velu dev my-docs
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Project layout
|
|
33
|
-
|
|
34
|
-
`velu init` produces a project shaped like this:
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
my-docs/
|
|
38
|
-
├─ velu.json # site config: name, colors, font, favicon, navigation
|
|
39
|
-
├─ favicon.svg
|
|
40
|
-
├─ index.mdx # pages, organized however your navigation references them
|
|
41
|
-
├─ quickstart.mdx
|
|
42
|
-
└─ …
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## `velu.json`
|
|
46
|
-
|
|
47
|
-
`velu.json` drives the whole site — branding and navigation:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"$schema": "https://veluai.com/velu.schema.json",
|
|
52
|
-
"name": "My Docs",
|
|
53
|
-
"colors": { "primary": "#dc143c" },
|
|
54
|
-
"favicon": "/favicon.svg",
|
|
55
|
-
"font": { "family": "Inter" },
|
|
56
|
-
"navigation": {
|
|
57
|
-
"tabs": [
|
|
58
|
-
{
|
|
59
|
-
"tab": "Guides",
|
|
60
|
-
"groups": [
|
|
61
|
-
{ "group": "Getting started", "pages": ["index", "quickstart"] }
|
|
62
|
-
]
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
- **`colors`** — `primary` is required; `light` and `dark` default to `primary`.
|
|
70
|
-
- **`navigation`** — Mintlify-compatible: `products → versions → languages →
|
|
71
|
-
tabs → anchors → groups → pages`. Switchable axes (products, versions,
|
|
72
|
-
languages) become URL path prefixes; the default value of each axis is
|
|
73
|
-
unprefixed. Languages are stored as ISO 639-1 codes and shown with their
|
|
74
|
-
native name.
|
|
75
|
-
|
|
76
|
-
Page labels come from each page's frontmatter `title`.
|
|
77
|
-
|
|
78
|
-
## License
|
|
79
|
-
|
|
80
|
-
Proprietary. © Velu.
|
|
1
|
+
# Velu
|
|
2
|
+
|
|
3
|
+
A documentation-site generator with live preview. Scaffold a docs project
|
|
4
|
+
and run it locally with two commands — author your pages in Markdown +
|
|
5
|
+
components, configure the site with a single `velu.json`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @veluai/velu
|
|
9
|
+
velu init my-docs
|
|
10
|
+
velu dev my-docs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then open <http://localhost:8358>. Editing any `.mdx` page or `velu.json`
|
|
14
|
+
reloads the browser automatically.
|
|
15
|
+
|
|
16
|
+
> Requires **Node.js 18+**. Prefer not to install globally? Use
|
|
17
|
+
> `npx @veluai/velu init my-docs` and `npx @veluai/velu dev my-docs`.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
| Command | What it does |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `velu init <dir>` | Scaffold a new docs project into `<dir>` (creates `velu.json`, a favicon, and a set of starter `.mdx` pages). |
|
|
24
|
+
| `velu dev [dir]` | Start the live-preview dev server for the project in `<dir>` (defaults to the current directory). |
|
|
25
|
+
|
|
26
|
+
Set a custom port with the `PORT` env var:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
PORT=5180 velu dev my-docs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Project layout
|
|
33
|
+
|
|
34
|
+
`velu init` produces a project shaped like this:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
my-docs/
|
|
38
|
+
├─ velu.json # site config: name, colors, font, favicon, navigation
|
|
39
|
+
├─ favicon.svg
|
|
40
|
+
├─ index.mdx # pages, organized however your navigation references them
|
|
41
|
+
├─ quickstart.mdx
|
|
42
|
+
└─ …
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## `velu.json`
|
|
46
|
+
|
|
47
|
+
`velu.json` drives the whole site — branding and navigation:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"$schema": "https://veluai.com/velu.schema.json",
|
|
52
|
+
"name": "My Docs",
|
|
53
|
+
"colors": { "primary": "#dc143c" },
|
|
54
|
+
"favicon": "/favicon.svg",
|
|
55
|
+
"font": { "family": "Inter" },
|
|
56
|
+
"navigation": {
|
|
57
|
+
"tabs": [
|
|
58
|
+
{
|
|
59
|
+
"tab": "Guides",
|
|
60
|
+
"groups": [
|
|
61
|
+
{ "group": "Getting started", "pages": ["index", "quickstart"] }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- **`colors`** — `primary` is required; `light` and `dark` default to `primary`.
|
|
70
|
+
- **`navigation`** — Mintlify-compatible: `products → versions → languages →
|
|
71
|
+
tabs → anchors → groups → pages`. Switchable axes (products, versions,
|
|
72
|
+
languages) become URL path prefixes; the default value of each axis is
|
|
73
|
+
unprefixed. Languages are stored as ISO 639-1 codes and shown with their
|
|
74
|
+
native name.
|
|
75
|
+
|
|
76
|
+
Page labels come from each page's frontmatter `title`.
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
Proprietary. © Velu.
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,93 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`,"utf-8");let
|
|
4
|
-
`)}var
|
|
2
|
+
var ut=Object.defineProperty;var b=(e,t)=>()=>(e&&(t=e(e=0)),t);var le=(e,t)=>{for(var o in t)ut(e,o,{get:t[o],enumerable:!0})};var Se={};le(Se,{initProject:()=>dt});import U from"node:fs/promises";import z from"node:path";import{fileURLToPath as ft}from"node:url";async function dt(e,t){try{if((await U.readdir(e)).length>0)throw new Error(`Directory "${t}" already exists and is not empty. Choose a different name or remove the folder first.`)}catch(s){if(s.code!=="ENOENT")throw s}await U.mkdir(e,{recursive:!0}),await U.cp(mt,e,{recursive:!0});let o=z.join(e,"velu.json"),n=JSON.parse(await U.readFile(o,"utf-8"));n.name=t,await U.writeFile(o,JSON.stringify(n,null,2)+`
|
|
3
|
+
`,"utf-8");let r=await $e(e);console.log(`[velu] created ${t}/`);for(let s of r)console.log(` ${s}`);console.log(""),console.log("Next steps:"),console.log(` cd ${t}`),console.log(" velu dev")}async function $e(e,t=e,o=[]){let n=await U.readdir(e,{withFileTypes:!0});for(let r of n){let s=z.join(e,r.name);r.isDirectory()?await $e(s,t,o):o.push(z.relative(t,s).split(z.sep).join("/"))}return o.sort()}var pt,mt,je=b(()=>{pt=z.dirname(ft(import.meta.url)),mt=z.resolve(pt,"..","templates","starter")});import{visit as gt}from"unist-util-visit";import{toString as ht}from"mdast-util-to-string";import vt from"github-slugger";import{valueToEstree as yt}from"estree-util-value-to-estree";function q(){return e=>{let t=new vt,o=[];gt(e,"heading",i=>{let a=ht(i);o.push({depth:i.depth,id:t.slug(a),label:a})});let n={children:[]},r=[{node:n,depth:0}];for(let i of o){for(;r.length>1&&r[r.length-1].depth>=i.depth;)r.pop();let a={id:i.id,label:i.label},l=r[r.length-1].node;l.children||(l.children=[]),l.children.push(a),r.push({node:a,depth:i.depth})}let s=n.children;e.children.unshift({type:"mdxjsEsm",value:"",data:{estree:{type:"Program",sourceType:"module",body:[{type:"ExportNamedDeclaration",specifiers:[],declaration:{type:"VariableDeclaration",kind:"const",declarations:[{type:"VariableDeclarator",id:{type:"Identifier",name:"toc"},init:yt(s)}]}}]}}})}}var ce=b(()=>{});import xt from"node:fs/promises";import Ae from"node:path";function ue(e={},t){let o=e.colors?.primary??wt;return{name:e.name??t??"docs",colors:{primary:o,light:e.colors?.light??o,dark:e.colors?.dark??o},favicon:e.favicon??null,font:{family:e.font?.family??bt},navigation:e.navigation??null}}async function Pe(e){let t=Ae.join(e,"velu.json"),o;try{o=await xt.readFile(t,"utf-8")}catch(r){throw r.code==="ENOENT"?new Error(`No velu.json found in ${e}. Run \`velu init <name>\` to scaffold one.`):r}let n;try{n=JSON.parse(o)}catch(r){throw new Error(`velu.json is not valid JSON: ${r.message}`)}return ue(n,Ae.basename(e))}function Ce(e){let{colors:t,font:o}=e;return[":root:root {",` --accent-color: ${t.light};`,` --font-sans: "${o.family}", sans-serif;`,"}",':root:root[data-theme="dark"] {',` --accent-color: ${t.dark};`,"}"].join(`
|
|
4
|
+
`)}var wt,bt,Ee=b(()=>{wt="#dc143c",bt="Google Sans Flex"});import kt from"github-slugger";import $t from"iso-639-1";function jt(e){let t=String(e).toLowerCase();return $t.getNativeName(t)||e}function X(e){return new kt().slug(String(e??""))}function At(e){let t=String(e).replace(/^\/+|\/+$/g,"").split("/").filter(Boolean);return t[t.length-1]==="index"&&t.pop(),"/"+t.join("/")}function B(e){let t={kind:"root",children:D(e??{})};return Oe(t.children),t}function D(e){let t=Array.isArray(e.anchors)?e.anchors.map(_t):[];if(Array.isArray(e.products))return[...t,...e.products.map(Pt)];if(Array.isArray(e.versions))return[...t,...e.versions.map(Ct)];if(Array.isArray(e.languages))return[...t,...e.languages.map(Et)];if(Array.isArray(e.tabs))return[...t,...e.tabs.map(Tt)];let o=[...t];return Array.isArray(e.groups)&&o.push(...e.groups.map(Te)),Array.isArray(e.pages)&&o.push(...e.pages.map(_e)),o}function Pt(e){return{kind:"product",label:e.name??e.product,slug:X(e.product),icon:e.icon,color:e.color,default:!!e.default,children:D(e)}}function Ct(e){return{kind:"version",label:e.version,slug:X(e.version),default:!!e.default,children:D(e)}}function Et(e){let t=String(e.language);return{kind:"language",code:t,label:jt(t),slug:X(t),default:!!e.default,children:D(e)}}function Tt(e){return{kind:"tab",label:e.tab,slug:X(e.tab),icon:e.icon,href:e.href,children:D(e)}}function _t(e){return{kind:"anchor",label:e.anchor,icon:e.icon,href:e.href,color:e.color}}function Te(e){let t=(e.pages??[]).map(_e);return e.root&&t.unshift({kind:"page",pagePath:e.root}),{kind:"group",label:e.group,icon:e.icon,expanded:!!e.expanded,root:e.root,children:t}}function _e(e){return typeof e=="string"?{kind:"page",pagePath:e}:Te(e)}function Oe(e){for(let t of St){let o=e.filter(n=>n.kind===t);o.length&&!o.some(n=>n.default)&&(o[0].default=!0)}for(let t of e)t.children&&Oe(t.children)}function Le(e){let t=[],o=(n,r,s)=>{if(n.kind==="page"){t.push({pagePath:n.pagePath,url:Ot(n.pagePath,r),ctx:{...r},ancestors:s,node:n});return}let i=r;n.kind==="product"?i={...r,product:n.default?null:n.slug}:n.kind==="version"?i={...r,version:n.default?null:n.slug}:n.kind==="language"&&(i={...r,language:n.default?null:n.slug});let a=n.kind==="root"?s:[...s,n];for(let l of n.children??[])o(l,i,a)};return o(e,{product:null,version:null,language:null},[]),t}function Ot(e,t){let o=[t.product,t.version,t.language].filter(Boolean),n=At(e).split("/").filter(Boolean);return"/"+[...o,...n].join("/")}var St,Y=b(()=>{St=["product","version","language"]});import Lt from"node:fs";import Ne from"node:path";function V(e,t){let o=[],n=[],r=new Set;for(let s of Le(e)){if(r.has(s.url)){o.push(`duplicate URL "${s.url}" (page "${s.pagePath}") \u2014 keeping the first occurrence`);continue}r.add(s.url);let i=s.pagePath.replace(/^\/+|\/+$/g,""),a=Ne.join(t,...i.split("/"))+".mdx",l=Lt.existsSync(a);l||o.push(`page "${s.pagePath}" \u2192 ${Ne.relative(t,a)} not found`),n.push({pagePath:s.pagePath,url:s.url,fileAbsPath:a,exists:l})}return{pageEntries:n,warnings:o}}var Q=b(()=>{Y()});import Nt from"node:fs";import ee from"node:path";function Re(e){return{name:"velu-site",resolveId(t){return t===Ie?Fe:null},load(t){return t!==Fe?null:Ft(e)}}}function Ft(e){let t={};try{t=JSON.parse(Nt.readFileSync(ee.join(e,"velu.json"),"utf-8"))}catch{}let o=B(t.navigation??{}),{pageEntries:n,warnings:r}=V(o,e);for(let l of r)console.warn(`[velu] nav: ${l}`);let s=[],i=[],a=0;for(let l of n)if(l.exists){let u=JSON.stringify(l.fileAbsPath.split(ee.sep).join("/")),c=JSON.stringify(ee.relative(e,l.fileAbsPath).split(ee.sep).join("/")),f=`__p${a++}`;s.push(`import * as ${f} from ${u};`),i.push(` ${JSON.stringify(l.url)}: { Component: ${f}.default, frontmatter: ${f}.frontmatter, toc: ${f}.toc, relPath: ${c} },`)}else i.push(` ${JSON.stringify(l.url)}: { missing: true },`);return["// AUTO-GENERATED by vite-plugin-velu-site. Do not edit.",s.join(`
|
|
5
5
|
`),"","export const pages = {",i.join(`
|
|
6
|
-
`),"};",`export const navigation = ${JSON.stringify(
|
|
7
|
-
`)}var
|
|
8
|
-
`)
|
|
9
|
-
${
|
|
10
|
-
|
|
11
|
-
`)
|
|
6
|
+
`),"};",`export const navigation = ${JSON.stringify(o)};`,""].join(`
|
|
7
|
+
`)}var Ie,Fe,Me=b(()=>{Y();Q();Ie="virtual:velu-site",Fe="\0"+Ie});function h(e){return{category:"render-crash",severity:"error",file:null,line:null,column:null,frame:null,title:"Something went wrong",detail:"",hint:"",suggestion:null,...e}}function It(e,t){if(e=String(e),t=String(t),e===t)return 0;if(!e.length)return t.length;if(!t.length)return e.length;let o=Array.from({length:t.length+1},(r,s)=>s),n=new Array(t.length+1);for(let r=1;r<=e.length;r++){n[0]=r;for(let s=1;s<=t.length;s++){let i=e[r-1]===t[s-1]?0:1;n[s]=Math.min(n[s-1]+1,o[s]+1,o[s-1]+i)}[o,n]=[n,o]}return o[t.length]}function te(e,t=[]){if(!e)return null;let o=String(e).toLowerCase(),n=null,r=1/0;for(let i of t){let a=It(o,String(i).toLowerCase());a<r&&(r=a,n=i)}let s=Math.min(3,Math.max(2,Math.floor(o.length/4)));return r<=s?n:null}function Rt(e,t){return e==="warning"?C(t,$.yellow,"\u26A0"):e==="info"?C(t,$.cyan,"\u2139"):C(t,$.red,"\u2716")}function pe(e,{color:t=!1}={}){let o=fe[e.category]||e.category,n=e.line?`${e.line}${e.column?`:${e.column}`:""}`:"",r=e.file?`${e.file}${n?`:${n}`:""}`:n,s=[];if(s.push(`${Rt(e.severity,t)} ${C(t,$.bold,o)}`+(r?` ${C(t,$.dim,r)}`:"")),e.title&&s.push(` ${e.title}`),e.detail&&e.detail!==e.title&&s.push(` ${C(t,$.dim,e.detail)}`),e.frame)for(let i of String(e.frame).split(`
|
|
8
|
+
`))s.push(` ${i}`);return e.suggestion&&s.push(` ${C(t,$.cyan,`Did you mean <${e.suggestion}>?`)}`),e.hint&&s.push(` ${C(t,$.dim,`\u2192 ${e.hint}`)}`),s.join(`
|
|
9
|
+
`)}function ne(e,{color:t=!1}={}){if(!e.length)return C(t,$.cyan,"\u2713 No issues found.");let o=new Map;for(let a of e){let l=a.file||"velu.json";o.has(l)||o.set(l,[]),o.get(l).push(a)}let n=[];for(let[a,l]of o){n.push(C(t,$.bold,a));for(let u of l)n.push(pe({...u,file:null},{color:t}).replace(/^/gm," "));n.push("")}let r=e.filter(a=>a.severity!=="warning"&&a.severity!=="info").length,s=e.length-r,i=`${r} error${r===1?"":"s"}`+(s?`, ${s} warning${s===1?"":"s"}`:"");return n.push(C(t,r?$.red:$.yellow,i)),n.join(`
|
|
10
|
+
`)}var fe,$,C,F=b(()=>{fe={"mdx-syntax":"MDX syntax",frontmatter:"Frontmatter","unknown-component":"Unknown component","invalid-props":"Invalid options","render-crash":"Render error","config-json":"velu.json","config-schema":"velu.json","config-nav":"Navigation","config-asset":"Asset"};$={reset:"\x1B[0m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m",bold:"\x1B[1m"},C=(e,t,o)=>e?`${t}${o}${$.reset}`:o});function Mt(e){let t=e,o=0;for(;t&&t.cause&&o<3&&!(t.loc||t.line||/`[^`]+` to be defined/.test(t.message||""));)t=t.cause,o+=1;return t||e}function me(e,t){if(!e)return null;let o=Ue(e).replace(/[?#].*$/,""),n=t?Ue(t).replace(/\/+$/,""):"";return n&&o.toLowerCase().startsWith(n.toLowerCase())?o.slice(n.length).replace(/^\/+/,""):!/^([a-zA-Z]:\/|\/)/.test(o)&&!/node_modules/.test(o)?o:null}function Ut(e){return e?String(e).replace(/([a-zA-Z]:\\|\/)[^\s'"()]+/g,t=>/node_modules|[\\/]vite[\\/]|@veluai|velu-cli|velu-ui/.test(t)?"\u2026":t).trim():""}function zt(e){let t=/\((\d+):(\d+)(?:-\d+:\d+)?\)\s*$/.exec(String(e||""));return t?{line:Number(t[1]),column:Number(t[2])}:null}function Bt(e){return String(e||"").replace(/\s*\(\d+:\d+(?:-\d+:\d+)?\)\s*$/,"").trim()}function Gt(e,t){if(!e||!t)return null;let o=String(e);return/node_modules|[\\/]vite[\\/]|@veluai[\\/]/.test(o)?null:o}function H(e,t={}){let{projectDir:o="",knownComponents:n=[],file:r=null}=t,s=null;for(let E=e,A=0;E&&A<6;E=E.cause,A+=1)if(E.veluIssue){s=E.veluIssue;break}if(s)return h({...s,file:s.file||r});let i=Mt(e)||{},a=i.message||String(e||""),l=/Expected component `([^`]+)` to be defined/.exec(a);if(l){let E=l[1],A=/referenced in your code at `(\d+):(\d+)/.exec(a),G=/\bin `([^`]+)`/.exec(a),v=G?me(G[1],o):null;return h({category:"unknown-component",file:v||r,line:A?Number(A[1]):null,column:A?Number(A[2]):null,title:`<${E}> is not a built-in component`,detail:"",hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:te(E,n)})}let u=i.loc||(i.line!=null?{line:i.line,column:i.column,file:i.file}:null)||zt(i.reason||a),c=i.id||u&&u.file||i.file||null,f=me(c,o)||r,_=!!f&&me(c,o)!=null,d=Gt(i.frame,_||!!r),j=Ut(Bt(i.reason||a)),m=Vt.test(a),N=i.source==="remark-frontmatter"||/\byaml\b|frontmatter/i.test(a)||u&&u.line===1&&/unexpected|expected/i.test(a)&&/---/.test(a);return u||m||d&&_?h({category:N?"frontmatter":"mdx-syntax",file:f,line:u?u.line:null,column:u?u.column:null,frame:d,title:j||(N?"Invalid frontmatter":"MDX syntax error"),detail:"",hint:N?"Check the YAML between the --- markers \u2014 indentation, quotes, and colons.":"Make sure every <Component> has a matching closing tag and that { } braces are balanced."}):/\.map is not a function|is not iterable|reading '|undefined \(reading/i.test(a)?h({category:"invalid-props",file:f,title:"A component received an invalid value",detail:j,hint:"Check the props/options you passed to a component on this page."}):h({category:"render-crash",file:f,title:"This page failed to render",detail:j,hint:"Set VELU_DEBUG=1 for the full stack trace."})}var Ue,Vt,de=b(()=>{F();Ue=e=>String(e).replace(/\\/g,"/");Vt=/closing tag|unexpected closing|could not parse (?:expression|import|export)|unexpected character|unexpected end of|expected a closing|expected the closing|unexpected `|in expression|misnested|before name/i});function Jt(e){let t=fe[e.category]||e.category,o=e.file?`${e.file}${e.line?`:${e.line}${e.column?`:${e.column}`:""}`:""}`:"",n=[];return n.push('<div class="velu-err-card">'),n.push('<div class="velu-err-head">'),n.push(`<span class="velu-err-pill">${O(t)}</span>`),n.push("</div>"),e.title&&n.push(`<div class="velu-err-title">${O(e.title)}</div>`),o&&n.push(`<a class="velu-err-loc" title="${O(o)}">${O(o)}</a>`),e.detail&&n.push(`<div class="velu-err-detail">${O(e.detail)}</div>`),e.frame&&n.push(`<pre class="velu-err-frame">${O(e.frame)}</pre>`),e.suggestion&&n.push(`<div class="velu-err-suggest">Did you mean <code><${O(e.suggestion)}></code>?</div>`),e.hint&&n.push(`<div class="velu-err-hint">${O(e.hint)}</div>`),n.push("</div>"),n.join("")}function ge(e,t={}){let o=Array.isArray(e)?e:[e],n=t.title||(o.length>1?`${o.length} problems to fix`:"There\u2019s a problem to fix"),r=o.map(Jt).join(`
|
|
11
|
+
`);return`<!doctype html>
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="utf-8" />
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
16
|
+
<title>Velu \u2014 error</title>
|
|
17
|
+
<style>
|
|
18
|
+
:root { color-scheme: light dark; }
|
|
19
|
+
* { box-sizing: border-box; }
|
|
20
|
+
body {
|
|
21
|
+
margin: 0;
|
|
22
|
+
min-height: 100vh;
|
|
23
|
+
background: #f7f7f8;
|
|
24
|
+
color: #111827;
|
|
25
|
+
font: 15px/1.55 system-ui, -apple-system, Segoe UI, sans-serif;
|
|
26
|
+
padding: 6vh 5vw;
|
|
27
|
+
}
|
|
28
|
+
@media (prefers-color-scheme: dark) {
|
|
29
|
+
body { background: #0c0d10; color: #e7e7ea; }
|
|
30
|
+
.velu-err-card { background: rgba(239,68,68,0.08); }
|
|
31
|
+
.velu-err-frame { background: rgba(255,255,255,0.05); color: #e7e7ea; }
|
|
32
|
+
}
|
|
33
|
+
.velu-err-wrap { max-width: 820px; margin: 0 auto; }
|
|
34
|
+
.velu-err-brand { font-weight: 700; letter-spacing: -0.02em; opacity: 0.7; margin-bottom: 0.4rem; }
|
|
35
|
+
.velu-err-h { font-size: 1.6rem; font-weight: 700; margin: 0 0 1.4rem; letter-spacing: -0.02em; }
|
|
36
|
+
.velu-err-card {
|
|
37
|
+
border: 1px solid #ef4444;
|
|
38
|
+
border-radius: 10px;
|
|
39
|
+
background: rgba(239,68,68,0.06);
|
|
40
|
+
padding: 1rem 1.1rem;
|
|
41
|
+
margin: 0 0 1rem;
|
|
42
|
+
}
|
|
43
|
+
.velu-err-head { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }
|
|
44
|
+
.velu-err-pill {
|
|
45
|
+
font: 600 11px/1 ui-monospace, monospace;
|
|
46
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
47
|
+
color: #ef4444; border: 1px solid #ef4444; border-radius: 999px;
|
|
48
|
+
padding: 4px 9px; white-space: nowrap;
|
|
49
|
+
}
|
|
50
|
+
.velu-err-loc {
|
|
51
|
+
display: inline-block;
|
|
52
|
+
margin-top: 0.7rem;
|
|
53
|
+
font: 600 15px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
54
|
+
color: #ef4444;
|
|
55
|
+
background: rgba(239,68,68,0.12);
|
|
56
|
+
border: 1px solid rgba(239,68,68,0.4);
|
|
57
|
+
border-radius: 7px;
|
|
58
|
+
padding: 7px 11px;
|
|
59
|
+
letter-spacing: 0.01em;
|
|
60
|
+
}
|
|
61
|
+
.velu-err-title { margin-top: 0.6rem; font-weight: 600; font-size: 1.05rem; }
|
|
62
|
+
.velu-err-detail { margin-top: 0.25rem; opacity: 0.7; }
|
|
63
|
+
.velu-err-frame {
|
|
64
|
+
margin: 0.75rem 0 0; padding: 0.75rem 0.9rem; overflow: auto;
|
|
65
|
+
background: rgba(0,0,0,0.05); border-radius: 6px;
|
|
66
|
+
font: 12.5px/1.5 ui-monospace, monospace;
|
|
67
|
+
}
|
|
68
|
+
.velu-err-suggest { margin-top: 0.75rem; }
|
|
69
|
+
.velu-err-suggest code, .velu-err-frame code { color: #ef4444; font-weight: 600; }
|
|
70
|
+
.velu-err-hint { margin-top: 0.6rem; opacity: 0.6; font-size: 0.92rem; }
|
|
71
|
+
.velu-err-foot { margin-top: 1.6rem; opacity: 0.5; font-size: 0.85rem; }
|
|
72
|
+
</style>
|
|
73
|
+
</head>
|
|
74
|
+
<body>
|
|
75
|
+
<div class="velu-err-wrap">
|
|
76
|
+
<div class="velu-err-brand">velu</div>
|
|
77
|
+
<h1 class="velu-err-h">${O(n)}</h1>
|
|
78
|
+
${r}
|
|
79
|
+
<div class="velu-err-foot">Fix the file and save \u2014 this page reloads automatically.</div>
|
|
80
|
+
</div>
|
|
81
|
+
</body>
|
|
82
|
+
</html>`}var O,ze=b(()=>{F();O=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")});var I,he=b(()=>{I=["Callout","Card","CardGroup","Accordion","AccordionGroup","Columns","Field","Prompt","Steps","Step","Tree","Folder","File","Image","CodeBlock","CodeGroup","MethodBadge","ApiPath","TryItBar","ApiField","ApiClient","ApiSidebar"]});import ve from"node:fs";import oe from"node:path";import{fileURLToPath as qt}from"node:url";import Dt from"iso-639-1";function W(e,t){if(!t)return null;let o=e.indexOf(`"${t}"`);return o===-1?null:e.slice(0,o).split(`
|
|
83
|
+
`).length}function Wt(e,t){return t==null||t<0?null:e.slice(0,t).split(`
|
|
84
|
+
`).length}function Be(e,t){if(!t)return null;let o=e.indexOf(`"${t}"`);return o===-1?null:e.slice(0,o).split(`
|
|
85
|
+
`).length}function Kt(e,t,o){let n=[];return a(e,t,"",null),n;function r(l){if(l&&l.$ref){let u=l.$ref.replace(/^#\//,"").split("/"),c=o;for(let f of u)c=c?.[f];return c||{}}return l}function s(l){return Array.isArray(l)?"array":l===null?"null":typeof l}function i(l,u){let c=n.length;a(l,u,"",null,!0);let f=n.length===c;return f||(n.length=c),f}function a(l,u,c,f,_){let d=r(u);if(d){if(d.oneOf){d.oneOf.some(m=>i(l,m))||n.push({path:c,key:f,message:"value does not match any allowed shape"});return}if(d.type&&s(l)!==d.type){n.push({path:c,key:f,message:`expected ${d.type}, got ${s(l)}`});return}if(d.type==="string"&&d.minLength!=null&&l.length<d.minLength&&n.push({path:c,key:f,message:"must not be empty"}),d.type==="object"&&s(l)==="object"){for(let m of d.required||[])m in l||n.push({path:c?`${c}.${m}`:m,key:m,message:`missing required "${m}"`});let j=d.properties||{};if(d.additionalProperties===!1)for(let m of Object.keys(l))m in j||n.push({path:c?`${c}.${m}`:m,key:m,message:`unknown field "${m}"`});for(let[m,N]of Object.entries(j))m in l&&a(l[m],N,c?`${c}.${m}`:m,m,_)}d.type==="array"&&Array.isArray(l)&&d.items&&l.forEach((j,m)=>a(j,d.items,`${c}[${m}]`,f,_))}}}function Zt(e){if(typeof e!="string")return!1;let t=e.trim();return/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t)||/^(rgb|rgba|hsl|hsla|color|oklch|lab|lch)\(/i.test(t)||/^[a-z][a-z0-9-]*$/i.test(t)}function re(e){let t=[],o=oe.join(e,"velu.json"),n;try{n=ve.readFileSync(o,"utf-8")}catch(i){return i.code==="ENOENT"?t.push(h({category:"config-json",file:"velu.json",title:"No velu.json found",hint:"Run `velu init <name>` to scaffold a project."})):t.push(h({category:"config-json",file:"velu.json",title:"Could not read velu.json"})),t}let r;try{r=JSON.parse(n)}catch(i){let a=/position (\d+)/.exec(i.message||""),l=a?Wt(n,Number(a[1])):null;return t.push(h({category:"config-json",file:"velu.json",line:l,title:"velu.json is not valid JSON",detail:String(i.message||"").replace(/\s+in JSON.*$/,""),hint:"Check for a trailing comma, a missing quote, or an unclosed brace."})),t}let s=null;try{s=JSON.parse(ve.readFileSync(Ht,"utf-8"))}catch{}if(s)for(let i of Kt(r,s,s)){let a=/^unknown field/.test(i.message);t.push(h({category:"config-schema",severity:a?"warning":"error",file:"velu.json",line:W(n,i.key),title:i.path?`${i.path}: ${i.message}`:i.message,hint:a?"Remove it, or check the spelling against the velu.json schema.":""}))}for(let i of["primary","light","dark"]){let a=r.colors?.[i];a!=null&&!Zt(a)&&t.push(h({category:"config-schema",severity:"warning",file:"velu.json",line:W(n,i),title:`colors.${i}: "${a}" doesn\u2019t look like a CSS color`,hint:"Use a hex value like #dc143c, an rgb()/hsl() function, or a CSS color name."}))}if(typeof r.favicon=="string"&&r.favicon.trim()){let i=oe.resolve(e,r.favicon.replace(/^\/+/,""));ve.existsSync(i)||t.push(h({category:"config-asset",file:"velu.json",line:W(n,"favicon"),title:`favicon not found: ${r.favicon}`,hint:"The path is relative to the project root."}))}if(r.navigation&&typeof r.navigation=="object"){let i;try{i=B(r.navigation)}catch(a){t.push(h({category:"config-nav",file:"velu.json",line:W(n,"navigation"),title:"navigation could not be processed",detail:String(a.message||"")})),i=null}if(i){let{pageEntries:a,warnings:l}=V(i,e);for(let u of l){let c=/not found$/.test(u),f=/page "([^"]+)"/.exec(u),_=f?Be(n,f[1]):null;t.push(h({category:"config-nav",severity:c?"error":"warning",file:"velu.json",line:_,title:u,hint:c?"Create the .mdx file, or remove the page from navigation.":""}))}Xt(i,n,t)}}return t}function Xt(e,t,o){let n=new Set,r=s=>{if(!(!s||typeof s!="object")){if(s.language&&!n.has(s.language)){n.add(s.language);let i=String(s.language).toLowerCase();Dt.validate(i)||o.push(h({category:"config-nav",severity:"warning",file:"velu.json",line:Be(t,s.language)||W(t,"language"),title:`"${s.language}" is not a valid ISO 639-1 language code`,hint:'Use a two-letter code like "en", "fr", or "ja".'}))}for(let i of Object.values(s))Array.isArray(i)?i.forEach(r):i&&typeof i=="object"&&r(i)}};r(e)}var Yt,Ht,ye=b(()=>{F();Y();Q();Yt=oe.dirname(qt(import.meta.url)),Ht=oe.resolve(Yt,"..","..","schema","velu.schema.json")});import Qt from"node:fs/promises";import en from"node:fs";import R from"node:path";import{fileURLToPath as tn,pathToFileURL as nn}from"node:url";import{compile as on}from"@mdx-js/mdx";import rn from"remark-frontmatter";import sn from"remark-mdx-frontmatter";import an from"remark-gfm";import ln from"rehype-slug";import{visit as cn}from"unist-util-visit";function xe(){if(ie)return ie;let e=R.dirname(tn(import.meta.url)),t=[R.resolve(e,"..","runtime","velu-ui"),R.resolve(e,"..","..","runtime","velu-ui"),R.resolve(e,"..","..","..","velu-ui","src")],o=null;for(let n of t){let r=R.join(n,"lib","component-schemas.js");if(en.existsSync(r)){o=r;break}}return ie=o?import(nn(o).href).then(n=>n.validateProps).catch(()=>null):Promise.resolve(null),ie}function un(e){let t={};for(let o of e.attributes||[])o.type==="mdxJsxAttribute"&&(o.value==null?t[o.name]=!0:typeof o.value=="string"&&(t[o.name]=o.value));return t}function fn(e,t){return()=>o=>{cn(o,n=>{if((n.type==="mdxJsxFlowElement"||n.type==="mdxJsxTextElement")&&typeof n.name=="string"&&/^[A-Z]/.test(n.name)&&!n.name.includes(".")&&e.push({name:n.name,props:un(n),line:n.position?.start?.line??null,column:n.position?.start?.column??null}),n.type==="mdxjsEsm"&&typeof n.value=="string")for(let r of n.value.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g))t.add(r[1])})}}async function pn(e,t){let o=[],n;try{n=await Qt.readFile(t.fileAbsPath,"utf-8")}catch{return o}let r=R.relative(e,t.fileAbsPath).split(R.sep).join("/"),s=[],i=new Set;try{await on({value:n,path:t.fileAbsPath},{remarkPlugins:[rn,sn,an,q,fn(s,i)],rehypePlugins:[ln],providerImportSource:"@mdx-js/react"})}catch(c){return o.push(H(c,{projectDir:e,knownComponents:I,file:r})),o}let a=new Set(I),l=await xe(),u=new Set;for(let c of s)if(!i.has(c.name)){if(!a.has(c.name)){if(u.has(c.name))continue;u.add(c.name),o.push(h({category:"unknown-component",file:r,line:c.line,column:c.column,title:`<${c.name}> is not a built-in component`,hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:te(c.name,I)}));continue}if(l){let f=l(c.name,c.props,{checkRequired:!1});f&&o.push(h({...f,file:r,line:c.line,column:c.column}))}}return o}async function Ve(e,t){let o=t.filter(a=>a.exists),n=[],r=8,s=0;async function i(){for(;s<o.length;){let a=o[s++],l=await pn(e,a);for(let u of l)n.push(u)}}return await Promise.all(Array.from({length:Math.min(r,o.length)},i)),n}var ie,we=b(()=>{ce();F();de();he()});import{visit as mn}from"unist-util-visit";function dn(e,t){let o=Ge(e).replace(/[?#].*$/,""),n=Ge(t).replace(/\/+$/,"");return n&&o.toLowerCase().startsWith(n.toLowerCase())?o.slice(n.length).replace(/^\/+/,""):null}function Je(e,t){return()=>(o,n)=>{typeof e=="function"&&mn(o,r=>{if(r.type!=="mdxJsxFlowElement"&&r.type!=="mdxJsxTextElement"||typeof r.name!="string"||!/^[A-Z]/.test(r.name)||r.name.includes("."))return;let s={};for(let a of r.attributes||[])a.type==="mdxJsxAttribute"&&(a.value==null?s[a.name]=!0:typeof a.value=="string"&&(s[a.name]=a.value));let i=e(r.name,s,{checkRequired:!1});if(i){let a=new Error(i.title);throw a.veluIssue={...i,file:dn(n?.path,t),line:r.position?.start?.line??null,column:r.position?.start?.column??null},a.loc={line:a.veluIssue.line,column:a.veluIssue.column},a}})}}var Ge,qe=b(()=>{Ge=e=>String(e||"").replace(/\\/g,"/")});var Qe={};le(Qe,{startDevServer:()=>Mn});import De from"node:fs/promises";import Ye from"node:fs";import gn from"node:http";import{spawn as hn}from"node:child_process";import S from"node:path";import{fileURLToPath as vn}from"node:url";import{createRequire as yn}from"node:module";import xn from"chokidar";import wn from"express";import bn from"@tailwindcss/vite";import kn from"@vitejs/plugin-react";import $n from"@mdx-js/rollup";import Sn from"remark-frontmatter";import jn from"remark-mdx-frontmatter";import An from"remark-gfm";import Pn from"rehype-slug";import{createServer as Cn,searchForWorkspaceRoot as En}from"vite";function Nn(e){return`<link rel="stylesheet" href="${`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e).replace(/%20/g,"+")}:wght@300;400;500;600;700&display=swap`}" />`}function We(e,t){let o=pe(e,{color:!!process.stderr.isTTY});console.error(`
|
|
86
|
+
`+o+`
|
|
87
|
+
`),process.env.VELU_DEBUG&&t&&console.error(t)}async function Ke(e){try{return await Pe(e)}catch{return ue({},S.basename(e))}}async function Ze(e,t){let o=await e.moduleGraph.getModuleByUrl(t,!0),n=new Map,r=new Set;async function s(i){if(!(!i||r.has(i.url))){if(r.add(i.url),i.id&&_n.test(i.id)){let a=i.url.includes("?")?"&":"?",l=await e.transformRequest(`${i.url}${a}direct`);l?.code&&n.set(i.url,l.code)}for(let a of i.importedModules)await s(a)}}return await s(o),[...n.values()].join(`
|
|
88
|
+
`)}function Rn(e,t){let o=()=>{process.stdout.isTTY&&!process.env.VELU_NO_BELL&&process.stdout.write("\x07")},n=process.stdout.isTTY,r=f=>n&&process.stdout.write(`\x1B]${f}\x1B\\`),s=()=>{r(`0;\u23F3 ${t}`),r("9;4;3;0")},i=()=>{r(`0;${t}`),r("9;4;0;0")};if(n&&process.once("exit",()=>r("9;4;0;0")),s(),!e)return console.log("Starting Velu\u2026"),{ready:f=>{console.log(`Velu ready \u2192 ${f}`),i(),o()}};let a="\x1B[38;2;220;20;60m",l="\x1B[0m";console.log("");for(let f of Fn)console.log(`${a}${f}${l}`);console.log("");let u=null;try{u=hn(process.execPath,["-e",In],{stdio:["ignore","inherit","ignore"]}),u.on("error",()=>{})}catch{}let c=()=>{if(u){try{u.kill()}catch{}u=null}};return process.once("exit",c),{ready:f=>{c(),process.stdout.write("\x1B[2K\r"),console.log(` \x1B[32m\u2713${l} Velu ready \u2192 \x1B[36m${f}${l}`),i(),o()}}}async function Mn(e){let t=!!process.env.VELU_PROFILE,o=performance.now(),n=(x,p)=>t&&console.log(`[velu-profile] ${x}: ${(performance.now()-p).toFixed(0)}ms`),r=Rn(!!process.stdout.isTTY&&!t,S.basename(e)),s=await Ke(e),i=a();function a(){let p=re(e).filter(w=>w.severity==="error"&&(w.category==="config-json"||w.category==="config-schema"));return p.length&&console.error(`
|
|
89
|
+
`+ne(p,{color:!!process.stderr.isTTY})+`
|
|
90
|
+
`),p}let l=e;try{l=Ye.realpathSync(e)}catch{}let u=0,c=x=>{let p=performance.now();if(p-u<500)return;u=p;let w=H(x,{projectDir:l,knownComponents:I});We(w,x)};process.on("unhandledRejection",c),process.on("uncaughtException",c);let _=yn(import.meta.url).resolve("@mdx-js/react"),d=S.resolve(K,"runtime","velu-ui"),j=Ye.existsSync(d)?d:S.resolve(K,"..","velu-ui","src"),m=[{find:"@mdx-js/react",replacement:_},{find:/^velu-ui$/,replacement:S.join(j,"index.js")},{find:/^velu-ui\//,replacement:j+"/"}],N=Number(process.env.PORT)||8358,E=await xe(),A=wn(),G=gn.createServer(A),v=await Cn({root:K,appType:"custom",logLevel:t?"info":"warn",plugins:[Re(e),$n({remarkPlugins:[Sn,jn,An,q,Je(E,e)],rehypePlugins:[Pn],providerImportSource:"@mdx-js/react"}),kn(),bn()],cacheDir:S.resolve(e,".velu","vite-cache"),optimizeDeps:{include:["react","react-dom","react-dom/client","react-router-dom","@mdx-js/react","lucide-react","prism-react-renderer","iso-639-1","github-slugger"],esbuildOptions:{loader:{".mdx":"jsx"}}},resolve:{alias:m,dedupe:["react","react-dom","@mdx-js/react"]},server:{middlewareMode:!0,fs:{allow:[En(K),e,l]},hmr:{server:G}}});n("vite server created",o),A.use(v.middlewares),A.get(He,async(x,p,w)=>{if(!s.favicon)return p.status(404).end();let g=S.resolve(e,s.favicon.replace(/^\//,""));p.sendFile(g,T=>{T&&p.status(404).end()})}),A.use("*",async(x,p,w)=>{let g=x.originalUrl,T=performance.now();if(i.length)return p.status(200).set({"Content-Type":"text/html"}).end(ge(i,{title:"Fix velu.json to continue"}));try{let y=performance.now(),P=await De.readFile(Xe,"utf-8");P=await v.transformIndexHtml(g,P),n(`transformIndexHtml ${g}`,y);let M="/src/runtime/server-entry.jsx";y=performance.now();let{render:Z}=await v.ssrLoadModule(M);n(`ssrLoadModule ${g} (1st req includes dep pre-bundle)`,y),y=performance.now();let k=await Z(g);n(`render ${g}`,y),y=performance.now();let J=await Ze(v,M);n(`collectSsrCss ${g}`,y);let ae=J?`<style data-velu-ssr>${J}</style>`:"",it=`<style data-velu-config>
|
|
91
|
+
${Ce(s)}
|
|
92
|
+
</style>`,st=On.has(s.font.family)?"":Nn(s.font.family),at=s.favicon?`<link rel="icon" href="${He}" />`:"",lt=[ae,it,st,at].filter(Boolean).join(`
|
|
93
|
+
`),ct=P.replace("<!--app-title-->",Ln(s.name)).replace("<!--app-head-->",lt).replace("<!--app-html-->",k);p.status(200).set({"Content-Type":"text/html"}).end(ct),n(`TOTAL ${g}`,T)}catch(y){v.ssrFixStacktrace(y);let P=H(y,{projectDir:l,knownComponents:I});We(P,y),p.status(200).set({"Content-Type":"text/html"}).end(ge([P]))}}),xn.watch(e,{ignoreInitial:!0,ignored:/(^|[\\/])(node_modules|\.git|\.velu)([\\/]|$)/,awaitWriteFinish:{stabilityThreshold:100,pollInterval:20}}).on("all",async(x,p)=>{console.log(`[velu-cli] content ${x}: ${S.relative(e,p)}`);let w=S.basename(p)==="velu.json",g=p.endsWith(".mdx"),T=w||g&&(x==="add"||x==="unlink");if(w&&(s=await Ke(e),i=a()),T)v.moduleGraph.invalidateAll();else if(g){let y=p.split(S.sep).join("/"),P=v.moduleGraph.getModulesByFile(y);if(P)for(let M of P)v.moduleGraph.invalidateModule(M)}v.ws.send({type:"full-reload"})});async function ke(x){let p=new Set,w=12,g=0,T=[],y=()=>g<w?(g+=1,Promise.resolve()):new Promise(k=>T.push(k)).then(()=>{g+=1}),P=()=>{g-=1,T.shift()?.()},M=k=>/[\\/]\.velu[\\/]vite-cache[\\/]|[\\/]deps[\\/]/.test(k)||/[\\/]node_modules[\\/]/.test(k)&&!/velu-ui/.test(k);async function Z(k){if(!(!k||p.has(k)||M(k))){p.add(k);try{await y();try{await v.transformRequest(k,{ssr:!1})}finally{P()}let J=await v.moduleGraph.getModuleByUrl(k,!1);J?.importedModules?.size&&await Promise.all([...J.importedModules].map(ae=>Z(ae.url)))}catch{}}}return await Z(x),p.size}G.listen(N,async()=>{let x=performance.now(),p=0;try{let{render:w}=await v.ssrLoadModule("/src/runtime/server-entry.jsx");await ke("/src/runtime/client-entry.jsx"),typeof v.waitForRequestsIdle=="function"&&await v.waitForRequestsIdle();let[g]=await Promise.allSettled([ke("/src/runtime/client-entry.jsx"),w("/"),v.transformIndexHtml("/",await De.readFile(Xe,"utf-8")),Ze(v,"/src/runtime/server-entry.jsx")]).then(T=>T.map(y=>y.status==="fulfilled"?y.value:0));p=g}catch(w){t&&console.log("[velu-profile] warmup error:",w?.message)}n(`cold-start warm-up (${p} client modules)`,x),r.ready(`http://localhost:${N}`)})}var Tn,_n,On,He,Ln,K,Xe,Fn,In,et=b(()=>{ce();Ee();Me();de();ze();F();he();ye();we();qe();Tn=S.dirname(vn(import.meta.url)),_n=/\.(css|less|sass|scss|styl|stylus|pcss|postcss)(\?|$)/,On=new Set(["Google Sans Flex","Google Sans Code","Outfit"]),He="/@velu-favicon",Ln=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");K=S.resolve(Tn,".."),Xe=S.resolve(K,"src","template.html"),Fn=[" _ __ __","| | / /__ / /_ __","| | / / _ \\/ / / / /","| |/ / __/ / /_/ /","|___/\\___/_/\\__,_/"],In="const F=['\u280B','\u2819','\u2839','\u2838','\u283C','\u2834','\u2826','\u2827','\u2807','\u280F'],M=['Starting Velu','Setting up your preview','Preparing your docs','Warming things up','Almost ready'];let f=0,m=0;const t=Date.now();const C='\\x1b[38;2;220;20;60m',R='\\x1b[0m',D='\\x1b[2m';const d=()=>{const s=(Date.now()-t)/1000|0;process.stdout.write('\\x1b[2K\\r '+C+F[f]+R+' '+M[m]+'\\u2026 '+D+s+'s'+R);f=(f+1)%F.length;};d();setInterval(d,90);setInterval(()=>{if(m<M.length-1)m++;},4000);"});var nt={};le(nt,{default:()=>Vn,runValidate:()=>tt});import Un from"node:fs";import zn from"node:path";function Bn(e){try{let t=JSON.parse(Un.readFileSync(zn.join(e,"velu.json"),"utf-8"));if(!t.navigation||typeof t.navigation!="object")return[];let o=B(t.navigation);return V(o,e).pageEntries}catch{return[]}}async function tt(e){let t=re(e),o=Bn(e),n=await Ve(e,o),r=[...t,...n],s=!!process.stdout.isTTY;return console.log(ne(r,{color:s})),r.some(a=>a.severity!=="warning"&&a.severity!=="info")?1:0}var Vn,ot=b(()=>{Y();Q();ye();we();F();Vn=tt});import be from"node:path";import L from"node:process";import{readFileSync as Gn}from"node:fs";var[,,rt,se]=L.argv;function Jn(){try{return JSON.parse(Gn(new URL("../package.json",import.meta.url),"utf8")).version}catch{return"unknown"}}async function qn(){switch(rt){case"--version":case"-v":case"version":{console.log(Jn());break}case"init":{se||(console.error("Usage: velu init <project-name>"),L.exit(1));let e=se,t=be.resolve(L.cwd(),e),{initProject:o}=await Promise.resolve().then(()=>(je(),Se));await o(t,e);break}case"dev":{let e=be.resolve(L.cwd(),se??"."),{startDevServer:t}=await Promise.resolve().then(()=>(et(),Qe));await t(e);break}case"validate":{let e=be.resolve(L.cwd(),se??"."),{runValidate:t}=await Promise.resolve().then(()=>(ot(),nt)),o=await t(e);L.exit(o);break}default:console.log("Usage:"),console.log(" velu init <project-name> scaffold a new docs project"),console.log(" velu dev [dir] start the dev preview server"),console.log(" velu validate [dir] check velu.json + content for problems"),L.exit(rt?1:0)}}qn().catch(e=>{console.error(L.env.VELU_DEBUG?e:`Error: ${e.message}`),L.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veluai/velu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "./dist/cli.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@icons-pack/react-simple-icons": ">=13.0.0 <13.13.0",
|
|
24
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
24
25
|
"@mdx-js/react": "^3.1.1",
|
|
25
26
|
"@mdx-js/rollup": "^3.1.1",
|
|
26
27
|
"@tailwindcss/vite": "^4.1.0",
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ErrorCard — a branded, self-contained card that renders ONE Velu "issue"
|
|
5
|
+
* (an MDX or velu.json problem). Used by the dev server's per-page error
|
|
6
|
+
* boundary. Deliberately presentational and dependency-free (no other Velu
|
|
7
|
+
* components, no effects) so it can never fail while reporting a failure.
|
|
8
|
+
*
|
|
9
|
+
* Styled with inline styles + design tokens (with hard fallbacks), so it looks
|
|
10
|
+
* right even when the page's own CSS hasn't loaded.
|
|
11
|
+
*/
|
|
12
|
+
const DANGER = 'var(--danger-stroke-color, #ef4444)';
|
|
13
|
+
const DANGER_BG =
|
|
14
|
+
'var(--danger-bg-color, color-mix(in srgb, #ef4444 7%, transparent))';
|
|
15
|
+
const MUTED = 'var(--muted-color, #6b7280)';
|
|
16
|
+
const TEXT = 'var(--text-color, #111827)';
|
|
17
|
+
|
|
18
|
+
export default function ErrorCard({
|
|
19
|
+
label,
|
|
20
|
+
title,
|
|
21
|
+
file,
|
|
22
|
+
line,
|
|
23
|
+
column,
|
|
24
|
+
frame,
|
|
25
|
+
detail,
|
|
26
|
+
hint,
|
|
27
|
+
suggestion,
|
|
28
|
+
}) {
|
|
29
|
+
const loc = file
|
|
30
|
+
? `${file}${line ? `:${line}${column ? `:${column}` : ''}` : ''}`
|
|
31
|
+
: null;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
role="alert"
|
|
36
|
+
style={{
|
|
37
|
+
border: `1px solid ${DANGER}`,
|
|
38
|
+
borderRadius: 'var(--radius-md, 10px)',
|
|
39
|
+
background: DANGER_BG,
|
|
40
|
+
padding: 'var(--s2, 1rem)',
|
|
41
|
+
margin: 'var(--s2, 1rem) 0',
|
|
42
|
+
fontFamily: 'var(--font-sans, system-ui, sans-serif)',
|
|
43
|
+
color: TEXT,
|
|
44
|
+
lineHeight: 1.5,
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<div
|
|
48
|
+
style={{
|
|
49
|
+
display: 'flex',
|
|
50
|
+
gap: '0.6rem',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
flexWrap: 'wrap',
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
<span
|
|
56
|
+
style={{
|
|
57
|
+
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
58
|
+
fontSize: 11,
|
|
59
|
+
textTransform: 'uppercase',
|
|
60
|
+
letterSpacing: '0.06em',
|
|
61
|
+
fontWeight: 600,
|
|
62
|
+
color: DANGER,
|
|
63
|
+
border: `1px solid ${DANGER}`,
|
|
64
|
+
borderRadius: 999,
|
|
65
|
+
padding: '2px 9px',
|
|
66
|
+
whiteSpace: 'nowrap',
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
{label}
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{title && (
|
|
74
|
+
<div style={{ marginTop: '0.6rem', fontWeight: 600, fontSize: '1.05rem' }}>
|
|
75
|
+
{title}
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
78
|
+
|
|
79
|
+
{loc && (
|
|
80
|
+
<div
|
|
81
|
+
style={{
|
|
82
|
+
display: 'inline-block',
|
|
83
|
+
marginTop: '0.7rem',
|
|
84
|
+
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
85
|
+
fontSize: 15,
|
|
86
|
+
fontWeight: 600,
|
|
87
|
+
letterSpacing: '0.01em',
|
|
88
|
+
color: DANGER,
|
|
89
|
+
background: 'var(--danger-bg-color, rgba(239,68,68,0.12))',
|
|
90
|
+
border: `1px solid ${DANGER}`,
|
|
91
|
+
borderRadius: 7,
|
|
92
|
+
padding: '7px 11px',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{loc}
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
{detail && (
|
|
99
|
+
<div style={{ marginTop: '0.25rem', color: MUTED }}>{detail}</div>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{frame && (
|
|
103
|
+
<pre
|
|
104
|
+
style={{
|
|
105
|
+
marginTop: '0.75rem',
|
|
106
|
+
marginBottom: 0,
|
|
107
|
+
padding: '0.75rem 0.9rem',
|
|
108
|
+
overflow: 'auto',
|
|
109
|
+
background: 'var(--code-bg-color, rgba(0,0,0,0.05))',
|
|
110
|
+
borderRadius: 'var(--radius-sm, 6px)',
|
|
111
|
+
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
112
|
+
fontSize: 12.5,
|
|
113
|
+
lineHeight: 1.5,
|
|
114
|
+
color: TEXT,
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
{frame}
|
|
118
|
+
</pre>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
{suggestion && (
|
|
122
|
+
<div style={{ marginTop: '0.75rem' }}>
|
|
123
|
+
Did you mean{' '}
|
|
124
|
+
<code style={{ fontWeight: 600, color: DANGER }}>
|
|
125
|
+
{`<${suggestion}>`}
|
|
126
|
+
</code>
|
|
127
|
+
?
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{hint && (
|
|
132
|
+
<div style={{ marginTop: '0.6rem', color: MUTED, fontSize: '0.92rem' }}>
|
|
133
|
+
{hint}
|
|
134
|
+
</div>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|