@forinda/kickjs-view 0.1.0 → 0.2.0

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.
@@ -1,14 +0,0 @@
1
- /**
2
- * @forinda/kickjs-view v0.1.0
3
- *
4
- * Copyright (c) Felix Orinda
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- import{_ as templateName,a as escapeHtml,b as decodeEntities,c as safeStyleValue,d as parse,g as layoutResolver,i as SafeHtml,l as sanitizeSrcset,m as check,n as BUILTIN_PIPES,o as escapeJsonForScript,r as builtinPipes,s as read,u as sanitizeUrl,x as error}from"./read-exports-CtiwXL4e.js";const ENV_PIPE=Symbol.for(`kickjs.view.envPipe`);function withEnv(make){return{[ENV_PIPE]:make}}const safeHtml=html=>new SafeHtml(html),isEnvPipe=p=>typeof p==`object`&&!!p&&ENV_PIPE in p;function pipesFor(app,env){let out=builtinPipes(env);for(let[name,p]of Object.entries(app))isEnvPipe(p)?out[name]=p[ENV_PIPE](env):typeof p==`function`&&(out[name]=p);return out}var RenderError=class extends Error{diagnostic;constructor(diagnostic){let{file,span,message}=diagnostic;super(`${file}:${span.start.line}:${span.start.column} — ${message}`),this.diagnostic=diagnostic,this.name=`RenderError`}};const MAX_DEPTH=64,warnedNames=/* @__PURE__ */ new WeakMap;var Renderer=class{env;out=[];constructor(env){this.env=env}html(){return this.out.join(``)}fail(inst,message){let[line,column]=inst.at??[1,1],pos={offset:0,line,column},d=error(inst.t.file,{start:pos,end:pos},message);throw d.stack=inst.stack,new RenderError(d)}path(value,p,inst){for(let seg of p){if(value==null)return;value=read(value,`n`in seg?seg.n:this.value(seg.e,inst))}return value}value(e,inst){switch(e.k){case`l`:return e.v;case`x`:return;case`d`:return e.n in inst.data||this.unresolved(e.n,inst),this.path(read(inst.data,e.n),e.p,inst);case`v`:return this.path(inst.slots[e.s],e.p,inst);case`m`:return loopVar(inst.slots[e.s],e.w);case`u`:{let a=this.value(e.a,inst);return e.o===`!`?!a:-a}case`b`:{if(e.o===`&&`)return this.value(e.l,inst)&&this.value(e.r,inst);if(e.o===`||`)return this.value(e.l,inst)||this.value(e.r,inst);if(e.o===`??`)return this.value(e.l,inst)??this.value(e.r,inst);let l=this.value(e.l,inst),r=this.value(e.r,inst);switch(e.o){case`==`:case`===`:return l===r;case`!=`:case`!==`:return l!==r;case`<`:return l<r;case`>`:return l>r;case`<=`:return l<=r;case`>=`:return l>=r;case`+`:return l+r;case`-`:return l-r}return}case`c`:return this.value(e.t,inst)?this.value(e.y,inst):this.value(e.n,inst);case`p`:{let pipe=this.env.pipes[e.n];pipe||this.fail(inst,`unknown pipe '${e.n}'`);let input=this.value(e.i,inst),args=e.a.map(a=>this.value(a,inst)),result;try{result=pipe(input,...args)}catch(err){if(err instanceof RenderError)throw err;this.fail(inst,`pipe '${e.n}' failed: ${err instanceof Error?err.message:String(err)}`)}return result&&typeof result.then==`function`&&this.fail(inst,`pipe '${e.n}' returned a Promise — pipes must be synchronous`),result}}}unresolved(name,inst){this.env.strict&&this.fail(inst,`'${name}' isn't in the data`);let seen=warnedNames.get(inst.t);seen||warnedNames.set(inst.t,seen=/* @__PURE__ */ new Set),!seen.has(name)&&(seen.add(name),this.env.warn(`${inst.t.file}: '${name}' isn't in the data passed to render`))}text(v,inst){if(v==null)return``;switch(typeof v){case`string`:return v;case`number`:case`bigint`:case`boolean`:return String(v)}if(v instanceof Date)return Number.isNaN(v.getTime())?``:v.toISOString();if(v instanceof SafeHtml)return v.html;let what=v&&typeof v.then==`function`?`a Promise — await it in the controller`:Array.isArray(v)?`an array — loop over it with @for, or use | json`:`an object — print one of its properties, or use | json`;return this.env.strict&&this.fail(inst,`can't print ${what}`),this.env.warn(`${inst.t.file}:${inst.at?.[0]??1}: can't print ${what}`),``}nodes(list,inst){for(let n of list)this.node(n,inst)}node(n,inst){switch(n.k){case`s`:this.out.push(n.t);return;case`i`:{inst.at=n.at;let v=this.value(n.e,inst);n.c===`json`?this.out.push(escapeJsonForScript(typeof v==`string`?v:JSON.stringify(v)??`null`)):v instanceof SafeHtml&&n.c===`text`?this.out.push(v.html):this.out.push(escapeHtml(v instanceof SafeHtml?v.html:this.text(v,inst)));return}case`A`:inst.at=n.at,this.attrs(this.resolve(n.a,inst),n.f?inst.fall:void 0);return;case`if`:for(let br of n.br){let v=!br.c||this.value(br.c,inst);if(v){br.a!==void 0&&(inst.slots[br.a]=v),this.nodes(br.b,inst);return}}return;case`for`:{inst.at=n.at;let items=this.iterable(this.value(n.e,inst),inst);if(!items.length){n.em&&this.nodes(n.em,inst);return}let meta={i:0,n:items.length};inst.slots[n.m]=meta;for(let i=0;i<items.length;i++){meta.i=i;let item=items[i];typeof n.it==`number`?inst.slots[n.it]=item:(inst.slots[n.it[0]]=item?.[0],inst.slots[n.it[1]]=item?.[1]),this.nodes(n.b,inst)}return}case`sw`:{let v=this.value(n.e,inst),hit=n.cs.find(c=>this.value(c.e,inst)===v);hit?this.nodes(hit.b,inst):n.d&&this.nodes(n.d,inst);return}case`let`:inst.slots[n.s]=this.value(n.e,inst);return;case`cmp`:inst.at=n.at,this.component(n,inst);return;case`o`:{let fill=inst.fills[n.n];fill?this.nodes(fill.nodes,fill.inst):this.nodes(n.fb,inst);return}case`as`:this.env.assets?this.out.push(this.env.assets(n.en,inst.data)):this.env.warn(`${inst.t.file}: @assets('${n.en}') needs the Vite plugin or an assets option`)}}iterable(v,inst){if(v==null)return[];if(Array.isArray(v))return v;if(typeof v==`string`)return[...v];if(v instanceof Map)return[...v.entries()];if(v instanceof Set)return[...v];this.fail(inst,`@for can't loop over ${typeof v==`object`?`an object — use | entries`:`a ${typeof v}`}`)}attrValue(v,inst){return escapeHtml(this.plain(v,inst))}plain(v,inst){return v instanceof SafeHtml?v.html:this.text(v,inst)}resolve(list,inst){let r={attrs:[],cls:[],style:[]},put=(name,value)=>{let lower=name.toLowerCase();lower===`class`?value!==!0&&value.trim()&&r.cls.push(value.trim()):lower===`style`?value!==!0&&value.trim()&&r.style.push(value.trim().replace(/;\s*$/,``)):r.attrs.push([name,value])};for(let a of list)switch(a.t){case`s`:put(a.n,a.v===!0||a.v.replace(/"/g,`&quot;`));break;case`i`:{let values=a.p.map(p=>typeof p==`string`?void 0:this.value(p,inst)),html=a.p.map((p,i)=>typeof p==`string`?p.replace(/"/g,`&quot;`):this.attrValue(values[i],inst)).join(``);if(!a.u){put(a.n,html);break}let plain=decodeEntities(html),safe=a.u===`url`?sanitizeUrl(plain):sanitizeSrcset(plain);put(a.n,safe===plain?html:escapeHtml(safe));break}case`b`:{let v=this.value(a.e,inst);if(v==null||v===!1)break;if(v===!0){put(a.n,!0);break}let plain=this.plain(v,inst);put(a.n,escapeHtml(a.u===`url`?sanitizeUrl(plain):a.u===`srcset`?sanitizeSrcset(plain):plain));break}case`c`:this.value(a.e,inst)&&r.cls.push(escapeHtml(a.n));break;case`y`:{let v=this.value(a.e,inst);if(v==null||v===!1)break;let value=safeStyleValue(`${this.text(v,inst)}${a.x??``}`);if(value===void 0){this.env.warn(`${inst.t.file}:${inst.at?.[0]??1}: dropped an unsafe value for [style.${a.n}]`);break}r.style.push(`${escapeHtml(a.n)}:${escapeHtml(value)}`);break}}return r}attrs(own,fall){let attrs=own.attrs,cls=own.cls,style=own.style;if(fall){let names=new Set(fall.attrs.map(([n])=>n.toLowerCase()));attrs=[...attrs.filter(([n])=>!names.has(n.toLowerCase())),...fall.attrs],cls=[...cls,...fall.cls],style=[...style,...fall.style]}for(let[n,v]of attrs)this.out.push(v===!0?` ${n}`:` ${n}="${v}"`);cls.length&&this.out.push(` class="${cls.join(` `)}"`),style.length&&this.out.push(` style="${style.join(`;`)}"`)}component(n,caller){caller.depth>=64&&this.fail(caller,`components nest more than 64 deep — is ${n.n} including itself?`);let t=this.env.resolve(n.n),slots=Array.from({length:t.slots});for(let i of t.inputs)i.d!==void 0&&(slots[i.s]=i.d);for(let i of n.in)slots[i.s]=this.value(i.e,caller);let fills={};for(let[name,nodes]of Object.entries(n.f))fills[name]={nodes,inst:caller};let inst={t,data:Object.create(null),slots,fills,fall:this.resolve(n.fa,caller),stack:[...caller.stack,n.n],depth:caller.depth+1};this.nodes(t.body,inst)}};function loopVar(m,w){switch(w){case`$index`:return m.i;case`$first`:return m.i===0;case`$last`:return m.i===m.n-1;case`$even`:return m.i%2==0;case`$odd`:return m.i%2==1;case`$count`:return m.n}}function render(template,data,env,opts={}){let r=new Renderer(env),page={t:template,data,slots:Array.from({length:template.slots}),fills:{},stack:[template.name],depth:0},none=opts.layout===!1||opts.layout===void 0&&template.layout===null,chain=[];if(!none){let next=typeof opts.layout==`string`?opts.layout:template.layout??env.layoutFor?.(template.name);for(;next&&next!==template.name&&!chain.some(t=>t.name===next);){let t=env.resolve(next);chain.push(t),next=t.layout??void 0}let base=env.baseLayout;base&&base!==template.name&&!chain.some(t=>t.name===base)&&chain.push(env.resolve(base))}if(!chain.length)return r.nodes(template.body,page),r.html();let fills={"":{nodes:template.body,inst:page}};for(let[name,nodes]of Object.entries(template.fills))fills[name]={nodes,inst:page};let inst=page;for(let[i,t]of chain.entries()){if(inst={t,data:page.data,slots:Array.from({length:t.slots}),fills,stack:[...inst.stack,t.name],depth:0},i===chain.length-1)break;let outer={...fills,"":{nodes:t.body,inst}};for(let[name,nodes]of Object.entries(t.fills))outer[name]={nodes,inst};fills=outer}return r.nodes(inst.t.body,inst),r.html()}function bundleLoader(bundle){if(bundle.v!==1)throw Error(`views bundle format v${bundle.v}, this runtime reads v1`);return{list:async()=>Object.keys(bundle.templates),read:async()=>{throw Error(`a bundled template has no source`)}}}let fileLoaderModule;function useFileLoader(load){fileLoaderModule=load}function fileLoaders(){return fileLoaderModule?fileLoaderModule():Promise.reject(/* @__PURE__ */ Error(`createViews has no templates: pass the build's bundle (import kickViews from 'virtual:kick-views') or a loader`))}function createViews(options={}){let bundle=options.bundle??void 0;bundle&&bundleLoader(bundle);let componentsDir=options.componentsDir??`components`,layoutFor=layoutResolver(options.layout),warn=options.warn??(m=>console.warn(`[kick/view] ${m}`)),loader,appPipes,state,settle=(p,forget)=>p.catch(err=>{throw forget(),err}),getLoader=()=>loader??=settle(options.loader?Promise.resolve(options.loader):fileLoaders().then(m=>m.fileLoader(options.viewsDir??`src/views`)),()=>loader=void 0),getPipes=()=>appPipes??=settle(options.pipes||bundle?Promise.resolve(options.pipes??{}):fileLoaders().then(m=>m.loadPipesFile(options.pipesFile??`src/views/pipes.ts`)).then(mod=>mod??{}),()=>appPipes=void 0),reload=()=>state=settle(load(),()=>state=void 0);async function load(){let l=await getLoader(),pipes=await getPipes(),names=await l.list(),templates=/* @__PURE__ */ new Map,versions=/* @__PURE__ */ new Map,parseErrors=/* @__PURE__ */ new Map;return await Promise.all(names.map(async name=>{let r=parse(await l.read(name),`${name}.kick`);templates.set(name,r.ast);let first=r.diagnostics.find(d=>d.severity===`error`);first&&parseErrors.set(name,first),options.dev&&l.version&&versions.set(name,await l.version(name))})),{project:{templates,pipes:/* @__PURE__ */ new Set([...BUILTIN_PIPES,...Object.keys(pipes)]),componentsDir,layouts:options.layout,baseLayout:options.baseLayout},versions,parseErrors,checked:/* @__PURE__ */ new Map}}async function current(){if(options.cache===!1)return reload();let s=await(state??reload());if(!options.dev)return s;let l=await getLoader();if(!l.version)return s;let names=await l.list();return names.length!==s.project.templates.size||(await Promise.all(names.map(async n=>await l.version(n)!==s.versions.get(n)))).some(Boolean)?reload():s}function checked(s,name){let t=s.checked.get(name);if(t)return t;let syntax=s.parseErrors.get(name);if(syntax)throw new RenderError(syntax);let r=check(name,s.project);if(!r.template)throw new RenderError(r.diagnostics.find(x=>x.severity===`error`));for(let w of r.diagnostics)warn(`${w.file}:${w.span.start.line}:${w.span.start.column} — ${w.message}`);return t=r.template,s.checked.set(name,t),t}async function has(name){return templateName(name)?bundle?Object.hasOwn(bundle.templates,name):(await current()).project.templates.has(name):!1}return{has,async render(name,data={},opts={}){if(!templateName(name))throw Error(`invalid template name '${name}'`);if(!await has(name))throw Error(`template '${name}' not found`);let resolve=bundle?n=>{let t=Object.hasOwn(bundle.templates,n)?bundle.templates[n]:void 0;if(!t)throw new RenderError(error(`${n}.kick`,zeroSpan,`template '${n}' not found`));return t}:await current().then(s=>n=>checked(s,n)),template=resolve(name),shared=options.share?await options.share(opts.ctx):{},locale=opts.locale??options.locale??`en-US`,timeZone=opts.timeZone??options.timeZone??`UTC`;return render(template,{...shared,...data},{locale,timeZone,strict:options.strict??!1,pipes:pipesFor(await getPipes(),{locale,timeZone}),warn,resolve,layoutFor,baseLayout:options.baseLayout,assets:options.assets},{layout:opts.layout})}}}const zeroSpan={start:{offset:0,line:1,column:1},end:{offset:0,line:1,column:1}},VIEW_RENDERER=Symbol.for(`kickjs.viewRenderer`);function rendererFor(views){return async(name,data,opts,ctx)=>await views.has(name)?views.render(name,data,{layout:opts.layout,locale:opts.locale,timeZone:opts.timeZone,ctx}):void 0}function bindViews(views){let renderer=rendererFor(views);return(req,_res,next)=>{req[VIEW_RENDERER]=renderer,next()}}function viewsMiddleware(views){let renderer=rendererFor(views);return(ctx,next)=>(ctx.req[VIEW_RENDERER]=renderer,next())}function kickViewDev(options,nodeEnv){return options.dev??(nodeEnv===`development`||options.bundle===null)}function KickView(options={}){let views=options.views??createViews({...options,dev:kickViewDev(options,globalThis.process?.env?.NODE_ENV)}),handler=bindViews(views);return{name:`KickView`,views,middleware:()=>[{handler,phase:`beforeGlobal`}]}}function assetTags(entry,mode,nonce){let base=mode.base.endsWith(`/`)?mode.base:`${mode.base}/`,n=nonce?` nonce="${escapeHtml(nonce)}"`:``,url=file=>escapeHtml(`${base}${file.replace(/^\//,``)}`);if(mode.dev)return[`<script type="module"${n} src="${url(`@vite/client`)}"><\/script>`,`<script type="module"${n} src="${url(entry)}"><\/script>`].join(`
12
- `);let chunk=mode.manifest[entry];if(!chunk)throw Error(`@assets: '${entry}' isn't an entry in the Vite manifest`);let css=new Set(chunk.css??[]),preload=/* @__PURE__ */ new Set,walk=key=>{let c=mode.manifest[key];if(c&&!preload.has(c.file)){preload.add(c.file);for(let s of c.css??[])css.add(s);for(let i of c.imports??[])walk(i)}};for(let i of chunk.imports??[])walk(i);return[...[...css].map(f=>`<link rel="stylesheet"${n} href="${url(f)}">`),...[...preload].map(f=>`<link rel="modulepreload"${n} href="${url(f)}">`),`<script type="module"${n} src="${url(chunk.file)}"><\/script>`].join(`
13
- `)}export{createViews as a,RenderError as c,safeHtml as d,withEnv as f,bundleLoader as i,render as l,KickView as n,useFileLoader as o,viewsMiddleware as r,MAX_DEPTH as s,assetTags as t,pipesFor as u};
14
- //# sourceMappingURL=exports-WibN1iWb.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"exports-WibN1iWb.js","names":[],"sources":["../src/pipes/env.ts","../src/render/render.ts","../src/views.ts","../src/adapter.ts","../src/assets.ts"],"sourcesContent":["import type { Pipe } from '../render/render'\nimport { SafeHtml } from '../render/safe'\nimport { builtinPipes, type PipeEnv } from './builtins'\n\nexport { BUILTIN_PIPES, builtinPipes, type PipeEnv } from './builtins'\n\nconst ENV_PIPE = Symbol.for('kickjs.view.envPipe')\n\n/** A pipe built per render from the render's locale and time zone. */\nexport interface EnvPipe {\n [ENV_PIPE]: (env: PipeEnv) => Pipe\n}\n\n/**\n * A pipe that needs the render's locale or time zone:\n * `export const ago = withEnv(({ locale }) => (date: Date) => …)`.\n */\nexport function withEnv(make: (env: PipeEnv) => Pipe): EnvPipe {\n return { [ENV_PIPE]: make }\n}\n\n/** Mark HTML as trusted: a pipe returning it prints unescaped, in text only. */\nexport const safeHtml = (html: string): SafeHtml => new SafeHtml(html)\n\nconst isEnvPipe = (p: unknown): p is EnvPipe => typeof p === 'object' && p !== null && ENV_PIPE in p\n\n/** The pipes for one render: the built-ins and the app's, with env pipes built for `env`. */\nexport function pipesFor(app: Record<string, Pipe | EnvPipe>, env: PipeEnv): Record<string, Pipe> {\n const out = builtinPipes(env)\n for (const [name, p] of Object.entries(app)) {\n if (isEnvPipe(p)) out[name] = p[ENV_PIPE](env)\n else if (typeof p === 'function') out[name] = p\n }\n return out\n}\n","/**\n * The renderer: walks a checked template over the data and writes HTML.\n * Synchronous, no `eval` — every value goes through `read` and the escaper\n * for where it lands.\n */\nimport type { At, CAttr, CExpr, CNode, CheckedTemplate, CSeg, LoopVar } from '../ast'\nimport { error, type Diagnostic } from '../diagnostics'\nimport {\n SafeHtml,\n escapeHtml,\n escapeJsonForScript,\n read,\n safeStyleValue,\n sanitizeSrcset,\n sanitizeUrl,\n} from './safe'\nimport { decodeEntities } from '../entities'\n\nexport type Pipe = (value: unknown, ...args: unknown[]) => unknown\n\nexport interface RenderEnv {\n locale: string\n timeZone: string\n strict: boolean\n pipes: Record<string, Pipe>\n warn(message: string): void\n /** A checked template by name: layouts and components. */\n resolve(name: string): CheckedTemplate\n /** The layout a page gets when it declares none (a folder mapping, usually). */\n layoutFor?(page: string): string | undefined\n /** The shell wrapped around every page's outermost layout. */\n baseLayout?: string\n /** `@assets('entry')`: the tags for a Vite entry; `data` is the page's (for a CSP nonce). */\n assets?(entry: string, data: Record<string, unknown>): string\n}\n\nexport class RenderError extends Error {\n constructor(readonly diagnostic: Diagnostic) {\n const { file, span, message } = diagnostic\n super(`${file}:${span.start.line}:${span.start.column} — ${message}`)\n this.name = 'RenderError'\n }\n}\n\n/** The most components one render may nest — a self-including component stops here. */\nexport const MAX_DEPTH = 64\n\ninterface LoopMeta {\n i: number\n n: number\n}\n\ninterface Resolved {\n attrs: Array<[string, string | true]>\n cls: string[]\n style: string[]\n}\n\n/** One template being rendered: its scope slots, data, slot fills and the template stack. */\ninterface Inst {\n t: CheckedTemplate\n data: Record<string, unknown>\n slots: unknown[]\n fills: Record<string, { nodes: CNode[]; inst: Inst }>\n fall?: Resolved\n stack: string[]\n depth: number\n /** The node being rendered, for error positions. */\n at?: At\n}\n\nconst warnedNames = new WeakMap<CheckedTemplate, Set<string>>()\n\nclass Renderer {\n private readonly out: string[] = []\n\n constructor(private readonly env: RenderEnv) {}\n\n html(): string {\n return this.out.join('')\n }\n\n fail(inst: Inst, message: string): never {\n const [line, column] = inst.at ?? [1, 1]\n const pos = { offset: 0, line, column }\n const d = error(inst.t.file, { start: pos, end: pos }, message)\n d.stack = inst.stack\n throw new RenderError(d)\n }\n\n // ── values ────────────────────────────────────────────────────────────\n\n private path(value: unknown, p: CSeg[], inst: Inst): unknown {\n for (const seg of p) {\n if (value === null || value === undefined) return undefined\n value = read(value, 'n' in seg ? seg.n : this.value(seg.e, inst))\n }\n return value\n }\n\n value(e: CExpr, inst: Inst): unknown {\n switch (e.k) {\n case 'l':\n return e.v\n case 'x':\n return undefined\n case 'd': {\n if (!(e.n in inst.data)) this.unresolved(e.n, inst)\n return this.path(read(inst.data, e.n), e.p, inst)\n }\n case 'v':\n return this.path(inst.slots[e.s], e.p, inst)\n case 'm':\n return loopVar(inst.slots[e.s] as LoopMeta, e.w)\n case 'u': {\n const a = this.value(e.a, inst)\n return e.o === '!' ? !a : -(a as number)\n }\n case 'b': {\n if (e.o === '&&') return this.value(e.l, inst) && this.value(e.r, inst)\n if (e.o === '||') return this.value(e.l, inst) || this.value(e.r, inst)\n if (e.o === '??') return this.value(e.l, inst) ?? this.value(e.r, inst)\n const l = this.value(e.l, inst) as never\n const r = this.value(e.r, inst) as never\n switch (e.o) {\n case '==':\n case '===':\n return l === r\n case '!=':\n case '!==':\n return l !== r\n case '<':\n return l < r\n case '>':\n return l > r\n case '<=':\n return l <= r\n case '>=':\n return l >= r\n case '+':\n return (l as number) + (r as number)\n case '-':\n return (l as number) - (r as number)\n }\n return undefined\n }\n case 'c':\n return this.value(e.t, inst) ? this.value(e.y, inst) : this.value(e.n, inst)\n case 'p': {\n const pipe = this.env.pipes[e.n]\n if (!pipe) this.fail(inst, `unknown pipe '${e.n}'`)\n const input = this.value(e.i, inst)\n const args = e.a.map((a) => this.value(a, inst))\n let result: unknown\n try {\n result = pipe(input, ...args)\n } catch (err) {\n if (err instanceof RenderError) throw err\n this.fail(\n inst,\n `pipe '${e.n}' failed: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n this.fail(inst, `pipe '${e.n}' returned a Promise — pipes must be synchronous`)\n }\n return result\n }\n }\n }\n\n private unresolved(name: string, inst: Inst): void {\n if (this.env.strict) this.fail(inst, `'${name}' isn't in the data`)\n let seen = warnedNames.get(inst.t)\n if (!seen) warnedNames.set(inst.t, (seen = new Set()))\n if (seen.has(name)) return\n seen.add(name)\n this.env.warn(`${inst.t.file}: '${name}' isn't in the data passed to render`)\n }\n\n /** A value as text, unescaped; `undefined` when it has no text form. */\n private text(v: unknown, inst: Inst): string {\n if (v === null || v === undefined) return ''\n switch (typeof v) {\n case 'string':\n return v\n case 'number':\n case 'bigint':\n case 'boolean':\n return String(v)\n }\n if (v instanceof Date) return Number.isNaN(v.getTime()) ? '' : v.toISOString()\n if (v instanceof SafeHtml) return v.html\n const what =\n v && typeof (v as PromiseLike<unknown>).then === 'function'\n ? 'a Promise — await it in the controller'\n : Array.isArray(v)\n ? 'an array — loop over it with @for, or use | json'\n : 'an object — print one of its properties, or use | json'\n if (this.env.strict) this.fail(inst, `can't print ${what}`)\n this.env.warn(`${inst.t.file}:${inst.at?.[0] ?? 1}: can't print ${what}`)\n return ''\n }\n\n // ── nodes ─────────────────────────────────────────────────────────────\n\n nodes(list: CNode[], inst: Inst): void {\n for (const n of list) this.node(n, inst)\n }\n\n private node(n: CNode, inst: Inst): void {\n switch (n.k) {\n case 's':\n this.out.push(n.t)\n return\n case 'i': {\n inst.at = n.at\n const v = this.value(n.e, inst)\n if (n.c === 'json') {\n this.out.push(\n escapeJsonForScript(typeof v === 'string' ? v : (JSON.stringify(v) ?? 'null')),\n )\n } else if (v instanceof SafeHtml && n.c === 'text') {\n // Trusted HTML prints as is in text — never in <title>/<textarea>,\n // where it could close the element.\n this.out.push(v.html)\n } else {\n this.out.push(escapeHtml(v instanceof SafeHtml ? v.html : this.text(v, inst)))\n }\n return\n }\n case 'A':\n inst.at = n.at\n this.attrs(this.resolve(n.a, inst), n.f ? inst.fall : undefined)\n return\n case 'if':\n for (const br of n.br) {\n const v = br.c ? this.value(br.c, inst) : true\n if (!v) continue\n if (br.a !== undefined) inst.slots[br.a] = v\n this.nodes(br.b, inst)\n return\n }\n return\n case 'for': {\n inst.at = n.at\n const items = this.iterable(this.value(n.e, inst), inst)\n if (!items.length) {\n if (n.em) this.nodes(n.em, inst)\n return\n }\n const meta: LoopMeta = { i: 0, n: items.length }\n inst.slots[n.m] = meta\n for (let i = 0; i < items.length; i++) {\n meta.i = i\n const item = items[i]\n if (typeof n.it === 'number') inst.slots[n.it] = item\n else {\n inst.slots[n.it[0]] = (item as unknown[] | undefined)?.[0]\n inst.slots[n.it[1]] = (item as unknown[] | undefined)?.[1]\n }\n this.nodes(n.b, inst)\n }\n return\n }\n case 'sw': {\n const v = this.value(n.e, inst)\n const hit = n.cs.find((c) => this.value(c.e, inst) === v)\n if (hit) this.nodes(hit.b, inst)\n else if (n.d) this.nodes(n.d, inst)\n return\n }\n case 'let':\n inst.slots[n.s] = this.value(n.e, inst)\n return\n case 'cmp':\n inst.at = n.at\n this.component(n, inst)\n return\n case 'o': {\n const fill = inst.fills[n.n]\n if (fill) this.nodes(fill.nodes, fill.inst)\n else this.nodes(n.fb, inst)\n return\n }\n case 'as':\n if (this.env.assets) this.out.push(this.env.assets(n.en, inst.data))\n else\n this.env.warn(\n `${inst.t.file}: @assets('${n.en}') needs the Vite plugin or an assets option`,\n )\n }\n }\n\n private iterable(v: unknown, inst: Inst): unknown[] {\n if (v === null || v === undefined) return []\n if (Array.isArray(v)) return v\n if (typeof v === 'string') return [...v]\n if (v instanceof Map) return [...v.entries()]\n if (v instanceof Set) return [...v]\n this.fail(\n inst,\n `@for can't loop over ${typeof v === 'object' ? 'an object — use | entries' : `a ${typeof v}`}`,\n )\n }\n\n // ── attributes ────────────────────────────────────────────────────────\n\n /** A value for an attribute: text form, HTML-escaped. */\n private attrValue(v: unknown, inst: Inst): string {\n return escapeHtml(this.plain(v, inst))\n }\n\n /** A value's text, unescaped (trusted HTML as its source). */\n private plain(v: unknown, inst: Inst): string {\n return v instanceof SafeHtml ? v.html : this.text(v, inst)\n }\n\n /**\n * Values in `Resolved` are ready to write between double quotes: the\n * author's static text as written (entities kept), interpolated values\n * escaped once.\n */\n resolve(list: CAttr[], inst: Inst): Resolved {\n const r: Resolved = { attrs: [], cls: [], style: [] }\n const put = (name: string, value: string | true) => {\n const lower = name.toLowerCase()\n if (lower === 'class') {\n if (value !== true && value.trim()) r.cls.push(value.trim())\n } else if (lower === 'style') {\n if (value !== true && value.trim()) r.style.push(value.trim().replace(/;\\s*$/, ''))\n } else {\n r.attrs.push([name, value])\n }\n }\n for (const a of list) {\n switch (a.t) {\n case 's':\n put(a.n, a.v === true ? true : a.v.replace(/\"/g, '&quot;'))\n break\n case 'i': {\n const values = a.p.map((p) => (typeof p === 'string' ? undefined : this.value(p, inst)))\n const html = a.p\n .map((p, i) =>\n typeof p === 'string' ? p.replace(/\"/g, '&quot;') : this.attrValue(values[i], inst),\n )\n .join('')\n if (!a.u) {\n put(a.n, html)\n break\n }\n // The scheme check reads what the browser will: the whole value as\n // written out, entities decoded — so a reference left unfinished in\n // static text (`&#10`) and completed by a value is read as one.\n const plain = decodeEntities(html)\n const safe = a.u === 'url' ? sanitizeUrl(plain) : sanitizeSrcset(plain)\n put(a.n, safe === plain ? html : escapeHtml(safe))\n break\n }\n case 'b': {\n const v = this.value(a.e, inst)\n if (v === null || v === undefined || v === false) break\n if (v === true) {\n put(a.n, true)\n break\n }\n const plain = this.plain(v, inst)\n put(\n a.n,\n escapeHtml(\n a.u === 'url' ? sanitizeUrl(plain) : a.u === 'srcset' ? sanitizeSrcset(plain) : plain,\n ),\n )\n break\n }\n case 'c':\n if (this.value(a.e, inst)) r.cls.push(escapeHtml(a.n))\n break\n case 'y': {\n const v = this.value(a.e, inst)\n if (v === null || v === undefined || v === false) break\n const value = safeStyleValue(`${this.text(v, inst)}${a.x ?? ''}`)\n if (value === undefined) {\n this.env.warn(\n `${inst.t.file}:${inst.at?.[0] ?? 1}: dropped an unsafe value for [style.${a.n}]`,\n )\n break\n }\n r.style.push(`${escapeHtml(a.n)}:${escapeHtml(value)}`)\n break\n }\n }\n }\n return r\n }\n\n private attrs(own: Resolved, fall?: Resolved): void {\n let attrs = own.attrs\n let cls = own.cls\n let style = own.style\n if (fall) {\n // The caller's attributes win over the root's own, except class and\n // style, which merge.\n const names = new Set(fall.attrs.map(([n]) => n.toLowerCase()))\n attrs = [...attrs.filter(([n]) => !names.has(n.toLowerCase())), ...fall.attrs]\n cls = [...cls, ...fall.cls]\n style = [...style, ...fall.style]\n }\n for (const [n, v] of attrs) this.out.push(v === true ? ` ${n}` : ` ${n}=\"${v}\"`)\n if (cls.length) this.out.push(` class=\"${cls.join(' ')}\"`)\n if (style.length) this.out.push(` style=\"${style.join(';')}\"`)\n }\n\n // ── components and layouts ────────────────────────────────────────────\n\n private component(n: Extract<CNode, { k: 'cmp' }>, caller: Inst): void {\n if (caller.depth >= MAX_DEPTH) {\n this.fail(caller, `components nest more than ${MAX_DEPTH} deep — is ${n.n} including itself?`)\n }\n const t = this.env.resolve(n.n)\n const slots: unknown[] = Array.from({ length: t.slots })\n for (const i of t.inputs) if (i.d !== undefined) slots[i.s] = i.d\n for (const i of n.in) slots[i.s] = this.value(i.e, caller)\n const fills: Inst['fills'] = {}\n for (const [name, nodes] of Object.entries(n.f)) fills[name] = { nodes, inst: caller }\n const inst: Inst = {\n t,\n data: Object.create(null),\n slots,\n fills,\n fall: this.resolve(n.fa, caller),\n stack: [...caller.stack, n.n],\n depth: caller.depth + 1,\n }\n this.nodes(t.body, inst)\n }\n}\n\nfunction loopVar(m: LoopMeta, w: LoopVar): unknown {\n switch (w) {\n case '$index':\n return m.i\n case '$first':\n return m.i === 0\n case '$last':\n return m.i === m.n - 1\n case '$even':\n return m.i % 2 === 0\n case '$odd':\n return m.i % 2 === 1\n case '$count':\n return m.n\n }\n}\n\n/**\n * Render a checked page with `data`. Its layouts wrap it, outermost last:\n * `opts.layout` (a name, or `false` for none), else the page's `@layout`, else\n * the environment's mapping — then the base layout around the outermost one.\n * `@layout(none)` and `layout: false` skip the base too.\n */\nexport function render(\n template: CheckedTemplate,\n data: object,\n env: RenderEnv,\n opts: { layout?: boolean | string } = {},\n): string {\n const r = new Renderer(env)\n const page: Inst = {\n t: template,\n data: data as Record<string, unknown>,\n slots: Array.from({ length: template.slots }),\n fills: {},\n stack: [template.name],\n depth: 0,\n }\n const none = opts.layout === false || (opts.layout === undefined && template.layout === null)\n const chain: CheckedTemplate[] = []\n if (!none) {\n let next =\n typeof opts.layout === 'string'\n ? opts.layout\n : (template.layout ?? env.layoutFor?.(template.name))\n while (next && next !== template.name && !chain.some((t) => t.name === next)) {\n const t = env.resolve(next)\n chain.push(t)\n next = t.layout ?? undefined\n }\n const base = env.baseLayout\n if (base && base !== template.name && !chain.some((t) => t.name === base))\n chain.push(env.resolve(base))\n }\n if (!chain.length) {\n r.nodes(template.body, page)\n return r.html()\n }\n // Each layout renders the one inside it into its default slot; named fills\n // pass outward until a layout's own fill replaces them.\n let fills: Inst['fills'] = { '': { nodes: template.body, inst: page } }\n for (const [name, nodes] of Object.entries(template.fills)) fills[name] = { nodes, inst: page }\n let inst: Inst = page\n for (const [i, t] of chain.entries()) {\n inst = {\n t,\n data: page.data,\n slots: Array.from({ length: t.slots }),\n fills,\n stack: [...inst.stack, t.name],\n depth: 0,\n }\n if (i === chain.length - 1) break\n const outer: Inst['fills'] = { ...fills, '': { nodes: t.body, inst } }\n for (const [name, nodes] of Object.entries(t.fills)) outer[name] = { nodes, inst }\n fills = outer\n }\n r.nodes(inst.t.body, inst)\n return r.html()\n}\n","/**\n * `createViews`: templates from a loader or a build's bundle, checked once\n * and cached, rendered with the app's pipes and shared data.\n */\nimport { AST_FORMAT_VERSION, type CheckedTemplate, type TemplateAst } from './ast'\nimport { error, type Diagnostic } from './diagnostics'\nimport { check } from './check/check'\nimport { layoutResolver, templateName, type Project } from './check/project'\nimport { parse } from './parse/template'\nimport { BUILTIN_PIPES } from './pipes/builtins'\nimport { pipesFor, type EnvPipe } from './pipes/env'\nimport { render, RenderError, type Pipe } from './render/render'\n\nexport interface Loader {\n /** Every template name (`users/show`, `components/user-card`). */\n list(): Promise<string[]>\n read(name: string): Promise<string>\n /** Changes when the source changes (an mtime); checked on every render in dev. */\n version?(name: string): Promise<number>\n}\n\n/** What a build emits: checked templates as data. */\nexport interface ViewsBundle {\n v: number\n templates: Record<string, CheckedTemplate>\n}\n\nexport interface RenderOptions {\n /** A layout for this render, or `false` for none at all (htmx and other partial responses). */\n layout?: boolean | string\n locale?: string\n timeZone?: string\n}\n\nexport interface ViewsOptions {\n /** Default `src/views`. */\n viewsDir?: string\n /** Default `components`, inside the views folder. */\n componentsDir?: string\n /** Default `src/views/pipes.ts`. Read when `pipes` isn't given and there is no bundle. */\n pipesFile?: string\n pipes?: Record<string, Pipe | EnvPipe>\n /**\n * The layout a page gets when it declares none: one name, or folder prefix →\n * layout (`{ admin: 'layouts/admin', '': 'layouts/main' }`; the longest prefix wins).\n */\n layout?: string | Record<string, string>\n /** The shell (CSS, assets, SEO tags) wrapped around every page's outermost layout. */\n baseLayout?: string\n /** Default `en-US`. */\n locale?: string\n /** Default `UTC`. */\n timeZone?: string\n /** Unresolved names and values that can't print become errors. */\n strict?: boolean\n /** Default `true`. `false` re-reads and re-checks on every render. */\n cache?: boolean\n /** Data every render gets, under the page's own: the current user, a CSP nonce. */\n share?: (ctx: unknown) => object | Promise<object>\n loader?: Loader\n /** Checked templates from the build (`virtual:kick-views`); `null` in dev. */\n bundle?: ViewsBundle | null\n /** Re-check templates whose source changed, on every render. */\n dev?: boolean\n /**\n * `@assets('entry')`: usually `(entry, data) => assetTags(entry, mode, data.cspNonce)`.\n * `data` is the page's data with shared data merged in.\n */\n assets?: (entry: string, data: Record<string, unknown>) => string\n warn?: (message: string) => void\n}\n\nexport interface Views {\n render(name: string, data?: object, opts?: RenderOptions & { ctx?: unknown }): Promise<string>\n /** Whether `name` is one of these views — `ctx.render` falls through to another engine when not. */\n has(name: string): Promise<boolean>\n}\n\nexport function bundleLoader(bundle: ViewsBundle): Loader {\n if (bundle.v !== AST_FORMAT_VERSION) {\n throw new Error(`views bundle format v${bundle.v}, this runtime reads v${AST_FORMAT_VERSION}`)\n }\n return {\n list: async () => Object.keys(bundle.templates),\n read: async () => {\n throw new Error('a bundled template has no source')\n },\n }\n}\n\ninterface State {\n project: Project\n /** Syntax errors from parsing, raised when the template is first used. */\n parseErrors: Map<string, Diagnostic>\n versions: Map<string, number>\n checked: Map<string, CheckedTemplate>\n}\n\ntype FileLoaderModule = typeof import('./loaders/file')\n\n/**\n * How `createViews` reaches the file loader when it's given neither a loader\n * nor a bundle. The Node entry sets it; the edge entry (`workerd`, `worker`,\n * `browser` conditions) doesn't, so an edge build never contains `node:fs`.\n */\nlet fileLoaderModule: (() => Promise<FileLoaderModule>) | undefined\n\nexport function useFileLoader(load: () => Promise<FileLoaderModule>): void {\n fileLoaderModule = load\n}\n\nfunction fileLoaders(): Promise<FileLoaderModule> {\n if (!fileLoaderModule) {\n return Promise.reject(\n new Error(\n \"createViews has no templates: pass the build's bundle (import kickViews from 'virtual:kick-views') or a loader\",\n ),\n )\n }\n return fileLoaderModule()\n}\n\nexport function createViews(options: ViewsOptions = {}): Views {\n const bundle = options.bundle ?? undefined\n if (bundle) bundleLoader(bundle) // version check\n const componentsDir = options.componentsDir ?? 'components'\n const layoutFor = layoutResolver(options.layout)\n const warn = options.warn ?? ((m: string) => console.warn(`[kick/view] ${m}`))\n let loader: Promise<Loader> | undefined\n let appPipes: Promise<Record<string, Pipe | EnvPipe>> | undefined\n let state: Promise<State> | undefined\n /**\n * A memoised promise forgets itself when it rejects: a load that failed\n * once (a file mid-save, too many open files) is retried on the next\n * render rather than failing every render after it.\n */\n const settle = <T>(p: Promise<T>, forget: () => void): Promise<T> =>\n p.catch((err: unknown) => {\n forget()\n throw err\n })\n\n const getLoader = (): Promise<Loader> =>\n (loader ??= settle(\n options.loader\n ? Promise.resolve(options.loader)\n : fileLoaders().then((m) => m.fileLoader(options.viewsDir ?? 'src/views')),\n () => (loader = undefined),\n ))\n\n const getPipes = (): Promise<Record<string, Pipe | EnvPipe>> =>\n (appPipes ??= settle(\n options.pipes || bundle\n ? Promise.resolve(options.pipes ?? {})\n : fileLoaders()\n .then((m) => m.loadPipesFile(options.pipesFile ?? 'src/views/pipes.ts'))\n .then((mod) => (mod ?? {}) as Record<string, Pipe | EnvPipe>),\n () => (appPipes = undefined),\n ))\n\n /** A fresh load, forgotten if it fails. */\n const reload = (): Promise<State> => (state = settle(load(), () => (state = undefined)))\n\n async function load(): Promise<State> {\n const l = await getLoader()\n const pipes = await getPipes()\n const names = await l.list()\n const templates = new Map<string, TemplateAst>()\n const versions = new Map<string, number>()\n const parseErrors = new Map<string, Diagnostic>()\n await Promise.all(\n names.map(async (name) => {\n const r = parse(await l.read(name), `${name}.kick`)\n templates.set(name, r.ast)\n const first = r.diagnostics.find((d) => d.severity === 'error')\n if (first) parseErrors.set(name, first)\n if (options.dev && l.version) versions.set(name, await l.version(name))\n }),\n )\n return {\n project: {\n templates,\n pipes: new Set([...BUILTIN_PIPES, ...Object.keys(pipes)]),\n componentsDir,\n layouts: options.layout,\n baseLayout: options.baseLayout,\n },\n versions,\n parseErrors,\n checked: new Map(),\n }\n }\n\n /** The current state, reloaded in dev when a source changed. */\n async function current(): Promise<State> {\n if (options.cache === false) return reload()\n const s = await (state ?? reload())\n if (!options.dev) return s\n const l = await getLoader()\n if (!l.version) return s\n const names = await l.list()\n const stale =\n names.length !== s.project.templates.size ||\n (await Promise.all(names.map(async (n) => (await l.version!(n)) !== s.versions.get(n)))).some(\n Boolean,\n )\n if (!stale) return s\n return reload()\n }\n\n function checked(s: State, name: string): CheckedTemplate {\n let t = s.checked.get(name)\n if (t) return t\n const syntax = s.parseErrors.get(name)\n if (syntax) throw new RenderError(syntax)\n const r = check(name, s.project)\n if (!r.template) {\n const d = r.diagnostics.find((x) => x.severity === 'error')!\n throw new RenderError(d)\n }\n for (const w of r.diagnostics) {\n warn(`${w.file}:${w.span.start.line}:${w.span.start.column} — ${w.message}`)\n }\n t = r.template\n s.checked.set(name, t)\n return t\n }\n\n async function has(name: string): Promise<boolean> {\n if (!templateName(name)) return false\n if (bundle) return Object.hasOwn(bundle.templates, name)\n return (await current()).project.templates.has(name)\n }\n\n return {\n has,\n async render(name, data = {}, opts = {}) {\n if (!templateName(name)) throw new Error(`invalid template name '${name}'`)\n if (!(await has(name))) throw new Error(`template '${name}' not found`)\n const resolve = bundle\n ? (n: string) => {\n const t = Object.hasOwn(bundle.templates, n) ? bundle.templates[n] : undefined\n if (!t) throw new RenderError(error(`${n}.kick`, zeroSpan, `template '${n}' not found`))\n return t\n }\n : await current().then((s) => (n: string) => checked(s, n))\n const template = resolve(name)\n const shared = options.share ? await options.share(opts.ctx) : {}\n const locale = opts.locale ?? options.locale ?? 'en-US'\n const timeZone = opts.timeZone ?? options.timeZone ?? 'UTC'\n return render(\n template,\n { ...shared, ...data },\n {\n locale,\n timeZone,\n strict: options.strict ?? false,\n pipes: pipesFor(await getPipes(), { locale, timeZone }),\n warn,\n resolve,\n layoutFor,\n baseLayout: options.baseLayout,\n assets: options.assets,\n },\n { layout: opts.layout },\n )\n },\n }\n}\n\nconst zeroSpan = {\n start: { offset: 0, line: 1, column: 1 },\n end: { offset: 0, line: 1, column: 1 },\n}\n","/**\n * `KickView`: makes `ctx.render()` render `.kick` templates on every\n * runtime. It binds a renderer onto each request through the slot core reads\n * (`Symbol.for('kickjs.viewRenderer')`), so this module never imports\n * `@forinda/kickjs` at runtime — it stays edge-safe.\n */\nimport { createViews, type Views, type ViewsOptions } from './views'\n\nconst VIEW_RENDERER = Symbol.for('kickjs.viewRenderer')\n\ntype Next = (err?: unknown) => void\n\n/** What `ctx.render` passes a bound renderer. Mirrors core's `ViewRenderOptions`. */\ninterface ViewRenderOptions {\n status?: number\n headers?: Record<string, string>\n layout?: boolean | string\n locale?: string\n timeZone?: string\n}\n\ntype Renderer = (\n name: string,\n data: Record<string, unknown>,\n opts: ViewRenderOptions,\n ctx: unknown,\n) => Promise<string | undefined>\n\nfunction rendererFor(views: Views): Renderer {\n return async (name, data, opts, ctx) =>\n (await views.has(name))\n ? views.render(name, data, {\n layout: opts.layout,\n locale: opts.locale,\n timeZone: opts.timeZone,\n ctx,\n })\n : undefined\n}\n\n/** Connect middleware binding `views` to each request (what the adapter mounts). */\nfunction bindViews(views: Views): (req: object, res: unknown, next: Next) => void {\n const renderer = rendererFor(views)\n return (req, _res, next) => {\n ;(req as Record<symbol, unknown>)[VIEW_RENDERER] = renderer\n next()\n }\n}\n\n/**\n * The web fetch entry's middleware (`createWebApp({ middlewares: [viewsMiddleware(views)] })`),\n * which takes `(ctx, next)` middleware rather than adapters.\n */\nexport function viewsMiddleware(\n views: Views,\n): (ctx: { req: object }, next: () => unknown) => unknown {\n const renderer = rendererFor(views)\n return (ctx, next) => {\n ;(ctx.req as Record<symbol, unknown>)[VIEW_RENDERER] = renderer\n return next()\n }\n}\n\nexport interface KickViewOptions extends ViewsOptions {\n /** A views instance to use — share it with error pages and emails. */\n views?: Views\n}\n\n/**\n * The `.kick` view engine for `bootstrap({ adapters })`.\n *\n * ```ts\n * const views = createViews({ layout: 'layouts/main' })\n * bootstrap({ modules, adapters: [KickView({ views })] })\n * // in a controller\n * await ctx.render('users/show', { user })\n * ```\n */\n/**\n * Re-check templates on every render only in development: NODE_ENV is\n * `development`, or the views come from `kick dev` (the virtual module hands\n * over `bundle: null` there). An unset NODE_ENV in production stays fast.\n */\nexport function kickViewDev(options: KickViewOptions, nodeEnv: string | undefined): boolean {\n return options.dev ?? (nodeEnv === 'development' || options.bundle === null)\n}\n\nexport function KickView(options: KickViewOptions = {}) {\n const views =\n options.views ??\n createViews({ ...options, dev: kickViewDev(options, globalThis.process?.env?.NODE_ENV) })\n const handler = bindViews(views)\n return {\n name: 'KickView',\n views,\n // Before any other middleware, so error pages and early answers can render too.\n middleware: () => [{ handler, phase: 'beforeGlobal' as const }],\n }\n}\n","/**\n * `@assets('src/client/main.ts')`: the tags a page needs for a Vite entry —\n * the dev client and module in dev, the hashed files from the build's\n * manifest in production.\n */\nimport { escapeHtml } from './render/safe'\n\nexport interface ViteManifestChunk {\n file: string\n css?: string[]\n imports?: string[]\n isEntry?: boolean\n}\n\nexport type ViteManifest = Record<string, ViteManifestChunk>\n\nexport type AssetsMode =\n | { dev: true; base: string }\n | { dev: false; manifest: ViteManifest; base: string }\n\nexport function assetTags(entry: string, mode: AssetsMode, nonce?: string): string {\n const base = mode.base.endsWith('/') ? mode.base : `${mode.base}/`\n const n = nonce ? ` nonce=\"${escapeHtml(nonce)}\"` : ''\n const url = (file: string) => escapeHtml(`${base}${file.replace(/^\\//, '')}`)\n if (mode.dev) {\n return [\n `<script type=\"module\"${n} src=\"${url('@vite/client')}\"></script>`,\n `<script type=\"module\"${n} src=\"${url(entry)}\"></script>`,\n ].join('\\n')\n }\n const chunk = mode.manifest[entry]\n if (!chunk) throw new Error(`@assets: '${entry}' isn't an entry in the Vite manifest`)\n const css = new Set<string>(chunk.css ?? [])\n const preload = new Set<string>()\n const walk = (key: string) => {\n const c = mode.manifest[key]\n if (!c || preload.has(c.file)) return\n preload.add(c.file)\n for (const s of c.css ?? []) css.add(s)\n for (const i of c.imports ?? []) walk(i)\n }\n for (const i of chunk.imports ?? []) walk(i)\n return [\n ...[...css].map((f) => `<link rel=\"stylesheet\"${n} href=\"${url(f)}\">`),\n ...[...preload].map((f) => `<link rel=\"modulepreload\"${n} href=\"${url(f)}\">`),\n `<script type=\"module\"${n} src=\"${url(chunk.file)}\"></script>`,\n ].join('\\n')\n}\n"],"mappings":"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"}
@@ -1,18 +0,0 @@
1
- /**
2
- * @forinda/kickjs-view v0.1.0
3
- *
4
- * Copyright (c) Felix Orinda
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- import{C as warning,d as parse}from"./read-exports-CtiwXL4e.js";const RAW=/* @__PURE__ */ new Set([`pre`,`textarea`,`script`,`style`]),VOID=new Set(`area base br col embed hr img input link meta param source track wbr`.split(` `)),HEADS=/@(else\s+if|if|for|switch|case|slot|layout|assets)\s*\(/y,DIRECTIVES=/* @__PURE__ */ new Set([`slot`,`layout`,`assets`]);function rawRanges(source,body){let ranges=[],stack=[body];for(;stack.length;)for(let n of stack.pop())if(n.k===`verbatim`||n.k===`comment`)ranges.push([n.span.start.offset,n.span.end.offset]);else if(n.k===`element`){let tag=n.tag.toLowerCase();if(RAW.has(tag)&&!n.selfClosing){let from=n.children.at(-1)?.span.end.offset??n.span.end.offset,close=source.toLowerCase().indexOf(`</${tag}`,from),end=close<0?source.length:source.indexOf(`>`,close)+1;ranges.push([n.span.start.offset,end])}else stack.push(n.children)}else if(n.k===`if`)for(let b of n.branches)stack.push(b.body);else n.k===`for`?stack.push(n.body,n.empty??[]):n.k===`switch`?stack.push(...n.cases.map(c=>c.body),n.default??[]):n.k===`slot-outlet`?stack.push(n.fallback):n.k===`slot-fill`&&stack.push(n.body);for(let m of source.matchAll(/\{\{--[\s\S]*?--\}\}/g))ranges.push([m.index,m.index+m[0].length]);return ranges.toSorted((a,b)=>a[0]-b[0])}function normalise(text){let s=text.replace(/\{\{(?!--)([\s\S]*?)\}\}/g,(_,inner)=>`{{ ${inner.trim()} }}`);s=s.replace(/\}[ \t]*@(else|empty)\b/g,`} @$1`),s=s.replace(/@(else|empty|default)[ \t]*\{/g,`@$1 {`);let out=``,i=0;for(;i<s.length;){HEADS.lastIndex=i;let at=s.indexOf(`@`,i);if(at<0)break;HEADS.lastIndex=at;let m=HEADS.exec(s);if(!m){out+=s.slice(i,at+1),i=at+1;continue}let kw=m[1].replace(/\s+/g,` `);out+=s.slice(i,at)+(DIRECTIVES.has(kw)?`@${kw}(`:`@${kw} (`);let depth=1,j=at+m[0].length,quote=``;for(;j<s.length&&depth>0;j++){let c=s[j];quote?c===`\\`?j++:c===quote&&(quote=``):c===`'`||c===`"`?quote=c:c===`(`?depth++:c===`)`&&depth--}out+=`${s.slice(at+m[0].length,j-1).trim()})`;let brace=/^[ \t]*\{/.exec(s.slice(j));brace&&(out+=` {`,j+=brace[0].length),i=j}return out+s.slice(i)}function outside(source,ranges,fn){let out=``,at=0;for(let[a,b]of ranges)a<at||(out+=fn(source.slice(at,a))+source.slice(a,b),at=b);return out+fn(source.slice(at))}const TOKENS=/<\/([A-Za-z][\w:.-]*)\s*>|<([A-Za-z][\w:.-]*)(?:[^>"']|"[^"]*"|'[^']*')*?(\/?)>|@(?:if|for|switch|case|slot|else|empty|default)\b[^{}\n]*\{|\}/g;function reindent(source,ranges,unit){let stack=[],lines=source.split(`
12
- `),offset=0,out=[];for(let raw of lines){let start=offset;if(offset+=raw.length+1,ranges.some(([a,b])=>start>a&&start<b)){out.push(raw);continue}let line=raw;for(let[a,b]of ranges){let from=Math.max(a,start)-start,to=Math.min(b,start+raw.length)-start;from<to&&(line=line.slice(0,from)+`\0`.repeat(to-from)+line.slice(to))}line=line.replace(/\{\{[\s\S]*?\}\}/g,m=>`\0`.repeat(m.length));let content=raw.trim();if(!content){out.push(``);continue}let leading=!0,depthForLine=stack.length;TOKENS.lastIndex=0;let m,last=0;for(;m=TOKENS.exec(line);){line.slice(last,m.index).trim()&&(leading=!1),last=m.index+m[0].length;let[tok,closeTag,openTag,selfClose]=m,closed=!1;if(tok===`}`){let i=stack.lastIndexOf(`{`);i>=0&&(stack.length=i,closed=!0)}else if(closeTag){let i=stack.lastIndexOf(`<${closeTag.toLowerCase()}`);i>=0&&(stack.length=i,closed=!0)}else if(openTag){let tag=openTag.toLowerCase();!selfClose&&!VOID.has(tag)&&!RAW.has(tag)&&stack.push(`<${tag}`)}else stack.push(`{`);leading&&closed&&(depthForLine=stack.length),closed||(leading=!1)}out.push(unit.repeat(Math.max(0,depthForLine))+content)}return out.join(`
13
- `)}const CHILD_KEYS=/* @__PURE__ */ new Set([`children`,`body`,`empty`,`default`,`fallback`]);function childLists(n){switch(n.k){case`element`:case`comment`:return[n.children];case`if`:return n.branches.map(b=>b.body);case`for`:return[n.body,n.empty??[]];case`switch`:return[...n.cases.map(c=>c.body),n.default??[]];case`slot-outlet`:return[n.fallback];case`slot-fill`:return[n.body];default:return[]}}function shape(nodes){let out=[],stack=nodes.toReversed();for(;stack.length;){let n=stack.pop();if(typeof n==`string`)out.push(n);else if(n.k===`text`){let v=n.value.replace(/\s+/g,` `).trim();v&&out.push(`t:${v}`)}else{out.push(JSON.stringify(n,(k,v)=>k===`span`||CHILD_KEYS.has(k)?void 0:v));for(let list of childLists(n).toReversed()){stack.push(`)`);for(let c of list.toReversed())stack.push(c);stack.push(`(`)}}}return out}function format(source,file,opts={}){let before=parse(source,file);if(before.diagnostics.some(d=>d.severity===`error`))return{diagnostics:before.diagnostics};let unit=` `.repeat(opts.indent??2),normalised=outside(source,rawRanges(source,before.ast.body),normalise),mid=parse(normalised,file),output=normalised;mid.diagnostics.some(d=>d.severity===`error`)||(output=reindent(normalised,rawRanges(normalised,mid.ast.body),unit)),output.endsWith(`
14
- `)||(output+=`
15
- `);let after=parse(output,file);if(after.diagnostics.some(d=>d.severity===`error`)||shape(after.ast.body).join(`
16
- `)!==shape(before.ast.body).join(`
17
- `)||after.ast.layout!==before.ast.layout){let pos={offset:0,line:1,column:1};return{output:source,diagnostics:[warning(file,{start:pos,end:pos},`left unformatted: formatting would have changed more than whitespace`)]}}return{output,diagnostics:[]}}export{format as t};
18
- //# sourceMappingURL=format-BVAljUk8.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format-BVAljUk8.js","names":[],"sources":["../src/format.ts"],"sourcesContent":["/**\n * `format`: tidy a `.kick` source — `{{ x }}` and `@if (x) {` spacing, and\n * indentation by block and element nesting. Raw regions (`<pre>`,\n * `<textarea>`, `<script>`, `<style>`, `@verbatim`, comments) are left\n * byte-exact. The result is re-parsed and compared with the original;\n * anything beyond whitespace changing returns the source untouched.\n */\nimport type { Element, Node } from './ast'\nimport { warning, type Diagnostic } from './diagnostics'\nimport { parse } from './parse/template'\n\nexport interface FormatOptions {\n /** Spaces per level. Default 2. */\n indent?: number\n}\n\nconst RAW = new Set(['pre', 'textarea', 'script', 'style'])\nconst VOID = new Set(\n 'area base br col embed hr img input link meta param source track wbr'.split(' '),\n)\n/** Block heads: control flow is spaced (`@if (a) {`), directives aren't (`@layout('x')`). */\nconst HEADS = /@(else\\s+if|if|for|switch|case|slot|layout|assets)\\s*\\(/y\nconst DIRECTIVES = new Set(['slot', 'layout', 'assets'])\n\ntype Range = [number, number]\n\n/** Source ranges formatting must not touch. */\nfunction rawRanges(source: string, body: Node[]): Range[] {\n const ranges: Range[] = []\n const stack: Node[][] = [body]\n while (stack.length) {\n for (const n of stack.pop()!) {\n if (n.k === 'verbatim' || n.k === 'comment') {\n ranges.push([n.span.start.offset, n.span.end.offset])\n } else if (n.k === 'element') {\n const tag = n.tag.toLowerCase()\n if (RAW.has(tag) && !n.selfClosing) {\n const from = n.children.at(-1)?.span.end.offset ?? n.span.end.offset\n const close = source.toLowerCase().indexOf(`</${tag}`, from)\n const end = close < 0 ? source.length : source.indexOf('>', close) + 1\n ranges.push([n.span.start.offset, end])\n } else stack.push(n.children)\n } else if (n.k === 'if') for (const b of n.branches) stack.push(b.body)\n else if (n.k === 'for') stack.push(n.body, n.empty ?? [])\n else if (n.k === 'switch') stack.push(...n.cases.map((c) => c.body), n.default ?? [])\n else if (n.k === 'slot-outlet') stack.push(n.fallback)\n else if (n.k === 'slot-fill') stack.push(n.body)\n }\n }\n for (const m of source.matchAll(/\\{\\{--[\\s\\S]*?--\\}\\}/g))\n ranges.push([m.index, m.index + m[0].length])\n return ranges.toSorted((a, b) => a[0] - b[0])\n}\n\n/** `{{x}}` → `{{ x }}`, `@if(a){` → `@if (a) {`, `}@else{` → `} @else {`. */\nfunction normalise(text: string): string {\n let s = text.replace(/\\{\\{(?!--)([\\s\\S]*?)\\}\\}/g, (_, inner: string) => `{{ ${inner.trim()} }}`)\n s = s.replace(/\\}[ \\t]*@(else|empty)\\b/g, '} @$1')\n s = s.replace(/@(else|empty|default)[ \\t]*\\{/g, '@$1 {')\n // `@kw(` → `@kw (`, and `) {` after the balanced header.\n let out = ''\n let i = 0\n while (i < s.length) {\n HEADS.lastIndex = i\n const at = s.indexOf('@', i)\n if (at < 0) break\n HEADS.lastIndex = at\n const m = HEADS.exec(s)\n if (!m) {\n out += s.slice(i, at + 1)\n i = at + 1\n continue\n }\n const kw = m[1]!.replace(/\\s+/g, ' ')\n out += s.slice(i, at) + (DIRECTIVES.has(kw) ? `@${kw}(` : `@${kw} (`)\n let depth = 1\n let j = at + m[0].length\n let quote = ''\n for (; j < s.length && depth > 0; j++) {\n const c = s[j]!\n if (quote) {\n if (c === '\\\\') j++\n else if (c === quote) quote = ''\n } else if (c === \"'\" || c === '\"') quote = c\n else if (c === '(') depth++\n else if (c === ')') depth--\n }\n // The header's own text, trimmed inside the parentheses.\n out += `${s.slice(at + m[0].length, j - 1).trim()})`\n const brace = /^[ \\t]*\\{/.exec(s.slice(j))\n if (brace) {\n out += ' {'\n j += brace[0].length\n }\n i = j\n }\n return out + s.slice(i)\n}\n\n/** Apply `fn` to the parts of `source` outside `ranges`. */\nfunction outside(source: string, ranges: Range[], fn: (s: string) => string): string {\n let out = ''\n let at = 0\n for (const [a, b] of ranges) {\n if (a < at) continue\n out += fn(source.slice(at, a)) + source.slice(a, b)\n at = b\n }\n return out + fn(source.slice(at))\n}\n\nconst TOKENS =\n /<\\/([A-Za-z][\\w:.-]*)\\s*>|<([A-Za-z][\\w:.-]*)(?:[^>\"']|\"[^\"]*\"|'[^']*')*?(\\/?)>|@(?:if|for|switch|case|slot|else|empty|default)\\b[^{}\\n]*\\{|\\}/g\n\n/** Re-indent lines by the blocks and elements open at their start. */\nfunction reindent(source: string, ranges: Range[], unit: string): string {\n const stack: string[] = []\n const lines = source.split('\\n')\n let offset = 0\n const out: string[] = []\n for (const raw of lines) {\n const start = offset\n offset += raw.length + 1\n const inside = ranges.some(([a, b]) => start > a && start < b)\n if (inside) {\n out.push(raw)\n continue\n }\n // Mask raw regions on this line so their content isn't read as structure.\n let line = raw\n for (const [a, b] of ranges) {\n const from = Math.max(a, start) - start\n const to = Math.min(b, start + raw.length) - start\n if (from < to) line = line.slice(0, from) + '\\u0000'.repeat(to - from) + line.slice(to)\n }\n line = line.replace(/\\{\\{[\\s\\S]*?\\}\\}/g, (m) => '\\u0000'.repeat(m.length))\n const content = raw.trim()\n if (!content) {\n out.push('')\n continue\n }\n let leading = true\n let depthForLine = stack.length\n TOKENS.lastIndex = 0\n let m: RegExpExecArray | null\n let last = 0\n while ((m = TOKENS.exec(line))) {\n if (line.slice(last, m.index).trim()) leading = false\n last = m.index + m[0].length\n const [tok, closeTag, openTag, selfClose] = m\n let closed = false\n if (tok === '}') {\n const i = stack.lastIndexOf('{')\n if (i >= 0) {\n stack.length = i\n closed = true\n }\n } else if (closeTag) {\n const i = stack.lastIndexOf(`<${closeTag.toLowerCase()}`)\n if (i >= 0) {\n stack.length = i\n closed = true\n }\n } else if (openTag) {\n const tag = openTag.toLowerCase()\n if (!selfClose && !VOID.has(tag) && !RAW.has(tag)) stack.push(`<${tag}`)\n } else {\n stack.push('{')\n }\n if (leading && closed) depthForLine = stack.length\n if (!closed) leading = false\n }\n out.push(unit.repeat(Math.max(0, depthForLine)) + content)\n }\n return out.join('\\n')\n}\n\n/** Keys holding child nodes: walked separately, so the shape is built without recursion. */\nconst CHILD_KEYS = new Set(['children', 'body', 'empty', 'default', 'fallback'])\n\nfunction childLists(n: Node): Node[][] {\n switch (n.k) {\n case 'element':\n case 'comment':\n return [n.children]\n case 'if':\n return n.branches.map((b) => b.body)\n case 'for':\n return [n.body, n.empty ?? []]\n case 'switch':\n return [...n.cases.map((c) => c.body), n.default ?? []]\n case 'slot-outlet':\n return [n.fallback]\n case 'slot-fill':\n return [n.body]\n default:\n return []\n }\n}\n\n/** The tree as a flat token list, with whitespace-only text differences removed. */\nfunction shape(nodes: Node[]): string[] {\n const out: string[] = []\n const stack: Array<Node | string> = nodes.toReversed()\n while (stack.length) {\n const n = stack.pop()!\n if (typeof n === 'string') {\n out.push(n)\n continue\n }\n if (n.k === 'text') {\n const v = n.value.replace(/\\s+/g, ' ').trim()\n if (v) out.push(`t:${v}`)\n continue\n }\n out.push(\n JSON.stringify(n, (k, v: unknown) => (k === 'span' || CHILD_KEYS.has(k) ? undefined : v)),\n )\n for (const list of childLists(n).toReversed()) {\n stack.push(')')\n for (const c of list.toReversed()) stack.push(c)\n stack.push('(')\n }\n }\n return out\n}\n\nexport function format(\n source: string,\n file: string,\n opts: FormatOptions = {},\n): { output?: string; diagnostics: Diagnostic[] } {\n const before = parse(source, file)\n if (before.diagnostics.some((d) => d.severity === 'error'))\n return { diagnostics: before.diagnostics }\n const unit = ' '.repeat(opts.indent ?? 2)\n const normalised = outside(source, rawRanges(source, before.ast.body), normalise)\n const mid = parse(normalised, file)\n let output = normalised\n if (!mid.diagnostics.some((d) => d.severity === 'error')) {\n output = reindent(normalised, rawRanges(normalised, mid.ast.body), unit)\n }\n if (!output.endsWith('\\n')) output += '\\n'\n const after = parse(output, file)\n const same =\n !after.diagnostics.some((d) => d.severity === 'error') &&\n shape(after.ast.body).join('\\n') === shape(before.ast.body).join('\\n') &&\n after.ast.layout === before.ast.layout\n if (!same) {\n const pos = { offset: 0, line: 1, column: 1 }\n return {\n output: source,\n diagnostics: [\n warning(\n file,\n { start: pos, end: pos },\n 'left unformatted: formatting would have changed more than whitespace',\n ),\n ],\n }\n }\n return { output, diagnostics: [] }\n}\n\nexport type { Element }\n"],"mappings":"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"}
@@ -1,19 +0,0 @@
1
- /**
2
- * @forinda/kickjs-view v0.1.0
3
- *
4
- * Copyright (c) Felix Orinda
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- const AST_FORMAT_VERSION=1;function advance(base,text,upTo){let{line,column}=base;for(let i=0;i<upTo;i++){let c=text.charCodeAt(i);c===10?(line++,column=1):c===13?text.charCodeAt(i+1)!==10&&(line++,column=1):column++}return{offset:base.offset+upTo,line,column}}const START={offset:0,line:1,column:1},positionAt=(source,offset)=>advance(START,source,offset),error=(file,span,message)=>({file,span,message,severity:`error`}),warning=(file,span,message)=>({file,span,message,severity:`warning`}),NAMED={amp:`&`,lt:`<`,gt:`>`,quot:`"`,apos:`'`,nbsp:`\xA0`,colon:`:`,Tab:` `,NewLine:`
12
- `,sol:`/`,bsol:`\\`,period:`.`,comma:`,`,semi:`;`,equals:`=`,quest:`?`,num:`#`,excl:`!`,lpar:`(`,rpar:`)`,plus:`+`,hyphen:`-`,dash:`-`,copy:`©`,reg:`®`,trade:`™`,hellip:`…`,mdash:`—`,ndash:`–`,laquo:`«`,raquo:`»`};function decodeEntities(s){return s.includes(`&`)?s.replace(/&(?:#[xX]([0-9a-fA-F]+)|#(\d+)|([A-Za-z][A-Za-z0-9]*));?/g,(m,hex,dec,name)=>{if(hex!==void 0||dec!==void 0){let code=parseInt(hex??dec,hex===void 0?10:16);return code>0&&code<=1114111&&!(code>=55296&&code<=57343)?String.fromCodePoint(code):`�`}return Object.hasOwn(NAMED,name)&&m.endsWith(`;`)?NAMED[name]:m}):s}const URL_ATTRS=/* @__PURE__ */ new Set([`href`,`src`,`action`,`formaction`,`poster`,`cite`,`background`,`ping`,`xlink:href`,`srcset`]);function isUrlAttr(tag,attr){let name=attr.toLowerCase();return URL_ATTRS.has(name)||name===`data`&&tag.toLowerCase()===`object`}function layoutResolver(layouts){if(layouts===void 0)return()=>void 0;if(typeof layouts==`string`)return()=>layouts;let prefixes=Object.keys(layouts).toSorted((a,b)=>b.length-a.length);return page=>{let hit=prefixes.find(p=>p===``||page===p||page.startsWith(`${p}/`));return hit===void 0?void 0:layouts[hit]}}function configuredLayouts(project){let names=/* @__PURE__ */ new Set;if(typeof project.layouts==`string`)names.add(project.layouts);else if(project.layouts)for(let v of Object.values(project.layouts))names.add(v);return project.baseLayout&&names.add(project.baseLayout),names}const SEGMENT=/^[A-Za-z0-9_-]+$/;function templateName(name){if(typeof name==`string`&&name)return name.split(`/`).every(s=>SEGMENT.test(s))?name:void 0}function componentTag(name,componentsDir){return name.slice(componentsDir.length+1).split(`/`).join(`-`).toLowerCase()}const isComponent=(name,componentsDir)=>name.startsWith(`${componentsDir}/`);function optimize(nodes){let out=[];for(let n of nodes){let node=deep(n),last=out[out.length-1];if(node.k===`s`){if(!node.t)continue;if(last?.k===`s`){last.t+=node.t;continue}}out.push(node)}return out}function deep(n){switch(n.k){case`if`:return{...n,br:n.br.map(b=>({...b,b:optimize(b.b)}))};case`for`:return n.em?{...n,b:optimize(n.b),em:optimize(n.em)}:{...n,b:optimize(n.b)};case`sw`:return{...n,cs:n.cs.map(c=>({...c,b:optimize(c.b)})),...n.d?{d:optimize(n.d)}:{}};case`cmp`:return{...n,f:Object.fromEntries(Object.entries(n.f).map(([k,v])=>[k,optimize(v)]))};case`o`:return{...n,fb:optimize(n.fb)};case`s`:return{...n};default:return n}}const ANIMATION=/* @__PURE__ */ new Set([`animate`,`set`,`animatemotion`,`animatetransform`]),ANIMATION_VALUES=/* @__PURE__ */ new Set([`values`,`to`,`from`,`by`,`attributename`]),JSON_SCRIPT_TYPES=/* @__PURE__ */ new Set([`application/json`,`application/ld+json`]),LOOP_VARS$1=/* @__PURE__ */ new Set([`$index`,`$first`,`$last`,`$even`,`$odd`,`$count`]),isFallthrough=a=>{if(a.kind===`class`||a.kind===`style`)return!0;let n=a.name.toLowerCase();return[`class`,`id`,`style`,`role`].includes(n)||n.startsWith(`aria-`)||n.startsWith(`data-`)},camel=name=>name.replace(/-([a-z])/g,(_,c)=>c.toUpperCase());var Checker=class{project;ast;component;diagnostics=[];slots=0;scopes=[/* @__PURE__ */ new Map];loops=[];warned=/* @__PURE__ */ new Set;tags=/* @__PURE__ */ new Map;signatures=/* @__PURE__ */ new Map;constructor(project,ast,component){this.project=project,this.ast=ast,this.component=component;for(let name of project.templates.keys()){if(!isComponent(name,project.componentsDir))continue;let tag=componentTag(name,project.componentsDir);this.tags.set(tag,[...this.tags.get(tag)??[],name])}}err(span,message){this.diagnostics.push(error(this.ast.file,span,message))}warn(span,message){this.diagnostics.push(warning(this.ast.file,span,message))}slot(){return this.slots++}bind(name,b){this.scopes[this.scopes.length-1].set(name,b)}lookup(name){for(let i=this.scopes.length-1;i>=0;i--){let b=this.scopes[i].get(name);if(b)return b}}scoped(fn){this.scopes.push(/* @__PURE__ */ new Map);try{return fn()}finally{this.scopes.pop()}}expr(e,where=`text`,whole=!1){switch(e.kind){case`literal`:return{k:`l`,v:e.value};case`unary`:return{k:`u`,o:e.op,a:this.expr(e.arg)};case`binary`:case`logical`:return{k:`b`,o:e.op,l:this.expr(e.left),r:this.expr(e.right)};case`conditional`:return{k:`c`,t:this.expr(e.test),y:this.expr(e.whenTrue),n:this.expr(e.whenFalse)};case`pipe`:return this.project.pipes.has(e.name)||this.err(e.span,`unknown pipe '${e.name}'`),e.name===`raw`&&!(whole&&where===`text`)&&this.err(e.span,where===`attr`?`raw isn't allowed in an attribute: it could break out of the quotes`:where===`text`?`raw must be the last pipe of the whole {{ }}: {{ value | raw }}`:`raw isn't allowed inside <${where===`rcdata`?`title> or <textarea`:`script`}>`),{k:`p`,n:e.name,i:this.expr(e.input),a:e.args.map(a=>this.expr(a))};case`path`:{let p=e.segments.map(s=>{let seg=s.computed?{e:this.expr(s.computed)}:{n:s.name};return s.optional&&(seg.o=1),seg});if(LOOP_VARS$1.has(e.root)){let loop=this.loops[this.loops.length-1];return loop===void 0?(this.err(e.span,`${e.root} is only available inside @for`),{k:`x`}):{k:`m`,s:loop,w:e.root}}let b=this.lookup(e.root);return b?.kind===`meta`?{k:`m`,s:b.s,w:b.w}:b?{k:`v`,s:b.s,p}:this.component?(this.warned.has(e.root)||(this.warned.add(e.root),this.warn(e.span,`'${e.root}' isn't an input of this component — declare it with @input ${e.root}`)),{k:`x`}):{k:`d`,n:e.root,p}}}}nodes(list,parent){let out=[],stack=[{list,i:0,parent}];for(;stack.length;){let f=stack[stack.length-1];if(f.i>=f.list.length){stack.pop(),f.close&&out.push({k:`s`,t:f.close});continue}let n=f.list[f.i++];if(n.k!==`element`){this.node(n,out,f.parent);continue}let open=this.element(n,out);open&&stack.push({list:open.children,i:0,parent:open,close:`</${open.tag}>`})}return out}node(n,out,parent){switch(n.k){case`text`:out.push({k:`s`,t:n.value});return;case`interp`:if(n.ctx===`comment`){this.err(n.span,`{{ }} isn't allowed inside an HTML comment — use {{-- --}} for a template comment`);return}if(n.ctx===`raw-text`){out.push(...this.rawText(n,parent));return}out.push({k:`i`,c:n.ctx===`rcdata`?`rcdata`:`text`,e:this.expr(n.expr,n.ctx===`rcdata`?`rcdata`:`text`,!0),at:at(n.span)});return;case`comment`:for(let c of n.children)c.k===`interp`&&this.node(c,out);out.push({k:`s`,t:`<!--${n.children.map(c=>c.k===`text`?c.value:``).join(``)}-->`});return;case`element`:{let open=this.element(n,out);open&&out.push(...this.nodes(open.children,open),{k:`s`,t:`</${open.tag}>`});return}case`if`:out.push({k:`if`,br:n.branches.map(b=>this.scoped(()=>{let cond=b.cond&&this.expr(b.cond),alias;b.alias&&(alias=this.slot(),this.bind(b.alias,{kind:`slot`,s:alias}));let br={b:this.nodes(b.body,parent)};return cond&&(br.c=cond),alias!==void 0&&(br.a=alias),br}))});return;case`for`:{let e=this.expr(n.of),m=this.slot(),it,body=this.scoped(()=>{typeof n.item==`string`?(it=this.slot(),this.bind(n.item,{kind:`slot`,s:it})):(it=[this.slot(),this.slot()],this.bind(n.item[0],{kind:`slot`,s:it[0]}),this.bind(n.item[1],{kind:`slot`,s:it[1]}));for(let[name,w]of Object.entries(n.lets))this.bind(name,{kind:`meta`,s:m,w});this.loops.push(m);try{return this.nodes(n.body,parent)}finally{this.loops.pop()}}),node={k:`for`,e,it,m,b:body,at:at(n.span)};n.empty&&(node.em=this.scoped(()=>this.nodes(n.empty,parent))),out.push(node);return}case`switch`:{let node={k:`sw`,e:this.expr(n.on),cs:n.cases.map(c=>({e:this.expr(c.value),b:this.scoped(()=>this.nodes(c.body,parent))}))};n.default&&(node.d=this.scoped(()=>this.nodes(n.default,parent))),out.push(node);return}case`let`:{let e=this.expr(n.expr),s=this.slot();this.scopes[this.scopes.length-1].has(n.name)&&this.err(n.span,`@let ${n.name} is declared twice here`),this.bind(n.name,{kind:`slot`,s}),out.push({k:`let`,s,e});return}case`verbatim`:out.push({k:`s`,t:n.text});return;case`slot-outlet`:out.push({k:`o`,n:n.name??``,fb:this.scoped(()=>this.nodes(n.fallback,parent))});return;case`slot-fill`:this.err(n.span,`@slot('…') { } goes at the top of a page with a layout, or inside a component tag`);return;case`assets`:out.push({k:`as`,en:n.entry})}}rawText(n,parent){let tag=parent?.tag.toLowerCase(),type=parent?.attrs.find(a=>a.name.toLowerCase()===`type`),typeValue=type?.kind===`static`?String(type.parts?.[0]??``).trim().toLowerCase():``,isJson=tag===`script`&&JSON_SCRIPT_TYPES.has(typeValue),only=parent?.children.filter(c=>!(c.k===`text`&&!c.value.trim())).length===1;return isJson&&only&&n.expr.kind===`pipe`&&n.expr.name===`json`?[{k:`i`,c:`json`,e:this.expr(n.expr,`json`),at:at(n.span)}]:(this.err(n.span,tag===`script`?`{{ }} isn't allowed inside <script>: pass data as <script type="application/json">{{ value | json }}<\/script>`:`{{ }} isn't allowed inside <${tag}>`),[])}element(el,out){let lower=el.tag.toLowerCase();if(!el.foreign&&lower.includes(`-`)){let names=this.tags.get(lower);if(names&&names.length>1){this.err(el.span,`<${lower}> matches more than one component: ${names.join(`, `)}`);return}if(names){this.call(el,names[0],out);return}this.warn(el.span,`<${lower}> isn't a component (no ${this.project.componentsDir}/…/${lower}.kick) — it's output as a custom element`)}let attrs=this.attrs(el);if(attrs.some(a=>a.t!==`s`)||el===this.rootElement){out.push({k:`s`,t:`<${el.tag}`});let node={k:`A`,tag:el.tag,a:attrs,at:at(el.span)};el===this.rootElement&&(node.f=1),out.push(node)}else out.push({k:`s`,t:`<${el.tag}${attrs.map(a=>staticAttr(a)).join(``)}`});if(el.void||el.selfClosing&&el.foreign)out.push({k:`s`,t:el.selfClosing?` />`:`>`});else return out.push({k:`s`,t:`>`}),el}rootElement;attrs(el){let tag=el.tag,out=[],httpEquiv=el.attrs.find(a=>a.name.toLowerCase()===`http-equiv`),refresh=tag.toLowerCase()===`meta`&&httpEquiv?.kind===`static`&&String(httpEquiv.parts?.[0]).trim().toLowerCase()===`refresh`;for(let a of el.attrs){let lower=a.name.toLowerCase();if(a.kind!==`static`&&a.kind!==`bare`&&a.kind!==`class`&&a.kind!==`style`){if(lower.startsWith(`on`)){this.err(a.span,`${a.name} can't be interpolated: event handler attributes run their value as script`);continue}if(lower===`srcdoc`){this.err(a.span,`srcdoc can't be interpolated: its value is a whole HTML document`);continue}if(lower===`style`){this.err(a.span,`style can't be interpolated — bind one property with [style.prop]="value"`);continue}if(lower===`class`&&a.kind===`interp`){this.err(a.span,`class can't be interpolated — add classes with [class.name]="condition"`);continue}if(ANIMATION.has(tag.toLowerCase())&&ANIMATION_VALUES.has(lower)){this.err(a.span,`${a.name} can't be interpolated on <${tag}>: an animation can set href to a javascript: URL`);continue}if(refresh&&lower===`content`){this.err(a.span,`a refresh <meta>'s content can't be interpolated: it holds a URL to navigate to`);continue}}let url=isUrlAttr(tag,a.name)?lower===`srcset`?`srcset`:`url`:void 0;if(a.kind!==`bind`&&a.kind!==`class`&&a.kind!==`style`||a.expr)switch(a.kind){case`bare`:out.push({t:`s`,n:a.name,v:!0});break;case`static`:out.push({t:`s`,n:a.name,v:String(a.parts?.[0]??``)});break;case`interp`:{let node={t:`i`,n:a.name,p:a.parts.map(p=>typeof p==`string`?p:this.expr(p,`attr`))};url&&(node.u=url),out.push(node);break}case`bind`:{let node={t:`b`,n:a.name,e:this.expr(a.expr,`attr`)};url&&(node.u=url),out.push(node);break}case`class`:out.push({t:`c`,n:a.name,e:this.expr(a.expr,`attr`)});break;case`style`:{let node={t:`y`,n:a.name,e:this.expr(a.expr,`attr`)};a.unit&&(node.x=a.unit),out.push(node);break}}}return out}signature(name){let cached=this.signatures.get(name);if(cached)return cached;let ast=this.project.templates.get(name),outlets=/* @__PURE__ */ new Set,stack=[ast.body];for(;stack.length;)for(let n of stack.pop())if(n.k===`slot-outlet`)outlets.add(n.name??``),stack.push(n.fallback);else if(n.k===`element`||n.k===`comment`)stack.push(n.children);else if(n.k===`if`)for(let b of n.branches)stack.push(b.body);else n.k===`for`?stack.push(n.body,n.empty??[]):n.k===`switch`?stack.push(...n.cases.map(c=>c.body),n.default??[]):n.k===`slot-fill`&&stack.push(n.body);let sig={name,inputs:new Map(ast.inputs.map(i=>[i.name,{required:!i.default,def:i.default?.value}])),outlets,roots:rootElements(ast.body).length};return this.signatures.set(name,sig),sig}call(el,name,out){let sig=this.signature(name),target=this.project.templates.get(name),slotOf=/* @__PURE__ */ new Map;target.inputs.forEach((i,idx)=>slotOf.set(i.name,idx));let inputs=[],given=/* @__PURE__ */ new Set,fallthrough=[];for(let a of el.attrs){if(isFallthrough(a)){fallthrough.push(a);continue}let input=sig.inputs.has(a.name)?a.name:camel(a.name);if(!sig.inputs.has(input)){this.err(a.span,`unknown input '${a.name}' on <${el.tag}> — its inputs are ${[...sig.inputs.keys()].join(`, `)||`none`}`);continue}if(a.kind===`bind`&&!a.expr)continue;given.add(input);let e;if(a.kind===`bind`)e=this.expr(a.expr);else if(a.kind===`bare`)e={k:`l`,v:!0};else if(a.kind===`static`){let v=String(a.parts?.[0]??``);typeof sig.inputs.get(input).def==`boolean`&&(v===`true`||v===`false`)&&this.warn(a.span,`${a.name}="${v}" passes the string "${v}", which is truthy — write [${a.name}]="${v}"`),e={k:`l`,v:decodeEntities(v)}}else if(a.kind===`interp`)e=a.parts.reduce((acc,p)=>({k:`b`,o:`+`,l:acc,r:typeof p==`string`?{k:`l`,v:decodeEntities(p)}:this.expr(p)}),{k:`l`,v:``});else{this.err(a.span,`[${a.kind}.${a.name}] goes on the component's root element, not an input`);continue}inputs.push({s:slotOf.get(input),e})}for(let[input,info]of sig.inputs)info.required&&!given.has(input)&&this.err(el.span,`missing input '${input}' on <${el.tag}>`);fallthrough.length&&sig.roots!==1&&this.err(fallthrough[0].span,`<${el.tag}> passes ${fallthrough.map(a=>a.name).join(`, `)} to its root element, but ${name}.kick needs exactly one root element for that`);let fills={},rest=[];for(let c of el.children)c.k===`slot-fill`?(c.name in fills?this.err(c.span,`slot '${c.name}' is filled twice`):sig.outlets.has(c.name)||this.err(c.span,`<${el.tag}> has no slot '${c.name}'`),fills[c.name]=this.scoped(()=>this.nodes(c.body))):rest.push(c);rest.some(c=>!(c.k===`text`&&!c.value.trim()))&&(sig.outlets.has(``)?fills[``]=this.scoped(()=>this.nodes(rest)):this.err(el.span,`<${el.tag}> has no default <slot /> for the content inside it`));let fa=this.attrs({...el,attrs:fallthrough});out.push({k:`cmp`,n:name,in:inputs,fa,f:fills,at:at(el.span)})}layoutChain(start,span,page){let outlets=/* @__PURE__ */ new Set,seen=[page],name=start;for(;name;){if(!templateName(name)){this.err(span,`'${name}' isn't a valid template name`);return}if(seen.includes(name)){this.err(span,`layout cycle: ${[...seen,name].join(` → `)}`);return}let ast=this.project.templates.get(name);if(!ast){this.err(span,`layout '${name}' not found`);return}seen.push(name);for(let o of this.signature(name).outlets)outlets.add(o);name=ast.layout??void 0}return outlets}};function rootElements(body){let roots=[];for(let n of body)(n.k!==`text`||n.value.trim())&&n.k!==`comment`&&n.k!==`let`&&roots.push(n.k===`element`?n:null);return roots}function staticAttr(a){return a.v===!0?` ${a.n}`:` ${a.n}="${a.v.replace(/"/g,`&quot;`)}"`}const at=span=>[span.start.line,span.start.column],zero={start:{offset:0,line:1,column:1},end:{offset:0,line:1,column:1}};function check(name,project){let ast=project.templates.get(name);if(!ast||!templateName(name))return{diagnostics:[error(`${name}.kick`,zero,`template '${name}' not found`)]};let component=isComponent(name,project.componentsDir),c=new Checker(project,ast,component);if(!component&&ast.inputs.length)for(let i of ast.inputs)c.diagnostics.push(error(ast.file,i.span,`only components declare @input`));let inputs=ast.inputs.map((i,idx)=>{let s=idx,entry={n:i.name,s,r:!i.default};return i.default&&(entry.d=i.default.value),entry});c.slots=inputs.length;for(let i of inputs)c.bind(i.n,{kind:`slot`,s:i.s});if(component){let roots=rootElements(ast.body);roots.length===1&&roots[0]&&(c.rootElement=roots[0])}let fills={},body=[],fillNodes=[];for(let n of ast.body)n.k===`slot-fill`&&!component?fillNodes.push(n):body.push(n);let base=project.baseLayout;base!==void 0&&!project.templates.has(base)&&c.diagnostics.push(error(ast.file,zero,`base layout '${base}' not found`));let mapped=component||configuredLayouts(project).has(name)?void 0:layoutResolver(project.layouts)(name),layoutName=ast.layout===void 0?mapped:ast.layout??void 0,outlets=layoutName===void 0?void 0:c.layoutChain(layoutName,ast.layoutSpan??zero,name);base!==void 0&&ast.layout!==null&&!component&&name!==base&&project.templates.has(base)&&(outlets=/* @__PURE__ */ new Set([...outlets??[],...c.signature(base).outlets]));for(let f of fillNodes)f.name in fills?c.diagnostics.push(error(ast.file,f.span,`slot '${f.name}' is filled twice`)):outlets?outlets.has(f.name)?fills[f.name]=optimize(c.nodes(f.body)):c.diagnostics.push(error(ast.file,f.span,`the layout has no slot '${f.name}'`)):(c.diagnostics.push(warning(ast.file,f.span,`@slot('${f.name}') has no layout to fill here`)),fills[f.name]=optimize(c.nodes(f.body)));let template={v:1,name,file:ast.file,slots:0,inputs,fills,body:optimize(c.nodes(body))};return template.slots=c.slots,ast.layout!==void 0&&(template.layout=ast.layout),c.diagnostics.some(d=>d.severity===`error`)?{diagnostics:c.diagnostics}:{template,diagnostics:c.diagnostics}}const FORBIDDEN_NAMES=/* @__PURE__ */ new Set([`__proto__`,`constructor`,`prototype`,`__defineGetter__`,`__defineSetter__`,`__lookupGetter__`,`__lookupSetter__`]),KEYWORDS$1={new:`constructing objects`,typeof:"`typeof`",instanceof:"`instanceof`",in:"`in`",delete:"`delete`",void:"`void`",function:`functions`,class:`classes`,await:"`await`",yield:"`yield`",this:"`this`"},FORBIDDEN_PUNCT={"(":`calls`,"=":`assignment`,"=>":`functions`,"*":"`*`","/":"`/`","%":"`%`","`":`template literals`,"{":`object literals`,"}":"`}`","...":`spread`,";":"`;`",",":"`,`","&":"`&`","^":"`^`","~":"`~`"},PUNCT=/* @__PURE__ */ "=== !== ... ?. ?? == != <= >= && || => ? : | ! < > + - . [ ] ( ) = * / % ` { } ; , & ^ ~".split(` `);var Fail=class extends Error{start;end;constructor(start,end,message){super(message),this.start=start,this.end=end}};const ESCAPES={"\\":`\\`,"'":`'`,'"':`"`,n:`
13
- `,t:` `,r:`\r`};function tokenize(src){let out=[],i=0;for(;i<src.length;){let c=src[i];if(/\s/.test(c)){i++;continue}let start=i;if(/[A-Za-z_$]/.test(c)){for(;i<src.length&&/[\w$]/.test(src[i]);)i++;out.push({t:`ident`,v:src.slice(start,i),start,end:i});continue}if(/\d/.test(c)){for(;i<src.length&&/\d/.test(src[i]);)i++;if(src[i]===`.`&&/\d/.test(src[i+1]??``))for(i++;i<src.length&&/\d/.test(src[i]);)i++;out.push({t:`num`,v:Number(src.slice(start,i)),start,end:i});continue}if(c===`'`||c===`"`){let v=``;for(i++;i<src.length&&src[i]!==c;)if(src[i]===`\\`){let e=src[i+1]??``;if(e===`u`){let hex=src.slice(i+2,i+6);if(!/^[0-9a-fA-F]{4}$/.test(hex))throw new Fail(i,i+2,`a \\u escape needs four hex digits`);v+=String.fromCharCode(parseInt(hex,16)),i+=6;continue}if(!(e in ESCAPES))throw new Fail(i,i+2,`unknown escape \\${e}`);v+=ESCAPES[e],i+=2}else v+=src[i],i++;if(i>=src.length)throw new Fail(start,i,`unterminated string`);i++,out.push({t:`str`,v,start,end:i});continue}let p=PUNCT.find(op=>src.startsWith(op,i));if(!p)throw new Fail(i,i+1,`unexpected character '${c}'`);i+=p.length,out.push({t:`punct`,v:p,start,end:i})}return out.push({t:`eof`,v:``,start:src.length,end:src.length}),out}const BP={pipe:1,ternary:2,nullish:3,or:4,and:5,eq:6,rel:7,add:8,unary:9},BINARY={"??":[BP.nullish,`logical`],"||":[BP.or,`logical`],"&&":[BP.and,`logical`],"==":[BP.eq,`binary`],"!=":[BP.eq,`binary`],"===":[BP.eq,`binary`],"!==":[BP.eq,`binary`],"<":[BP.rel,`binary`],">":[BP.rel,`binary`],"<=":[BP.rel,`binary`],">=":[BP.rel,`binary`],"+":[BP.add,`binary`],"-":[BP.add,`binary`]};var Parser=class{src;base;tokens;i=0;constructor(src,base,tokens){this.src=src,this.base=base,this.tokens=tokens}peek(){return this.tokens[this.i]}next(){return this.tokens[this.i++]}span(start,end){return{start:advance(this.base,this.src,start),end:advance(this.base,this.src,end)}}isPunct(v){let t=this.peek();return t.t===`punct`&&t.v===v}expect(v){let t=this.peek();if(t.t!==`punct`||t.v!==v)throw new Fail(t.start,t.end,t.t===`eof`?`expected '${v}'`:`expected '${v}', found '${this.text(t)}'`);return this.next()}text(t){return this.src.slice(t.start,t.end)}forbidden(t){let what=t.t===`punct`?FORBIDDEN_PUNCT[t.v]:KEYWORDS$1[t.v];throw new Fail(t.start,t.end,`${what??`'${this.text(t)}'`} aren't allowed in templates`)}parseAll(){let e=this.expr(0),t=this.peek();if(t.t!==`eof`)throw(t.t===`punct`&&Object.hasOwn(FORBIDDEN_PUNCT,t.v)||t.t===`ident`&&Object.hasOwn(KEYWORDS$1,t.v))&&this.forbidden(t),new Fail(t.start,t.end,`unexpected '${this.text(t)}'`);return e}expr(min){let left=this.prefix();for(;;){let t=this.peek();if(t.t===`ident`&&(t.v===`in`||t.v===`instanceof`)&&this.forbidden(t),t.t!==`punct`)break;if(t.v===`|`){if(min>BP.pipe)break;this.next();let name=this.next();if(name.t!==`ident`)throw new Fail(name.start,name.end,`expected a pipe name after |`);let args=[];for(;this.isPunct(`:`);)if(this.next(),args.push(this.expr(BP.nullish)),this.isPunct(`?`)){let q=this.peek();throw new Fail(q.start,q.end,`wrap a conditional pipe argument in parentheses`)}left={kind:`pipe`,input:left,name:name.v,args,span:this.join(left,name.end)};continue}if(t.v===`?`){if(min>BP.ternary)break;this.next();let whenTrue=this.expr(BP.ternary);this.expect(`:`);let whenFalse=this.expr(BP.ternary);left={kind:`conditional`,test:left,whenTrue,whenFalse,span:this.joinExpr(left,whenFalse)};continue}let bin=BINARY[t.v];if(bin){let[bp,kind]=bin;if(bp<min)break;this.next();let right=this.expr(bp+1);left={kind,op:t.v,left,right,span:this.joinExpr(left,right)}}else{Object.hasOwn(FORBIDDEN_PUNCT,t.v)&&this.forbidden(t);break}}return left}join(left,end){return{start:left.span.start,end:advance(this.base,this.src,end)}}joinExpr(left,right){return{start:left.span.start,end:right.span.end}}prefix(){let t=this.next();switch(t.t){case`num`:return{kind:`literal`,value:t.v,span:this.span(t.start,t.end)};case`str`:return{kind:`literal`,value:t.v,span:this.span(t.start,t.end)};case`ident`:if(Object.hasOwn(KEYWORDS$1,t.v)&&this.forbidden(t),t.v===`true`||t.v===`false`)return{kind:`literal`,value:t.v===`true`,span:this.span(t.start,t.end)};if(t.v===`null`)return{kind:`literal`,value:null,span:this.span(t.start,t.end)};if(FORBIDDEN_NAMES.has(t.v))throw new Fail(t.start,t.end,`'${t.v}' is not allowed in templates`);return this.path(t);case`punct`:if(t.v===`!`||t.v===`-`){let arg=this.expr(BP.unary);return{kind:`unary`,op:t.v,arg,span:{start:this.span(t.start,t.end).start,end:arg.span.end}}}if(t.v===`(`){let e=this.expr(0);if(this.expect(`)`),this.isPunct(`.`)||this.isPunct(`[`)||this.isPunct(`?.`)){let m=this.peek();throw new Fail(m.start,m.end,`property access needs a name in front: (…).x is not allowed`)}return e}throw t.v===`[`?new Fail(t.start,t.end,`array literals aren't allowed in templates`):(Object.hasOwn(FORBIDDEN_PUNCT,t.v)&&this.forbidden(t),new Fail(t.start,t.end,`unexpected '${t.v}'`));case`eof`:throw new Fail(t.start,t.end,`expected an expression`)}}path(root){let segments=[],end=root.end;for(;;){let t=this.peek();if(t.t!==`punct`)break;if(t.v===`.`||t.v===`?.`){this.next();let optional=t.v===`?.`;if(optional&&this.isPunct(`[`)){this.next();let computed=this.expr(0);end=this.expect(`]`).end,segments.push({computed,optional});continue}optional&&this.isPunct(`(`)&&this.forbidden(this.peek());let name=this.next();if(name.t!==`ident`)throw new Fail(name.start,name.end,`expected a property name`);if(FORBIDDEN_NAMES.has(name.v))throw new Fail(name.start,name.end,`'${name.v}' is not allowed in templates`);segments.push({name:name.v,optional}),end=name.end}else if(t.v===`[`){this.next();let computed=this.expr(0);end=this.expect(`]`).end,segments.push({computed,optional:!1})}else{t.v===`(`&&this.forbidden(t);break}}return{kind:`path`,root:root.v,segments,span:this.span(root.start,end)}}};function parseExpression(src,file,base){try{return{expr:new Parser(src,base,tokenize(src)).parseAll(),diagnostics:[]}}catch(err){if(!(err instanceof Fail))throw err;let span={start:advance(base,src,err.start),end:advance(base,src,err.end)};return{diagnostics:[error(file,span,err.message)]}}}const VOID=new Set(`area base br col embed hr img input link meta param source track wbr`.split(` `)),RAW_TEXT=/* @__PURE__ */ new Set([`script`,`style`]),RCDATA=/* @__PURE__ */ new Set([`title`,`textarea`]),INTEGRATION_POINTS=/* @__PURE__ */ new Set([`foreignobject`,`desc`,`title`,`annotation-xml`]),KEYWORDS=/^@(if|else|for|empty|switch|case|default|let|layout|input|slot|verbatim|assets)(?![\w$-])/,LOOP_VARS=/* @__PURE__ */ new Set([`$index`,`$first`,`$last`,`$even`,`$odd`,`$count`]);var Fatal=class extends Error{},TemplateParser=class{s;file;i=0;text=``;textStart=0;seenOutput=!1;lineStarts=[0];diagnostics=[];ast;frames;constructor(s,file){this.s=s,this.file=file;for(let j=0;j<s.length;j++){let c=s.charCodeAt(j);(c===10||c===13&&s.charCodeAt(j+1)!==10)&&this.lineStarts.push(j+1)}this.ast={file,inputs:[],body:[]},this.frames=[{type:`root`,children:this.ast.body}]}pos(offset){let lo=0,hi=this.lineStarts.length-1;for(;lo<hi;){let mid=lo+hi+1>>1;this.lineStarts[mid]<=offset?lo=mid:hi=mid-1}return{offset,line:lo+1,column:offset-this.lineStarts[lo]+1}}span(start,end){return{start:this.pos(start),end:this.pos(end)}}err(start,end,message){this.diagnostics.push(error(this.file,this.span(start,end),message))}warn(start,end,message){this.diagnostics.push(warning(this.file,this.span(start,end),message))}fatal(start,end,message){throw this.err(start,end,message),new Fatal}expr(src,start){let r=parseExpression(src,this.file,this.pos(start));return this.diagnostics.push(...r.diagnostics),r.expr}get top(){return this.frames[this.frames.length-1]}children(){let f=this.top;return f.type===`switch`?[]:f.children}flush(){this.text&&=(/\S/.test(this.text)&&(this.seenOutput=!0),this.children().push({k:`text`,value:this.text,span:this.span(this.textStart,this.i)}),``)}emit(node){this.flush(),node.k!==`let`&&node.k!==`slot-fill`&&(this.seenOutput=!0),this.children().push(node)}addText(chunk,at){this.text||(this.textStart=at),this.text+=chunk}inPre(){return this.frames.some(f=>f.type===`element`&&f.name===`pre`)}standalone(tokenStart,tokenEnd){if(this.inPre())return tokenEnd;let a=tokenStart;for(;a>0&&(this.s[a-1]===` `||this.s[a-1]===` `);)a--;if(a>0&&this.s[a-1]!==`
14
- `&&this.s[a-1]!==`\r`)return tokenEnd;let b=tokenEnd;for(;b<this.s.length&&(this.s[b]===` `||this.s[b]===` `);)b++;if(b<this.s.length&&this.s[b]!==`
15
- `&&this.s[b]!==`\r`)return tokenEnd;let lead=tokenStart-a;return lead&&this.text.endsWith(this.s.slice(a,tokenStart))&&(this.text=this.text.slice(0,-lead)),this.s[b]===`\r`&&b++,this.s[b]===`
16
- `&&b++,b}run(){try{for(;this.i<this.s.length;)this.top.type===`switch`?this.switchBody():this.step();this.flush();for(let f of this.frames)(f.type===`block`||f.type===`switch`)&&this.err(f.start,f.start+1,`@${f.type===`block`?f.keyword:`switch`} is never closed — expected }`)}catch(e){if(!(e instanceof Fatal))throw e}}step(){let s=this.s,i=this.i,c=s[i];if(c===`{`&&s.startsWith(`{{--`,i)){let end=s.indexOf(`--}}`,i+4);end<0&&this.fatal(i,i+4,`template comment is never closed — expected --}}`),this.i=end+4}else if(c===`{`&&s[i+1]===`{`)this.interp(i,`text`);else{if(c===`<`){if(s.startsWith(`<!--`,i))return this.htmlComment(i);if(s[i+1]===`/`&&/[A-Za-z]/.test(s[i+2]??``))return this.closeTag(i);if(/[A-Za-z]/.test(s[i+1]??``))return this.openTag(i);s[i+1]===`{`&&this.fatal(i,i+2,`tag names can't be interpolated`)}if(c===`@`){let m=KEYWORDS.exec(s.slice(i,i+12));if(m&&this.block(m[1],i))return}c===`}`&&this.frames.some(f=>f.type===`block`)?this.closeBlock(i):(this.addText(c,i),this.i++)}}interpSource(i){let at=i+2,j=at,quote=``;for(;j<this.s.length;){let ch=this.s[j];if(quote)ch===`\\`?j++:ch===quote&&(quote=``);else if(ch===`'`||ch===`"`)quote=ch;else if(ch===`}`&&this.s[j+1]===`}`)return{src:this.s.slice(at,j),at,end:j+2};j++}this.fatal(i,i+2,`interpolation is never closed — expected }}`)}interp(i,ctx){let{src,at,end}=this.interpSource(i),expr=this.expr(src,at);expr&&this.emit({k:`interp`,expr,ctx,span:this.span(i,end)}),this.i=end}textWithInterps(from,stop,ctx){let out=[],j=from,start=from;for(;j<stop;)if(this.s.startsWith(`{{--`,j)){j>start&&out.push({k:`text`,value:this.s.slice(start,j),span:this.span(start,j)});let end=this.s.indexOf(`--}}`,j+4);j=start=end<0||end>stop?stop:end+4}else if(this.s.startsWith(`{{`,j)){j>start&&out.push({k:`text`,value:this.s.slice(start,j),span:this.span(start,j)});let{src,at,end}=this.interpSource(j),expr=this.expr(src,at);expr&&out.push({k:`interp`,expr,ctx,span:this.span(j,end)}),j=start=end}else j++;return stop>start&&out.push({k:`text`,value:this.s.slice(start,stop),span:this.span(start,stop)}),out}htmlComment(i){let end=this.s.indexOf(`-->`,i+4);end<0&&this.fatal(i,i+4,`HTML comment is never closed — expected -->`),this.emit({k:`comment`,children:this.textWithInterps(i+4,end,`comment`),span:this.span(i,end+3)}),this.i=end+3}openTag(i){let s=this.s,m=/^<([A-Za-z][\w:.-]*)/.exec(s.slice(i,i+200)),tag=m[1],j=i+m[0].length,parent=this.frames.findLast(f=>f.type===`element`),lower=tag.toLowerCase(),foreign=!!parent?.el.foreign&&!INTEGRATION_POINTS.has(parent.el.tag.toLowerCase())||lower===`svg`||lower===`math`,attrs=[],selfClosing=!1;for(;;){for(;j<s.length&&/\s/.test(s[j]);)j++;if(j>=s.length&&this.fatal(i,i+m[0].length,`<${tag}> is never closed — expected >`),s[j]===`>`){j++;break}if(s[j]===`/`&&s[j+1]===`>`){selfClosing=!0,j+=2;break}j=this.attr(j,attrs)}this.i=j;let name=foreign?tag:lower,el={k:`element`,tag,attrs,children:[],foreign,void:!foreign&&VOID.has(lower),selfClosing,span:this.span(i,j)};if(!foreign&&lower===`slot`){let nameAttr=attrs.find(a=>a.name===`name`),slotName=nameAttr?.kind===`static`?String(nameAttr.parts?.[0]??``):void 0;nameAttr&&nameAttr.kind!==`static`&&this.err(nameAttr.span.start.offset,nameAttr.span.end.offset,`a slot name must be plain text`);let node={k:`slot-outlet`,name:slotName,fallback:[],span:el.span};this.emit(node),selfClosing||this.frames.push({type:`slot`,children:node.fallback})}else if(this.emit(el),!(el.void||selfClosing)){if(RAW_TEXT.has(lower)||!foreign&&RCDATA.has(lower)){let end=RegExp(`</${lower}(?=[\\t\\n\\f\\r />])`,`i`);end.lastIndex=0;let found=end.exec(s.slice(j)),close=found?j+found.index:-1,stop=close<0?s.length:close;if(RAW_TEXT.has(lower)){let content=s.slice(j,stop);foreign&&content.includes(`<`)?this.err(j,stop,`markup isn't allowed inside <${lower}> in SVG or MathML — move the code to a separate file`):(/<!\[CDATA\[/i.test(content)||lower===`script`&&/<!--/.test(content)&&/<script/i.test(content))&&this.err(j,stop,`this <${lower}> content (<!-- with <script, or CDATA) is read differently by browsers — move it to a separate file`)}if(el.children=this.textWithInterps(j,stop,RAW_TEXT.has(lower)?`raw-text`:`rcdata`),close<0){this.i=s.length;return}let gt=s.indexOf(`>`,close);this.i=gt<0?s.length:gt+1}else this.frames.push({type:`element`,el,children:el.children,name})}}attr(j,attrs){let s=this.s,start=j;for(s.startsWith(`{{`,j)&&this.fatal(j,j+2,`attribute names can't be interpolated`);j<s.length&&!/[\s"'>/=]/.test(s[j]);)s.startsWith(`{{`,j)&&this.fatal(j,j+2,`attribute names can't be interpolated`),j++;j===start&&this.fatal(j,j+1,`unexpected '${s[j]}' in a tag`);let raw=s.slice(start,j),k=j;for(;k<s.length&&/[ \t]/.test(s[k]);)k++;if(s[k]!==`=`)return attrs.push(this.classify(raw,void 0,start,j,!1)),j;for(k++;k<s.length&&/\s/.test(s[k]);)k++;let q=s[k];if(q===`"`||q===`'`){let close=s.indexOf(q,k+1);return close<0&&this.fatal(start,k+1,`the value of ${raw} is never closed — expected ${q}`),attrs.push(this.classify(raw,{from:k+1,to:close},start,close+1,!0)),close+1}let e=k;for(;e<s.length&&!/[\s>]/.test(s[e]);)e++;return s.slice(k,e).includes(`{{`)&&this.fatal(k,e,`quote the value of ${raw}: an interpolated attribute must be in quotes`),attrs.push(this.classify(raw,{from:k,to:e},start,e,!1)),e}classify(raw,value,start,end,quoted){let span=this.span(start,end),binding=/^\[(?:(class)\.([\w-]+)|(style)\.([\w-]+)(?:\.(\w+))?|([^\]]+))\]$/.exec(raw);if(binding){value||this.fatal(start,end,`${raw} needs a value: ${raw}="expression"`);let src=this.s.slice(value.from,value.to);src.includes(`{{`)&&this.fatal(value.from,value.to,`${raw} takes an expression, without {{ }}`);let expr=this.expr(src,value.from),[,cls,clsName,sty,styName,unit,bind]=binding;return cls?{name:clsName,kind:`class`,expr,quoted,span}:sty?{name:styName,kind:`style`,expr,unit,quoted,span}:{name:bind,kind:`bind`,expr,quoted,span}}if(!value)return{name:raw,kind:`bare`,quoted:!1,span};let parts=[];for(let n of this.textWithInterps(value.from,value.to,`text`))n.k===`text`?parts.push(n.value):n.k===`interp`&&parts.push(n.expr);return{name:raw,kind:parts.some(p=>typeof p!=`string`)?`interp`:`static`,parts:parts.length?parts:[``],quoted,span}}closeTag(i){let m=/^<\/([A-Za-z][\w:.-]*)\s*>/.exec(this.s.slice(i,i+200));m||this.fatal(i,i+2,`malformed closing tag`),this.i=i+m[0].length;let tag=m[1];for(let f=this.frames.length-1;f>0;f--){let frame=this.frames[f];if(frame.type===`block`||frame.type===`switch`||frame.type===`root`)break;if(frame.type===`slot`?tag.toLowerCase()===`slot`:frame.el.foreign?frame.name===tag:frame.name===tag.toLowerCase()){this.flush(),this.frames.length=f;return}}this.warn(i,this.i,`</${tag}> closes nothing`)}parens(j,what){this.s[j]!==`(`&&this.fatal(j,j+1,`expected ( after ${what}`);let depth=0,quote=``;for(let k=j;k<this.s.length;k++){let ch=this.s[k];if(quote)ch===`\\`?k++:ch===quote&&(quote=``);else if(ch===`'`||ch===`"`)quote=ch;else if(ch===`(`)depth++;else if(ch===`)`&&--depth===0)return{src:this.s.slice(j+1,k),at:j+1,end:k+1}}this.fatal(j,j+1,`${what} ( is never closed — expected )`)}skipWs(j){for(;j<this.s.length&&/\s/.test(this.s[j]);)j++;return j}openBrace(j,what){return j=this.skipWs(j),this.s[j]!==`{`&&this.fatal(j,j+1,`expected { after ${what}`),j+1}splitHeader(src,at){let out=[],quote=``,start=0;for(let k=0;k<src.length;k++){let ch=src[k];quote?ch===`\\`?k++:ch===quote&&(quote=``):ch===`'`||ch===`"`?quote=ch:ch===`;`&&(out.push({src:src.slice(start,k),at:at+start}),start=k+1)}return out.push({src:src.slice(start),at:at+start}),out}stringArg(src,at,what){let m=/^\s*(['"])([^'"]*)\1\s*$/.exec(src);return m||this.fatal(at,at+src.length,`${what} takes a quoted name`),m[2]}block(kw,i){let s=this.s,after=i+1+kw.length,next=this.skipWs(after),ch=s[next];switch(kw){case`if`:case`for`:case`switch`:case`slot`:case`layout`:case`assets`:if(ch!==`(`)return!1;break;case`verbatim`:if(ch!==`{`)return!1;break;case`let`:case`input`:if(!/[ \t]/.test(s[after]??``))return!1;break;case`else`:case`empty`:case`case`:case`default`:if(ch!==`{`&&ch!==`(`&&!(kw===`else`&&s.startsWith(`if`,next)))return!1;this.fatal(i,after,`@${kw} has no matching ${kw===`else`?`@if`:kw===`empty`?`@for`:`@switch`}`)}if(kw===`layout`)return this.layout(i,next);if(kw===`input`)return this.input(i,after);if(kw===`let`)return this.let(i,after);if(kw===`verbatim`)return this.verbatim(i,next);if(kw===`assets`){let p=this.parens(next,`@assets`),entry=this.stringArg(p.src,p.at,`@assets`);return this.i=this.standalone(i,p.end),this.emit({k:`assets`,entry,span:this.span(i,p.end)}),!0}let p=this.parens(next,`@${kw}`),brace=this.openBrace(p.end,`@${kw} (…)`),resume=this.standalone(i,brace);if(kw===`if`){let branch=this.ifBranch(p.src,p.at),node={k:`if`,branches:[branch],span:this.span(i,brace)};this.emit(node),this.frames.push({type:`block`,children:branch.body,next:`else`,node,keyword:`if`,start:i})}else if(kw===`for`){let node=this.forHeader(p.src,p.at,i,brace);this.emit(node),this.frames.push({type:`block`,children:node.body,next:`empty`,node,keyword:`for`,start:i})}else if(kw===`switch`){let node={k:`switch`,on:this.expr(p.src,p.at)??{kind:`literal`,value:null,span:this.span(p.at,p.at)},cases:[],span:this.span(i,brace)};this.emit(node),this.frames.push({type:`switch`,node,start:i})}else{let node={k:`slot-fill`,name:this.stringArg(p.src,p.at,`@slot`),body:[],span:this.span(i,brace)};this.emit(node),this.frames.push({type:`block`,children:node.body,node,keyword:`slot`,start:i})}return this.i=resume,!0}ifBranch(src,at){let parts=this.splitHeader(src,at),branch={cond:this.expr(parts[0].src,parts[0].at),body:[]};if(parts[1]){let m=/^\s*as\s+([A-Za-z_$][\w$]*)\s*$/.exec(parts[1].src);m?branch.alias=m[1]:this.err(parts[1].at,parts[1].at+parts[1].src.length,"expected `as name` after ;")}return parts.length>2&&this.err(parts[2].at,parts[2].at+1,`unexpected ; in @if`),branch}forHeader(src,at,start,end){let parts=this.splitHeader(src,at),head=parts[0],m=/^(\s*)(?:\[\s*([A-Za-z_$][\w$]*)\s*,\s*([A-Za-z_$][\w$]*)\s*\]|([A-Za-z_$][\w$]*))\s+of\s+/.exec(head.src);m||this.fatal(head.at,head.at+head.src.length,"@for needs `item of items`");let item=m[4]??[m[2],m[3]],ofSrc=head.src.slice(m[0].length),of=this.expr(ofSrc,head.at+m[0].length)??{kind:`literal`,value:null,span:this.span(at,at)},lets={};for(let part of parts.slice(1)){let t=part.src.trim();if(t.startsWith(`track`))this.expr(part.src.replace(/^\s*track\b/,w=>` `.repeat(w.length)),part.at);else if(t.startsWith(`let`)){let body=part.src.replace(/^\s*let\b/,``);for(let decl of body.split(`,`)){let d=/^\s*([A-Za-z_$][\w$]*)\s*=\s*(\$\w+)\s*$/.exec(decl);!d||!LOOP_VARS.has(d[2])?this.err(part.at,part.at+part.src.length,`unknown loop variable in \`${decl.trim()}\` — use ${[...LOOP_VARS].join(`, `)}`):lets[d[1]]=d[2]}}else this.err(part.at,part.at+part.src.length,`expected track or let in @for, found \`${t}\``)}return{k:`for`,item,of,lets,body:[],span:this.span(start,end)}}closeBlock(i){let f=this.frames.length-1;for(;this.frames[f].type!==`block`;)f--;let frame=this.frames[f],s=this.s,j=this.skipWs(i+1),branch,empty=!1,end=i+1;if(frame.next===`else`&&/^@else(?![\w$-])/.test(s.slice(j,j+6))){let k=this.skipWs(j+5);if(s.startsWith(`if`,k)&&/[\s(]/.test(s[k+2]??``)){let p=this.parens(this.skipWs(k+2),`@else if`);branch=this.ifBranch(p.src,p.at),k=p.end}else branch={body:[]};end=this.openBrace(k,`@else`)}else frame.next===`empty`&&/^@empty(?![\w$-])/.test(s.slice(j,j+7))&&(empty=!0,end=this.openBrace(j+6,`@empty`));let resume=this.standalone(i,end);if(this.flush(),this.frames.length=f,this.i=resume,branch){let node=frame.node;node.branches.push(branch),this.frames.push({type:`block`,children:branch.body,next:branch.cond?`else`:void 0,node,keyword:`else`,start:j})}else if(empty){let node=frame.node;node.empty=[],this.frames.push({type:`block`,children:node.empty,node,keyword:`empty`,start:j})}}switchBody(){let s=this.s,j=this.skipWs(this.i),frame=this.top;if(j>=s.length){this.i=j;return}if(s[j]===`}`){this.frames.pop(),this.i=this.standalone(j,j+1);return}let m=/^@(case|default)(?![\w$-])/.exec(s.slice(j,j+9));m||this.fatal(j,j+1,`only @case and @default go inside @switch`);let k=j+m[0].length,value;if(m[1]===`case`){let p=this.parens(this.skipWs(k),`@case`);value=this.expr(p.src,p.at),k=p.end}else frame.node.default&&this.err(j,k,`@switch has two @default blocks`);let brace=this.openBrace(k,`@${m[1]}`),body=[];m[1]===`case`?frame.node.cases.push({value:value??frame.node.on,body}):frame.node.default=body,this.i=this.standalone(j,brace),this.frames.push({type:`block`,children:body,node:frame.node,keyword:m[1],start:j})}verbatim(i,brace){let depth=0,quote=``;for(let k=brace;k<this.s.length;k++){let ch=this.s[k];if(quote)ch===`\\`?k++:ch===quote&&(quote=``);else if(ch===`'`||ch===`"`||ch==="`")quote=ch;else if(ch===`{`)depth++;else if(ch===`}`&&--depth===0){let resume=this.standalone(i,k+1);return this.emit({k:`verbatim`,text:this.s.slice(brace+1,k),span:this.span(i,k+1)}),this.i=resume,!0}}this.fatal(i,brace+1,`@verbatim is never closed — expected }`)}layout(i,at){let p=this.parens(at,`@layout`);return this.seenOutput||this.frames.length>1?this.err(i,p.end,`@layout must come before any output`):this.ast.layout===void 0?(this.ast.layout=/^\s*none\s*$/.test(p.src)?null:this.stringArg(p.src,p.at,`@layout`),this.ast.layoutSpan=this.span(i,p.end)):this.err(i,p.end,`a template has one @layout`),this.i=this.standalone(i,p.end),!0}input(i,after){let eol=this.s.indexOf(`
17
- `,after);eol<0&&(eol=this.s.length);let line=this.s.slice(after,eol).replace(/\r$/,``),m=/^\s*([A-Za-z_$][\w$]*)\s*(?:=\s*(.*?))?\s*$/.exec(line);m||this.fatal(i,eol,`@input needs a name: @input name or @input name = value`),this.frames.length>1&&this.err(i,eol,`@input goes at the top of a component, outside any block`);let decl={name:m[1],span:this.span(i,after+line.length)};if(m[2]!==void 0){let at=after+line.indexOf(m[2],m[0].indexOf(`=`)+1),e=this.expr(m[2],at),literal=e?.kind===`literal`?e.value:e?.kind===`unary`&&e.op===`-`&&e.arg.kind===`literal`&&typeof e.arg.value==`number`?-e.arg.value:void 0;e&&literal===void 0?this.err(at,at+m[2].length,`an @input default must be a literal: a string, number, true, false or null`):e&&(decl.default={value:literal,span:e.span})}return this.ast.inputs.some(d=>d.name===decl.name)&&this.err(i,eol,`@input ${decl.name} is declared twice`),this.ast.inputs.push(decl),this.i=this.standalone(i,after+line.length),!0}let(i,after){let quote=``;for(let k=after;k<this.s.length;k++){let ch=this.s[k];if(quote)ch===`\\`?k++:ch===quote&&(quote=``);else if(ch===`'`||ch===`"`)quote=ch;else if(ch===`;`){let src=this.s.slice(after,k),m=/^\s*([A-Za-z_$][\w$]*)\s*=/.exec(src);m||this.fatal(i,k,`@let needs a name: @let name = expression;`);let expr=this.expr(src.slice(m[0].length),after+m[0].length),resume=this.standalone(i,k+1);return expr&&this.emit({k:`let`,name:m[1],expr,span:this.span(i,k+1)}),this.i=resume,!0}}this.fatal(i,after,`@let is never ended — expected ;`)}};function parse(source,file){let p=new TemplateParser(source.charCodeAt(0)===65279?source.slice(1):source,file);return p.run(),{ast:p.ast,diagnostics:p.diagnostics}}var SafeHtml=class{html;constructor(html){this.html=html}toString(){return this.html}};function read(obj,key){if(obj==null)return;let k=typeof key==`number`||typeof key==`symbol`?key:String(key);if(typeof k==`string`&&FORBIDDEN_NAMES.has(k))return;let value=obj[k];return typeof value==`function`?void 0:value}const HTML_ESCAPES={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&#39;`},escapeHtml=s=>s.replace(/[&<>"']/g,c=>HTML_ESCAPES[c]),SAFE_SCHEMES=/* @__PURE__ */ new Set([`http`,`https`,`mailto`,`tel`]);function sanitizeUrl(value){let normalised=value.replace(/[\u0000- \u007F]/g,``),m=/^([a-z][a-z0-9+.-]*):/i.exec(normalised);return m?SAFE_SCHEMES.has(m[1].toLowerCase())?value:`#`:value}function sanitizeSrcset(value){return value.split(`,`).map(candidate=>{let m=/^(\s*)(\S+)([\s\S]*)$/.exec(candidate);return m?`${m[1]}${sanitizeUrl(m[2])}${m[3]}`:candidate}).join(`,`)}const JSON_ESCAPES={"<":`\\u003c`,">":`\\u003e`,"&":`\\u0026`,"\u2028":`\\u2028`,"\u2029":`\\u2029`},escapeJsonForScript=json=>json.replace(/[<>&\u2028\u2029]/g,c=>JSON_ESCAPES[c]);function safeStyleValue(v){return/[;{}\\"'<]|\/\*|url\s*\(|expression\s*\(/i.test(v)?void 0:v}const BUILTIN_PIPES=[`uppercase`,`lowercase`,`titlecase`,`json`,`slice`,`keys`,`entries`,`url`,`raw`,`date`,`number`,`currency`,`percent`],DATE_FORMATS={short:{dateStyle:`short`,timeStyle:`short`},medium:{dateStyle:`medium`,timeStyle:`medium`},long:{dateStyle:`long`,timeStyle:`long`},full:{dateStyle:`full`,timeStyle:`long`},shortDate:{dateStyle:`short`},mediumDate:{dateStyle:`medium`},longDate:{dateStyle:`long`},fullDate:{dateStyle:`full`},shortTime:{timeStyle:`short`},mediumTime:{timeStyle:`medium`}};function digits(info){if(info==null)return{};let m=/^(\d+)\.(\d+)-(\d+)$/.exec(String(info));if(!m)throw Error(`digits must look like '1.0-2', got '${String(info)}'`);return{minimumIntegerDigits:Number(m[1]),minimumFractionDigits:Number(m[2]),maximumFractionDigits:Number(m[3])}}const formatters=/* @__PURE__ */ new Map;function remember(key,f){return formatters.size>=256&&formatters.clear(),formatters.set(key,f),f}function cached(key,make){return formatters.get(key)??remember(key,make())}const toNumber=v=>{if(v==null||v===``)return;let n=Number(v);return Number.isNaN(n)?void 0:n},str=v=>v==null?``:String(v);function builtinPipes(env){return{uppercase:v=>str(v).toUpperCase(),lowercase:v=>str(v).toLowerCase(),titlecase:v=>str(v).replace(/\b\p{L}/gu,c=>c.toUpperCase()),json:v=>JSON.stringify(v,null,2),slice:(v,start,end)=>typeof v==`string`||Array.isArray(v)?v.slice(start,end):v,keys:v=>v instanceof Map?[...v.keys()]:v&&typeof v==`object`?Object.keys(v):[],entries:v=>v instanceof Map?[...v.entries()]:v&&typeof v==`object`?Object.entries(v):[],url:v=>encodeURIComponent(str(v)),raw:v=>v instanceof SafeHtml?v:new SafeHtml(str(v)),date:(v,format=`medium`,timeZone)=>{if(v==null||v===``)return``;let d=v instanceof Date?v:new Date(v);if(Number.isNaN(d.getTime()))return``;let preset=DATE_FORMATS[String(format)];if(!preset)throw Error(`unknown date format '${String(format)}'`);let tz=timeZone??env.timeZone;return cached(`d|${env.locale}|${String(format)}|${tz}`,()=>new Intl.DateTimeFormat(env.locale,{...preset,timeZone:tz})).format(d)},number:(v,info)=>{let n=toNumber(v);return n===void 0?``:cached(`n|${env.locale}|${String(info)}`,()=>new Intl.NumberFormat(env.locale,digits(info))).format(n)},currency:(v,code,info)=>{let n=toNumber(v);return n===void 0?``:cached(`c|${env.locale}|${String(code)}|${String(info)}`,()=>new Intl.NumberFormat(env.locale,{style:`currency`,currency:String(code??`USD`),...digits(info)})).format(n)},percent:(v,info)=>{let n=toNumber(v);return n===void 0?``:cached(`p|${env.locale}|${String(info)}`,()=>new Intl.NumberFormat(env.locale,{style:`percent`,...digits(info)})).format(n)}}}function topLevelTokens(src){let out=[],depth=0,i=0;for(;i<src.length;){let c=src[i];if(c===`/`&&src[i+1]===`/`){let nl=src.indexOf(`
18
- `,i);i=nl<0?src.length:nl}else if(c===`/`&&src[i+1]===`*`){let end=src.indexOf(`*/`,i+2);i=end<0?src.length:end+2}else if(c===`'`||c===`"`||c==="`"){for(i++;i<src.length&&src[i]!==c;)i+=src[i]===`\\`?2:1;i++}else if(c===`{`||c===`(`||c===`[`)depth===0&&out.push({v:c,start:i}),depth++,i++;else if(c===`}`||c===`)`||c===`]`)depth--,depth===0&&out.push({v:c,start:i}),i++;else if(depth===0&&/[A-Za-z_$*]/.test(c)){let m=/^[A-Za-z_$][\w$]*|^\*/.exec(src.slice(i));out.push({v:m[0],start:i}),i+=m[0].length}else depth===0&&(c===`,`||c===`;`||c===`=`)&&out.push({v:c,start:i}),i++}return out}function braceNames(src,open){let close=src.indexOf(`}`,open),body=src.slice(open+1,close<0?src.length:close),names=[],offset=open+1;for(let part of body.split(`,`)){let m=/^(\s*)([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?\s*$/.exec(part);m&&names.push({local:m[2],exported:m[3]??m[2],at:offset+m[1].length}),offset+=part.length+1}return{names,end:close<0?src.length:close+1}}function readPipeExports(source,file){let names=[],diagnostics=[],fail=(at,len,message)=>diagnostics.push(error(file,{start:positionAt(source,at),end:positionAt(source,at+len)},message)),add=(name,at)=>{BUILTIN_PIPES.includes(name)?fail(at,name.length,`'${name}' is a built-in pipe — choose another name`):names.push(name)},tokens=topLevelTokens(source);for(let t=0;t<tokens.length;t++){if(tokens[t].v!==`export`)continue;let at=tokens[t].start,next=tokens[t+1],after=tokens[t+2];switch(next?.v){case`const`:case`let`:case`var`:after&&/^[A-Za-z_$]/.test(after.v)?add(after.v,after.start):fail(at,6,`export one pipe per name: export const name = …`);break;case`function`:after&&/^[A-Za-z_$]/.test(after.v)&&add(after.v,after.start);break;case`async`:fail(at,6,`pipes must be synchronous — an async function returns a Promise`);break;case`{`:{let{names:list,end}=braceNames(source,next.start);if(tokens.find(x=>x.start>=end)?.v===`from`){fail(at,6,`re-exports aren't read — import the pipe and export it from this file`);break}for(let n of list)add(n.exported,n.at);break}case`type`:case`interface`:break;case`*`:fail(at,6,`export * isn't read — export each pipe by name`);break;case`default`:fail(at,6,`a default export is not a pipe — export each pipe by name`);break;default:fail(at,6,`export ${next?.v??``} is not a pipe — export const or function`)}}return{names,diagnostics}}export{warning as C,positionAt as S,templateName as _,escapeHtml as a,decodeEntities as b,safeStyleValue as c,parse as d,FORBIDDEN_NAMES as f,layoutResolver as g,componentTag as h,SafeHtml as i,sanitizeSrcset as l,check as m,BUILTIN_PIPES as n,escapeJsonForScript as o,parseExpression as p,builtinPipes as r,read as s,readPipeExports as t,sanitizeUrl as u,URL_ATTRS as v,AST_FORMAT_VERSION as w,error as x,isUrlAttr as y};
19
- //# sourceMappingURL=read-exports-CtiwXL4e.js.map