diff options
| author | Akshay Nair <phenax5@gmail.com> | 2023-08-11 21:40:54 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2023-08-11 21:50:20 +0530 |
| commit | 845d503bb16cb5046a4fec6d046b7b527a080187 (patch) | |
| tree | a9f8fdf4510ad4d61e8d105065be9071946e2bdf | |
| parent | 5a9942fde65787b35d4eb8e3441af6fe68819612 (diff) | |
| download | css-everything-845d503bb16cb5046a4fec6d046b7b527a080187.tar.gz css-everything-845d503bb16cb5046a4fec6d046b7b527a080187.zip | |
chore: adds prettier
Diffstat (limited to '')
| -rw-r--r-- | .editorconfig | 7 | ||||
| -rw-r--r-- | .prettierrc | 5 | ||||
| -rw-r--r-- | TODO.norg | 4 | ||||
| -rw-r--r-- | examples/counter/index.html | 6 | ||||
| -rw-r--r-- | examples/counter/style.css | 6 | ||||
| -rw-r--r-- | examples/form/index.html | 6 | ||||
| -rw-r--r-- | examples/form/signup.css | 42 | ||||
| -rw-r--r-- | examples/form/style.css | 24 | ||||
| -rw-r--r-- | examples/todo-list/style.css | 9 | ||||
| -rw-r--r-- | package.json | 4 | ||||
| -rw-r--r-- | src/eval.ts | 22 | ||||
| -rw-r--r-- | src/index.ts | 43 | ||||
| -rw-r--r-- | src/parser.ts | 11 | ||||
| -rw-r--r-- | src/utils/adt.ts | 17 | ||||
| -rw-r--r-- | src/utils/parser-comb.ts | 171 | ||||
| -rw-r--r-- | src/utils/result.ts | 18 | ||||
| -rw-r--r-- | tests/eval.spec.ts | 44 | ||||
| -rw-r--r-- | tests/parser.spec.ts | 2 | ||||
| -rw-r--r-- | yarn.lock | 5 |
19 files changed, 264 insertions, 182 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..346ac31 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true
\ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e6e4310 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +semi: false +singleQuote: true +bracketSpacing: true +arrowParens: avoid +printWidth: 80
\ No newline at end of file @@ -7,6 +7,8 @@ - (x) Specify node type - `button(id)` or `button#id` - (x) attributes - (x) `--cssx-text` (and maybe `--cssx-html`?) + - ( ) Evaluate `calc` + - ( ) Additional events + - ( ) Proper dom tests - ( ) Improve error messages - - ( ) Evaluate `calc`? - ( ) `list` & `tuple` data structures? diff --git a/examples/counter/index.html b/examples/counter/index.html index 158ee16..9aa89d2 100644 --- a/examples/counter/index.html +++ b/examples/counter/index.html @@ -1,9 +1,9 @@ -<!DOCTYPE html> +<!doctype html> <html lang="en"> <head> <title>Counter example</title> - <meta charset="UTF-8"> - <link href="./style.css" rel="stylesheet"> + <meta charset="UTF-8" /> + <link href="./style.css" rel="stylesheet" /> </head> <body> <script async defer src="../../dist/index.js"></script> diff --git a/examples/counter/style.css b/examples/counter/style.css index 9cf50e0..b60785f 100644 --- a/examples/counter/style.css +++ b/examples/counter/style.css @@ -1,6 +1,6 @@ body { --cssx-children: container todo-container; - --cssx-on-load: js(console.log("what have we done?!")); + --cssx-on-load: js(console.log('what have we done?!')); } #container { @@ -11,7 +11,7 @@ body { #counter { } #counter::before { - content: "Count: " var(--count); + content: 'Count: ' var(--count); } #btn-increment { @@ -22,5 +22,5 @@ body { --cssx-on-click: update(container, --count, calc(var(--count) + 1)); } #btn-increment::after { - content: "Increment"; + content: 'Increment'; } diff --git a/examples/form/index.html b/examples/form/index.html index 1d55241..618b21b 100644 --- a/examples/form/index.html +++ b/examples/form/index.html @@ -1,9 +1,9 @@ -<!DOCTYPE html> +<!doctype html> <html lang="en"> <head> <title>Register to this awesome website</title> - <meta charset="UTF-8"> - <link href="./style.css" rel="stylesheet"> + <meta charset="UTF-8" /> + <link href="./style.css" rel="stylesheet" /> </head> <body> <script async defer src="../../dist/index.js"></script> diff --git a/examples/form/signup.css b/examples/form/signup.css index 96b9ac1..1a5f3ff 100644 --- a/examples/form/signup.css +++ b/examples/form/signup.css @@ -1,11 +1,10 @@ - #signup-page-content { border: 1px solid #888; padding: 1rem; max-width: 700px; margin: 1rem auto; - --cssx-disgustingly-set-innerhtml: <h1 class="form-title">Sign-<b>Up</b></h1>; + --cssx-disgustingly-set-innerhtml: "<h1 class= 'form-title'>Sign-<b>Up</b></h1>"; --cssx-children: form#form; --count: '0'; @@ -19,29 +18,26 @@ color: gray; } .form-title b { - font-weight: bold; color: black; + font-weight: bold; + color: black; } #form { display: block; - --cssx-on-submit: - prevent-default() - add-class(form, 'submitting') - request('/examples/') - remove-class(form, 'submitting') - add-class(form, 'submitted') - ; + --cssx-on-submit: prevent-default() add-class(form, 'submitting') + request('/examples/') remove-class(form, 'submitting') + add-class(form, 'submitted'); --cssx-children: input#input-email input#input-password actions #message; } #form.submitted #message::after { display: block; - content: "Form submitted successfully"; + content: 'Form submitted successfully'; } #form.submitting #submit-btn { pointer-events: none; - opacity: .5; + opacity: 0.5; } #form input { @@ -52,21 +48,18 @@ } #input-email { - --cssx-on-mount: - set-attr('type', 'email') - set-attr('name', 'email') + --cssx-on-mount: set-attr('type', 'email') set-attr('name', 'email') set-attr('required', 'true') - set-attr('placeholder', 'Email. Eg:- mail@postbox.com') - ; + set-attr('placeholder', 'Email. Eg:- mail@postbox.com'); } #input-password { - --cssx-on-mount: - set-attr('type', 'password') - set-attr('name', 'password') + --cssx-on-mount: set-attr('type', 'password') set-attr('name', 'password') set-attr('required', 'true') - set-attr('placeholder', 'Password. Eg:- password, password1, password2, password123') - ; + set-attr( + 'placeholder', + 'Password. Eg:- password, password1, password2, password123' + ); } #actions { @@ -79,5 +72,6 @@ padding: 0.4rem 0.7rem; --cssx-on-mount: set-attr('type', 'submit'); } -#submit-btn::after { content: "Sign-Up"; } - +#submit-btn::after { + content: 'Sign-Up'; +} diff --git a/examples/form/style.css b/examples/form/style.css index b79f265..113ab81 100644 --- a/examples/form/style.css +++ b/examples/form/style.css @@ -8,22 +8,25 @@ body * { #signup-btn { display: inline-block; background: #5180e9; - color: #000; + color: #fff; + border: none; + outline: none; padding: 0.5rem 1rem; cursor: pointer; --cssx-on-mount: set-attr('type', 'button'); - --cssx-on-click: - add-class(signup-page, 'loading') - add-class(signup-btn, 'loading') - delay(0.5s) + --cssx-on-click: add-class(signup-page, 'loading') + add-class(signup-btn, 'loading') delay(0.5s) load-cssx(signup-page-content, './signup.css') - remove-class(signup-page, 'loading') - remove-class(signup-btn, 'loading') - ; + remove-class(signup-page, 'loading') remove-class(signup-btn, 'loading'); +} +#signup-btn::after { + content: 'Register now to start your free trail for $99'; +} +#signup-btn:hover { + opacity: 0.8; } -#signup-btn::after { content: "Register now to start your free trail for $99"; } #signup-btn.loading { pointer-events: none; opacity: 0.4; @@ -33,6 +36,5 @@ body * { --cssx-children: signup-page-content; } #signup-page.loading::after { - content: "Loading..."; + content: 'Loading...'; } - diff --git a/examples/todo-list/style.css b/examples/todo-list/style.css index aeffde5..7533210 100644 --- a/examples/todo-list/style.css +++ b/examples/todo-list/style.css @@ -15,14 +15,11 @@ body { --cssx-on-click: update( todo-container, --todo-list, - list-append( - var(--todo-list), - tuple(get-attr(input-field, value), false) - ) + list-append(var(--todo-list), tuple(get-attr(input-field, value), false)) ); } #submit-btn::after { - content: "Submit"; + content: 'Submit'; } #todo-list { @@ -30,9 +27,7 @@ body { } #todo-item { - } #todo-item::after { content: var(--todo-item); } - diff --git a/package.json b/package.json index bcb7de9..e72b517 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "node esbuild.js", "serve": "serve -p 3000 .", + "format": "prettier --write ./{src,tests}/**/*.ts ./examples/**/*.{html,css}", "test": "jest" }, "devDependencies": { @@ -15,10 +16,11 @@ "esbuild": "^0.18.17", "jest": "^29.6.2", "jest-environment-jsdom": "^29.6.2", + "prettier": "^3.0.1", "serve": "^14.2.0", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", "typescript": "^5.1.6" }, "dependencies": {} -} +}
\ No newline at end of file diff --git a/src/eval.ts b/src/eval.ts index 191a76b..5e99282 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -12,7 +12,11 @@ export type EvalActions = { setAttribute(name: string, value: string): Promise<void> withEvent(fn: (e: any) => void): Promise<void> getFormData(): Promise<FormData | undefined> - sendRequest(_: { method: string, url: string, data: FormData | undefined }): Promise<void> + sendRequest(_: { + method: string + url: string + data: FormData | undefined + }): Promise<void> // calculate ?? } @@ -20,19 +24,19 @@ type EvalValue = string | undefined | void export const evalExpr = async ( expr: Expr, - actions: EvalActions + actions: EvalActions, ): Promise<EvalValue> => match<Promise<EvalValue>, Expr>(expr, { Call: async ({ name, args }) => getFunctions(name, args, actions), - LiteralString: async (s) => s, + LiteralString: async s => s, LiteralNumber: async ({ value, unit }) => matchString<number, CSSUnit>(unit, { s: () => value * 1000, _: () => value, }).toString(), - Identifier: async (s) => s, - VarIdentifier: async (s) => s, - _: async (_) => undefined, + Identifier: async s => s, + VarIdentifier: async s => s, + _: async _ => undefined, }) const getFunctions = (name: string, args: Expr[], actions: EvalActions) => @@ -93,9 +97,11 @@ const getFunctions = (name: string, args: Expr[], actions: EvalActions) => }, 'prevent-default': async () => actions.withEvent(e => e.preventDefault()), - 'request': async () => { + request: async () => { const url = await evalExpr(args[0], actions) - const method = args[1] ? (await evalExpr(args[1], actions) ?? 'post') : 'post' + const method = args[1] + ? (await evalExpr(args[1], actions)) ?? 'post' + : 'post' if (url) { const data = await actions.getFormData() diff --git a/src/index.ts b/src/index.ts index b48b1d8..2d70c3f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,7 @@ const EVENT_HANDLERS = { const PROPERTIES = [ '--cssx-children', '--cssx-text', - '--cssx-disgustingly-set-innerhtml' + '--cssx-disgustingly-set-innerhtml', ] const injectStyles = () => { @@ -25,7 +25,7 @@ const injectStyles = () => { const properties = [...PROPERTIES, ...Object.values(EVENT_HANDLERS)] $style.textContent = `.cssx-layer { - ${properties.map((p) => `${p}: ${UNSET_PROPERTY_VALUE};`).join(' ')} + ${properties.map(p => `${p}: ${UNSET_PROPERTY_VALUE};`).join(' ')} }` document.body.appendChild($style) @@ -45,8 +45,8 @@ const getEvalActions = ($element: Element, event: any): EvalActions => ({ addClass: async (id, cls) => document.getElementById(id)?.classList.add(cls), removeClass: async (id, cls) => document.getElementById(id)?.classList.remove(cls), - delay: (delay) => new Promise((res) => setTimeout(res, delay)), - jsEval: async (js) => (0, eval)(js), + delay: delay => new Promise(res => setTimeout(res, delay)), + jsEval: async js => (0, eval)(js), loadCssx: async (id, url) => new Promise((resolve, reject) => { const $link = Object.assign(document.createElement('link'), { @@ -66,7 +66,7 @@ const getEvalActions = ($element: Element, event: any): EvalActions => ({ } document.body.appendChild($link) }), - getVariable: async (varName) => getPropertyValue($element, varName), + getVariable: async varName => getPropertyValue($element, varName), updateVariable: async (targetId, varName, value) => { const $el = document.getElementById(targetId) if ($el) { @@ -76,15 +76,21 @@ const getEvalActions = ($element: Element, event: any): EvalActions => ({ setAttribute: async (name, value) => { $element.setAttribute(name, value) }, - withEvent: async (fn) => fn(event), - getFormData: async () => $element.nodeName === 'FORM' ? new FormData($element as HTMLFormElement) : undefined, + withEvent: async fn => fn(event), + getFormData: async () => + $element.nodeName === 'FORM' + ? new FormData($element as HTMLFormElement) + : undefined, sendRequest: async ({ url, method, data }) => { await fetch(url, { method, body: data }) // TODO: Handle response? }, }) -const handleEvents = async ($element: Element, isNewElement: boolean = false) => { +const handleEvents = async ( + $element: Element, + isNewElement: boolean = false, +) => { for (const [eventType, property] of Object.entries(EVENT_HANDLERS)) { const handlerExpr = getPropertyValue($element, property) @@ -106,17 +112,17 @@ const handleEvents = async ($element: Element, isNewElement: boolean = false) => } } -let nodeCount = 0 -const manageElement = async ($element: Element, isNewElement: boolean = false) => { - if (nodeCount++ > 100) return // NOTE: Temporary. To prevent infinite rec - +const manageElement = async ( + $element: Element, + isNewElement: boolean = false, +) => { await handleEvents($element, isNewElement) const text = getPropertyValue($element, '--cssx-text') if (text) $element.textContent = text const html = getPropertyValue($element, '--cssx-disgustingly-set-innerhtml') - if (html) $element.innerHTML = html + if (html) $element.innerHTML = html.replace(/(^'|")|('|"$)/g, '') const childrenIds = getChildrenIds($element) if (childrenIds.length > 0) { @@ -127,12 +133,13 @@ const manageElement = async ($element: Element, isNewElement: boolean = false) = $element.appendChild($childrenRoot) for (const childId of childrenIds) { - let isNewElement = false; const selector = childId.split('#') const [tag, id] = selector.length >= 2 ? selector : ['div', ...selector] - const $child = - $childrenRoot.querySelector(`:scope > #${id}`) ?? - (isNewElement = true, Object.assign(document.createElement(tag || 'div'), { id })) + let $child = $childrenRoot.querySelector(`:scope > #${id}`) + const isNewElement = !$child + if (!$child) { + $child = Object.assign(document.createElement(tag || 'div'), { id }) + } $childrenRoot.appendChild($child) await manageElement($child, isNewElement) } @@ -147,4 +154,4 @@ const render = async ({ root = document.body }: Options = {}) => { await manageElement(root) } -render() +render()
\ No newline at end of file diff --git a/src/parser.ts b/src/parser.ts index 9cb0405..3279f57 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -8,7 +8,7 @@ export type Expr = Enum<{ Identifier: string VarIdentifier: string LiteralString: string - LiteralNumber: { value: number, unit: CSSUnit } + LiteralNumber: { value: number; unit: CSSUnit } }> export const Expr = constructors<Expr>() @@ -31,9 +31,9 @@ const callExprParser = (input: string) => P.map( P.zip2( consumeWhitespace(identifierParser), - parens(consumeWhitespace(P.sepBy(exprParser, comma))) + parens(consumeWhitespace(P.sepBy(exprParser, comma))), ), - ([name, args]) => Expr.Call({ name, args }) + ([name, args]) => Expr.Call({ name, args }), )(input) const stringLiteralParser: P.Parser<Expr> = P.map( @@ -41,14 +41,15 @@ const stringLiteralParser: P.Parser<Expr> = P.map( P.between(singleQuote, P.regex(/^[^']*/), singleQuote), P.between(doubleQuote, P.regex(/^[^"]*/), doubleQuote), ]), - Expr.LiteralString + Expr.LiteralString, ) const numberParser = P.regex(/^[-+]?((\d*\.\d+)|\d+)/) const numberExprParser: P.Parser<Expr> = P.map( P.zip2(numberParser, P.optional(P.regex(/^(s|ms)/i))), - ([value, unit]) => Expr.LiteralNumber({ value: Number(value), unit: (unit ?? '') as CSSUnit }), + ([value, unit]) => + Expr.LiteralNumber({ value: Number(value), unit: (unit ?? '') as CSSUnit }), ) const exprParser: P.Parser<Expr> = P.or([ diff --git a/src/utils/adt.ts b/src/utils/adt.ts index 78ab667..45d9e50 100644 --- a/src/utils/adt.ts +++ b/src/utils/adt.ts @@ -1,14 +1,18 @@ type TagValue<T, N> = T extends Tag<N, infer V> ? V : never -export const match = - <R, T extends Tag<string, any>>(tag: T, pattern: { +export const match = <R, T extends Tag<string, any>>( + tag: T, + pattern: { [key in T['tag'] | '_']?: (v: TagValue<T, key>) => R - }): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value) + }, +): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value) -export const matchString = - <R, T extends string = string>(key: T, pattern: { +export const matchString = <R, T extends string = string>( + key: T, + pattern: { [key in T | '_']?: (key: key) => R - }): R => ((pattern as any)[key] || (pattern._ as any))(key) + }, +): 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] @@ -26,4 +30,3 @@ export const constructors = <T extends Tag<string, any>>(): { }, }, ) as any - diff --git a/src/utils/parser-comb.ts b/src/utils/parser-comb.ts index f682068..3f171b8 100644 --- a/src/utils/parser-comb.ts +++ b/src/utils/parser-comb.ts @@ -1,83 +1,120 @@ -import { match } from './adt'; -import { Result, mapResult, chainResult } from './result'; +import { match } from './adt' +import { Result, mapResult, chainResult } from './result' -export type ParseResult<T> = Result<{ value: T, input: string }, { error: string, input: string }>; +export type ParseResult<T> = Result< + { value: T; input: string }, + { error: string; input: string } +> -export type Parser<T> = (input: string) => ParseResult<T>; +export type Parser<T> = (input: string) => ParseResult<T> -export const regex = (re: RegExp): Parser<string> => input => { - if (input.length === 0) return Result.Err({ error: 'fuckedinput', input }) - const res = input.match(re) - if (!res) return Result.Err({ error: 'fucked', input }); - return Result.Ok({ value: res[0], input: input.replace(re, '') }); -} +export const regex = + (re: RegExp): Parser<string> => + input => { + if (input.length === 0) return Result.Err({ error: 'fuckedinput', input }) + const res = input.match(re) + if (!res) return Result.Err({ error: 'fucked', input }) + return Result.Ok({ value: res[0], input: input.replace(re, '') }) + } -export const string = (str: string): Parser<string> => input => { - if (input.length === 0) return Result.Err({ error: 'fuckedinput', input }) - if (!input.startsWith(str)) return Result.Err({ error: 'fuckedstring', input }) - return Result.Ok({ value: str, input: input.slice(str.length) }); -} +export const string = + (str: string): Parser<string> => + input => { + if (input.length === 0) return Result.Err({ error: 'fuckedinput', input }) + if (!input.startsWith(str)) + return Result.Err({ error: 'fuckedstring', input }) + return Result.Ok({ value: str, input: input.slice(str.length) }) + } -export const or = <T>([parser, ...rest]: Array<Parser<T>>): Parser<T> => input => { - if (rest.length === 0) return parser(input); - const result = parser(input) - return match(result, { - Ok: () => result, - Err: (_) => or(rest)(input), - }); -} +export const or = + <T>([parser, ...rest]: Array<Parser<T>>): Parser<T> => + input => { + if (rest.length === 0) return parser(input) + const result = parser(input) + return match(result, { + Ok: () => result, + Err: _ => or(rest)(input), + }) + } -export const mapParseResult = <T, R>(parser: Parser<T>, fn: (_: { value: T, input: string }) => { value: R, input: string }): Parser<R> => input => - mapResult(parser(input), fn) +export const mapParseResult = + <T, R>( + parser: Parser<T>, + fn: (_: { value: T; input: string }) => { value: R; input: string }, + ): Parser<R> => + input => + mapResult(parser(input), fn) export const map = <T, R>(parser: Parser<T>, fn: (_: T) => R): Parser<R> => - mapParseResult(parser, ({ value, ...rest }) => ({ ...rest, value: fn(value) })); + mapParseResult(parser, ({ value, ...rest }) => ({ + ...rest, + value: fn(value), + })) -export const zip2 = <A, B>(parserA: Parser<A>, parserB: Parser<B>): Parser<readonly [A, B]> => input => { - // TODO: refactor please. shit code - const resa: Result<{ value: A, input: string }, { error: string, input: string }> = parserA(input); - return chainResult(resa, ({ value: a, input: inputB }) => { - const res: Result<{ value: readonly [A, B], input: string }, { error: string, input: string }> = - map(parserB, (b) => [a, b] as const)(inputB) - return res - }) -} +export const zip2 = + <A, B>(parserA: Parser<A>, parserB: Parser<B>): Parser<readonly [A, B]> => + input => { + // TODO: refactor please. shit code + const resa: Result< + { value: A; input: string }, + { error: string; input: string } + > = parserA(input) + return chainResult(resa, ({ value: a, input: inputB }) => { + const res: Result< + { value: readonly [A, B]; input: string }, + { error: string; input: string } + > = map(parserB, b => [a, b] as const)(inputB) + return res + }) + } -export const prefixed = <A>(parserPrefix: Parser<any>, parser: Parser<A>): Parser<A> => - map(zip2(parserPrefix, parser), ([_, a]) => a); +export const prefixed = <A>( + parserPrefix: Parser<any>, + parser: Parser<A>, +): Parser<A> => map(zip2(parserPrefix, parser), ([_, a]) => a) -export const suffixed = <A>(parser: Parser<A>, parserSuffix: Parser<any>): Parser<A> => - map(zip2(parser, parserSuffix), ([a, _]) => a); +export const suffixed = <A>( + parser: Parser<A>, + parserSuffix: Parser<any>, +): Parser<A> => map(zip2(parser, parserSuffix), ([a, _]) => a) -export const between = <A>(prefix: Parser<any>, parser: Parser<A>, suffix: Parser<any>): Parser<A> => - suffixed(prefixed(prefix, parser), suffix) +export const between = <A>( + prefix: Parser<any>, + parser: Parser<A>, + suffix: Parser<any>, +): Parser<A> => suffixed(prefixed(prefix, parser), suffix) -export const many0 = <A>(parser: Parser<A>): Parser<Array<A>> => originalInput => - match(parser(originalInput), { - Ok: ({ value, input }) => map(many0(parser), ls => [value, ...ls])(input), - Err: ({ input }) => Result.Ok({ value: [], input }), - }) +export const many0 = + <A>(parser: Parser<A>): Parser<Array<A>> => + originalInput => + match(parser(originalInput), { + Ok: ({ value, input }) => map(many0(parser), ls => [value, ...ls])(input), + Err: ({ input }) => Result.Ok({ value: [], input }), + }) -export const many1 = <A>(parser: Parser<A>): Parser<Array<A>> => originalInput => - match(parser(originalInput), { - Ok: ({ value, input }) => map(many0(parser), ls => [value, ...ls])(input), - Err: err => Result.Err(err), - }) +export const many1 = + <A>(parser: Parser<A>): Parser<Array<A>> => + originalInput => + match(parser(originalInput), { + Ok: ({ value, input }) => map(many0(parser), ls => [value, ...ls])(input), + Err: err => Result.Err(err), + }) -export const sepBy = <A>(parser: Parser<A>, sepP: Parser<any>): Parser<Array<A>> => originalInput => - match(parser(originalInput), { - Ok: ({ value, input }) => map( - many0(prefixed(sepP, parser)), - ls => [value, ...ls] - )(input), - Err: _ => Result.Ok({ value: [], input: originalInput }), - }) - -export const optional = <A>(parser: Parser<A>): Parser<undefined | A> => input => { - const result = parser(input) - return match(result, { - Ok: _ => result, - Err: _ => Result.Ok({ value: undefined, input }) - }) -} +export const sepBy = + <A>(parser: Parser<A>, sepP: Parser<any>): Parser<Array<A>> => + originalInput => + match(parser(originalInput), { + Ok: ({ value, input }) => + map(many0(prefixed(sepP, parser)), ls => [value, ...ls])(input), + Err: _ => Result.Ok({ value: [], input: originalInput }), + }) +export const optional = + <A>(parser: Parser<A>): Parser<undefined | A> => + input => { + const result = parser(input) + return match(result, { + Ok: _ => result, + Err: _ => Result.Ok({ value: undefined, input }), + }) + } diff --git a/src/utils/result.ts b/src/utils/result.ts index c0120b8..39a7fe6 100644 --- a/src/utils/result.ts +++ b/src/utils/result.ts @@ -1,14 +1,18 @@ -import { Enum, constructors, match } from "./adt"; +import { Enum, constructors, match } from './adt' -export type Result<V, E> = Enum<{ Ok: V, Err: E }> +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 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> => +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 index 49ef4c4..2212ba4 100644 --- a/tests/eval.spec.ts +++ b/tests/eval.spec.ts @@ -14,40 +14,52 @@ describe('eval', () => { } it('should add classes', async () => { - await evalExpr(Expr.Call({ - name: 'add-class', - args: [ Expr.Identifier('element-id'), Expr.LiteralString('class-name') ], - }), deps) + 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 remove classes', async () => { - await evalExpr(Expr.Call({ - name: 'remove-class', - args: [ Expr.Identifier('element-id'), Expr.LiteralString('class-name') ], - }), deps) + 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') }) it('should add a delay', async () => { - await evalExpr(Expr.Call({ - name: 'delay', - args: [ Expr.LiteralString('200') ], - }), deps) + await evalExpr( + Expr.Call({ + name: 'delay', + args: [Expr.LiteralString('200')], + }), + deps, + ) expect(deps.delay).toHaveBeenCalledTimes(1) expect(deps.delay).toHaveBeenCalledWith(200) }) it('should get variable', async () => { - await evalExpr(Expr.Call({ - name: 'var', - args: [ Expr.LiteralString('--my-var'), Expr.LiteralString('def value') ], - }), deps) + await evalExpr( + Expr.Call({ + name: 'var', + args: [Expr.LiteralString('--my-var'), Expr.LiteralString('def value')], + }), + deps, + ) expect(deps.getVariable).toHaveBeenCalledTimes(1) expect(deps.getVariable).toHaveBeenCalledWith('--my-var') diff --git a/tests/parser.spec.ts b/tests/parser.spec.ts index f2893b8..41fafa3 100644 --- a/tests/parser.spec.ts +++ b/tests/parser.spec.ts @@ -49,7 +49,7 @@ describe('parser', () => { ]) expect(parse(` 'hello world toodles \" nice double quote there' `)).toEqual( - [Expr.LiteralString(`hello world toodles \" nice double quote there`)] + [Expr.LiteralString(`hello world toodles \" nice double quote there`)], ) }) @@ -2497,6 +2497,11 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +prettier@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.1.tgz#65271fc9320ce4913c57747a70ce635b30beaa40" + integrity sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ== + pretty-format@^29.0.0, pretty-format@^29.6.2: version "29.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" |
