aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/api/style.css2
-rw-r--r--src/eval.ts40
-rw-r--r--src/parser.ts (renamed from src/parse-expr.ts)0
-rw-r--r--src/utils/adt.ts5
-rw-r--r--src/utils/parser-comb.ts15
-rw-r--r--src/utils/result.ts14
-rw-r--r--tests/eval.spec.ts29
-rw-r--r--tests/parser.spec.ts (renamed from tests/parse-expr.spec.ts)2
8 files changed, 92 insertions, 15 deletions
diff --git a/examples/api/style.css b/examples/api/style.css
index ad1dff9..d1be912 100644
--- a/examples/api/style.css
+++ b/examples/api/style.css
@@ -5,7 +5,7 @@ body {
#load-btn {
--cssx-on-click:
add-class(load-btn, 'loading')
- get(url('./more-style.css'))
+ get('./more-style.css')
add-class(load-btn, 'hidden');
}
#load-btn.loading {
diff --git a/src/eval.ts b/src/eval.ts
new file mode 100644
index 0000000..1e18457
--- /dev/null
+++ b/src/eval.ts
@@ -0,0 +1,40 @@
+import { Expr } from "./parser";
+import { match, matchString } from "./utils/adt";
+
+export type Dependencies = {
+ addClass(id: string, classes: string): Promise<void>
+ removeClass(id: string, classes: string): Promise<void>
+ // requestGetCss(url: string): Promise<string>
+ // getVarable(name: string, def?: string): Promise<string>
+ // updateVariable(id: string, varName: string, value: string): Promise<void>
+ // calculate ??
+}
+
+export const evalExpr = async (expr: Expr, deps: Dependencies): Promise<string | undefined> =>
+ match<Promise<string | undefined>, Expr>(expr, {
+ Call: async ({ name, args }) => {
+ await matchString(name, {
+ 'add-class': async () => {
+ const id = await evalExpr(args[0], deps)
+ const classes = await evalExpr(args[1], deps)
+ if (id && classes) {
+ await deps.addClass(id, classes)
+ }
+ },
+ 'remove-class': async () => {
+ const id = await evalExpr(args[0], deps)
+ const classes = await evalExpr(args[1], deps)
+ if (id && classes) {
+ await deps.removeClass(id, classes)
+ }
+ },
+ _: () => Promise.reject(new Error('not supposed to be here')),
+ })
+ return undefined
+ },
+ LiteralString: async s => s,
+ Identifier: async s => s,
+ VarIdentifier: async s => s,
+ _: async _ => undefined,
+ })
+
diff --git a/src/parse-expr.ts b/src/parser.ts
index 1c5c08f..1c5c08f 100644
--- a/src/parse-expr.ts
+++ b/src/parser.ts
diff --git a/src/utils/adt.ts b/src/utils/adt.ts
index e9a6c51..7234f67 100644
--- a/src/utils/adt.ts
+++ b/src/utils/adt.ts
@@ -5,6 +5,11 @@ export const match =
[key in T['tag'] | '_']?: (v: TagValue<T, key>) => R
}): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value)
+export const matchString =
+ <R, T extends string>(key: T, pattern: {
+ [key in T | '_']?: (key: key) => R
+ }): R => ((pattern as any)[key] || (pattern._ as any))(key)
+
type Tag<N, V> = { tag: N; value: V }
export type Enum<T> = { [N in keyof T]: Tag<N, T[N]> }[keyof T]
diff --git a/src/utils/parser-comb.ts b/src/utils/parser-comb.ts
index 49f633e..e0665f6 100644
--- a/src/utils/parser-comb.ts
+++ b/src/utils/parser-comb.ts
@@ -1,16 +1,5 @@
-import { Enum, constructors, match } from './adt';
-
-export type Result<V, E> = Enum<{ Ok: V, Err: E }>
-export const Result = constructors<Result<any, any>>()
-
-export const mapResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => B): Result<B, E> =>
- chainResult(res, a => Result.Ok(fn(a)))
-
-export const chainResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => Result<B, E>): Result<B, E> =>
- match(res, {
- Ok: a => fn(a),
- Err: e => Result.Err(e),
- });
+import { match } from './adt';
+import { Result, mapResult, chainResult } from './result';
export type ParseResult<T> = Result<{ value: T, input: string }, { error: string, input: string }>;
diff --git a/src/utils/result.ts b/src/utils/result.ts
new file mode 100644
index 0000000..c0120b8
--- /dev/null
+++ b/src/utils/result.ts
@@ -0,0 +1,14 @@
+import { Enum, constructors, match } from "./adt";
+
+export type Result<V, E> = Enum<{ Ok: V, Err: E }>
+export const Result = constructors<Result<any, any>>()
+
+export const mapResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => B): Result<B, E> =>
+ chainResult(res, a => Result.Ok(fn(a)))
+
+export const chainResult = <A, B, E>(res: Result<A, E>, fn: (_: A) => Result<B, E>): Result<B, E> =>
+ match(res, {
+ Ok: a => fn(a),
+ Err: e => Result.Err(e),
+ });
+
diff --git a/tests/eval.spec.ts b/tests/eval.spec.ts
new file mode 100644
index 0000000..63062e3
--- /dev/null
+++ b/tests/eval.spec.ts
@@ -0,0 +1,29 @@
+import { Dependencies, evalExpr } from '../src/eval'
+import { Expr } from '../src/parser'
+
+describe('eval', () => {
+ const deps: Dependencies = {
+ addClass: jest.fn(),
+ removeClass: jest.fn(),
+ }
+
+ it('should add classes', async () => {
+ await evalExpr(Expr.Call({
+ name: 'add-class',
+ args: [ Expr.Identifier('element-id'), Expr.LiteralString('class-name') ],
+ }), deps)
+
+ expect(deps.addClass).toHaveBeenCalledTimes(1)
+ expect(deps.addClass).toHaveBeenCalledWith('element-id', 'class-name')
+ })
+
+ it('should add classes', async () => {
+ await evalExpr(Expr.Call({
+ name: 'remove-class',
+ args: [ Expr.Identifier('element-id'), Expr.LiteralString('class-name') ],
+ }), deps)
+
+ expect(deps.removeClass).toHaveBeenCalledTimes(1)
+ expect(deps.removeClass).toHaveBeenCalledWith('element-id', 'class-name')
+ })
+})
diff --git a/tests/parse-expr.spec.ts b/tests/parser.spec.ts
index f873464..48c398c 100644
--- a/tests/parse-expr.spec.ts
+++ b/tests/parser.spec.ts
@@ -1,4 +1,4 @@
-import { Expr, parse } from '../src/parse-expr'
+import { Expr, parse } from '../src/parser'
describe('parser', () => {
it('should parse function call', () => {