Socket
Socket
Sign inDemoInstall

mini-van-plate

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mini-van-plate - npm Package Compare versions

Comparing version 0.3.9 to 0.4.0-rc.0

9

package.json
{
"name": "mini-van-plate",
"version": "0.3.9",
"version": "0.4.0-rc.0",
"description": "A minimalist template engine for DOM generation and manipulation, working for both client-side and server-side rendering",

@@ -36,5 +36,6 @@ "files": [

"devDependencies": {
"esbuild": "^0.17.12",
"terser": "^5.17.1",
"typescript": "^5.0.4"
"esbuild": "^0.17.19",
"node-jq": "^2.3.5",
"terser": "^5.19.2",
"typescript": "^5.1.6"
},

@@ -41,0 +42,0 @@ "repository": {

@@ -27,3 +27,3 @@ # **Mini-Van**: A Minimalist Template Engine for Client/Server-side Rendering without JSX

## Server-Side: Npm Integration
## Server-Side: NPM Integration

@@ -54,3 +54,3 @@ **Mini-Van** can be used on the server side as a template engine to render dynamic web content for HTTP servers. An NPM package was published here: [www.npmjs.com/package/mini-van-plate](https://www.npmjs.com/package/mini-van-plate). Thus it can be used in [Node.js](https://nodejs.org/) or [Bun](https://bun.sh/).

console.log("Testing DOM rendering...")
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` in the console
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())

@@ -77,2 +77,4 @@

Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/node-examples/van-plate-server?file=/van-plate-server.mjs:1,1).
As illustrated in the example, `render` method can be called on the object returned from the [`tag function`](https://vanjs.org/tutorial#api-tags) to generate a `string` that can be used for serving.

@@ -139,2 +141,4 @@

Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/node-examples/mini-van-server?file=/mini-van-server.mjs:1,1).
Similar to `van-plate` mode, we have a helper function `html` defined in `mini-van.js` which is equivalent to:

@@ -153,4 +157,6 @@

Sample code:
_Requires Deno `1.35` or later._
```typescript
import { serve } from "https://deno.land/std@0.184.0/http/server.ts"
import van from "https://deno.land/x/minivan@0.3.9/src/van-plate.js"

@@ -163,7 +169,7 @@

console.log("Testing DOM rendering...")
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` in the console
// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())
console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`)
await serve(req => new Response(
Deno.serve({port}, req => new Response(
van.html(

@@ -183,5 +189,7 @@ body(

},
), {port})
))
```
Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/deno-examples/van-plate-server?file=/van-plate-server.ts:1,1).
### `mini-van` mode

@@ -193,4 +201,5 @@

_Requires Deno `1.35` or later._
```typescript
import { serve } from "https://deno.land/std@0.184.0/http/server.ts"
import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"

@@ -212,3 +221,3 @@ import van from "https://deno.land/x/minivan@0.3.9/src/mini-van.js"

console.log(`HTTP webserver running. Access it at: http://localhost:${port}/`)
await serve(req => new Response(
Deno.serve({port}, req => new Response(
html(

@@ -228,5 +237,7 @@ body(

},
), {port})
))
```
Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/deno-examples/mini-van-server?file=/mini-van-server.ts:1,1).
## Client-Side: Getting Started

@@ -233,0 +244,0 @@

@@ -0,22 +1,36 @@

export interface State<T> {
val: T
readonly oldVal: T
}
// Defining readonly view of State<T> for covariance.
// Basically we want StateView<string> to implement StateView<string | number>
export type StateView<T> = Readonly<State<T>>
export type Primitive = string | number | boolean | bigint
export type PropValue = Primitive | Function | null
export type PropValue = Primitive | null
export interface Props {
readonly [key: string]: PropValue
}
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)>
export type ChildDom<ElementType, TextNodeType> = Primitive | ElementType | TextNodeType
| readonly ChildDom<ElementType, TextNodeType>[] | null | undefined
export type ValidChildDomValue<ElementType, TextNodeType> =
Primitive | ElementType | TextNodeType | null | undefined
export type BindingFunc<ElementType, TextNodeType> =
(dom: ElementType | TextNodeType) => ValidChildDomValue<ElementType, TextNodeType>
export type ChildDom<ElementType, TextNodeType> =
| ValidChildDomValue<ElementType, TextNodeType>
| StateView<Primitive | null | undefined>
| BindingFunc<ElementType, TextNodeType>
| readonly ChildDom<ElementType, TextNodeType>[]
type AddFunc<ElementType, TextNodeType> =
(dom: ElementType, ...children: readonly ChildDom<ElementType, TextNodeType>[]) => ElementType
export type TagFunc<ElementType = Element, TextNodeType = Text, ResultType = ElementType> =
export type TagFunc<ElementType, TextNodeType, ResultType = ElementType> =
(first?: Props | ChildDom<ElementType, TextNodeType>,
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => ResultType
interface Tags<ElementType, TextNodeType> {
readonly [key: string]: TagFunc<ElementType, TextNodeType>
}
type Tags<ElementType, TextNodeType> = Record<string, TagFunc<ElementType, TextNodeType>>

@@ -131,9 +145,13 @@ // Tags type in browser context, which contains the signatures to tag functions that return

type VanWithDoc = <ElementType, TextNodeType>(
doc: {
createElement(s: any): ElementType,
createTextNode(s: any): TextNodeType,
}) => {
add: AddFunc<ElementType, TextNodeType>
tags: Tags<ElementType, TextNodeType>
export interface VanObj<ElementType, TextNodeType> {
readonly state: <T>(initVal: T) => State<T>
readonly val: <T>(s: T | StateView<T>) => T
readonly oldVal: <T>(s: T | StateView<T>) => T
readonly derive: <T>(f: () => T) => State<T>
readonly add: AddFunc<ElementType, TextNodeType>
readonly _: (f: () => PropValue) => () => PropValue
readonly tags: Tags<ElementType, TextNodeType>
readonly tagsNS: (namespaceURI: string) => Tags<ElementType, TextNodeType>
// Mini-Van specific API
html: (first?: Props | ChildDom<ElementType, TextNodeType>,

@@ -143,8 +161,8 @@ ...rest: readonly ChildDom<ElementType, TextNodeType>[]) => string

export interface Van {
readonly vanWithDoc: VanWithDoc
readonly add: AddFunc<Element, Text>
export interface Van extends VanObj<Element, Text> {
readonly vanWithDoc: <ElementType, TextNodeType>(doc: {
createElement(s: any): ElementType,
createTextNode(s: any): TextNodeType,
}) => VanObj<ElementType, TextNodeType>
readonly tags: BrowserTags
html: (first?: Props | ChildDom<Element, Text>,
...rest: readonly ChildDom<Element, Text>[]) => string
}

@@ -151,0 +169,0 @@

@@ -6,29 +6,42 @@ /// <reference types="./mini-van.d.ts" />

// Aliasing some builtin symbols to reduce the bundle size.
let Obj = Object, protoOf = Obj.getPrototypeOf, _undefined
let protoOf = Object.getPrototypeOf, _undefined, funcProto = protoOf(protoOf)
let stateProto = {get oldVal() { return this.val }}, objProto = protoOf(stateProto)
let state = initVal => ({__proto__: stateProto, val: initVal})
let val = s => protoOf(s ?? 0) === stateProto ? s.val : s
let plainValue = (k, v) => {
let protoOfV = protoOf(v ?? 0)
return protoOfV === stateProto ? v.val :
protoOfV === funcProto && (!k?.startsWith("on") || v._isBindingFunc) ? v() : v
}
let add = (dom, ...children) =>
(dom.append(...children.flat(Infinity)
.map(plainValue.bind(_undefined, _undefined))
.filter(c => c != _undefined)),
dom)
let vanWithDoc = doc => {
let propSetterCache = {}
let tagsNS = ns => new Proxy((name, ...args) => {
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name)
for (let [k, v] of Object.entries(props)) {
let plainV = plainValue(k, v)
// Disable setting attribute for function-valued properties (mostly event handlers),
// as they're usually not useful for SSR (server-side rendering).
protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV)
}
return add(dom, ...children)
}, {get: (tag, name) => tag.bind(null, name)})
let _result = {
add: (dom, ...children) =>
(dom.append(...children.flat(Infinity).filter(c => c != _undefined)), dom),
let tags = tagsNS()
tags: new Proxy((name, ...args) => {
let [props, ...children] = args[0]?.constructor === Obj ? args : [{}, ...args]
let dom = doc.createElement(name)
for (let [k, v] of Obj.entries(props)) {
let getPropDescriptor = proto => proto ?
Obj.getOwnPropertyDescriptor(proto, k) ?? getPropDescriptor(protoOf(proto)) :
_undefined
let cacheKey = name + "," + k
let propSetter = propSetterCache[cacheKey] ??
(propSetterCache[cacheKey] = getPropDescriptor(protoOf(dom))?.set ?? 0)
propSetter ? propSetter.call(dom, v) : dom.setAttribute(k, v)
}
return _result.add(dom, ...children)
}, {get: (tag, name) => tag.bind(null, name)}),
"html": (...args) => "<!DOCTYPE html>" + _result.tags.html(...args).outerHTML,
return {
add, _: f => (f._isBindingFunc = 1, f), tags, tagsNS, state,
val, oldVal: val, derive: f => state(f()),
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML,
}
return _result
}

@@ -35,0 +48,0 @@

@@ -1,23 +0,40 @@

type Primitive = string | number | boolean | bigint
export interface Props {
readonly [key: string]: Primitive
export interface State<T> {
val: T
readonly oldVal: T
}
// Defining readonly view of State<T> for covariance.
// Basically we want StateView<string> to implement StateView<string | number>
export type StateView<T> = Readonly<State<T>>
export type Primitive = string | number | boolean | bigint
export type PropValue = Primitive | null
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)>
export interface Element { render(): string }
export type ChildDom = Primitive | Element | readonly ChildDom[] | null | undefined
export type ValidChildDomValue = Primitive | Element | null | undefined
export type BindingFunc = (dom: any) => ValidChildDomValue
export type ChildDom = ValidChildDomValue | StateView<Primitive | null | undefined> | BindingFunc | readonly ChildDom[]
export type TagFunc = (first?: Props | ChildDom, ...rest: readonly ChildDom[]) => Element
export type Tags = {
readonly [key: string]: TagFunc
}
declare const van: {
export interface Van {
readonly state: <T>(initVal: T) => State<T>
readonly val: <T>(s: T | StateView<T>) => T
readonly oldVal: <T>(s: T | StateView<T>) => T
readonly derive: <T>(f: () => T) => State<T>
readonly add: (dom: Element, ...children: readonly ChildDom[]) => Element
readonly tags: Tags
readonly _: (f: () => PropValue) => () => PropValue
readonly tags: Record<string, TagFunc>
readonly tagsNS: (namespaceURI: string) => Record<string, TagFunc>
readonly html: (first?: Props | ChildDom, ...rest: readonly ChildDom[]) => string
}
declare const van: Van
export default van

@@ -22,11 +22,26 @@ /// <reference types="./van-plate.d.ts" />

const escape = s => {
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
}
return s.replace(/[&<>]/g, tag => map[tag] || tag)
const escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
}
const escape = s => s.replace(/[&<>]/g, tag => escapeMap[tag] || tag)
const escapeAttr = v => v.replace(/"/g, "&quot;")
const protoOf = Object.getPrototypeOf, funcProto = protoOf(protoOf), objProto = protoOf(noChild)
const stateProto = {get oldVal() { return this.val }}
const state = initVal => ({__proto__: stateProto, val: initVal})
const val = s => protoOf(s ?? 0) === stateProto ? s.val : s
const plainValue = (v, k) => {
let protoOfV = protoOf(v ?? 0)
return protoOfV === stateProto ? v.val :
protoOfV === funcProto && (!k?.startsWith("on") || v._isBindingFunc) ? v() : v
}
const elementProto = {

@@ -41,10 +56,16 @@ render() {

const toStr = children => children.map(
c => Object.getPrototypeOf(c) === elementProto ? c.render() : escape(c.toString())).join("")
c => {
const plainC = plainValue(c)
return protoOf(plainC) === elementProto ? plainC.render() : escape(plainC.toString())
}).join("")
const tags = new Proxy((name, ...args) => {
const [props, ...children] = Object.getPrototypeOf(args[0] ?? 0) === Object.prototype ?
args : [{}, ...args]
const propsStr = Object.entries(props).map(([k, v]) =>
typeof v === "boolean" ?
(v ? " " + k : "") : ` ${k}=${JSON.stringify(v)}`).join("")
const [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
const propsStr = Object.entries(props).map(([k, v]) => {
const plainV = plainValue(v, k), lowerK = k.toLowerCase()
return typeof plainV === "boolean" ? (plainV ? " " + lowerK : "") :
// Disable setting attribute for function-valued properties (mostly event handlers),
// as they're usually not useful for SSR (server-side rendering).
protoOf(plainV) !== funcProto ? ` ${lowerK}=${JSON.stringify(escapeAttr(plainV.toString()))}` : ""
}).join("")
const flattenedChildren = children.flat(Infinity).filter(c => c != null)

@@ -61,4 +82,6 @@ return {__proto__: elementProto, name, propsStr,

const html = (...args) => "<!DOCTYPE html>" + tags.html(...args).render()
export default {add, tags, html}
export default {
add, _: f => (f._isBindingFunc = 1, f), tags, tagsNS: () => tags, state,
val, oldVal: val, derive: f => state(f()),
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).render()
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc