@css-everything/render
Advanced tools
Comparing version
@@ -1,15 +0,11 @@ | ||
import { EvalActions } from './eval'; | ||
import { EvalActions, EvalValue } from './eval'; | ||
import { Expr, Selector } from './parser'; | ||
export interface Declaration { | ||
selector: Selector; | ||
properties: Map<string, Expr>; | ||
properties: Map<string, EvalValue>; | ||
children: Array<Declaration>; | ||
isInstance: boolean; | ||
} | ||
export interface DeclarationEval { | ||
selector: Selector; | ||
properties: Array<readonly [string, string]>; | ||
} | ||
export declare const evaluateDeclaration: ({ selector, properties }: Declaration, actions: EvalActions) => Promise<DeclarationEval>; | ||
export declare const toDeclaration: (expr: Expr) => Declaration | undefined; | ||
export declare const expressionsToDeclrs: (exprs: Array<Expr>, actions: EvalActions) => Promise<Array<DeclarationEval>>; | ||
export declare const extractDeclaration: (input: string, actions: EvalActions) => Promise<Array<DeclarationEval>>; | ||
export declare const toDeclaration: (actions: EvalActions) => (expr: Expr) => Promise<Declaration | undefined>; | ||
export declare const expressionsToDeclrs: (exprs: Array<Expr>, actions: EvalActions) => Promise<Array<Declaration>>; | ||
export declare const extractDeclaration: (input: string, actions: EvalActions) => Promise<Array<Declaration>>; |
import { evalExpr } from './eval'; | ||
import { SelectorComp, parseDeclarations } from './parser'; | ||
import { match, matchString } from './utils/adt'; | ||
export const evaluateDeclaration = async ({ selector, properties }, actions) => { | ||
if (properties.size === 0) | ||
return { selector, properties: [] }; | ||
const props = await Promise.all([...properties.entries()].map(async ([key, expr]) => { | ||
// Ignore errors? | ||
const result = await evalExpr(expr, actions).catch(e => console.warn(e)); | ||
return [key, result ?? '']; | ||
})); | ||
return { selector, properties: props }; | ||
}; | ||
const instanceCountMap = new Map(); | ||
@@ -20,13 +10,38 @@ const getUniqueInstanceId = (id) => { | ||
}; | ||
export const toDeclaration = (expr) => { | ||
export const toDeclaration = (actions) => async (expr) => { | ||
let selector; | ||
const properties = new Map(); | ||
const children = []; | ||
let isInstance = false; | ||
match(expr, { | ||
Selector: sel => { | ||
await match(expr, { | ||
Selector: async (sel) => { | ||
selector = sel; | ||
}, | ||
Call: ({ name, args }) => { | ||
matchString(name, { | ||
instance: () => { | ||
Call: async ({ name, args }) => { | ||
return matchString(name, { | ||
h: async () => { | ||
const [sel, map, childreExpr] = args; | ||
// Selector | ||
match(sel, { | ||
Selector: sel => { | ||
selector = sel; | ||
}, | ||
_: _ => { }, | ||
}); | ||
const props = await evalExpr(map, actions); | ||
match(props, { | ||
Map: props => { | ||
for (const [key, value] of Object.entries(props)) { | ||
properties.set(key, value); | ||
} | ||
}, | ||
_: _ => { }, | ||
}); | ||
const childrenExprs = await match(await evalExpr(childreExpr, actions), { | ||
Lazy: async (exprs) => Promise.all(exprs.map(toDeclaration(actions))), | ||
_: async (_) => [], | ||
}); | ||
children.push(...childrenExprs.filter(Boolean)); | ||
}, | ||
instance: async () => { | ||
isInstance = true; | ||
@@ -41,16 +56,13 @@ const [sel, map] = args; | ||
}); | ||
match(map, { | ||
Call: ({ name, args }) => { | ||
if (name !== 'map') | ||
return; | ||
for (const arg of args) { | ||
match(arg, { | ||
Pair: ({ key, value }) => properties.set(key, value), | ||
_: _ => { }, | ||
}); | ||
const props = await evalExpr(map, actions); | ||
match(props, { | ||
Map: props => { | ||
for (const [key, value] of Object.entries(props)) { | ||
properties.set(key, value); | ||
} | ||
}, | ||
_: _ => { }, | ||
}); | ||
}, | ||
_: () => { | ||
_: async () => { | ||
throw new Error(`weird function in cssx-chi9ldren: ${name}`); | ||
@@ -60,3 +72,3 @@ }, | ||
}, | ||
_: () => { }, | ||
_: async () => { }, | ||
}); | ||
@@ -70,9 +82,6 @@ if (!selector) | ||
} | ||
return { selector, properties, isInstance }; | ||
return { selector, properties, children, isInstance }; | ||
}; | ||
export const expressionsToDeclrs = async (exprs, actions) => { | ||
const declrs = await Promise.all(exprs | ||
.map(toDeclaration) | ||
.filter(declr => !!declr) | ||
.map(declr => declr && evaluateDeclaration(declr, actions))); | ||
const declrs = await Promise.all(exprs.map(toDeclaration(actions))); | ||
return declrs.filter(declr => !!declr); | ||
@@ -79,0 +88,0 @@ }; |
import { Expr } from './parser'; | ||
import { Enum } from './utils/adt'; | ||
export interface EvalActions { | ||
@@ -21,7 +22,32 @@ addClass(id: string, classes: string): Promise<void>; | ||
removeElement(id: string | undefined): Promise<void>; | ||
callMethod(id: string | undefined, method: string, args: EvalValue[]): Promise<void>; | ||
callMethod(id: string | undefined, method: string, args: (string | undefined)[]): Promise<void>; | ||
evaluateInScope(exprs: Expr[], properties: Record<string, EvalValue>): Promise<EvalValue>; | ||
} | ||
type EvalValue = string | undefined | void; | ||
export type EvalValue = Enum<{ | ||
String: string; | ||
Number: number; | ||
Boolean: boolean; | ||
Lazy: Array<Expr>; | ||
Void: never; | ||
VarIdentifier: string; | ||
Map: { | ||
[key in string]: EvalValue; | ||
}; | ||
Value: any; | ||
}>; | ||
export declare const EvalValue: { | ||
VarIdentifier: (value: string) => EvalValue; | ||
String: (value: string) => EvalValue; | ||
Number: (value: number) => EvalValue; | ||
Boolean: (value: boolean) => EvalValue; | ||
Lazy: (value: Expr[]) => EvalValue; | ||
Void: (value?: null | undefined) => EvalValue; | ||
Map: (value: { | ||
[x: string]: EvalValue; | ||
}) => EvalValue; | ||
Value: ((value?: null | undefined) => EvalValue) | ((value: any) => EvalValue); | ||
}; | ||
export declare const evalExprAsString: (expr: Expr, actions: EvalActions) => Promise<string | undefined>; | ||
export declare const evalExpr: (expr: Expr, actions: EvalActions) => Promise<EvalValue>; | ||
export declare const evalValueToString: (val: EvalValue) => string | undefined; | ||
export declare const evalArgs: (args: Array<Expr>, count: number, actions: EvalActions) => Promise<EvalValue[]>; | ||
export {}; |
229
dist/eval.js
@@ -1,13 +0,42 @@ | ||
import { match, matchString } from './utils/adt'; | ||
export const evalExpr = async (expr, actions) => match(expr, { | ||
Call: async ({ name, args }) => getFunctions(name, args, actions), | ||
LiteralString: async (s) => s, | ||
LiteralNumber: async ({ value, unit }) => matchString(unit, { | ||
s: () => value * 1000, | ||
_: () => value, | ||
}).toString(), | ||
Identifier: async (s) => s, | ||
VarIdentifier: async (s) => s, | ||
_: async (_) => undefined, | ||
import { parse } from './parser'; | ||
import { constructors, match, matchString } from './utils/adt'; | ||
export const EvalValue = constructors(); | ||
export const evalExprAsString = async (expr, actions) => evalValueToString(await evalExpr(expr, actions)); | ||
export const evalExpr = async (expr, actions) => { | ||
return match(expr, { | ||
Call: async ({ name, args }) => getFunctions(name, args, actions), | ||
LiteralString: async (s) => EvalValue.String(s), | ||
LiteralNumber: async ({ value, unit }) => EvalValue.Number(matchString(unit, { | ||
s: () => value * 1000, | ||
_: () => value, | ||
})), | ||
Identifier: async (s) => EvalValue.String(s), | ||
VarIdentifier: async (s) => EvalValue.VarIdentifier(s), | ||
_: async (_) => EvalValue.Void(), | ||
}); | ||
}; | ||
const QUOTE_REGEX = /^['"](.*)(?=['"]$)['"]$/g; | ||
const unquotify = (s) => s.replace(QUOTE_REGEX, '$1'); | ||
export const evalValueToString = (val) => match(val, { | ||
String: s => unquotify(s), | ||
Boolean: b => `${b}`, | ||
Number: n => `${n}`, | ||
VarIdentifier: s => s, | ||
Value: v => `${v}`, | ||
_: () => undefined, | ||
}); | ||
const evalValueToNumber = (val) => match(val, { | ||
String: s => parseFloat(s), | ||
Boolean: b => (b ? 1 : 0), | ||
Number: n => n, | ||
Value: v => parseFloat(v), | ||
_: () => undefined, | ||
}); | ||
const evalValueToBoolean = (val) => match(val, { | ||
String: s => !['false', '', '0'].includes(unquotify(s)), | ||
Boolean: b => b, | ||
Number: n => !!n, | ||
Value: v => !!v, | ||
_: () => false, | ||
}); | ||
const getFunctions = (name, args, actions) => { | ||
@@ -17,23 +46,37 @@ const getVariable = async () => { | ||
const defaultValue = args[1] && (await evalExpr(args[1], actions)); | ||
return varName && (actions.getVariable(varName) ?? defaultValue); | ||
return match(varName, { | ||
VarIdentifier: async (name) => { | ||
const value = await actions.getVariable(name); | ||
return value === undefined ? defaultValue : EvalValue.String(value); | ||
}, | ||
_: async () => EvalValue.Void(), | ||
}); | ||
}; | ||
const jsEval = async () => { | ||
const js = await evalExprAsString(args[0], actions); | ||
const result = js && (await actions.jsEval(js)); | ||
if (result === undefined || result === null) | ||
return EvalValue.Void(); | ||
return EvalValue.Value(result); | ||
}; | ||
return matchString(name, { | ||
'add-class': async () => { | ||
const id = await evalExpr(args[0], actions); | ||
const classes = await evalExpr(args[1], actions); | ||
const id = evalValueToString(await evalExpr(args[0], actions)); | ||
const classes = evalValueToString(await evalExpr(args[1], actions)); | ||
if (id && classes) { | ||
await actions.addClass(id, classes); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
'remove-class': async () => { | ||
const id = await evalExpr(args[0], actions); | ||
const classes = await evalExpr(args[1], actions); | ||
const id = evalValueToString(await evalExpr(args[0], actions)); | ||
const classes = evalValueToString(await evalExpr(args[1], actions)); | ||
if (id && classes) { | ||
await actions.removeClass(id, classes); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
if: async () => { | ||
const cond = await evalExpr(args[0], actions); | ||
const FALSEY = ['0', 'false']; | ||
if (cond && !FALSEY.includes(cond.replace(/(^'|")|('|"$)/g, ''))) { | ||
const cond = evalValueToBoolean(await evalExpr(args[0], actions)); | ||
if (cond) { | ||
return evalExpr(args[1], actions); | ||
@@ -46,15 +89,15 @@ } | ||
delay: async () => { | ||
const num = await evalExpr(args[0], actions); | ||
num && (await actions.delay(parseInt(num, 10))); | ||
const num = evalValueToNumber(await evalExpr(args[0], actions)); | ||
num !== undefined ? await actions.delay(num) : undefined; | ||
return EvalValue.Void(); | ||
}, | ||
'js-eval': async () => { | ||
const js = await evalExpr(args[0], actions); | ||
return js && (await actions.jsEval(js)); | ||
}, | ||
'js-eval': jsEval, | ||
'js-expr': jsEval, | ||
'load-cssx': async () => { | ||
const id = await evalExpr(args[0], actions); | ||
const url = await evalExpr(args[1], actions); | ||
const id = evalValueToString(await evalExpr(args[0], actions)); | ||
const url = evalValueToString(await evalExpr(args[1], actions)); | ||
if (id && url) { | ||
await actions.loadCssx(id, url); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
@@ -65,28 +108,42 @@ var: getVariable, | ||
const [id, name, value] = args.length >= 3 | ||
? await evalArgs(args, 3, actions) | ||
: [undefined, ...(await evalArgs(args, 2, actions))]; | ||
? (await evalArgs(args, 3, actions)).map(evalValueToString) | ||
: [ | ||
undefined, | ||
...(await evalArgs(args, 2, actions)).map(evalValueToString), | ||
]; | ||
if (name) { | ||
actions.updateVariable(id ?? undefined, name, value ?? ''); | ||
await actions.updateVariable(id ?? undefined, name, value ?? ''); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
'set-attr': async () => { | ||
const [id, name, value] = args.length >= 3 | ||
? await evalArgs(args, 3, actions) | ||
: [undefined, ...(await evalArgs(args, 2, actions))]; | ||
? (await evalArgs(args, 3, actions)).map(evalValueToString) | ||
: [ | ||
undefined, | ||
...(await evalArgs(args, 2, actions)).map(evalValueToString), | ||
]; | ||
if (name) { | ||
actions.setAttribute(id ?? undefined, name, value ?? ''); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
attr: async () => { | ||
const [id, name] = args.length >= 2 | ||
? await evalArgs(args, 2, actions) | ||
: [undefined, await evalExpr(args[0], actions)]; | ||
? (await evalArgs(args, 2, actions)).map(evalValueToString) | ||
: [undefined, evalValueToString(await evalExpr(args[0], actions))]; | ||
if (name) { | ||
return actions.getAttribute(id, name); | ||
const val = await actions.getAttribute(id, name); | ||
return val === undefined ? EvalValue.Void() : EvalValue.String(val); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
'prevent-default': async () => actions.withEvent(e => e.preventDefault()), | ||
'prevent-default': async () => { | ||
await actions.withEvent(e => e.preventDefault()); | ||
return EvalValue.Void(); | ||
}, | ||
request: async () => { | ||
const url = await evalExpr(args[0], actions); | ||
const method = (args[1] && (await evalExpr(args[1], actions))) ?? 'post'; | ||
const url = evalValueToString(await evalExpr(args[0], actions)); | ||
const method = (args[1] && evalValueToString(await evalExpr(args[1], actions))) || | ||
'post'; | ||
if (url) { | ||
@@ -96,18 +153,100 @@ const data = await actions.getFormData(); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
'add-children': async () => { | ||
const id = await evalExpr(args[0], actions); | ||
const id = evalValueToString(await evalExpr(args[0], actions)); | ||
if (id) | ||
actions.addChildren(id, args.slice(1)); | ||
await actions.addChildren(id, args.slice(1)); | ||
return EvalValue.Void(); | ||
}, | ||
'remove-element': async () => actions.removeElement((args[0] && (await evalExpr(args[0], actions))) ?? undefined), | ||
call: async () => { | ||
const [id, method, ...methodArgs] = await Promise.all(args.map(a => evalExpr(a, actions))); | ||
'remove-element': async () => { | ||
const selector = (args[0] && evalValueToString(await evalExpr(args[0], actions))) ?? | ||
undefined; | ||
if (selector) | ||
await actions.removeElement(selector); | ||
return EvalValue.Void(); | ||
}, | ||
'call-method': async () => { | ||
const [id, method, ...methodArgs] = (await Promise.all(args.map(a => evalExpr(a, actions)))).map(evalValueToString); | ||
if (id && method) { | ||
actions.callMethod(id, method, methodArgs); | ||
await actions.callMethod(id, method, methodArgs); | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
_: () => Promise.reject(new Error('not supposed to be here')), | ||
map: async () => { | ||
const values = await Promise.all(args.map(async (mapExpr) => match(mapExpr, { | ||
Pair: async ({ key, value }) => [ | ||
key, | ||
await evalExpr(value, actions), | ||
], | ||
_: async () => undefined, | ||
}))); | ||
return EvalValue.Map(Object.fromEntries(values.filter(Boolean))); | ||
}, | ||
seq: async () => EvalValue.Lazy(args), | ||
// noop | ||
noop: async () => EvalValue.Void(), | ||
func: async () => EvalValue.Void(), | ||
call: async () => { | ||
const varId = match(await evalExpr(args[0], actions), { | ||
VarIdentifier: id => id, | ||
_: () => undefined, | ||
}); | ||
const propMapExpr = args[1] | ||
? await evalExpr(args[1], actions) | ||
: EvalValue.Void(); | ||
const properties = match(propMapExpr, { | ||
Map: m => m, | ||
_: () => ({}), | ||
}); | ||
if (varId) { | ||
const prop = await actions.getVariable(varId); | ||
if (prop) { | ||
const exprs = parse(prop); | ||
return actions.evaluateInScope(exprs, properties); | ||
} | ||
} | ||
return EvalValue.Void(); | ||
}, | ||
string: async () => { | ||
const str = await Promise.all(args.map(a => evalExprAsString(a, actions))); | ||
return EvalValue.String(str.filter(Boolean).join('')); | ||
}, | ||
quotify: async () => { | ||
const str = await evalExprAsString(args[0], actions); | ||
return EvalValue.String(`'${str || ''}'`); | ||
}, | ||
unquotify: async () => { | ||
const str = await evalExprAsString(args[0], actions); | ||
return EvalValue.String(unquotify(str || '')); | ||
}, | ||
try: async () => { | ||
try { | ||
return await evalExpr(args[0], actions); | ||
} | ||
catch (e) { | ||
return actions.evaluateInScope([args[1]], { | ||
'--error': EvalValue.Value(e), | ||
}); | ||
} | ||
}, | ||
do: async () => { | ||
let result = EvalValue.Void(); | ||
for (const expr of args) { | ||
result = await evalExpr(expr, actions); | ||
} | ||
return result; | ||
}, | ||
let: async () => { | ||
const varName = await evalExprAsString(args[0], actions); | ||
const result = await evalExpr(args[1], actions); | ||
if (!varName) | ||
return EvalValue.Void(); | ||
return actions.evaluateInScope([args[2]], { | ||
[varName]: result, | ||
}); | ||
}, | ||
_: () => Promise.reject(new Error(`Not implemented: ${name}`)), | ||
}); | ||
}; | ||
export const evalArgs = (args, count, actions) => Promise.all(args.slice(0, count).map(e => evalExpr(e, actions))); |
import { EvalActions } from './eval'; | ||
import { DeclarationEval } from './declarations'; | ||
import { Declaration } from './declarations'; | ||
export declare const injectStyles: () => void; | ||
export declare const getPropertyValue: ($element: HTMLElement, prop: string) => string; | ||
export declare const getDeclarations: ($element: HTMLElement, actions: EvalActions) => Promise<Array<DeclarationEval>>; | ||
export declare const getDeclarations: ($element: HTMLElement, actions: EvalActions) => Promise<Array<Declaration>>; | ||
export declare const handleEvents: ($element: HTMLElement, isNewElement?: boolean) => Promise<void>; | ||
@@ -7,0 +7,0 @@ export declare const manageElement: ($element: HTMLElement, isNewElement?: boolean) => Promise<void>; |
@@ -1,2 +0,2 @@ | ||
import { evalExpr } from './eval'; | ||
import { EvalValue, evalExpr, evalExprAsString, evalValueToString, } from './eval'; | ||
import { extractDeclaration, expressionsToDeclrs, } from './declarations'; | ||
@@ -66,3 +66,4 @@ import { parse } from './parser'; | ||
}; | ||
const getEvalActions = ($element, { event = null, pure = false }) => { | ||
const getEvalActions = ($element, ctx) => { | ||
const { event = null, pure = false } = ctx; | ||
const actions = { | ||
@@ -155,5 +156,26 @@ addClass: async (id, cls) => getElement(id, $element)?.classList.add(cls), | ||
}, | ||
evaluateInScope: async (exprs, properties) => { | ||
const node = document.createElement('div'); | ||
node.style.display = 'none'; | ||
for (const [key, evalVal] of Object.entries(properties)) { | ||
const value = evalValueToString(evalVal); | ||
value && node.style.setProperty(key, value); | ||
} | ||
$element.appendChild(node); | ||
const result = await evalExprInScope(exprs, getEvalActions(node, ctx)); | ||
if (!$element.hasAttribute('data-debug-stack')) { | ||
node.parentNode?.removeChild(node); | ||
} | ||
return result; | ||
}, | ||
}; | ||
return actions; | ||
}; | ||
const evalExprInScope = async (exprs, actions) => { | ||
let lastVal = EvalValue.Void(); | ||
for (const expr of exprs) { | ||
lastVal = await evalExpr(expr, actions); | ||
} | ||
return lastVal; | ||
}; | ||
export const handleEvents = async ($element, isNewElement = false) => { | ||
@@ -164,6 +186,3 @@ for (const [eventType, property] of Object.entries(EVENT_HANDLERS)) { | ||
const eventHandler = async (event) => { | ||
const exprs = parse(handlerExpr); | ||
for (const expr of exprs) { | ||
await evalExpr(expr, getEvalActions($element, { event })); | ||
} | ||
await evalExprInScope(parse(handlerExpr), getEvalActions($element, { event })); | ||
}; | ||
@@ -189,3 +208,3 @@ matchString(eventType, { | ||
}; | ||
const declarationToElement = (declaration, $parent) => { | ||
const declarationToElement = async (declaration, $parent) => { | ||
const { tag, id, selectors } = declaration.selector; | ||
@@ -206,4 +225,5 @@ const tagName = tag || 'div'; | ||
} | ||
for (const [key, value] of declaration.properties) { | ||
$child?.style.setProperty(key, JSON.stringify(value)); | ||
for (const [key, evalValue] of declaration.properties) { | ||
const value = evalValueToString(evalValue); | ||
$child?.style.setProperty(key, JSON.stringify(value || '')); | ||
} | ||
@@ -220,5 +240,8 @@ return { node: $child, isNewElement }; | ||
for (const declaration of declarations) { | ||
const { node: $child, isNewElement } = declarationToElement(declaration, $childrenRoot); | ||
const { node: $child, isNewElement } = await declarationToElement(declaration, $childrenRoot); | ||
$childrenRoot.appendChild($child); | ||
await manageElement($child, isNewElement); | ||
if (declaration.children.length > 0) { | ||
await createLayer(declaration.children, $child); | ||
} | ||
} | ||
@@ -234,3 +257,3 @@ }; | ||
$element.textContent = | ||
(exprs[0] ? await evalExpr(exprs[0], actions) : text) ?? text; | ||
(exprs[0] ? await evalExprAsString(exprs[0], actions) : text) ?? text; | ||
} | ||
@@ -237,0 +260,0 @@ catch (e) { |
@@ -52,3 +52,4 @@ import { Enum } from './utils/adt'; | ||
}; | ||
export declare const parseExpr: (input: string) => Expr; | ||
export declare const parseDeclarations: (input: string) => Expr[]; | ||
export declare const parse: (input: string) => Array<Expr>; |
@@ -39,2 +39,14 @@ import { constructors, match } from './utils/adt'; | ||
]); | ||
export const parseExpr = (input) => { | ||
return match(exprParser(input), { | ||
Ok: ({ value, input }) => { | ||
if (input) | ||
throw new Error(`Aaaaaa. Input left: ${input}`); | ||
return value; | ||
}, | ||
Err: e => { | ||
throw e; | ||
}, | ||
}); | ||
}; | ||
const declarationParser = P.or([callExprParser, selectorExprParser]); | ||
@@ -55,3 +67,3 @@ const multiDeclarationParser = P.sepBy(declarationParser, whitespace); | ||
export const parse = (input) => { | ||
const res = P.many1(exprParser)(input.trim()); | ||
const res = P.sepBy(exprParser, P.or([comma, whitespace]))(input.trim()); | ||
return match(res, { | ||
@@ -58,0 +70,0 @@ Ok: ({ value, input }) => { |
@@ -1,4 +0,4 @@ | ||
"use strict";(()=>{var fe=Object.defineProperty,ge=Object.defineProperties;var xe=Object.getOwnPropertyDescriptors;var _=Object.getOwnPropertySymbols;var Y=Object.prototype.hasOwnProperty,J=Object.prototype.propertyIsEnumerable;var X=(r,t,e)=>t in r?fe(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e,W=(r,t)=>{for(var e in t||(t={}))Y.call(t,e)&&X(r,e,t[e]);if(_)for(var e of _(t))J.call(t,e)&&X(r,e,t[e]);return r},Q=(r,t)=>ge(r,xe(t));var G=(r,t)=>{var e={};for(var a in r)Y.call(r,a)&&t.indexOf(a)<0&&(e[a]=r[a]);if(r!=null&&_)for(var a of _(r))t.indexOf(a)<0&&J.call(r,a)&&(e[a]=r[a]);return e};var i=(r,t,e)=>new Promise((a,n)=>{var s=u=>{try{c(e.next(u))}catch(d){n(d)}},o=u=>{try{c(e.throw(u))}catch(d){n(d)}},c=u=>u.done?a(u.value):Promise.resolve(u.value).then(s,o);c((e=e.apply(r,t)).next())});var p=(r,t)=>(t[r.tag]||t._)(r.value),v=(r,t)=>(t[r]||t._)(r),S=()=>new Proxy({},{get(r,t){return e=>({tag:t,value:e})}});var l=(r,t)=>i(void 0,null,function*(){return p(r,{Call:n=>i(void 0,[n],function*({name:e,args:a}){return ve(e,a,t)}),LiteralString:e=>i(void 0,null,function*(){return e}),LiteralNumber:n=>i(void 0,[n],function*({value:e,unit:a}){return v(a,{s:()=>e*1e3,_:()=>e}).toString()}),Identifier:e=>i(void 0,null,function*(){return e}),VarIdentifier:e=>i(void 0,null,function*(){return e}),_:e=>i(void 0,null,function*(){})})}),ve=(r,t,e)=>{let a=()=>i(void 0,null,function*(){var o;let n=yield l(t[0],e),s=t[1]&&(yield l(t[1],e));return n&&((o=e.getVariable(n))!=null?o:s)});return v(r,{"add-class":()=>i(void 0,null,function*(){let n=yield l(t[0],e),s=yield l(t[1],e);n&&s&&(yield e.addClass(n,s))}),"remove-class":()=>i(void 0,null,function*(){let n=yield l(t[0],e),s=yield l(t[1],e);n&&s&&(yield e.removeClass(n,s))}),if:()=>i(void 0,null,function*(){let n=yield l(t[0],e);return n&&!["0","false"].includes(n.replace(/(^'|")|('|"$)/g,""))?l(t[1],e):l(t[2],e)}),delay:()=>i(void 0,null,function*(){let n=yield l(t[0],e);n&&(yield e.delay(parseInt(n,10)))}),"js-eval":()=>i(void 0,null,function*(){let n=yield l(t[0],e);return n&&(yield e.jsEval(n))}),"load-cssx":()=>i(void 0,null,function*(){let n=yield l(t[0],e),s=yield l(t[1],e);n&&s&&(yield e.loadCssx(n,s))}),var:a,"get-var":a,update:()=>i(void 0,null,function*(){let[n,s,o]=t.length>=3?yield C(t,3,e):[void 0,...yield C(t,2,e)];s&&e.updateVariable(n!=null?n:void 0,s,o!=null?o:"")}),"set-attr":()=>i(void 0,null,function*(){let[n,s,o]=t.length>=3?yield C(t,3,e):[void 0,...yield C(t,2,e)];s&&e.setAttribute(n!=null?n:void 0,s,o!=null?o:"")}),attr:()=>i(void 0,null,function*(){let[n,s]=t.length>=2?yield C(t,2,e):[void 0,yield l(t[0],e)];if(s)return e.getAttribute(n,s)}),"prevent-default":()=>i(void 0,null,function*(){return e.withEvent(n=>n.preventDefault())}),request:()=>i(void 0,null,function*(){var o;let n=yield l(t[0],e),s=(o=t[1]&&(yield l(t[1],e)))!=null?o:"post";if(n){let c=yield e.getFormData();yield e.sendRequest({method:s,url:n,data:c})}}),"add-children":()=>i(void 0,null,function*(){let n=yield l(t[0],e);n&&e.addChildren(n,t.slice(1))}),"remove-element":()=>i(void 0,null,function*(){var n;return e.removeElement((n=t[0]&&(yield l(t[0],e)))!=null?n:void 0)}),call:()=>i(void 0,null,function*(){let[n,s,...o]=yield Promise.all(t.map(c=>l(c,e)));n&&s&&e.callMethod(n,s,o)}),_:()=>Promise.reject(new Error("not supposed to be here"))})},C=(r,t,e)=>Promise.all(r.slice(0,t).map(a=>l(a,e)));var P=S(),K=(r,t)=>O(r,e=>P.Ok(t(e))),O=(r,t)=>p(r,{Ok:e=>t(e),Err:e=>P.Err(e)});var g=r=>t=>{if(t.length===0)return P.Err({error:"fuckedinput",input:t});let e=t.match(r);return e?P.Ok({value:e[0],input:t.replace(r,"")}):P.Err({error:"fucked",input:t})},E=r=>t=>t.length===0?P.Err({error:"fuckedinput",input:t}):t.startsWith(r)?P.Ok({value:r,input:t.slice(r.length)}):P.Err({error:"fuckedstring",input:t}),A=([r,...t])=>e=>{if(t.length===0)return r(e);let a=r(e);return p(a,{Ok:()=>a,Err:n=>A(t)(e)})},Ae=(r,t)=>e=>K(r(e),t),m=(r,t)=>Ae(r,n=>{var s=n,{value:e}=s,a=G(s,["value"]);return Q(W({},a),{value:t(e)})}),y=(r,t)=>e=>{let a=r(e);return O(a,({value:n,input:s})=>m(t,c=>[n,c])(s))},R=(r,t)=>m(y(r,t),([e,a])=>a),N=(r,t)=>m(y(r,t),([e,a])=>e),w=(r,t,e)=>N(R(r,t),e),L=r=>t=>p(r(t),{Ok:({value:e,input:a})=>m(L(r),n=>[e,...n])(a),Err:({input:e})=>P.Ok({value:[],input:e})}),Z=r=>t=>p(r(t),{Ok:({value:e,input:a})=>m(L(r),n=>[e,...n])(a),Err:e=>P.Err(e)}),M=(r,t)=>e=>p(r(e),{Ok:({value:a,input:n})=>m(L(R(t,r)),s=>[a,...s])(n),Err:a=>P.Ok({value:[],input:e})}),H=r=>t=>{let e=r(t);return p(e,{Ok:a=>e,Err:a=>P.Ok({value:void 0,input:t})})};var k=S(),T=S(),j=g(/^\s*/),D=r=>w(j,r,j),he=D(E(",")),we=r=>w(E("("),r,E(")")),h=g(/^[a-z][a-z0-9_-]*/i),te=g(/^--[a-z][a-z0-9-]*/i),$=E("'"),ee=E('"'),be=m(h,T.Identifier),Se=m(te,T.VarIdentifier),re=r=>m(y(D(h),we(D(M(I,he)))),([t,e])=>T.Call({name:t,args:e}))(r),ne=A([w($,g(/^[^']*/),$),w(ee,g(/^[^"]*/),ee)]),Ce=m(ne,T.LiteralString),se=g(/^[-+]?((\d*\.\d+)|\d+)/),Re=m(y(se,H(g(/^(s|ms)/i))),([r,t])=>T.LiteralNumber({value:Number(r),unit:t!=null?t:""})),Le=h,_e=R(E("#"),h),Ne=m(R(E("."),h),k.ClassName),De=A([h,ne,se]),ke=m(w(E("["),y(N(h,E("=")),De),E("]")),k.Attr),ae=r=>m(y(y(H(Le),_e),L(A([Ne,ke]))),([[t,e],a])=>T.Selector({tag:t,id:e,selectors:a}))(r),Ve=r=>m(y(N(te,D(E(":"))),I),([t,e])=>T.Pair({key:t,value:e}))(r),I=A([Ce,Re,re,Ve,Se,ae,be]),Oe=A([re,ae]),Me=M(Oe,j),oe=r=>p(Me(r),{Ok:({value:t,input:e})=>(e&&console.error(`Declaration stopped parsing at: "${e}"`),t),Err:({error:t})=>(console.error(t),[])}),z=r=>{let t=Z(I)(r.trim());return p(t,{Ok:({value:e,input:a})=>{if(a)throw new Error(`Input not consumed completely here brosky: "${a}"`);return e},Err:({error:e,input:a})=>{throw new Error(`${e}. | ||
Left input: ${a.slice(0,20)}...`)}})};var He=(a,n)=>i(void 0,[a,n],function*({selector:r,properties:t},e){if(t.size===0)return{selector:r,properties:[]};let s=yield Promise.all([...t.entries()].map(u=>i(void 0,[u],function*([o,c]){let d=yield l(c,e).catch(x=>console.warn(x));return[o,d!=null?d:""]})));return{selector:r,properties:s}}),ie=new Map,je=r=>{var e;let t=(e=ie.get(r))!=null?e:0;return ie.set(r,t+1),`${r}--index-${t}`},Ie=r=>{let t,e=new Map,a=!1;if(p(r,{Selector:n=>{t=n},Call:({name:n,args:s})=>{v(n,{instance:()=>{a=!0;let[o,c]=s;p(o,{Selector:u=>{t=u},_:u=>{}}),p(c,{Call:({name:u,args:d})=>{if(u==="map")for(let x of d)p(x,{Pair:({key:q,value:ye})=>e.set(q,ye),_:q=>{}})}})},_:()=>{throw new Error(`weird function in cssx-chi9ldren: ${n}`)}})},_:()=>{}}),!!t){if(a){let n=t.id;t.id=je(t.id),t.selectors.push(k.Attr(["data-instance",n]))}return{selector:t,properties:e,isInstance:a}}},B=(r,t)=>i(void 0,null,function*(){return(yield Promise.all(r.map(Ie).filter(a=>!!a).map(a=>a&&He(a,t)))).filter(a=>!!a)}),ce=(r,t)=>i(void 0,null,function*(){let e=oe(r);return B(e,t)});var U="cssx--update",ue="cssx--mount",de="<unset>",pe={click:"--cssx-on-click",load:"--cssx-on-load",submit:"--cssx-on-submit",blur:"--cssx-on-blur",focus:"--cssx-on-focus",[ue]:"--cssx-on-mount",[U]:"--cssx-on-update"},le="cssx-layer",V={CHILDREN:"--cssx-children",TEXT:"--cssx-text",HTML:"--cssx-disgustingly-set-innerhtml"},ze=()=>{let r="cssx-style-root";if(document.querySelector(`.${r}`))return;let t=document.createElement("style");t.className=r;let e=[...Object.values(V),...Object.values(pe)];t.textContent=`.cssx-layer { | ||
${e.map(a=>`${a}: ${de};`).join(" ")} | ||
"use strict";(()=>{var Se=Object.defineProperty,_e=Object.defineProperties;var Ce=Object.getOwnPropertyDescriptors;var M=Object.getOwnPropertySymbols;var te=Object.prototype.hasOwnProperty,re=Object.prototype.propertyIsEnumerable;var ee=(r,e,t)=>e in r?Se(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,ne=(r,e)=>{for(var t in e||(e={}))te.call(e,t)&&ee(r,t,e[t]);if(M)for(var t of M(e))re.call(e,t)&&ee(r,t,e[t]);return r},ae=(r,e)=>_e(r,Ce(e));var se=(r,e)=>{var t={};for(var s in r)te.call(r,s)&&e.indexOf(s)<0&&(t[s]=r[s]);if(r!=null&&M)for(var s of M(r))e.indexOf(s)<0&&re.call(r,s)&&(t[s]=r[s]);return t};var o=(r,e,t)=>new Promise((s,d)=>{var n=l=>{try{i(t.next(l))}catch(m){d(m)}},a=l=>{try{i(t.throw(l))}catch(m){d(m)}},i=l=>l.done?s(l.value):Promise.resolve(l.value).then(n,a);i((t=t.apply(r,e)).next())});var p=(r,e)=>(e[r.tag]||e._)(r.value),b=(r,e)=>(e[r]||e._)(r),S=()=>new Proxy({},{get(r,e){return t=>({tag:e,value:t})}});var P=S(),oe=(r,e)=>X(r,t=>P.Ok(e(t))),X=(r,e)=>p(r,{Ok:t=>e(t),Err:t=>P.Err(t)});var V=r=>e=>{if(e.length===0)return P.Err({error:"fuckedinput",input:e});let t=e.match(r);return t?P.Ok({value:t[0],input:e.replace(r,"")}):P.Err({error:"fucked",input:e})},x=r=>e=>e.length===0?P.Err({error:"fuckedinput",input:e}):e.startsWith(r)?P.Ok({value:r,input:e.slice(r.length)}):P.Err({error:"fuckedstring",input:e}),h=([r,...e])=>t=>{if(e.length===0)return r(t);let s=r(t);return p(s,{Ok:()=>s,Err:d=>h(e)(t)})},Ne=(r,e)=>t=>oe(r(t),e),f=(r,e)=>Ne(r,d=>{var n=d,{value:t}=n,s=se(n,["value"]);return ae(ne({},s),{value:e(t)})}),A=(r,e)=>t=>{let s=r(t);return X(s,({value:d,input:n})=>f(e,i=>[d,i])(n))},k=(r,e)=>f(A(r,e),([t,s])=>s),I=(r,e)=>f(A(r,e),([t,s])=>t),R=(r,e,t)=>I(k(r,e),t),j=r=>e=>p(r(e),{Ok:({value:t,input:s})=>f(j(r),d=>[t,...d])(s),Err:({input:t})=>P.Ok({value:[],input:t})});var B=(r,e)=>t=>p(r(t),{Ok:({value:s,input:d})=>f(j(k(e,r)),n=>[s,...n])(d),Err:s=>P.Ok({value:[],input:t})}),J=r=>e=>{let t=r(e);return p(t,{Ok:s=>t,Err:s=>P.Ok({value:void 0,input:e})})};var q=S(),_=S(),H=V(/^\s*/),z=r=>R(H,r,H),ce=z(x(",")),Le=r=>R(x("("),r,x(")")),C=V(/^[a-z][a-z0-9_-]*/i),ue=V(/^--[a-z][a-z0-9-]*/i),ie=x("'"),le=x('"'),ke=f(C,_.Identifier),Oe=f(ue,_.VarIdentifier),de=r=>f(A(z(C),Le(z(B(Q,ce)))),([e,t])=>_.Call({name:e,args:t}))(r),pe=h([R(ie,V(/^[^']*/),ie),R(le,V(/^[^"]*/),le)]),De=f(pe,_.LiteralString),me=V(/^[-+]?((\d*\.\d+)|\d+)/),Me=f(A(me,J(V(/^(s|ms)/i))),([r,e])=>_.LiteralNumber({value:Number(r),unit:e!=null?e:""})),Ie=C,je=k(x("#"),C),Be=f(k(x("."),C),q.ClassName),He=h([C,pe,me]),ze=f(R(x("["),A(I(C,x("=")),He),x("]")),q.Attr),ye=r=>f(A(A(J(Ie),je),j(h([Be,ze]))),([[e,t],s])=>_.Selector({tag:e,id:t,selectors:s}))(r),qe=r=>f(A(I(ue,z(x(":"))),Q),([e,t])=>_.Pair({key:e,value:t}))(r),Q=h([De,Me,de,qe,Oe,ye,ke]);var Ue=h([de,ye]),Fe=B(Ue,H),Ee=r=>p(Fe(r),{Ok:({value:e,input:t})=>(t&&console.error(`Declaration stopped parsing at: "${t}"`),e),Err:({error:e})=>(console.error(e),[])}),O=r=>{let e=B(Q,h([ce,H]))(r.trim());return p(e,{Ok:({value:t,input:s})=>{if(s)throw new Error(`Input not consumed completely here brosky: "${s}"`);return t},Err:({error:t,input:s})=>{throw new Error(`${t}. | ||
Left input: ${s.slice(0,20)}...`)}})};var c=S(),N=(r,e)=>o(void 0,null,function*(){return y(yield u(r,e))}),u=(r,e)=>o(void 0,null,function*(){return p(r,{Call:d=>o(void 0,[d],function*({name:t,args:s}){return We(t,s,e)}),LiteralString:t=>o(void 0,null,function*(){return c.String(t)}),LiteralNumber:d=>o(void 0,[d],function*({value:t,unit:s}){return c.Number(b(s,{s:()=>t*1e3,_:()=>t}))}),Identifier:t=>o(void 0,null,function*(){return c.String(t)}),VarIdentifier:t=>o(void 0,null,function*(){return c.VarIdentifier(t)}),_:t=>o(void 0,null,function*(){return c.Void()})})}),Xe=/^['"](.*)(?=['"]$)['"]$/g,W=r=>r.replace(Xe,"$1"),y=r=>p(r,{String:e=>W(e),Boolean:e=>`${e}`,Number:e=>`${e}`,VarIdentifier:e=>e,Value:e=>`${e}`,_:()=>{}}),Je=r=>p(r,{String:e=>parseFloat(e),Boolean:e=>e?1:0,Number:e=>e,Value:e=>parseFloat(e),_:()=>{}}),Qe=r=>p(r,{String:e=>!["false","","0"].includes(W(e)),Boolean:e=>e,Number:e=>!!e,Value:e=>!!e,_:()=>!1}),We=(r,e,t)=>{let s=()=>o(void 0,null,function*(){let n=yield u(e[0],t),a=e[1]&&(yield u(e[1],t));return p(n,{VarIdentifier:i=>o(void 0,null,function*(){let l=yield t.getVariable(i);return l===void 0?a:c.String(l)}),_:()=>o(void 0,null,function*(){return c.Void()})})}),d=()=>o(void 0,null,function*(){let n=yield N(e[0],t),a=n&&(yield t.jsEval(n));return a==null?c.Void():c.Value(a)});return b(r,{"add-class":()=>o(void 0,null,function*(){let n=y(yield u(e[0],t)),a=y(yield u(e[1],t));return n&&a&&(yield t.addClass(n,a)),c.Void()}),"remove-class":()=>o(void 0,null,function*(){let n=y(yield u(e[0],t)),a=y(yield u(e[1],t));return n&&a&&(yield t.removeClass(n,a)),c.Void()}),if:()=>o(void 0,null,function*(){return Qe(yield u(e[0],t))?u(e[1],t):u(e[2],t)}),delay:()=>o(void 0,null,function*(){let n=Je(yield u(e[0],t));return n!==void 0&&(yield t.delay(n)),c.Void()}),"js-eval":d,"js-expr":d,"load-cssx":()=>o(void 0,null,function*(){let n=y(yield u(e[0],t)),a=y(yield u(e[1],t));return n&&a&&(yield t.loadCssx(n,a)),c.Void()}),var:s,"get-var":s,update:()=>o(void 0,null,function*(){let[n,a,i]=e.length>=3?(yield D(e,3,t)).map(y):[void 0,...(yield D(e,2,t)).map(y)];return a&&(yield t.updateVariable(n!=null?n:void 0,a,i!=null?i:"")),c.Void()}),"set-attr":()=>o(void 0,null,function*(){let[n,a,i]=e.length>=3?(yield D(e,3,t)).map(y):[void 0,...(yield D(e,2,t)).map(y)];return a&&t.setAttribute(n!=null?n:void 0,a,i!=null?i:""),c.Void()}),attr:()=>o(void 0,null,function*(){let[n,a]=e.length>=2?(yield D(e,2,t)).map(y):[void 0,y(yield u(e[0],t))];if(a){let i=yield t.getAttribute(n,a);return i===void 0?c.Void():c.String(i)}return c.Void()}),"prevent-default":()=>o(void 0,null,function*(){return yield t.withEvent(n=>n.preventDefault()),c.Void()}),request:()=>o(void 0,null,function*(){let n=y(yield u(e[0],t)),a=e[1]&&y(yield u(e[1],t))||"post";if(n){let i=yield t.getFormData();yield t.sendRequest({method:a,url:n,data:i})}return c.Void()}),"add-children":()=>o(void 0,null,function*(){let n=y(yield u(e[0],t));return n&&(yield t.addChildren(n,e.slice(1))),c.Void()}),"remove-element":()=>o(void 0,null,function*(){var a;let n=(a=e[0]&&y(yield u(e[0],t)))!=null?a:void 0;return n&&(yield t.removeElement(n)),c.Void()}),"call-method":()=>o(void 0,null,function*(){let[n,a,...i]=(yield Promise.all(e.map(l=>u(l,t)))).map(y);return n&&a&&(yield t.callMethod(n,a,i)),c.Void()}),map:()=>o(void 0,null,function*(){let n=yield Promise.all(e.map(a=>o(void 0,null,function*(){return p(a,{Pair:m=>o(void 0,[m],function*({key:i,value:l}){return[i,yield u(l,t)]}),_:()=>o(void 0,null,function*(){})})})));return c.Map(Object.fromEntries(n.filter(Boolean)))}),seq:()=>o(void 0,null,function*(){return c.Lazy(e)}),noop:()=>o(void 0,null,function*(){return c.Void()}),func:()=>o(void 0,null,function*(){return c.Void()}),call:()=>o(void 0,null,function*(){let n=p(yield u(e[0],t),{VarIdentifier:l=>l,_:()=>{}}),a=e[1]?yield u(e[1],t):c.Void(),i=p(a,{Map:l=>l,_:()=>({})});if(n){let l=yield t.getVariable(n);if(l){let m=O(l);return t.evaluateInScope(m,i)}}return c.Void()}),string:()=>o(void 0,null,function*(){let n=yield Promise.all(e.map(a=>N(a,t)));return c.String(n.filter(Boolean).join(""))}),quotify:()=>o(void 0,null,function*(){let n=yield N(e[0],t);return c.String(`'${n||""}'`)}),unquotify:()=>o(void 0,null,function*(){let n=yield N(e[0],t);return c.String(W(n||""))}),try:()=>o(void 0,null,function*(){try{return yield u(e[0],t)}catch(n){return t.evaluateInScope([e[1]],{"--error":c.Value(n)})}}),do:()=>o(void 0,null,function*(){let n=c.Void();for(let a of e)n=yield u(a,t);return n}),let:()=>o(void 0,null,function*(){let n=yield N(e[0],t),a=yield u(e[1],t);return n?t.evaluateInScope([e[2]],{[n]:a}):c.Void()}),_:()=>Promise.reject(new Error(`Not implemented: ${r}`))})},D=(r,e,t)=>Promise.all(r.slice(0,e).map(s=>u(s,t)));var fe=new Map,Ye=r=>{var t;let e=(t=fe.get(r))!=null?t:0;return fe.set(r,e+1),`${r}--index-${e}`},Pe=r=>e=>o(void 0,null,function*(){let t,s=new Map,d=[],n=!1;if(yield p(e,{Selector:a=>o(void 0,null,function*(){t=a}),Call:l=>o(void 0,[l],function*({name:a,args:i}){return b(a,{h:()=>o(void 0,null,function*(){let[m,E,T]=i;p(m,{Selector:v=>{t=v},_:v=>{}});let g=yield u(E,r);p(g,{Map:v=>{for(let[Te,be]of Object.entries(v))s.set(Te,be)},_:v=>{}});let F=yield p(yield u(T,r),{Lazy:v=>o(void 0,null,function*(){return Promise.all(v.map(Pe(r)))}),_:v=>o(void 0,null,function*(){return[]})});d.push(...F.filter(Boolean))}),instance:()=>o(void 0,null,function*(){n=!0;let[m,E]=i;p(m,{Selector:g=>{t=g},_:g=>{}});let T=yield u(E,r);p(T,{Map:g=>{for(let[F,v]of Object.entries(g))s.set(F,v)},_:g=>{}})}),_:()=>o(void 0,null,function*(){throw new Error(`weird function in cssx-chi9ldren: ${a}`)})})}),_:()=>o(void 0,null,function*(){})}),!!t){if(n){let a=t.id;t.id=Ye(t.id),t.selectors.push(q.Attr(["data-instance",a]))}return{selector:t,properties:s,children:d,isInstance:n}}}),Y=(r,e)=>o(void 0,null,function*(){return(yield Promise.all(r.map(Pe(e)))).filter(s=>!!s)}),xe=(r,e)=>o(void 0,null,function*(){let t=Ee(r);return Y(t,e)});var G="cssx--update",ve="cssx--mount",Ae="<unset>",we={click:"--cssx-on-click",load:"--cssx-on-load",submit:"--cssx-on-submit",blur:"--cssx-on-blur",focus:"--cssx-on-focus",[ve]:"--cssx-on-mount",[G]:"--cssx-on-update"},ge="cssx-layer",U={CHILDREN:"--cssx-children",TEXT:"--cssx-text",HTML:"--cssx-disgustingly-set-innerhtml"},Ge=()=>{let r="cssx-style-root";if(document.querySelector(`.${r}`))return;let e=document.createElement("style");e.className=r;let t=[...Object.values(U),...Object.values(we)];e.textContent=`.cssx-layer { | ||
${t.map(s=>`${s}: ${Ae};`).join(" ")} | ||
display: inherit; | ||
@@ -9,3 +9,3 @@ width: inherit; | ||
justify-content: inherit; | ||
}`,document.body.appendChild(t)},b=(r,t)=>{let e=`${getComputedStyle(r).getPropertyValue(t)}`.trim();return e=e.replace(/(^['"])|(['"]$)/gi,""),!e||e===de?"":e},Be=(r,t)=>{let e=b(r,V.CHILDREN);return ce(e,t)},f=(r,t=document)=>{let e=document,a=r;return/^('|")?[a-z0-9_-]+\1$/gi.test(r)?a=`[data-element=${r}]`:/^:scope/i.test(r)?e=t:/^:parent\s+/i.test(r)&&(e=t.parentNode,a=r.replace(/^:parent\s+/i,"")),e==null?void 0:e.querySelector(a)},me=(r,{event:t=null,pure:e=!1})=>{let a={addClass:(n,s)=>i(void 0,null,function*(){var o;return(o=f(n,r))==null?void 0:o.classList.add(s)}),removeClass:(n,s)=>i(void 0,null,function*(){var o;return(o=f(n,r))==null?void 0:o.classList.remove(s)}),delay:n=>new Promise(s=>setTimeout(s,n)),jsEval:n=>i(void 0,null,function*(){return!e&&(0,eval)(n)}),loadCssx:(n,s)=>i(void 0,null,function*(){return e?"":new Promise((o,c)=>{let u=Object.assign(document.createElement("link"),{href:s,rel:"stylesheet"});u.onload=()=>{let d=f(n,r);d?(F(d),o(n)):(console.error(`[CSSX] Unable to find root for ${n}`),c(`[CSSX] Unable to find root for ${n}`))},document.body.appendChild(u)})}),getVariable:n=>i(void 0,null,function*(){return b(r,n)}),updateVariable:(n,s,o)=>i(void 0,null,function*(){let c=n?f(n,r):r,u=s.startsWith("--");if(c){let d=b(c,s);if(u?c.style.setProperty(s,JSON.stringify(o)):c.style[s]=o,JSON.stringify(o)!==d&&u){let x={name:s,value:o,prevValue:d};c.dispatchEvent(new CustomEvent(U,{detail:x}))}}}),setAttribute:(n,s,o)=>i(void 0,null,function*(){let c=n?f(n,r):r;s==="value"?c.value=o:o?c==null||c.setAttribute(s,o):c==null||c.removeAttribute(s)}),getAttribute:(n,s)=>i(void 0,null,function*(){var c;let o=n?f(n,r):r;return s==="value"?o.value:(c=o==null?void 0:o.getAttribute(s))!=null?c:void 0}),withEvent:n=>i(void 0,null,function*(){return t&&n(t)}),getFormData:()=>i(void 0,null,function*(){return r.nodeName==="FORM"?new FormData(r):void 0}),sendRequest:c=>i(void 0,[c],function*({url:n,method:s,data:o}){e||(yield fetch(n,{method:s,body:o}))}),addChildren:(n,s)=>i(void 0,null,function*(){let o=f(n,r),c=yield B(s,a);o&&Pe(c,o)}),removeElement:n=>i(void 0,null,function*(){var o;let s=n?f(n,r):r;(o=s==null?void 0:s.parentNode)==null||o.removeChild(s)}),callMethod:(n,s,o)=>i(void 0,null,function*(){let c=n?f(n,r):r;c[s].call(c,o)})};return a},Ue=(r,t=!1)=>i(void 0,null,function*(){for(let[e,a]of Object.entries(pe)){let n=b(r,a);if(n){let s=o=>i(void 0,null,function*(){let c=z(n);for(let u of c)yield l(u,me(r,{event:o}))});v(e,{[U]:()=>{r.hasAttribute("data-hooked")||(r.addEventListener(e,s),r.setAttribute("data-hooked","true"))},[ue]:()=>{t&&setTimeout(s)},_:()=>{r[`on${e}`]=s}})}}}),Fe=(r,t)=>{let{tag:e,id:a,selectors:n}=r.selector,s=e||"div",o=t==null?void 0:t.querySelector(`:scope > #${a}`),c=!o;o||(o=Object.assign(document.createElement(s),{id:a}),o.dataset.element=a);for(let u of n)p(u,{ClassName:d=>!(o!=null&&o.classList.contains(d))&&(o==null?void 0:o.classList.add(d)),Attr:([d,x])=>o==null?void 0:o.setAttribute(d,x)});for(let[u,d]of r.properties)o==null||o.style.setProperty(u,JSON.stringify(d));return{node:o,isNewElement:c}},Pe=(r,t)=>i(void 0,null,function*(){var a;let e=(a=t==null?void 0:t.querySelector(`:scope > .${le}`))!=null?a:Object.assign(document.createElement("div"),{className:le});e.parentNode||t.appendChild(e);for(let n of r){let{node:s,isNewElement:o}=Fe(n,e);e.appendChild(s),yield F(s,o)}}),F=(r,t=!1)=>i(void 0,null,function*(){var o;yield Ue(r,t);let e=me(r,{pure:!0}),a=b(r,V.TEXT);if(a)try{let c=z(a);r.textContent=(o=c[0]?yield l(c[0],e):a)!=null?o:a}catch(c){r.textContent=a}let n=b(r,V.HTML);n&&(r.innerHTML=n.replace(/(^'|")|('|"$)/g,""));let s=yield Be(r,e);s.length>0&&(yield Pe(s,r))}),Ee=(...t)=>i(void 0,[...t],function*({root:r=document.body}={}){ze(),yield F(r)});Ee({root:document.body});})(); | ||
}`,document.body.appendChild(e)},L=(r,e)=>{let t=`${getComputedStyle(r).getPropertyValue(e)}`.trim();return t=t.replace(/(^['"])|(['"]$)/gi,""),!t||t===Ae?"":t},Ke=(r,e)=>{let t=L(r,U.CHILDREN);return xe(t,e)},w=(r,e=document)=>{let t=document,s=r;return/^('|")?[a-z0-9_-]+\1$/gi.test(r)?s=`[data-element=${r}]`:/^:scope/i.test(r)?t=e:/^:parent\s+/i.test(r)&&(t=e.parentNode,s=r.replace(/^:parent\s+/i,"")),t==null?void 0:t.querySelector(s)},K=(r,e)=>{let{event:t=null,pure:s=!1}=e,d={addClass:(n,a)=>o(void 0,null,function*(){var i;return(i=w(n,r))==null?void 0:i.classList.add(a)}),removeClass:(n,a)=>o(void 0,null,function*(){var i;return(i=w(n,r))==null?void 0:i.classList.remove(a)}),delay:n=>new Promise(a=>setTimeout(a,n)),jsEval:n=>o(void 0,null,function*(){return!s&&(0,eval)(n)}),loadCssx:(n,a)=>o(void 0,null,function*(){return s?"":new Promise((i,l)=>{let m=Object.assign(document.createElement("link"),{href:a,rel:"stylesheet"});m.onload=()=>{let E=w(n,r);E?($(E),i(n)):(console.error(`[CSSX] Unable to find root for ${n}`),l(`[CSSX] Unable to find root for ${n}`))},document.body.appendChild(m)})}),getVariable:n=>o(void 0,null,function*(){return L(r,n)}),updateVariable:(n,a,i)=>o(void 0,null,function*(){let l=n?w(n,r):r,m=a.startsWith("--");if(l){let E=L(l,a);if(m?l.style.setProperty(a,JSON.stringify(i)):l.style[a]=i,JSON.stringify(i)!==E&&m){let T={name:a,value:i,prevValue:E};l.dispatchEvent(new CustomEvent(G,{detail:T}))}}}),setAttribute:(n,a,i)=>o(void 0,null,function*(){let l=n?w(n,r):r;a==="value"?l.value=i:i?l==null||l.setAttribute(a,i):l==null||l.removeAttribute(a)}),getAttribute:(n,a)=>o(void 0,null,function*(){var l;let i=n?w(n,r):r;return a==="value"?i.value:(l=i==null?void 0:i.getAttribute(a))!=null?l:void 0}),withEvent:n=>o(void 0,null,function*(){return t&&n(t)}),getFormData:()=>o(void 0,null,function*(){return r.nodeName==="FORM"?new FormData(r):void 0}),sendRequest:l=>o(void 0,[l],function*({url:n,method:a,data:i}){s||(yield fetch(n,{method:a,body:i}))}),addChildren:(n,a)=>o(void 0,null,function*(){let i=w(n,r),l=yield Y(a,d);i&&Z(l,i)}),removeElement:n=>o(void 0,null,function*(){var i;let a=n?w(n,r):r;(i=a==null?void 0:a.parentNode)==null||i.removeChild(a)}),callMethod:(n,a,i)=>o(void 0,null,function*(){let l=n?w(n,r):r;l[a].call(l,i)}),evaluateInScope:(n,a)=>o(void 0,null,function*(){var m;let i=document.createElement("div");i.style.display="none";for(let[E,T]of Object.entries(a)){let g=y(T);g&&i.style.setProperty(E,g)}r.appendChild(i);let l=yield Ve(n,K(i,e));return r.hasAttribute("data-debug-stack")||(m=i.parentNode)==null||m.removeChild(i),l})};return d},Ve=(r,e)=>o(void 0,null,function*(){let t=c.Void();for(let s of r)t=yield u(s,e);return t}),Ze=(r,e=!1)=>o(void 0,null,function*(){for(let[t,s]of Object.entries(we)){let d=L(r,s);if(d){let n=a=>o(void 0,null,function*(){yield Ve(O(d),K(r,{event:a}))});b(t,{[G]:()=>{r.hasAttribute("data-hooked")||(r.addEventListener(t,n),r.setAttribute("data-hooked","true"))},[ve]:()=>{e&&setTimeout(n)},_:()=>{r[`on${t}`]=n}})}}}),$e=(r,e)=>o(void 0,null,function*(){let{tag:t,id:s,selectors:d}=r.selector,n=t||"div",a=e==null?void 0:e.querySelector(`:scope > #${s}`),i=!a;a||(a=Object.assign(document.createElement(n),{id:s}),a.dataset.element=s);for(let l of d)p(l,{ClassName:m=>!(a!=null&&a.classList.contains(m))&&(a==null?void 0:a.classList.add(m)),Attr:([m,E])=>a==null?void 0:a.setAttribute(m,E)});for(let[l,m]of r.properties){let E=y(m);a==null||a.style.setProperty(l,JSON.stringify(E||""))}return{node:a,isNewElement:i}}),Z=(r,e)=>o(void 0,null,function*(){var s;let t=(s=e==null?void 0:e.querySelector(`:scope > .${ge}`))!=null?s:Object.assign(document.createElement("div"),{className:ge});t.parentNode||e.appendChild(t);for(let d of r){let{node:n,isNewElement:a}=yield $e(d,t);t.appendChild(n),yield $(n,a),d.children.length>0&&(yield Z(d.children,n))}}),$=(r,e=!1)=>o(void 0,null,function*(){var a;yield Ze(r,e);let t=K(r,{pure:!0}),s=L(r,U.TEXT);if(s)try{let i=O(s);r.textContent=(a=i[0]?yield N(i[0],t):s)!=null?a:s}catch(i){r.textContent=s}let d=L(r,U.HTML);d&&(r.innerHTML=d.replace(/(^'|")|('|"$)/g,""));let n=yield Ke(r,t);n.length>0&&(yield Z(n,r))}),he=(...e)=>o(void 0,[...e],function*({root:r=document.body}={}){Ge(),yield $(r)});he({root:document.body});})(); | ||
//# sourceMappingURL=index.js.map |
export const match = (tag, pattern) => (pattern[tag.tag] || pattern._)(tag.value); | ||
// type TagValues< | ||
// T extends Tag<any, string>, | ||
// Keys extends Array<string>, | ||
// Values extends Array<any> = [], | ||
// > = Keys extends [] | ||
// ? Values | ||
// : Keys extends [ | ||
// infer key extends string, | ||
// ...infer restOfKeys extends string[], | ||
// ] | ||
// ? TagValues<T, restOfKeys, [...Values, TagValue<T, key>]> | ||
// : never | ||
// | ||
// export const ifLet = <T extends Tag<string, any>, Keys extends Array<T['tag']>>( | ||
// tag: T, | ||
// kinds: Keys, | ||
// cb: (...values: TagValues<T, Keys>) => void, | ||
// ): void => { | ||
// const values = kinds.map(k => (tag.tag === k ? tag.value : undefined)) | ||
// ;(cb as any)(...values) | ||
// } | ||
export const matchString = (key, pattern) => (pattern[key] || pattern._)(key); | ||
@@ -3,0 +24,0 @@ export const constructors = () => new Proxy({}, { |
{ | ||
"name": "@css-everything/render", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"main": "src/index.ts", | ||
@@ -20,2 +20,3 @@ "repository": "https://github.com/phenax/css-everything", | ||
"fix": "yarn lint --fix && yarn format", | ||
"pub:patch": "yarn lint && yarn build && yarn publish --access=public --patch", | ||
"test": "jest" | ||
@@ -22,0 +23,0 @@ }, |
@@ -6,8 +6,8 @@ # css-everything | ||
## Usage | ||
### Docs | ||
WIP. Coming soon maybe? | ||
- [Read the documentation](https://github.com/phenax/css-everything/tree/main/docs/README.md) to become enlightened. | ||
- [Here's how this works](https://github.com/phenax/css-everything/tree/main/docs/how-it-works.md). | ||
### Simple example | ||
@@ -22,3 +22,3 @@ You can start by adding the script tag for the renderer inside the body | ||
<body> | ||
<script async defer src="https://unpkg.com/@css-everything/render@0.0.1/dist/renderer/index.js"></script> | ||
<script async defer src="https://unpkg.com/@css-everything/render/dist/renderer/index.js"></script> | ||
</body> | ||
@@ -52,3 +52,5 @@ </html> | ||
/* On click, waits for 1 second and then updates the --text property #main-el */ | ||
--cssx-on-click: update(main-el, --text, "Loading...") delay(1s) | ||
--cssx-on-click: | ||
update(main-el, --text, "Loading...") | ||
delay(1s) | ||
update(main-el, --text, "Hello world!"); | ||
@@ -55,0 +57,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { EvalActions, evalExpr } from './eval' | ||
import { EvalActions, EvalValue, evalExpr } from './eval' | ||
import { Expr, Selector, SelectorComp, parseDeclarations } from './parser' | ||
@@ -7,28 +7,7 @@ import { match, matchString } from './utils/adt' | ||
selector: Selector | ||
properties: Map<string, Expr> | ||
properties: Map<string, EvalValue> | ||
children: Array<Declaration> | ||
isInstance: boolean | ||
} | ||
export interface DeclarationEval { | ||
selector: Selector | ||
properties: Array<readonly [string, string]> | ||
} | ||
export const evaluateDeclaration = async ( | ||
{ selector, properties }: Declaration, | ||
actions: EvalActions, | ||
): Promise<DeclarationEval> => { | ||
if (properties.size === 0) return { selector, properties: [] } | ||
const props = await Promise.all( | ||
[...properties.entries()].map(async ([key, expr]) => { | ||
// Ignore errors? | ||
const result = await evalExpr(expr, actions).catch(e => console.warn(e)) | ||
return [key, result ?? ''] as const | ||
}), | ||
) | ||
return { selector, properties: props } | ||
} | ||
const instanceCountMap = new Map<string, number>() | ||
@@ -41,67 +20,97 @@ const getUniqueInstanceId = (id: string) => { | ||
export const toDeclaration = (expr: Expr): Declaration | undefined => { | ||
let selector: Selector | undefined | ||
const properties: Map<string, Expr> = new Map() | ||
let isInstance = false | ||
export const toDeclaration = | ||
(actions: EvalActions) => | ||
async (expr: Expr): Promise<Declaration | undefined> => { | ||
let selector: Selector | undefined | ||
const properties: Map<string, EvalValue> = new Map() | ||
const children: Array<Declaration> = [] | ||
let isInstance = false | ||
match(expr, { | ||
Selector: sel => { | ||
selector = sel | ||
}, | ||
Call: ({ name, args }) => { | ||
matchString(name, { | ||
instance: () => { | ||
isInstance = true | ||
const [sel, map] = args | ||
await match(expr, { | ||
Selector: async sel => { | ||
selector = sel | ||
}, | ||
Call: async ({ name, args }) => { | ||
return matchString(name, { | ||
h: async () => { | ||
const [sel, map, childreExpr] = args | ||
// Selector | ||
match(sel, { | ||
Selector: sel => { | ||
selector = sel | ||
}, | ||
_: _ => {}, | ||
}) | ||
// Selector | ||
match(sel, { | ||
Selector: sel => { | ||
selector = sel | ||
}, | ||
_: _ => {}, | ||
}) | ||
match(map, { | ||
Call: ({ name, args }) => { | ||
if (name !== 'map') return | ||
for (const arg of args) { | ||
match(arg, { | ||
Pair: ({ key, value }) => properties.set(key, value), | ||
_: _ => {}, | ||
}) | ||
} | ||
}, | ||
}) | ||
}, | ||
_: () => { | ||
throw new Error(`weird function in cssx-chi9ldren: ${name}`) | ||
}, | ||
}) | ||
}, | ||
_: () => {}, | ||
}) | ||
const props = await evalExpr(map, actions) | ||
match(props, { | ||
Map: props => { | ||
for (const [key, value] of Object.entries(props)) { | ||
properties.set(key, value) | ||
} | ||
}, | ||
_: _ => {}, | ||
}) | ||
if (!selector) return undefined | ||
const childrenExprs = await match< | ||
Promise<Array<Declaration | undefined>>, | ||
EvalValue | ||
>(await evalExpr(childreExpr, actions), { | ||
Lazy: async exprs => | ||
Promise.all(exprs.map(toDeclaration(actions))), | ||
_: async _ => [], | ||
}) | ||
if (isInstance) { | ||
const baseId = selector.id | ||
selector.id = getUniqueInstanceId(selector.id) | ||
selector.selectors.push(SelectorComp.Attr(['data-instance', baseId])) | ||
children.push( | ||
...(childrenExprs.filter(Boolean) as Array<Declaration>), | ||
) | ||
}, | ||
instance: async () => { | ||
isInstance = true | ||
const [sel, map] = args | ||
// Selector | ||
match(sel, { | ||
Selector: sel => { | ||
selector = sel | ||
}, | ||
_: _ => {}, | ||
}) | ||
const props = await evalExpr(map, actions) | ||
match(props, { | ||
Map: props => { | ||
for (const [key, value] of Object.entries(props)) { | ||
properties.set(key, value) | ||
} | ||
}, | ||
_: _ => {}, | ||
}) | ||
}, | ||
_: async () => { | ||
throw new Error(`weird function in cssx-chi9ldren: ${name}`) | ||
}, | ||
}) | ||
}, | ||
_: async () => {}, | ||
}) | ||
if (!selector) return undefined | ||
if (isInstance) { | ||
const baseId = selector.id | ||
selector.id = getUniqueInstanceId(selector.id) | ||
selector.selectors.push(SelectorComp.Attr(['data-instance', baseId])) | ||
} | ||
return { selector, properties, children, isInstance } | ||
} | ||
return { selector, properties, isInstance } | ||
} | ||
export const expressionsToDeclrs = async ( | ||
exprs: Array<Expr>, | ||
actions: EvalActions, | ||
): Promise<Array<DeclarationEval>> => { | ||
const declrs = await Promise.all( | ||
exprs | ||
.map(toDeclaration) | ||
.filter(declr => !!declr) | ||
.map(declr => declr && evaluateDeclaration(declr, actions)), | ||
) | ||
return declrs.filter(declr => !!declr) as Array<DeclarationEval> | ||
): Promise<Array<Declaration>> => { | ||
const declrs = await Promise.all(exprs.map(toDeclaration(actions))) | ||
return declrs.filter(declr => !!declr) as Array<Declaration> | ||
} | ||
@@ -112,5 +121,5 @@ | ||
actions: EvalActions, | ||
): Promise<Array<DeclarationEval>> => { | ||
): Promise<Array<Declaration>> => { | ||
const exprs = parseDeclarations(input) | ||
return expressionsToDeclrs(exprs, actions) | ||
} |
296
src/eval.ts
@@ -1,3 +0,3 @@ | ||
import { CSSUnit, Expr } from './parser' | ||
import { match, matchString } from './utils/adt' | ||
import { CSSUnit, Expr, parse } from './parser' | ||
import { Enum, constructors, match, matchString } from './utils/adt' | ||
@@ -37,53 +37,126 @@ export interface EvalActions { | ||
method: string, | ||
args: EvalValue[], | ||
args: (string | undefined)[], | ||
): Promise<void> | ||
evaluateInScope( | ||
exprs: Expr[], | ||
properties: Record<string, EvalValue>, | ||
): Promise<EvalValue> | ||
// calculate ?? | ||
} | ||
type EvalValue = string | undefined | void | ||
export type EvalValue = Enum<{ | ||
String: string | ||
Number: number | ||
Boolean: boolean | ||
Lazy: Array<Expr> | ||
Void: never | ||
VarIdentifier: string | ||
Map: { [key in string]: EvalValue } | ||
Value: any | ||
}> | ||
export const EvalValue = constructors<EvalValue>() | ||
export const evalExprAsString = async ( | ||
expr: Expr, | ||
actions: EvalActions, | ||
): Promise<string | undefined> => | ||
evalValueToString(await evalExpr(expr, actions)) | ||
export const evalExpr = async ( | ||
expr: Expr, | ||
actions: EvalActions, | ||
): Promise<EvalValue> => | ||
match<Promise<EvalValue>, Expr>(expr, { | ||
): Promise<EvalValue> => { | ||
return match<Promise<EvalValue>, Expr>(expr, { | ||
Call: async ({ name, args }) => getFunctions(name, args, actions), | ||
LiteralString: async s => s, | ||
LiteralString: async s => EvalValue.String(s), | ||
LiteralNumber: async ({ value, unit }) => | ||
matchString<number, CSSUnit>(unit, { | ||
s: () => value * 1000, | ||
_: () => value, | ||
}).toString(), | ||
Identifier: async s => s, | ||
VarIdentifier: async s => s, | ||
_: async _ => undefined, | ||
EvalValue.Number( | ||
matchString<number, CSSUnit>(unit, { | ||
s: () => value * 1000, | ||
_: () => value, | ||
}), | ||
), | ||
Identifier: async s => EvalValue.String(s), | ||
VarIdentifier: async s => EvalValue.VarIdentifier(s), | ||
_: async _ => EvalValue.Void(), | ||
}) | ||
} | ||
const getFunctions = (name: string, args: Expr[], actions: EvalActions) => { | ||
const QUOTE_REGEX = /^['"](.*)(?=['"]$)['"]$/g | ||
const unquotify = (s: string) => s.replace(QUOTE_REGEX, '$1') | ||
export const evalValueToString = (val: EvalValue): string | undefined => | ||
match<string | undefined, EvalValue>(val, { | ||
String: s => unquotify(s), | ||
Boolean: b => `${b}`, | ||
Number: n => `${n}`, | ||
VarIdentifier: s => s, | ||
Value: v => `${v}`, | ||
_: () => undefined, | ||
}) | ||
const evalValueToNumber = (val: EvalValue): number | undefined => | ||
match<number | undefined, EvalValue>(val, { | ||
String: s => parseFloat(s), | ||
Boolean: b => (b ? 1 : 0), | ||
Number: n => n, | ||
Value: v => parseFloat(v), | ||
_: () => undefined, | ||
}) | ||
const evalValueToBoolean = (val: EvalValue): boolean => | ||
match<boolean, EvalValue>(val, { | ||
String: s => !['false', '', '0'].includes(unquotify(s)), | ||
Boolean: b => b, | ||
Number: n => !!n, | ||
Value: v => !!v, | ||
_: () => false, | ||
}) | ||
const getFunctions = ( | ||
name: string, | ||
args: Expr[], | ||
actions: EvalActions, | ||
): Promise<EvalValue> => { | ||
const getVariable = async () => { | ||
const varName = await evalExpr(args[0], actions) | ||
const defaultValue = args[1] && (await evalExpr(args[1], actions)) | ||
return varName && (actions.getVariable(varName) ?? defaultValue) | ||
return match<Promise<EvalValue>, EvalValue>(varName, { | ||
VarIdentifier: async name => { | ||
const value = await actions.getVariable(name) | ||
return value === undefined ? defaultValue : EvalValue.String(value) | ||
}, | ||
_: async () => EvalValue.Void(), | ||
}) | ||
} | ||
const jsEval = async () => { | ||
const js = await evalExprAsString(args[0], actions) | ||
const result = js && (await actions.jsEval(js)) | ||
if (result === undefined || result === null) return EvalValue.Void() | ||
return EvalValue.Value(result) | ||
} | ||
return matchString<Promise<EvalValue>>(name, { | ||
'add-class': async () => { | ||
const id = await evalExpr(args[0], actions) | ||
const classes = await evalExpr(args[1], actions) | ||
const id = evalValueToString(await evalExpr(args[0], actions)) | ||
const classes = evalValueToString(await evalExpr(args[1], actions)) | ||
if (id && classes) { | ||
await actions.addClass(id, classes) | ||
} | ||
return EvalValue.Void() | ||
}, | ||
'remove-class': async () => { | ||
const id = await evalExpr(args[0], actions) | ||
const classes = await evalExpr(args[1], actions) | ||
const id = evalValueToString(await evalExpr(args[0], actions)) | ||
const classes = evalValueToString(await evalExpr(args[1], actions)) | ||
if (id && classes) { | ||
await actions.removeClass(id, classes) | ||
} | ||
return EvalValue.Void() | ||
}, | ||
if: async () => { | ||
const cond = await evalExpr(args[0], actions) | ||
const FALSEY = ['0', 'false'] | ||
if (cond && !FALSEY.includes(cond.replace(/(^'|")|('|"$)/g, ''))) { | ||
const cond = evalValueToBoolean(await evalExpr(args[0], actions)) | ||
if (cond) { | ||
return evalExpr(args[1], actions) | ||
@@ -95,16 +168,17 @@ } else { | ||
delay: async () => { | ||
const num = await evalExpr(args[0], actions) | ||
num && (await actions.delay(parseInt(num, 10))) | ||
const num = evalValueToNumber(await evalExpr(args[0], actions)) | ||
num !== undefined ? await actions.delay(num) : undefined | ||
return EvalValue.Void() | ||
}, | ||
'js-eval': async () => { | ||
const js = await evalExpr(args[0], actions) | ||
return js && (await actions.jsEval(js)) | ||
}, | ||
'js-eval': jsEval, | ||
'js-expr': jsEval, | ||
'load-cssx': async () => { | ||
const id = await evalExpr(args[0], actions) | ||
const url = await evalExpr(args[1], actions) | ||
const id = evalValueToString(await evalExpr(args[0], actions)) | ||
const url = evalValueToString(await evalExpr(args[1], actions)) | ||
if (id && url) { | ||
await actions.loadCssx(id, url) | ||
} | ||
return EvalValue.Void() | ||
}, | ||
@@ -118,7 +192,11 @@ | ||
args.length >= 3 | ||
? await evalArgs(args, 3, actions) | ||
: [undefined, ...(await evalArgs(args, 2, actions))] | ||
? (await evalArgs(args, 3, actions)).map(evalValueToString) | ||
: [ | ||
undefined, | ||
...(await evalArgs(args, 2, actions)).map(evalValueToString), | ||
] | ||
if (name) { | ||
actions.updateVariable(id ?? undefined, name, value ?? '') | ||
await actions.updateVariable(id ?? undefined, name, value ?? '') | ||
} | ||
return EvalValue.Void() | ||
}, | ||
@@ -129,7 +207,11 @@ | ||
args.length >= 3 | ||
? await evalArgs(args, 3, actions) | ||
: [undefined, ...(await evalArgs(args, 2, actions))] | ||
? (await evalArgs(args, 3, actions)).map(evalValueToString) | ||
: [ | ||
undefined, | ||
...(await evalArgs(args, 2, actions)).map(evalValueToString), | ||
] | ||
if (name) { | ||
actions.setAttribute(id ?? undefined, name, value ?? '') | ||
} | ||
return EvalValue.Void() | ||
}, | ||
@@ -139,14 +221,21 @@ attr: async () => { | ||
args.length >= 2 | ||
? await evalArgs(args, 2, actions) | ||
: [undefined, await evalExpr(args[0], actions)] | ||
? (await evalArgs(args, 2, actions)).map(evalValueToString) | ||
: [undefined, evalValueToString(await evalExpr(args[0], actions))] | ||
if (name) { | ||
return actions.getAttribute(id as string | undefined, name) | ||
const val = await actions.getAttribute(id as string | undefined, name) | ||
return val === undefined ? EvalValue.Void() : EvalValue.String(val) | ||
} | ||
return EvalValue.Void() | ||
}, | ||
'prevent-default': async () => actions.withEvent(e => e.preventDefault()), | ||
'prevent-default': async () => { | ||
await actions.withEvent(e => e.preventDefault()) | ||
return EvalValue.Void() | ||
}, | ||
request: async () => { | ||
const url = await evalExpr(args[0], actions) | ||
const method = (args[1] && (await evalExpr(args[1], actions))) ?? 'post' | ||
const url = evalValueToString(await evalExpr(args[0], actions)) | ||
const method = | ||
(args[1] && evalValueToString(await evalExpr(args[1], actions))) || | ||
'post' | ||
@@ -157,22 +246,123 @@ if (url) { | ||
} | ||
return EvalValue.Void() | ||
}, | ||
'add-children': async () => { | ||
const id = await evalExpr(args[0], actions) | ||
if (id) actions.addChildren(id, args.slice(1)) | ||
const id = evalValueToString(await evalExpr(args[0], actions)) | ||
if (id) await actions.addChildren(id, args.slice(1)) | ||
return EvalValue.Void() | ||
}, | ||
'remove-element': async () => | ||
actions.removeElement( | ||
(args[0] && (await evalExpr(args[0], actions))) ?? undefined, | ||
), | ||
'remove-element': async () => { | ||
const selector = | ||
(args[0] && evalValueToString(await evalExpr(args[0], actions))) ?? | ||
undefined | ||
if (selector) await actions.removeElement(selector) | ||
return EvalValue.Void() | ||
}, | ||
'call-method': async () => { | ||
const [id, method, ...methodArgs] = ( | ||
await Promise.all(args.map(a => evalExpr(a, actions))) | ||
).map(evalValueToString) | ||
if (id && method) { | ||
await actions.callMethod(id, method, methodArgs) | ||
} | ||
return EvalValue.Void() | ||
}, | ||
map: async () => { | ||
const values = await Promise.all( | ||
args.map(async mapExpr => | ||
match<Promise<undefined | [string, EvalValue]>, Expr>(mapExpr, { | ||
Pair: async ({ key, value }) => [ | ||
key, | ||
await evalExpr(value, actions), | ||
], | ||
_: async () => undefined, | ||
}), | ||
), | ||
) | ||
return EvalValue.Map(Object.fromEntries(values.filter(Boolean) as any)) | ||
}, | ||
seq: async () => EvalValue.Lazy(args), | ||
// noop | ||
noop: async () => EvalValue.Void(), | ||
func: async () => EvalValue.Void(), | ||
call: async () => { | ||
const [id, method, ...methodArgs] = await Promise.all( | ||
args.map(a => evalExpr(a, actions)), | ||
const varId = match<string | undefined, EvalValue>( | ||
await evalExpr(args[0], actions), | ||
{ | ||
VarIdentifier: id => id, | ||
_: () => undefined, | ||
}, | ||
) | ||
if (id && method) { | ||
actions.callMethod(id, method, methodArgs) | ||
const propMapExpr = args[1] | ||
? await evalExpr(args[1], actions) | ||
: EvalValue.Void() | ||
const properties = match<Record<string, EvalValue>, EvalValue>( | ||
propMapExpr, | ||
{ | ||
Map: m => m, | ||
_: () => ({}), | ||
}, | ||
) | ||
if (varId) { | ||
const prop = await actions.getVariable(varId) | ||
if (prop) { | ||
const exprs = parse(prop) | ||
return actions.evaluateInScope(exprs, properties) | ||
} | ||
} | ||
return EvalValue.Void() | ||
}, | ||
_: () => Promise.reject(new Error('not supposed to be here')), | ||
string: async () => { | ||
const str = await Promise.all(args.map(a => evalExprAsString(a, actions))) | ||
return EvalValue.String(str.filter(Boolean).join('')) | ||
}, | ||
quotify: async () => { | ||
const str = await evalExprAsString(args[0], actions) | ||
return EvalValue.String(`'${str || ''}'`) | ||
}, | ||
unquotify: async () => { | ||
const str = await evalExprAsString(args[0], actions) | ||
return EvalValue.String(unquotify(str || '')) | ||
}, | ||
try: async () => { | ||
try { | ||
return await evalExpr(args[0], actions) | ||
} catch (e) { | ||
return actions.evaluateInScope([args[1]], { | ||
'--error': EvalValue.Value(e), | ||
}) | ||
} | ||
}, | ||
do: async () => { | ||
let result = EvalValue.Void() | ||
for (const expr of args) { | ||
result = await evalExpr(expr, actions) | ||
} | ||
return result | ||
}, | ||
let: async () => { | ||
const varName = await evalExprAsString(args[0], actions) | ||
const result = await evalExpr(args[1], actions) | ||
if (!varName) return EvalValue.Void() | ||
return actions.evaluateInScope([args[2]], { | ||
[varName]: result, | ||
}) | ||
}, | ||
_: () => Promise.reject(new Error(`Not implemented: ${name}`)), | ||
}) | ||
@@ -179,0 +369,0 @@ } |
@@ -1,8 +0,14 @@ | ||
import { EvalActions, evalExpr } from './eval' | ||
import { | ||
EvalActions, | ||
EvalValue, | ||
evalExpr, | ||
evalExprAsString, | ||
evalValueToString, | ||
} from './eval' | ||
import { | ||
extractDeclaration, | ||
DeclarationEval, | ||
expressionsToDeclrs, | ||
Declaration, | ||
} from './declarations' | ||
import { parse } from './parser' | ||
import { Expr, parse } from './parser' | ||
import { match, matchString } from './utils/adt' | ||
@@ -65,3 +71,3 @@ | ||
actions: EvalActions, | ||
): Promise<Array<DeclarationEval>> => { | ||
): Promise<Array<Declaration>> => { | ||
const value = getPropertyValue($element, PROPERTIES.CHILDREN) | ||
@@ -92,4 +98,6 @@ return extractDeclaration(value, actions) | ||
$element: HTMLElement, | ||
{ event = null, pure = false }: { event?: any; pure?: boolean }, | ||
ctx: { event?: any; pure?: boolean }, | ||
): EvalActions => { | ||
const { event = null, pure = false } = ctx | ||
const actions: EvalActions = { | ||
@@ -177,2 +185,21 @@ addClass: async (id, cls) => getElement(id, $element)?.classList.add(cls), | ||
}, | ||
evaluateInScope: async (exprs, properties) => { | ||
const node = document.createElement('div') | ||
node.style.display = 'none' | ||
for (const [key, evalVal] of Object.entries(properties)) { | ||
const value = evalValueToString(evalVal) | ||
value && node.style.setProperty(key, value) | ||
} | ||
$element.appendChild(node) | ||
const result = await evalExprInScope(exprs, getEvalActions(node, ctx)) | ||
if (!$element.hasAttribute('data-debug-stack')) { | ||
node.parentNode?.removeChild(node) | ||
} | ||
return result | ||
}, | ||
} | ||
@@ -182,2 +209,13 @@ return actions | ||
const evalExprInScope = async ( | ||
exprs: Expr[], | ||
actions: EvalActions, | ||
): Promise<EvalValue> => { | ||
let lastVal = EvalValue.Void() | ||
for (const expr of exprs) { | ||
lastVal = await evalExpr(expr, actions) | ||
} | ||
return lastVal | ||
} | ||
export const handleEvents = async ( | ||
@@ -192,6 +230,6 @@ $element: HTMLElement, | ||
const eventHandler = async (event: any) => { | ||
const exprs = parse(handlerExpr) | ||
for (const expr of exprs) { | ||
await evalExpr(expr, getEvalActions($element, { event })) | ||
} | ||
await evalExprInScope( | ||
parse(handlerExpr), | ||
getEvalActions($element, { event }), | ||
) | ||
} | ||
@@ -217,6 +255,6 @@ | ||
const declarationToElement = ( | ||
declaration: DeclarationEval, | ||
const declarationToElement = async ( | ||
declaration: Declaration, | ||
$parent?: HTMLElement, | ||
): { node: HTMLElement; isNewElement: boolean } => { | ||
): Promise<{ node: HTMLElement; isNewElement: boolean }> => { | ||
const { tag, id, selectors } = declaration.selector | ||
@@ -241,4 +279,5 @@ const tagName = tag || 'div' | ||
for (const [key, value] of declaration.properties) { | ||
$child?.style.setProperty(key, JSON.stringify(value)) | ||
for (const [key, evalValue] of declaration.properties) { | ||
const value = evalValueToString(evalValue) | ||
$child?.style.setProperty(key, JSON.stringify(value || '')) | ||
} | ||
@@ -250,3 +289,3 @@ | ||
const createLayer = async ( | ||
declarations: Array<DeclarationEval>, | ||
declarations: Array<Declaration>, | ||
$parent: HTMLElement, | ||
@@ -263,3 +302,3 @@ ) => { | ||
for (const declaration of declarations) { | ||
const { node: $child, isNewElement } = declarationToElement( | ||
const { node: $child, isNewElement } = await declarationToElement( | ||
declaration, | ||
@@ -270,2 +309,6 @@ $childrenRoot, | ||
await manageElement($child, isNewElement) | ||
if (declaration.children.length > 0) { | ||
await createLayer(declaration.children, $child) | ||
} | ||
} | ||
@@ -287,3 +330,3 @@ } | ||
$element.textContent = | ||
(exprs[0] ? await evalExpr(exprs[0], actions) : text) ?? text | ||
(exprs[0] ? await evalExprAsString(exprs[0], actions) : text) ?? text | ||
} catch (e) { | ||
@@ -290,0 +333,0 @@ $element.textContent = text |
@@ -111,2 +111,14 @@ import { Enum, constructors, match } from './utils/adt' | ||
export const parseExpr = (input: string): Expr => { | ||
return match(exprParser(input), { | ||
Ok: ({ value, input }) => { | ||
if (input) throw new Error(`Aaaaaa. Input left: ${input}`) | ||
return value | ||
}, | ||
Err: e => { | ||
throw e | ||
}, | ||
}) | ||
} | ||
const declarationParser = P.or([callExprParser, selectorExprParser]) | ||
@@ -134,3 +146,3 @@ | ||
export const parse = (input: string): Array<Expr> => { | ||
const res = P.many1(exprParser)(input.trim()) | ||
const res = P.sepBy(exprParser, P.or([comma, whitespace]))(input.trim()) | ||
return match(res, { | ||
@@ -137,0 +149,0 @@ Ok: ({ value, input }) => { |
@@ -10,2 +10,24 @@ type TagValue<T, N> = T extends Tag<N, infer V> ? V : never | ||
// type TagValues< | ||
// T extends Tag<any, string>, | ||
// Keys extends Array<string>, | ||
// Values extends Array<any> = [], | ||
// > = Keys extends [] | ||
// ? Values | ||
// : Keys extends [ | ||
// infer key extends string, | ||
// ...infer restOfKeys extends string[], | ||
// ] | ||
// ? TagValues<T, restOfKeys, [...Values, TagValue<T, key>]> | ||
// : never | ||
// | ||
// export const ifLet = <T extends Tag<string, any>, Keys extends Array<T['tag']>>( | ||
// tag: T, | ||
// kinds: Keys, | ||
// cb: (...values: TagValues<T, Keys>) => void, | ||
// ): void => { | ||
// const values = kinds.map(k => (tag.tag === k ? tag.value : undefined)) | ||
// ;(cb as any)(...values) | ||
// } | ||
export const matchString = <R, T extends string = string>( | ||
@@ -12,0 +34,0 @@ key: T, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
182258
21.51%2068
30.39%87
2.35%