Skip to content

Commit 369c88f

Browse files
committed
0.6.1: [van-plate] not escaping for <style> tag as well (in addition to <script> tag)
1 parent 6d4f92a commit 369c88f

12 files changed

+265
-11
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ Sample code:
154154
_Requires Deno `1.35` or later._
155155
156156
```typescript
157-
import van from "https://deno.land/x/[email protected].0/src/van-plate.js"
157+
import van from "https://deno.land/x/[email protected].1/src/van-plate.js"
158158

159159
const {a, body, li, p, ul} = van.tags
160160

@@ -195,7 +195,7 @@ _Requires Deno `1.35` or later._
195195
196196
```typescript
197197
import { DOMParser } from "https://deno.land/x/[email protected]/deno-dom-wasm.ts"
198-
import van from "https://deno.land/x/[email protected].0/src/mini-van.js"
198+
import van from "https://deno.land/x/[email protected].1/src/mini-van.js"
199199

200200
const document = new DOMParser().parseFromString("", "text/html")!
201201
const {tags, html} = van.vanWithDoc(document)
@@ -235,16 +235,16 @@ Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanj
235235
To get started on the client side, add the line below to your script:
236236
237237
```javascript
238-
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.0.min.js"
238+
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.1.min.js"
239239
```
240240
241241
To code without ES6 modules, add the following line to your HTML file instead:
242242
243243
```html
244-
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.0.nomodule.min.js"></script>
244+
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.1.nomodule.min.js"></script>
245245
```
246246
247-
Alternative, you can download the files ([`mini-van-0.6.0.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.min.js), [`mini-van-0.6.0.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.nomodule.min.js)) and serve them locally.
247+
Alternative, you can download the files ([`mini-van-0.6.1.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.1.min.js), [`mini-van-0.6.1.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.1.nomodule.min.js)) and serve them locally.
248248
249249
You can find all relevant **Mini-Van** files in this [Download Table](https://vanjs.org/minivan#download-table).
250250

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mini-van-plate",
3-
"version": "0.6.0",
3+
"version": "0.6.1",
44
"description": "A minimalist template engine for DOM generation and manipulation, working for both client-side and server-side rendering",
55
"files": [
66
"src/mini-van.js",

public/mini-van-0.6.1.d.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export interface State<T> {
2+
val: T
3+
readonly oldVal: T
4+
readonly rawVal: T
5+
}
6+
7+
// Defining readonly view of State<T> for covariance.
8+
// Basically we want StateView<string> to implement StateView<string | number>
9+
export type StateView<T> = Readonly<State<T>>
10+
11+
export type Primitive = string | number | boolean | bigint
12+
13+
export type PropValue = Primitive | ((e: any) => void) | null
14+
15+
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)>
16+
17+
interface HasFirstChild {firstChild?: unknown}
18+
19+
type NodeType<ElementType extends HasFirstChild> =
20+
Omit<ElementType["firstChild"], "after" | "before" | "remove" | "replaceWith">
21+
22+
export type ValidChildDomValue<ElementType extends HasFirstChild, TextNodeType> =
23+
Primitive | ElementType | NodeType<ElementType> | TextNodeType | null | undefined
24+
25+
export type BindingFunc<ElementType extends HasFirstChild, TextNodeType> =
26+
| ((dom?: ElementType | TextNodeType) => ValidChildDomValue<ElementType, TextNodeType>)
27+
| ((dom?: ElementType) => ElementType)
28+
29+
export type ChildDom<ElementType extends HasFirstChild, TextNodeType> =
30+
| ValidChildDomValue<ElementType, TextNodeType>
31+
| StateView<Primitive | null | undefined>
32+
| BindingFunc<ElementType, TextNodeType>
33+
| readonly ChildDom<ElementType, TextNodeType>[]
34+
35+
type AddFunc<ElementType extends HasFirstChild, TextNodeType> =
36+
(dom: ElementType, ...children: readonly ChildDom<ElementType, TextNodeType>[]) => ElementType
37+
38+
export type TagFunc<ElementType extends HasFirstChild, TextNodeType, ResultType = ElementType> =
39+
(first?: Props | ChildDom<ElementType, TextNodeType>,
40+
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => ResultType
41+
42+
type Tags<ElementType extends HasFirstChild, TextNodeType> =
43+
Readonly<Record<string, TagFunc<ElementType, TextNodeType>>>
44+
45+
// Tags type in browser context, which contains the signatures to tag functions that return
46+
// specialized DOM elements.
47+
type BrowserTags = Tags<Element, Text> & {
48+
[K in keyof HTMLElementTagNameMap]: TagFunc<Element, Text, HTMLElementTagNameMap[K]>
49+
}
50+
51+
declare function state<T>(): State<T>
52+
declare function state<T>(initVal: T): State<T>
53+
54+
export interface VanObj<ElementType extends HasFirstChild, TextNodeType> {
55+
readonly state: typeof state
56+
readonly derive: <T>(f: () => T) => State<T>
57+
readonly add: AddFunc<ElementType, TextNodeType>
58+
readonly tags: Tags<ElementType, TextNodeType> & ((namespaceURI: string) => Tags<ElementType, TextNodeType>)
59+
60+
// Mini-Van specific API
61+
html: (first?: Props | ChildDom<ElementType, TextNodeType>,
62+
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => string
63+
}
64+
65+
export interface Van extends VanObj<Element, Text> {
66+
readonly vanWithDoc: <ElementType extends HasFirstChild, TextNodeType>(doc: {
67+
createElement(s: any): ElementType,
68+
createTextNode(s: any): TextNodeType,
69+
}) => VanObj<ElementType, TextNodeType>
70+
readonly tags: BrowserTags & ((namespaceURI: string) => Tags<Element, Text>)
71+
}
72+
73+
declare const van: Van
74+
75+
export default van

public/mini-van-0.6.1.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/// <reference types="./mini-van.d.ts" />
2+
3+
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.
4+
5+
// Aliasing some builtin symbols to reduce the bundle size.
6+
let protoOf = Object.getPrototypeOf, _undefined, funcProto = protoOf(protoOf)
7+
8+
let stateProto = {get oldVal() { return this.val }, get rawVal() { return this.val }}
9+
let objProto = protoOf(stateProto)
10+
11+
let state = initVal => ({__proto__: stateProto, val: initVal})
12+
13+
let plainValue = (k, v) => {
14+
let protoOfV = protoOf(v ?? 0)
15+
return protoOfV === stateProto ? v.val :
16+
protoOfV !== funcProto || k?.startsWith("on") ? v : v()
17+
}
18+
19+
let add = (dom, ...children) =>
20+
(dom.append(...children.flat(Infinity)
21+
.map(plainValue.bind(_undefined, _undefined))
22+
.filter(c => c != _undefined)),
23+
dom)
24+
25+
let vanWithDoc = doc => {
26+
let tag = (ns, name, ...args) => {
27+
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
28+
let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name)
29+
for (let [k, v] of Object.entries(props)) {
30+
let plainV = plainValue(k, v)
31+
// Disable setting attribute for function-valued properties (mostly event handlers),
32+
// as they're usually not useful for SSR (server-side rendering).
33+
protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV)
34+
}
35+
return add(dom, ...children)
36+
}
37+
38+
let handler = ns => ({get: (_, name) => tag.bind(_undefined, ns, name)})
39+
let tags = new Proxy(ns => new Proxy(tag, handler(ns)), handler())
40+
41+
return {
42+
add, tags, state, derive: f => state(f()),
43+
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML,
44+
}
45+
}
46+
47+
export default {"vanWithDoc": vanWithDoc,
48+
...vanWithDoc(typeof window !== "undefined" ? window.document : null)}

public/mini-van-0.6.1.min.d.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export interface State<T> {
2+
val: T
3+
readonly oldVal: T
4+
readonly rawVal: T
5+
}
6+
7+
// Defining readonly view of State<T> for covariance.
8+
// Basically we want StateView<string> to implement StateView<string | number>
9+
export type StateView<T> = Readonly<State<T>>
10+
11+
export type Primitive = string | number | boolean | bigint
12+
13+
export type PropValue = Primitive | ((e: any) => void) | null
14+
15+
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)>
16+
17+
interface HasFirstChild {firstChild?: unknown}
18+
19+
type NodeType<ElementType extends HasFirstChild> =
20+
Omit<ElementType["firstChild"], "after" | "before" | "remove" | "replaceWith">
21+
22+
export type ValidChildDomValue<ElementType extends HasFirstChild, TextNodeType> =
23+
Primitive | ElementType | NodeType<ElementType> | TextNodeType | null | undefined
24+
25+
export type BindingFunc<ElementType extends HasFirstChild, TextNodeType> =
26+
| ((dom?: ElementType | TextNodeType) => ValidChildDomValue<ElementType, TextNodeType>)
27+
| ((dom?: ElementType) => ElementType)
28+
29+
export type ChildDom<ElementType extends HasFirstChild, TextNodeType> =
30+
| ValidChildDomValue<ElementType, TextNodeType>
31+
| StateView<Primitive | null | undefined>
32+
| BindingFunc<ElementType, TextNodeType>
33+
| readonly ChildDom<ElementType, TextNodeType>[]
34+
35+
type AddFunc<ElementType extends HasFirstChild, TextNodeType> =
36+
(dom: ElementType, ...children: readonly ChildDom<ElementType, TextNodeType>[]) => ElementType
37+
38+
export type TagFunc<ElementType extends HasFirstChild, TextNodeType, ResultType = ElementType> =
39+
(first?: Props | ChildDom<ElementType, TextNodeType>,
40+
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => ResultType
41+
42+
type Tags<ElementType extends HasFirstChild, TextNodeType> =
43+
Readonly<Record<string, TagFunc<ElementType, TextNodeType>>>
44+
45+
// Tags type in browser context, which contains the signatures to tag functions that return
46+
// specialized DOM elements.
47+
type BrowserTags = Tags<Element, Text> & {
48+
[K in keyof HTMLElementTagNameMap]: TagFunc<Element, Text, HTMLElementTagNameMap[K]>
49+
}
50+
51+
declare function state<T>(): State<T>
52+
declare function state<T>(initVal: T): State<T>
53+
54+
export interface VanObj<ElementType extends HasFirstChild, TextNodeType> {
55+
readonly state: typeof state
56+
readonly derive: <T>(f: () => T) => State<T>
57+
readonly add: AddFunc<ElementType, TextNodeType>
58+
readonly tags: Tags<ElementType, TextNodeType> & ((namespaceURI: string) => Tags<ElementType, TextNodeType>)
59+
60+
// Mini-Van specific API
61+
html: (first?: Props | ChildDom<ElementType, TextNodeType>,
62+
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => string
63+
}
64+
65+
export interface Van extends VanObj<Element, Text> {
66+
readonly vanWithDoc: <ElementType extends HasFirstChild, TextNodeType>(doc: {
67+
createElement(s: any): ElementType,
68+
createTextNode(s: any): TextNodeType,
69+
}) => VanObj<ElementType, TextNodeType>
70+
readonly tags: BrowserTags & ((namespaceURI: string) => Tags<Element, Text>)
71+
}
72+
73+
declare const van: Van
74+
75+
export default van

public/mini-van-0.6.1.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mini-van-0.6.1.nomodule.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
(() => {
2+
// mini-van.js
3+
var protoOf = Object.getPrototypeOf;
4+
var _undefined;
5+
var funcProto = protoOf(protoOf);
6+
var stateProto = { get oldVal() {
7+
return this.val;
8+
}, get rawVal() {
9+
return this.val;
10+
} };
11+
var objProto = protoOf(stateProto);
12+
var state = (initVal) => ({ __proto__: stateProto, val: initVal });
13+
var plainValue = (k, v) => {
14+
let protoOfV = protoOf(v ?? 0);
15+
return protoOfV === stateProto ? v.val : protoOfV !== funcProto || k?.startsWith("on") ? v : v();
16+
};
17+
var add = (dom, ...children) => (dom.append(...children.flat(Infinity).map(plainValue.bind(_undefined, _undefined)).filter((c) => c != _undefined)), dom);
18+
var vanWithDoc = (doc) => {
19+
let tag = (ns, name, ...args) => {
20+
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args];
21+
let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name);
22+
for (let [k, v] of Object.entries(props)) {
23+
let plainV = plainValue(k, v);
24+
protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV);
25+
}
26+
return add(dom, ...children);
27+
};
28+
let handler = (ns) => ({ get: (_, name) => tag.bind(_undefined, ns, name) });
29+
let tags = new Proxy((ns) => new Proxy(tag, handler(ns)), handler());
30+
return {
31+
add,
32+
tags,
33+
state,
34+
derive: (f) => state(f()),
35+
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML
36+
};
37+
};
38+
var mini_van_default = {
39+
"vanWithDoc": vanWithDoc,
40+
...vanWithDoc(typeof window !== "undefined" ? window.document : null)
41+
};
42+
43+
// mini-van.forbundle.js
44+
window.van = mini_van_default;
45+
})();

public/mini-van-0.6.1.nomodule.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mini-van.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.6.0
1+
0.6.1

src/van-plate.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const noChild = {
1919
keygen: 1,
2020
}
2121

22+
const tagsNoEscape = {
23+
"script": 1,
24+
"style": 1,
25+
}
26+
2227
const escapeMap = {
2328
'&': '&amp;',
2429
'<': '&lt;',
@@ -48,7 +53,7 @@ const elementProto = {
4853
for (const c of this.children) {
4954
const plainC = plainValue(c)
5055
protoOf(plainC) === elementProto ? plainC.renderToBuf(buf) :
51-
buf.push((this.name === "script" ? x => x : escape)(plainC.toString()))
56+
buf.push((tagsNoEscape[this.name] ? x => x : escape)(plainC.toString()))
5257
}
5358
buf.push(`</${this.name}>`)
5459
},

test/deno/van-plate.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
22
import van from "../../src/van-plate.js"
33

4-
const {a, body, br, button, div, head, hr, input, li, p, pre, script, span, title, ul} = van.tags
4+
const {a, body, br, button, div, head, hr, input, li, p, pre, script, span, style, title, ul} = van.tags
55

66
Deno.test("tags", () => {
77
assertEquals(div(
@@ -41,6 +41,10 @@ Deno.test("don't escape script tag", () => {
4141
assertEquals(script("console.log(a < b && c > d)").render(), "<script>console.log(a < b && c > d)</script>")
4242
})
4343

44+
Deno.test("don't escape style tag", () => {
45+
assertEquals(style("ul > li { list-style-type: square; }").render(), "<style>ul > li { list-style-type: square; }</style>")
46+
})
47+
4448
Deno.test("nested children", () => {
4549
assertEquals(ul([li("Item 1"), li("Item 2"), li("Item 3")]).render(),
4650
"<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>")

0 commit comments

Comments
 (0)