diff options
| author | Akshay Nair <phenax5@gmail.com> | 2023-08-13 14:50:26 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2023-08-13 14:50:26 +0530 |
| commit | 1f147a779114a641b4abe5e47ac0b05433ec02fb (patch) | |
| tree | d27845a0ac2deee6bd5ba652da692e733c0cf589 /src/declarations.ts | |
| parent | 48455e6caaa7ad98316bbb4896b59f4487ad8650 (diff) | |
| download | css-everything-1f147a779114a641b4abe5e47ac0b05433ec02fb.tar.gz css-everything-1f147a779114a641b4abe5e47ac0b05433ec02fb.zip | |
feat: finalizes component system. it fucking works holy shit.
Diffstat (limited to 'src/declarations.ts')
| -rw-r--r-- | src/declarations.ts | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/declarations.ts b/src/declarations.ts new file mode 100644 index 0000000..6c33fda --- /dev/null +++ b/src/declarations.ts @@ -0,0 +1,102 @@ +import { EvalActions, evalExpr } from './eval' +import { Expr, Selector, SelectorComp, parseDeclarations } from './parser' +import { match, matchString } from './utils/adt' + +export interface Declaration { + selector: Selector + properties: Map<string, Expr> +} + +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>() +const getUniqueInstanceId = (id: string) => { + const instanceCount = instanceCountMap.get(id) ?? 0 + instanceCountMap.set(id, instanceCount + 1) + return `${id}--index-${instanceCount}` +} + +export const toDeclaration = (expr: Expr): Declaration | undefined => { + let selector: Selector | undefined + const properties: Map<string, Expr> = new Map() + let isInstance = false + + match(expr, { + Selector: sel => { + selector = sel + }, + Call: ({ name, args }) => { + matchString(name, { + instance: () => { + isInstance = true + const [sel, map] = args + 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}`) + }, + }) + }, + _: () => {}, + }) + + 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 } +} + +export const extractDeclaration = async ( + input: string, + actions: EvalActions, +): Promise<Array<DeclarationEval>> => { + const exprs = parseDeclarations(input) + 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> +} |
