@forinda/kickjs-view 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/{assets-30rOQ1d0.d.ts → assets-DzVT6upX.d.ts} +2 -2
- package/dist/{assets-30rOQ1d0.d.ts.map → assets-DzVT6upX.d.ts.map} +1 -1
- package/dist/cli.js +2 -8
- package/dist/cli.js.map +1 -1
- package/dist/edge.d.ts +2 -2
- package/dist/edge.js +2 -2
- package/dist/{exports-DM4MVXs6.js → exports-CE5wwor2.js} +3 -3
- package/dist/exports-CE5wwor2.js.map +1 -0
- package/dist/file-loader.d.ts +1 -1
- package/dist/file-loader.js +1 -1
- package/dist/format-Qy3r4aci.js +18 -0
- package/dist/format-Qy3r4aci.js.map +1 -0
- package/dist/index.d.ts +14 -3
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{read-exports-D9hlBJY1.js → read-exports-BdIwY1WT.js} +2 -2
- package/dist/{read-exports-D9hlBJY1.js.map → read-exports-BdIwY1WT.js.map} +1 -1
- package/dist/{views-DA6Conh5.d.ts → views-BNSzhk2I.d.ts} +2 -2
- package/dist/{views-DA6Conh5.d.ts.map → views-BNSzhk2I.d.ts.map} +1 -1
- package/package.json +4 -4
- package/dist/exports-DM4MVXs6.js.map +0 -1
package/README.md
CHANGED
|
@@ -29,6 +29,15 @@ bootstrap({ modules, adapters: [KickView({ views })] })
|
|
|
29
29
|
await ctx.render('users/show', { user })
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
`kick fmt:views` and `kick check:views` come from a CLI plugin. Add it to `kick.config.ts`:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { defineConfig } from '@forinda/kickjs-cli'
|
|
36
|
+
import { viewCliPlugin } from '@forinda/kickjs-view/cli'
|
|
37
|
+
|
|
38
|
+
export default defineConfig({ plugins: [viewCliPlugin] })
|
|
39
|
+
```
|
|
40
|
+
|
|
32
41
|
Experimental while 0.x. Guide: [kickjs.app/guide/views](https://kickjs.app/guide/views).
|
|
33
42
|
|
|
34
43
|
## License
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as ViewsOptions, r as Views } from "./views-
|
|
2
|
+
import { a as ViewsOptions, r as Views } from "./views-BNSzhk2I.js";
|
|
3
3
|
import { _ as TemplateAst, s as CheckedTemplate, u as Expr, v as Diagnostic, y as Pos } from "./ast-B7pxZgFT.js";
|
|
4
4
|
import { t as Project } from "./project-J0t2RzxZ.js";
|
|
5
5
|
//#region src/parse/expression.d.ts
|
|
@@ -85,4 +85,4 @@ type AssetsMode = {
|
|
|
85
85
|
declare function assetTags(entry: string, mode: AssetsMode, nonce?: string): string;
|
|
86
86
|
//#endregion
|
|
87
87
|
export { KickView as a, readPipeExports as c, CheckResult as d, check as f, parseExpression as g, FORBIDDEN_NAMES as h, assetTags as i, URL_ATTRS as l, parse as m, ViteManifest as n, KickViewOptions as o, ParseResult as p, ViteManifestChunk as r, viewsMiddleware as s, AssetsMode as t, isUrlAttr as u };
|
|
88
|
-
//# sourceMappingURL=assets-
|
|
88
|
+
//# sourceMappingURL=assets-DzVT6upX.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-
|
|
1
|
+
{"version":3,"file":"assets-DzVT6upX.d.ts","names":[],"sources":["../src/parse/expression.ts","../src/parse/template.ts","../src/check/check.ts","../src/urls.ts","../src/pipes/read-exports.ts","../src/adapter.ts","../src/assets.ts"],"mappings":";;;;;;cAWa,iBAAiB;;;;;iBA+Yd,gBACd,aACA,cACA,MAAM;EACH,OAAO;EAAM,aAAa;;;;UCzYd;EACf,KAAK;EACL,aAAa;;;iBA01BC,MAAM,gBAAgB,eAAe;;;UC/0BpC;EACf,WAAW;EACX,aAAa;;;iBAmoBC,MAAM,cAAc,SAAS,UAAU;;;;;;;cCnqB1C,WAAW;iBAaR,UAAU,aAAa;;;iBC6DvB,gBACd,gBACA;EACG;EAAiB,aAAa;;;;KCvE9B,QAAQ;;;;;iBA2CG,gBACd,OAAO,SACL;EAAO;GAAe;UAQT,wBAAwB;;EAEvC,QAAQ;;iBAsBM,SAAS,UAAS;;;;IA9CM,UAAA,aAAM,cAAc,MAAQ;IAuD3B;;;;;UCzFxB;EACf;EACA;EACA;EACA;;KAGU,eAAe,eAAe;KAE9B;EACN;EAAW;;EACX;EAAY,UAAU;EAAc;;iBAE1B,UAAU,eAAe,MAAM,YAAY"}
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-view v0.
|
|
2
|
+
* @forinda/kickjs-view v0.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,11 +8,5 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{
|
|
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:[]}}const line=(d,prefix)=>`${prefix}${d.file}:${d.span.start.line}:${d.span.start.column} — ${d.message}`;async function templates(viewsDir,root,paths){return paths?.length?paths.map(p=>relative(viewsDir,resolve(root,p))).filter(p=>p.endsWith(`.kick`)&&!p.startsWith(`..`)).map(p=>p.slice(0,-5).split(sep).join(`/`)):existsSync(viewsDir)?(await readdir(viewsDir,{recursive:!0,withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(`.kick`)).map(e=>relative(viewsDir,join(direntDir(e),e.name)).slice(0,-5).split(sep).join(`/`)).toSorted():[]}async function fmtViews(opts){let dir=opts.dir??`src/views`,viewsDir=resolve(opts.root,dir),failed=!1,changed=0;for(let name of await templates(viewsDir,opts.root,opts.paths)){let file=join(viewsDir,`${name}.kick`),source=await readFile(file,`utf8`),r=format(source,`${name}.kick`,{indent:opts.indent});for(let d of r.diagnostics)opts.log(line(d,`${dir}/`));r.output===void 0?failed=!0:r.output!==source&&(changed++,opts.check?opts.log(`would reformat ${dir}/${name}.kick`):(await writeFile(file,r.output),opts.log(`formatted ${dir}/${name}.kick`)))}return failed||opts.check&&changed?1:0}async function checkViews(opts){let dir=opts.dir??`src/views`,viewsDir=resolve(opts.root,dir),pipesFile=resolve(opts.root,opts.pipesFile??join(dir,`pipes.ts`)),all=await templates(viewsDir,opts.root),pipes=new Set(BUILTIN_PIPES),errors=0,report=(d,prefix)=>{d.severity===`error`&&errors++,opts.log(line(d,prefix))};if(existsSync(pipesFile)){let read=readPipeExports(await readFile(pipesFile,`utf8`),relative(opts.root,pipesFile));for(let n of read.names)pipes.add(n);for(let d of read.diagnostics)report(d,``)}let project={templates:/* @__PURE__ */ new Map,pipes,componentsDir:opts.componentsDir??`components`,layouts:opts.layouts,baseLayout:opts.baseLayout},syntax=/* @__PURE__ */ new Set;for(let name of all){let r=parse(await readFile(join(viewsDir,`${name}.kick`),`utf8`),`${name}.kick`);project.templates.set(name,r.ast);for(let d of r.diagnostics)report(d,`${dir}/`);r.diagnostics.some(d=>d.severity===`error`)&&syntax.add(name)}let wanted=opts.paths?.length?await templates(viewsDir,opts.root,opts.paths):all;for(let name of wanted)if(!syntax.has(name))for(let d of check(name,project).diagnostics)report(d,`${dir}/`);return errors||opts.log(`${wanted.length} template(s) checked, no errors`),+!!errors}const viewCliPlugin={name:`kick/view`,register(program,ctx){program.command(`fmt:views [paths...]`).description(`Format .kick templates (spacing and indentation; raw regions untouched)`).option(`--check`,`list files that would change and exit 1, writing nothing`).option(`--dir <dir>`,`views folder`,`src/views`).action(async(paths,o)=>{process.exitCode=await fmtViews({root:ctx.projectRoot,dir:o.dir,paths,check:o.check,log:ctx.log})}),program.command(`check:views [paths...]`).description(`Check .kick templates for errors: syntax, unknown pipes, inputs, slots, layouts, unsafe interpolation`).option(`--dir <dir>`,`views folder`,`src/views`).option(`--pipes <file>`,`pipes file (default <dir>/pipes.ts)`).action(async(paths,o)=>{process.exitCode=await checkViews({root:ctx.projectRoot,dir:o.dir,paths,pipesFile:o.pipes,log:ctx.log})})}};function direntDir(e){return e.parentPath??e.path??``}export{checkViews,fmtViews,viewCliPlugin};
|
|
11
|
+
import{d as parse,m as check,n as BUILTIN_PIPES,t as readPipeExports}from"./read-exports-BdIwY1WT.js";import{t as format}from"./format-Qy3r4aci.js";import{readFile,readdir,writeFile}from"node:fs/promises";import{join,relative,resolve,sep}from"node:path";import{existsSync}from"node:fs";const line=(d,prefix)=>`${prefix}${d.file}:${d.span.start.line}:${d.span.start.column} — ${d.message}`;async function templates(viewsDir,root,paths){return paths?.length?paths.map(p=>relative(viewsDir,resolve(root,p))).filter(p=>p.endsWith(`.kick`)&&!p.startsWith(`..`)).map(p=>p.slice(0,-5).split(sep).join(`/`)):existsSync(viewsDir)?(await readdir(viewsDir,{recursive:!0,withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(`.kick`)).map(e=>relative(viewsDir,join(direntDir(e),e.name)).slice(0,-5).split(sep).join(`/`)).toSorted():[]}async function fmtViews(opts){let dir=opts.dir??`src/views`,viewsDir=resolve(opts.root,dir),failed=!1,changed=0;for(let name of await templates(viewsDir,opts.root,opts.paths)){let file=join(viewsDir,`${name}.kick`),source=await readFile(file,`utf8`),r=format(source,`${name}.kick`,{indent:opts.indent});for(let d of r.diagnostics)opts.log(line(d,`${dir}/`));r.output===void 0?failed=!0:r.output!==source&&(changed++,opts.check?opts.log(`would reformat ${dir}/${name}.kick`):(await writeFile(file,r.output),opts.log(`formatted ${dir}/${name}.kick`)))}return failed||opts.check&&changed?1:0}async function checkViews(opts){let dir=opts.dir??`src/views`,viewsDir=resolve(opts.root,dir),pipesFile=resolve(opts.root,opts.pipesFile??join(dir,`pipes.ts`)),all=await templates(viewsDir,opts.root),pipes=new Set(BUILTIN_PIPES),errors=0,report=(d,prefix)=>{d.severity===`error`&&errors++,opts.log(line(d,prefix))};if(existsSync(pipesFile)){let read=readPipeExports(await readFile(pipesFile,`utf8`),relative(opts.root,pipesFile));for(let n of read.names)pipes.add(n);for(let d of read.diagnostics)report(d,``)}let project={templates:/* @__PURE__ */ new Map,pipes,componentsDir:opts.componentsDir??`components`,layouts:opts.layouts,baseLayout:opts.baseLayout},syntax=/* @__PURE__ */ new Set;for(let name of all){let r=parse(await readFile(join(viewsDir,`${name}.kick`),`utf8`),`${name}.kick`);project.templates.set(name,r.ast);for(let d of r.diagnostics)report(d,`${dir}/`);r.diagnostics.some(d=>d.severity===`error`)&&syntax.add(name)}let wanted=opts.paths?.length?await templates(viewsDir,opts.root,opts.paths):all;for(let name of wanted)if(!syntax.has(name))for(let d of check(name,project).diagnostics)report(d,`${dir}/`);return errors||opts.log(`${wanted.length} template(s) checked, no errors`),+!!errors}const viewCliPlugin={name:`kick/view`,register(program,ctx){program.command(`fmt:views [paths...]`).description(`Format .kick templates (spacing and indentation; raw regions untouched)`).option(`--check`,`list files that would change and exit 1, writing nothing`).option(`--dir <dir>`,`views folder`,`src/views`).action(async(paths,o)=>{process.exitCode=await fmtViews({root:ctx.projectRoot,dir:o.dir,paths,check:o.check,log:ctx.log})}),program.command(`check:views [paths...]`).description(`Check .kick templates for errors: syntax, unknown pipes, inputs, slots, layouts, unsafe interpolation`).option(`--dir <dir>`,`views folder`,`src/views`).option(`--pipes <file>`,`pipes file (default <dir>/pipes.ts)`).action(async(paths,o)=>{process.exitCode=await checkViews({root:ctx.projectRoot,dir:o.dir,paths,pipesFile:o.pipes,log:ctx.log})})}};function direntDir(e){return e.parentPath??e.path??``}export{checkViews,fmtViews,viewCliPlugin};
|
|
18
12
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/format.ts","../src/cli.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","/**\n * `kick fmt:views` and `kick check:views`, as a kick CLI plugin:\n *\n * ```ts\n * // kick.config.ts\n * import { viewCliPlugin } from '@forinda/kickjs-view/cli'\n * export default defineConfig({ plugins: [viewCliPlugin] })\n * ```\n */\nimport { existsSync } from 'node:fs'\nimport { readdir, readFile, writeFile } from 'node:fs/promises'\nimport { join, relative, resolve, sep } from 'node:path'\nimport type { KickCliPlugin } from '@forinda/kickjs-cli-kit'\nimport type { Diagnostic } from './diagnostics'\nimport { check } from './check/check'\nimport type { Project } from './check/project'\nimport { format } from './format'\nimport { parse } from './parse/template'\nimport { BUILTIN_PIPES } from './pipes/builtins'\nimport { readPipeExports } from './pipes/read-exports'\n\nexport interface ViewsCliOptions {\n /** Project root. */\n root: string\n /** Views folder, relative to the root. Default `src/views`. */\n dir?: string\n /** Only these files (relative to the root). Default: every `.kick` file in the views folder. */\n paths?: string[]\n log: (message: string) => void\n}\n\nconst line = (d: Diagnostic, prefix: string) =>\n `${prefix}${d.file}:${d.span.start.line}:${d.span.start.column} — ${d.message}`\n\n/** Template names (`users/show`) under the views folder, or those `paths` name. */\nasync function templates(viewsDir: string, root: string, paths?: string[]): Promise<string[]> {\n if (paths?.length) {\n return paths\n .map((p) => relative(viewsDir, resolve(root, p)))\n .filter((p) => p.endsWith('.kick') && !p.startsWith('..'))\n .map((p) => p.slice(0, -'.kick'.length).split(sep).join('/'))\n }\n if (!existsSync(viewsDir)) return []\n const entries = await readdir(viewsDir, { recursive: true, withFileTypes: true })\n return entries\n .filter((e) => e.isFile() && e.name.endsWith('.kick'))\n .map((e) =>\n relative(viewsDir, join(direntDir(e), e.name))\n .slice(0, -'.kick'.length)\n .split(sep)\n .join('/'),\n )\n .toSorted()\n}\n\n/** Format templates in place, or with `check` report the ones that would change. Returns the exit code. */\nexport async function fmtViews(\n opts: ViewsCliOptions & { check?: boolean; indent?: number },\n): Promise<number> {\n const dir = opts.dir ?? 'src/views'\n const viewsDir = resolve(opts.root, dir)\n let failed = false\n let changed = 0\n for (const name of await templates(viewsDir, opts.root, opts.paths)) {\n const file = join(viewsDir, `${name}.kick`)\n const source = await readFile(file, 'utf8')\n const r = format(source, `${name}.kick`, { indent: opts.indent })\n for (const d of r.diagnostics) opts.log(line(d, `${dir}/`))\n if (r.output === undefined) {\n failed = true\n continue\n }\n if (r.output === source) continue\n changed++\n if (opts.check) opts.log(`would reformat ${dir}/${name}.kick`)\n else {\n await writeFile(file, r.output)\n opts.log(`formatted ${dir}/${name}.kick`)\n }\n }\n return failed || (opts.check && changed) ? 1 : 0\n}\n\n/** Parse and check every template; print each problem with its position. Returns the exit code. */\nexport async function checkViews(\n opts: ViewsCliOptions & {\n pipesFile?: string\n componentsDir?: string\n layouts?: Project['layouts']\n baseLayout?: string\n },\n): Promise<number> {\n const dir = opts.dir ?? 'src/views'\n const viewsDir = resolve(opts.root, dir)\n const pipesFile = resolve(opts.root, opts.pipesFile ?? join(dir, 'pipes.ts'))\n const all = await templates(viewsDir, opts.root)\n const pipes = new Set(BUILTIN_PIPES)\n let errors = 0\n const report = (d: Diagnostic, prefix: string) => {\n if (d.severity === 'error') errors++\n opts.log(line(d, prefix))\n }\n if (existsSync(pipesFile)) {\n const read = readPipeExports(await readFile(pipesFile, 'utf8'), relative(opts.root, pipesFile))\n for (const n of read.names) pipes.add(n)\n for (const d of read.diagnostics) report(d, '')\n }\n const project: Project = {\n templates: new Map(),\n pipes,\n componentsDir: opts.componentsDir ?? 'components',\n layouts: opts.layouts,\n baseLayout: opts.baseLayout,\n }\n const syntax = new Set<string>()\n for (const name of all) {\n const r = parse(await readFile(join(viewsDir, `${name}.kick`), 'utf8'), `${name}.kick`)\n project.templates.set(name, r.ast)\n for (const d of r.diagnostics) report(d, `${dir}/`)\n if (r.diagnostics.some((d) => d.severity === 'error')) syntax.add(name)\n }\n const wanted = opts.paths?.length ? await templates(viewsDir, opts.root, opts.paths) : all\n for (const name of wanted) {\n if (syntax.has(name)) continue\n for (const d of check(name, project).diagnostics) report(d, `${dir}/`)\n }\n if (!errors) opts.log(`${wanted.length} template(s) checked, no errors`)\n return errors ? 1 : 0\n}\n\nexport const viewCliPlugin: KickCliPlugin = {\n name: 'kick/view',\n register(program, ctx) {\n program\n .command('fmt:views [paths...]')\n .description('Format .kick templates (spacing and indentation; raw regions untouched)')\n .option('--check', 'list files that would change and exit 1, writing nothing')\n .option('--dir <dir>', 'views folder', 'src/views')\n .action(async (paths: string[], o: { check?: boolean; dir: string }) => {\n process.exitCode = await fmtViews({\n root: ctx.projectRoot,\n dir: o.dir,\n paths,\n check: o.check,\n log: ctx.log,\n })\n })\n program\n .command('check:views [paths...]')\n .description(\n 'Check .kick templates for errors: syntax, unknown pipes, inputs, slots, layouts, unsafe interpolation',\n )\n .option('--dir <dir>', 'views folder', 'src/views')\n .option('--pipes <file>', 'pipes file (default <dir>/pipes.ts)')\n .action(async (paths: string[], o: { dir: string; pipes?: string }) => {\n process.exitCode = await checkViews({\n root: ctx.projectRoot,\n dir: o.dir,\n paths,\n pipesFile: o.pipes,\n log: ctx.log,\n })\n })\n },\n}\n\n/** A dirent's folder: `parentPath` from Node 20.12, `path` before it. */\nfunction direntDir(e: { parentPath?: string; path?: string }): string {\n return e.parentPath ?? e.path ?? ''\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["/**\n * `kick fmt:views` and `kick check:views`, as a kick CLI plugin:\n *\n * ```ts\n * // kick.config.ts\n * import { viewCliPlugin } from '@forinda/kickjs-view/cli'\n * export default defineConfig({ plugins: [viewCliPlugin] })\n * ```\n */\nimport { existsSync } from 'node:fs'\nimport { readdir, readFile, writeFile } from 'node:fs/promises'\nimport { join, relative, resolve, sep } from 'node:path'\nimport type { KickCliPlugin } from '@forinda/kickjs-cli-kit'\nimport type { Diagnostic } from './diagnostics'\nimport { check } from './check/check'\nimport type { Project } from './check/project'\nimport { format } from './format'\nimport { parse } from './parse/template'\nimport { BUILTIN_PIPES } from './pipes/builtins'\nimport { readPipeExports } from './pipes/read-exports'\n\nexport interface ViewsCliOptions {\n /** Project root. */\n root: string\n /** Views folder, relative to the root. Default `src/views`. */\n dir?: string\n /** Only these files (relative to the root). Default: every `.kick` file in the views folder. */\n paths?: string[]\n log: (message: string) => void\n}\n\nconst line = (d: Diagnostic, prefix: string) =>\n `${prefix}${d.file}:${d.span.start.line}:${d.span.start.column} — ${d.message}`\n\n/** Template names (`users/show`) under the views folder, or those `paths` name. */\nasync function templates(viewsDir: string, root: string, paths?: string[]): Promise<string[]> {\n if (paths?.length) {\n return paths\n .map((p) => relative(viewsDir, resolve(root, p)))\n .filter((p) => p.endsWith('.kick') && !p.startsWith('..'))\n .map((p) => p.slice(0, -'.kick'.length).split(sep).join('/'))\n }\n if (!existsSync(viewsDir)) return []\n const entries = await readdir(viewsDir, { recursive: true, withFileTypes: true })\n return entries\n .filter((e) => e.isFile() && e.name.endsWith('.kick'))\n .map((e) =>\n relative(viewsDir, join(direntDir(e), e.name))\n .slice(0, -'.kick'.length)\n .split(sep)\n .join('/'),\n )\n .toSorted()\n}\n\n/** Format templates in place, or with `check` report the ones that would change. Returns the exit code. */\nexport async function fmtViews(\n opts: ViewsCliOptions & { check?: boolean; indent?: number },\n): Promise<number> {\n const dir = opts.dir ?? 'src/views'\n const viewsDir = resolve(opts.root, dir)\n let failed = false\n let changed = 0\n for (const name of await templates(viewsDir, opts.root, opts.paths)) {\n const file = join(viewsDir, `${name}.kick`)\n const source = await readFile(file, 'utf8')\n const r = format(source, `${name}.kick`, { indent: opts.indent })\n for (const d of r.diagnostics) opts.log(line(d, `${dir}/`))\n if (r.output === undefined) {\n failed = true\n continue\n }\n if (r.output === source) continue\n changed++\n if (opts.check) opts.log(`would reformat ${dir}/${name}.kick`)\n else {\n await writeFile(file, r.output)\n opts.log(`formatted ${dir}/${name}.kick`)\n }\n }\n return failed || (opts.check && changed) ? 1 : 0\n}\n\n/** Parse and check every template; print each problem with its position. Returns the exit code. */\nexport async function checkViews(\n opts: ViewsCliOptions & {\n pipesFile?: string\n componentsDir?: string\n layouts?: Project['layouts']\n baseLayout?: string\n },\n): Promise<number> {\n const dir = opts.dir ?? 'src/views'\n const viewsDir = resolve(opts.root, dir)\n const pipesFile = resolve(opts.root, opts.pipesFile ?? join(dir, 'pipes.ts'))\n const all = await templates(viewsDir, opts.root)\n const pipes = new Set(BUILTIN_PIPES)\n let errors = 0\n const report = (d: Diagnostic, prefix: string) => {\n if (d.severity === 'error') errors++\n opts.log(line(d, prefix))\n }\n if (existsSync(pipesFile)) {\n const read = readPipeExports(await readFile(pipesFile, 'utf8'), relative(opts.root, pipesFile))\n for (const n of read.names) pipes.add(n)\n for (const d of read.diagnostics) report(d, '')\n }\n const project: Project = {\n templates: new Map(),\n pipes,\n componentsDir: opts.componentsDir ?? 'components',\n layouts: opts.layouts,\n baseLayout: opts.baseLayout,\n }\n const syntax = new Set<string>()\n for (const name of all) {\n const r = parse(await readFile(join(viewsDir, `${name}.kick`), 'utf8'), `${name}.kick`)\n project.templates.set(name, r.ast)\n for (const d of r.diagnostics) report(d, `${dir}/`)\n if (r.diagnostics.some((d) => d.severity === 'error')) syntax.add(name)\n }\n const wanted = opts.paths?.length ? await templates(viewsDir, opts.root, opts.paths) : all\n for (const name of wanted) {\n if (syntax.has(name)) continue\n for (const d of check(name, project).diagnostics) report(d, `${dir}/`)\n }\n if (!errors) opts.log(`${wanted.length} template(s) checked, no errors`)\n return errors ? 1 : 0\n}\n\nexport const viewCliPlugin: KickCliPlugin = {\n name: 'kick/view',\n register(program, ctx) {\n program\n .command('fmt:views [paths...]')\n .description('Format .kick templates (spacing and indentation; raw regions untouched)')\n .option('--check', 'list files that would change and exit 1, writing nothing')\n .option('--dir <dir>', 'views folder', 'src/views')\n .action(async (paths: string[], o: { check?: boolean; dir: string }) => {\n process.exitCode = await fmtViews({\n root: ctx.projectRoot,\n dir: o.dir,\n paths,\n check: o.check,\n log: ctx.log,\n })\n })\n program\n .command('check:views [paths...]')\n .description(\n 'Check .kick templates for errors: syntax, unknown pipes, inputs, slots, layouts, unsafe interpolation',\n )\n .option('--dir <dir>', 'views folder', 'src/views')\n .option('--pipes <file>', 'pipes file (default <dir>/pipes.ts)')\n .action(async (paths: string[], o: { dir: string; pipes?: string }) => {\n process.exitCode = await checkViews({\n root: ctx.projectRoot,\n dir: o.dir,\n paths,\n pipesFile: o.pipes,\n log: ctx.log,\n })\n })\n },\n}\n\n/** A dirent's folder: `parentPath` from Node 20.12, `path` before it. */\nfunction direntDir(e: { parentPath?: string; path?: string }): string {\n return e.parentPath ?? e.path ?? ''\n}\n"],"mappings":"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"}
|
package/dist/edge.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { C as SafeHtml, D as safeStyleValue, E as read, O as sanitizeSrcset, S as render, T as escapeJsonForScript, _ as builtinPipes, a as ViewsOptions, b as RenderEnv, c as useFileLoader, d as EnvPipe, f as pipesFor, g as PipeEnv, h as BUILTIN_PIPES, i as ViewsBundle, k as sanitizeUrl, m as withEnv, n as RenderOptions, o as bundleLoader, p as safeHtml, r as Views, s as createViews, t as Loader, v as MAX_DEPTH, w as escapeHtml, x as RenderError, y as Pipe } from "./views-
|
|
2
|
+
import { C as SafeHtml, D as safeStyleValue, E as read, O as sanitizeSrcset, S as render, T as escapeJsonForScript, _ as builtinPipes, a as ViewsOptions, b as RenderEnv, c as useFileLoader, d as EnvPipe, f as pipesFor, g as PipeEnv, h as BUILTIN_PIPES, i as ViewsBundle, k as sanitizeUrl, m as withEnv, n as RenderOptions, o as bundleLoader, p as safeHtml, r as Views, s as createViews, t as Loader, v as MAX_DEPTH, w as escapeHtml, x as RenderError, y as Pipe } from "./views-BNSzhk2I.js";
|
|
3
3
|
import { _ as TemplateAst, a as CNode, b as Span, c as Ctx, d as IfBranch, f as InputDecl, g as PathSegment, h as Node, i as CExpr, l as Element, m as LoopVar, n as Attr, o as CSeg, p as Literal, r as CAttr, s as CheckedTemplate, t as AST_FORMAT_VERSION, u as Expr, v as Diagnostic, x as positionAt, y as Pos } from "./ast-B7pxZgFT.js";
|
|
4
4
|
import { i as templateName, n as componentTag, r as layoutResolver, t as Project } from "./project-J0t2RzxZ.js";
|
|
5
|
-
import { a as KickView, c as readPipeExports, d as CheckResult, f as check, g as parseExpression, h as FORBIDDEN_NAMES, i as assetTags, l as URL_ATTRS, m as parse, n as ViteManifest, o as KickViewOptions, p as ParseResult, r as ViteManifestChunk, s as viewsMiddleware, t as AssetsMode, u as isUrlAttr } from "./assets-
|
|
5
|
+
import { a as KickView, c as readPipeExports, d as CheckResult, f as check, g as parseExpression, h as FORBIDDEN_NAMES, i as assetTags, l as URL_ATTRS, m as parse, n as ViteManifest, o as KickViewOptions, p as ParseResult, r as ViteManifestChunk, s as viewsMiddleware, t as AssetsMode, u as isUrlAttr } from "./assets-DzVT6upX.js";
|
|
6
6
|
export { AST_FORMAT_VERSION, type AssetsMode, type Attr, BUILTIN_PIPES, type CAttr, type CExpr, type CNode, type CSeg, type CheckResult, type CheckedTemplate, type Ctx, type Diagnostic, type Element, type EnvPipe, type Expr, FORBIDDEN_NAMES, type IfBranch, type InputDecl, KickView, type KickViewOptions, type Literal, type Loader, type LoopVar, MAX_DEPTH, type Node, type ParseResult, type PathSegment, type Pipe, type PipeEnv, type Pos, type Project, type RenderEnv, RenderError, type RenderOptions, SafeHtml, type Span, type TemplateAst, URL_ATTRS, type Views, type ViewsBundle, type ViewsOptions, type ViteManifest, type ViteManifestChunk, assetTags, builtinPipes, bundleLoader, check, componentTag, createViews, escapeHtml, escapeJsonForScript, isUrlAttr, layoutResolver, parse, parseExpression, pipesFor, positionAt, read, readPipeExports, render, safeHtml, safeStyleValue, sanitizeSrcset, sanitizeUrl, templateName, useFileLoader, viewsMiddleware, withEnv };
|
package/dist/edge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-view v0.
|
|
2
|
+
* @forinda/kickjs-view v0.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{S as positionAt,_ as templateName,a as escapeHtml,c as safeStyleValue,d as parse,f as FORBIDDEN_NAMES,g as layoutResolver,h as componentTag,i as SafeHtml,l as sanitizeSrcset,m as check,n as BUILTIN_PIPES,o as escapeJsonForScript,p as parseExpression,r as builtinPipes,s as read,t as readPipeExports,u as sanitizeUrl,v as URL_ATTRS,w as AST_FORMAT_VERSION,y as isUrlAttr}from"./read-exports-
|
|
11
|
+
import{S as positionAt,_ as templateName,a as escapeHtml,c as safeStyleValue,d as parse,f as FORBIDDEN_NAMES,g as layoutResolver,h as componentTag,i as SafeHtml,l as sanitizeSrcset,m as check,n as BUILTIN_PIPES,o as escapeJsonForScript,p as parseExpression,r as builtinPipes,s as read,t as readPipeExports,u as sanitizeUrl,v as URL_ATTRS,w as AST_FORMAT_VERSION,y as isUrlAttr}from"./read-exports-BdIwY1WT.js";import{a as createViews,c as RenderError,d as safeHtml,f as withEnv,i as bundleLoader,l as render,n as KickView,o as useFileLoader,r as viewsMiddleware,s as MAX_DEPTH,t as assetTags,u as pipesFor}from"./exports-CE5wwor2.js";export{AST_FORMAT_VERSION,BUILTIN_PIPES,FORBIDDEN_NAMES,KickView,MAX_DEPTH,RenderError,SafeHtml,URL_ATTRS,assetTags,builtinPipes,bundleLoader,check,componentTag,createViews,escapeHtml,escapeJsonForScript,isUrlAttr,layoutResolver,parse,parseExpression,pipesFor,positionAt,read,readPipeExports,render,safeHtml,safeStyleValue,sanitizeSrcset,sanitizeUrl,templateName,useFileLoader,viewsMiddleware,withEnv};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-view v0.
|
|
2
|
+
* @forinda/kickjs-view v0.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
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-D9hlBJY1.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,`"`));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,`"`):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(`
|
|
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-BdIwY1WT.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,`"`));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,`"`):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,dev=options.dev??options.bundle===null;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),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(!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
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
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-
|
|
14
|
+
//# sourceMappingURL=exports-CE5wwor2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-CE5wwor2.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, '"'))\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, '"') : 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 (`
`) 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. Default: on when `bundle` is `null` (`kick dev`). */\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 // `kick dev` hands over `bundle: null`: the sources change under us there.\n const dev = options.dev ?? options.bundle === null\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 (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 (!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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"}
|
package/dist/file-loader.d.ts
CHANGED
package/dist/file-loader.js
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @forinda/kickjs-view v0.1.1
|
|
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-BdIwY1WT.js";const RAW=/* @__PURE__ */ new Set([`pre`,`textarea`,`script`,`style`]),RCDATA=/* @__PURE__ */ new Set([`<title`,`<textarea`]),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 spacePipes(expr){let out=``,quote=``;for(let i=0;i<expr.length;i++){let c=expr[i];if(quote)out+=c,c===`\\`?out+=expr[++i]??``:c===quote&&(quote=``);else if(c===`'`||c===`"`||c==="`")quote=c,out+=c;else if(c===`|`&&expr[i+1]===`|`)out+=`||`,i++;else if(c===`|`)for(out=`${out.trimEnd()} | `;/[ \t]/.test(expr[i+1]??``);)i++;else out+=c}return out}function normalise(text){let s=text.replace(/\{\{(?!--)([\s\S]*?)\}\}/g,(_,inner)=>`{{ ${spacePipes(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--}let header=s.slice(at+m[0].length,j-1).trim();out+=`${DIRECTIVES.has(kw)?header:spacePipes(header)})`;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=[],lastIndex=key=>stack.findLastIndex(e=>e.key===key),out=[],queue=source.split(`
|
|
12
|
+
`),offset=0;for(let n=0;n<queue.length;n++){let raw=queue[n],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,split=-1;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,top=stack.at(-1)?.key;if(top&&RCDATA.has(top)&&`<${closeTag?.toLowerCase()}`!==top)continue;let i=tok===`}`?lastIndex(`{`):closeTag?lastIndex(`<${closeTag.toLowerCase()}`):-1;if(i>=0&&!leading&&stack[i].line<n){split=m.index;break}if(i>=0)stack.length=i,leading&&(depthForLine=stack.length);else{if(openTag){let tag=openTag.toLowerCase();!selfClose&&!VOID.has(tag)&&!RAW.has(tag)&&stack.push({key:`<${tag}`,line:n})}else!closeTag&&tok!==`}`&&stack.push({key:`{`,line:n});leading=!1}}split<0?out.push(unit.repeat(Math.max(0,depthForLine))+content):(out.push(unit.repeat(Math.max(0,depthForLine))+raw.slice(0,split).trim()),queue.splice(n+1,0,raw.slice(split)),offset=start+split)}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-Qy3r4aci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-Qy3r4aci.js","names":[],"sources":["../src/format.ts"],"sourcesContent":["/**\n * `format`: tidy a `.kick` source — `{{ x | pipe }}` 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'])\n/** Text up to its own closing tag: tag-like text inside isn't structure. */\nconst RCDATA = new Set(['<title', '<textarea'])\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/** `a|b` → `a | b` in an expression; `||` and quoted text are left alone. */\nfunction spacePipes(expr: string): string {\n let out = ''\n let quote = ''\n for (let i = 0; i < expr.length; i++) {\n const c = expr[i]!\n if (quote) {\n out += c\n if (c === '\\\\') out += expr[++i] ?? ''\n else if (c === quote) quote = ''\n } else if (c === \"'\" || c === '\"' || c === '`') {\n quote = c\n out += c\n } else if (c === '|' && expr[i + 1] === '|') {\n out += '||'\n i++\n } else if (c === '|') {\n out = `${out.trimEnd()} | `\n while (/[ \\t]/.test(expr[i + 1] ?? '')) i++\n } else out += c\n }\n return out\n}\n\n/** `{{x|p}}` → `{{ x | p }}`, `@if(a){` → `@if (a) {`, `}@else{` → `} @else {`. */\nfunction normalise(text: string): string {\n let s = text.replace(\n /\\{\\{(?!--)([\\s\\S]*?)\\}\\}/g,\n (_, inner: string) => `{{ ${spacePipes(inner.trim())} }}`,\n )\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 const header = s.slice(at + m[0].length, j - 1).trim()\n out += `${DIRECTIVES.has(kw) ? header : spacePipes(header)})`\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/**\n * Re-indent lines by the blocks and elements open at their start. A closer\n * after content (`<b>x</b></slot>`, `x }`) whose opener is on an earlier line\n * moves to its own line.\n */\nfunction reindent(source: string, ranges: Range[], unit: string): string {\n /** Open blocks and elements, with the line each opened on. */\n const stack: Array<{ key: string; line: number }> = []\n const lastIndex = (key: string) => stack.findLastIndex((e) => e.key === key)\n const out: string[] = []\n const queue = source.split('\\n')\n let offset = 0\n for (let n = 0; n < queue.length; n++) {\n const raw = queue[n]!\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 let split = -1\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 const top = stack.at(-1)?.key\n if (top && RCDATA.has(top) && `<${closeTag?.toLowerCase()}` !== top) continue\n const i =\n tok === '}' ? lastIndex('{') : closeTag ? lastIndex(`<${closeTag.toLowerCase()}`) : -1\n if (i >= 0 && !leading && stack[i]!.line < n) {\n split = m.index\n break\n }\n if (i >= 0) {\n stack.length = i\n if (leading) depthForLine = stack.length\n continue\n }\n if (openTag) {\n const tag = openTag.toLowerCase()\n if (!selfClose && !VOID.has(tag) && !RAW.has(tag)) stack.push({ key: `<${tag}`, line: n })\n } else if (!closeTag && tok !== '}') stack.push({ key: '{', line: n })\n leading = false\n }\n if (split < 0) {\n out.push(unit.repeat(Math.max(0, depthForLine)) + content)\n continue\n }\n // The closer and what follows become the next line.\n out.push(unit.repeat(Math.max(0, depthForLine)) + raw.slice(0, split).trim())\n queue.splice(n + 1, 0, raw.slice(split))\n offset = start + split\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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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
|
|
2
|
-
import { C as SafeHtml, D as safeStyleValue, E as read, O as sanitizeSrcset, S as render, T as escapeJsonForScript, _ as builtinPipes, a as ViewsOptions, b as RenderEnv, c as useFileLoader, d as EnvPipe, f as pipesFor, g as PipeEnv, h as BUILTIN_PIPES, i as ViewsBundle, k as sanitizeUrl, m as withEnv, n as RenderOptions, o as bundleLoader, p as safeHtml, r as Views, s as createViews, t as Loader, v as MAX_DEPTH, w as escapeHtml, x as RenderError, y as Pipe } from "./views-
|
|
2
|
+
import { C as SafeHtml, D as safeStyleValue, E as read, O as sanitizeSrcset, S as render, T as escapeJsonForScript, _ as builtinPipes, a as ViewsOptions, b as RenderEnv, c as useFileLoader, d as EnvPipe, f as pipesFor, g as PipeEnv, h as BUILTIN_PIPES, i as ViewsBundle, k as sanitizeUrl, m as withEnv, n as RenderOptions, o as bundleLoader, p as safeHtml, r as Views, s as createViews, t as Loader, v as MAX_DEPTH, w as escapeHtml, x as RenderError, y as Pipe } from "./views-BNSzhk2I.js";
|
|
3
3
|
import { _ as TemplateAst, a as CNode, b as Span, c as Ctx, d as IfBranch, f as InputDecl, g as PathSegment, h as Node, i as CExpr, l as Element, m as LoopVar, n as Attr, o as CSeg, p as Literal, r as CAttr, s as CheckedTemplate, t as AST_FORMAT_VERSION, u as Expr, v as Diagnostic, x as positionAt, y as Pos } from "./ast-B7pxZgFT.js";
|
|
4
4
|
import { i as templateName, n as componentTag, r as layoutResolver, t as Project } from "./project-J0t2RzxZ.js";
|
|
5
|
-
import { a as KickView, c as readPipeExports, d as CheckResult, f as check, g as parseExpression, h as FORBIDDEN_NAMES, i as assetTags, l as URL_ATTRS, m as parse, n as ViteManifest, o as KickViewOptions, p as ParseResult, r as ViteManifestChunk, s as viewsMiddleware, t as AssetsMode, u as isUrlAttr } from "./assets-
|
|
6
|
-
|
|
5
|
+
import { a as KickView, c as readPipeExports, d as CheckResult, f as check, g as parseExpression, h as FORBIDDEN_NAMES, i as assetTags, l as URL_ATTRS, m as parse, n as ViteManifest, o as KickViewOptions, p as ParseResult, r as ViteManifestChunk, s as viewsMiddleware, t as AssetsMode, u as isUrlAttr } from "./assets-DzVT6upX.js";
|
|
6
|
+
//#region src/format.d.ts
|
|
7
|
+
interface FormatOptions {
|
|
8
|
+
/** Spaces per level. Default 2. */
|
|
9
|
+
indent?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function format(source: string, file: string, opts?: FormatOptions): {
|
|
12
|
+
output?: string;
|
|
13
|
+
diagnostics: Diagnostic[];
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { AST_FORMAT_VERSION, type AssetsMode, type Attr, BUILTIN_PIPES, type CAttr, type CExpr, type CNode, type CSeg, type CheckResult, type CheckedTemplate, type Ctx, type Diagnostic, type Element, type EnvPipe, type Expr, FORBIDDEN_NAMES, type FormatOptions, type IfBranch, type InputDecl, KickView, type KickViewOptions, type Literal, type Loader, type LoopVar, MAX_DEPTH, type Node, type ParseResult, type PathSegment, type Pipe, type PipeEnv, type Pos, type Project, type RenderEnv, RenderError, type RenderOptions, SafeHtml, type Span, type TemplateAst, URL_ATTRS, type Views, type ViewsBundle, type ViewsOptions, type ViteManifest, type ViteManifestChunk, assetTags, builtinPipes, bundleLoader, check, componentTag, createViews, escapeHtml, escapeJsonForScript, isUrlAttr, layoutResolver, parse, parseExpression, pipesFor, positionAt, read, readPipeExports, render, safeHtml, safeStyleValue, sanitizeSrcset, sanitizeUrl, templateName, useFileLoader, viewsMiddleware, withEnv };
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/format.ts"],"mappings":";;;;;;UAWiB;;EAEf;;wBAgQc,OACd,gBACA,cACA,OAAM;EACH;EAAiB,aAAa"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-view v0.
|
|
2
|
+
* @forinda/kickjs-view v0.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Felix Orinda
|
|
5
5
|
*
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import{S as positionAt,_ as templateName,a as escapeHtml,c as safeStyleValue,d as parse,f as FORBIDDEN_NAMES,g as layoutResolver,h as componentTag,i as SafeHtml,l as sanitizeSrcset,m as check,n as BUILTIN_PIPES,o as escapeJsonForScript,p as parseExpression,r as builtinPipes,s as read,t as readPipeExports,u as sanitizeUrl,v as URL_ATTRS,w as AST_FORMAT_VERSION,y as isUrlAttr}from"./read-exports-
|
|
11
|
+
import{S as positionAt,_ as templateName,a as escapeHtml,c as safeStyleValue,d as parse,f as FORBIDDEN_NAMES,g as layoutResolver,h as componentTag,i as SafeHtml,l as sanitizeSrcset,m as check,n as BUILTIN_PIPES,o as escapeJsonForScript,p as parseExpression,r as builtinPipes,s as read,t as readPipeExports,u as sanitizeUrl,v as URL_ATTRS,w as AST_FORMAT_VERSION,y as isUrlAttr}from"./read-exports-BdIwY1WT.js";import{a as createViews,c as RenderError,d as safeHtml,f as withEnv,i as bundleLoader,l as render,n as KickView,o as useFileLoader,r as viewsMiddleware,s as MAX_DEPTH,t as assetTags,u as pipesFor}from"./exports-CE5wwor2.js";import{t as format}from"./format-Qy3r4aci.js";useFileLoader(()=>import(`./file-loader.js`));export{AST_FORMAT_VERSION,BUILTIN_PIPES,FORBIDDEN_NAMES,KickView,MAX_DEPTH,RenderError,SafeHtml,URL_ATTRS,assetTags,builtinPipes,bundleLoader,check,componentTag,createViews,escapeHtml,escapeJsonForScript,format,isUrlAttr,layoutResolver,parse,parseExpression,pipesFor,positionAt,read,readPipeExports,render,safeHtml,safeStyleValue,sanitizeSrcset,sanitizeUrl,templateName,useFileLoader,viewsMiddleware,withEnv};
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * The Node entry (Node, Bun, Deno): everything, plus the file loader as the\n * default template source. Edge runtimes resolve `./edge` instead.\n */\nimport { useFileLoader } from './views'\n\nuseFileLoader(() => import('./loaders/file'))\n\nexport * from './exports'\n"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * The Node entry (Node, Bun, Deno): everything, plus the file loader as the\n * default template source. Edge runtimes resolve `./edge` instead.\n */\nimport { useFileLoader } from './views'\n\nuseFileLoader(() => import('./loaders/file'))\n\nexport * from './exports'\nexport { format, type FormatOptions } from './format'\n"],"mappings":";;;;;;;;;;wqBAMA,kBAAoB,OAAO,mBAAiB"}
|