aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/todo-list/style.css8
-rw-r--r--src/declarations.ts1
-rw-r--r--src/eval.ts54
-rw-r--r--src/index.ts51
-rw-r--r--tests/eval.spec.ts3
5 files changed, 107 insertions, 10 deletions
diff --git a/examples/todo-list/style.css b/examples/todo-list/style.css
index 66ec5f0..cda7003 100644
--- a/examples/todo-list/style.css
+++ b/examples/todo-list/style.css
@@ -18,6 +18,14 @@ body * { box-sizing: border-box; }
border-radius: 5px;
overflow: hidden;
+ /* --my-func: */
+ /* js-eval(get-var(--js)) */
+ /* delay(1s) */
+ /* call(--my-func, map(--js: get-var(--js))) */
+ /* ; */
+ /**/
+ /* --cssx-on-mount: call(--my-func, map(--js: "console.log(`yay`)")); */
+
--cssx-children: form#task-input-form #task-list;
}
diff --git a/src/declarations.ts b/src/declarations.ts
index 5c2f9a3..c0966fa 100644
--- a/src/declarations.ts
+++ b/src/declarations.ts
@@ -62,6 +62,7 @@ export const toDeclaration = (expr: Expr): Declaration | undefined => {
_: _ => {},
})
+ // TODO: Refactor with eval
match(map, {
Call: ({ name, args }) => {
if (name !== 'map') return
diff --git a/src/eval.ts b/src/eval.ts
index e421d7a..8112353 100644
--- a/src/eval.ts
+++ b/src/eval.ts
@@ -1,4 +1,4 @@
-import { CSSUnit, Expr } from './parser'
+import { CSSUnit, Expr, parse } from './parser'
import { Enum, constructors, match, matchString } from './utils/adt'
export interface EvalActions {
@@ -36,6 +36,10 @@ export interface EvalActions {
method: string,
args: (string | undefined)[],
): Promise<void>
+ evaluateInScope(
+ exprs: Expr[],
+ properties: Record<string, EvalValue>,
+ ): Promise<EvalValue>
// calculate ??
}
@@ -46,6 +50,7 @@ export type EvalValue = Enum<{
Lazy: Expr[]
Void: never
VarIdentifier: string
+ Map: { [key in string]: EvalValue }
// Object: Record<any, any>
}>
export const EvalValue = constructors<EvalValue>()
@@ -75,7 +80,7 @@ export const evalExpr = async (
_: async _ => EvalValue.Void(),
})
-const evalValueToString = (val: EvalValue): string | undefined =>
+export const evalValueToString = (val: EvalValue): string | undefined =>
match<string | undefined, EvalValue>(val, {
String: s => s.replace(/(^'|")|('|"$)/g, ''),
Boolean: b => `${b}`,
@@ -245,8 +250,53 @@ const getFunctions = (
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))
+ },
+
func: async () => EvalValue.Lazy(args),
+ call: async () => {
+ const varId = match<string | undefined, EvalValue>(
+ await evalExpr(args[0], actions),
+ {
+ VarIdentifier: id => id,
+ _: () => undefined,
+ },
+ )
+
+ const propMapExpr = await evalExpr(args[1], actions)
+ 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 implemented: ${name}`)),
})
}
diff --git a/src/index.ts b/src/index.ts
index 52f3a1b..e7e42cb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,10 +1,16 @@
-import { EvalActions, evalExpr, evalExprAsString } from './eval'
+import {
+ EvalActions,
+ EvalValue,
+ evalExpr,
+ evalExprAsString,
+ evalValueToString,
+} from './eval'
import {
extractDeclaration,
DeclarationEval,
expressionsToDeclrs,
} from './declarations'
-import { parse } from './parser'
+import { Expr, parse } from './parser'
import { match, matchString } from './utils/adt'
const CSSX_ON_UPDATE_EVENT = 'cssx--update'
@@ -88,8 +94,10 @@ const getElement = (
const getEvalActions = (
$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 = {
addClass: async (id, cls) => getElement(id, $element)?.classList.add(cls),
removeClass: async (id, cls) =>
@@ -172,10 +180,39 @@ const getEvalActions = (
const $el = id ? getElement(id, $element) : $element
;($el as any)[method].call($el, args)
},
+
+ 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)
+ console.log(key, evalVal, value)
+ value && node.style.setProperty(key, value)
+ }
+ $element.appendChild(node)
+
+ const result = await evalExprInScope(exprs, getEvalActions(node, ctx))
+
+ // node.parentNode?.removeChild(node)
+
+ return result
+ },
}
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 (
$element: HTMLElement,
isNewElement: boolean = false,
@@ -185,10 +222,10 @@ export const handleEvents = async (
if (handlerExpr) {
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 }),
+ )
}
matchString(eventType, {
diff --git a/tests/eval.spec.ts b/tests/eval.spec.ts
index d61a470..2b226f7 100644
--- a/tests/eval.spec.ts
+++ b/tests/eval.spec.ts
@@ -1,5 +1,5 @@
import { EvalActions, EvalValue, evalExpr } from '../src/eval'
-import { Expr, exprParser, parseExpr } from '../src/parser'
+import { Expr, parseExpr } from '../src/parser'
describe('eval', () => {
const deps: EvalActions = {
@@ -18,6 +18,7 @@ describe('eval', () => {
addChildren: jest.fn(),
removeElement: jest.fn(),
callMethod: jest.fn(),
+ evaluateInScope: jest.fn(),
}
fdescribe('function/call', () => {