From 8530f848309916b68b573fba39e2c87f3af9602f Mon Sep 17 00:00:00 2001 From: Artemy Egorov Date: Thu, 25 Jul 2024 18:39:46 +0300 Subject: [PATCH] feat: heading tag, new normalizers --- libs/typescript/package.json | 9 +++-- libs/typescript/pnpm-lock.yaml | 20 +++++----- libs/typescript/src/daletl/main.ts | 22 ++++++++--- libs/typescript/src/daletl/normalizers.ts | 37 +++++++++++++------ libs/typescript/src/daletl/tags/el.ts | 10 ++--- libs/typescript/src/daletl/tags/heading.ts | 17 +++++++++ libs/typescript/src/index.ts | 12 ++++++ libs/typescript/src/lib.ts | 7 +++- libs/typescript/src/utils.ts | 43 +++++++++++++++++----- libs/typescript/tsconfig.json | 3 +- 10 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 libs/typescript/src/daletl/tags/heading.ts create mode 100644 libs/typescript/src/index.ts diff --git a/libs/typescript/package.json b/libs/typescript/package.json index b354338..592ea5a 100644 --- a/libs/typescript/package.json +++ b/libs/typescript/package.json @@ -8,7 +8,9 @@ "/dist" ], "scripts": { - "build": "tsc" + "build": "tsc", + "start": "node ./dist/index.js", + "bstart": "tsc && node ./dist/index.js" }, "repository": { "type": "git", @@ -31,10 +33,11 @@ "@eslint/js": "^9.7.0", "eslint": "9.x", "globals": "^15.8.0", - "tsc": "^2.0.4", + "typescript": "^5.5.4", "typescript-eslint": "^7.17.0" }, "dependencies": { - "@msgpack/msgpack": "3.0.0-beta2" + "@msgpack/msgpack": "3.0.0-beta2", + "zod": "^3.23.8" } } diff --git a/libs/typescript/pnpm-lock.yaml b/libs/typescript/pnpm-lock.yaml index cf2d816..eef30c2 100644 --- a/libs/typescript/pnpm-lock.yaml +++ b/libs/typescript/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@msgpack/msgpack': specifier: 3.0.0-beta2 version: 3.0.0-beta2 + zod: + specifier: ^3.23.8 + version: 3.23.8 devDependencies: '@eslint/js': specifier: ^9.7.0 @@ -21,9 +24,9 @@ importers: globals: specifier: ^15.8.0 version: 15.8.0 - tsc: - specifier: ^2.0.4 - version: 2.0.4 + typescript: + specifier: ^5.5.4 + version: 5.5.4 typescript-eslint: specifier: ^7.17.0 version: 7.17.0(eslint@9.7.0)(typescript@5.5.4) @@ -495,10 +498,6 @@ packages: peerDependencies: typescript: '>=4.2.0' - tsc@2.0.4: - resolution: {integrity: sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q==} - hasBin: true - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -534,6 +533,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + snapshots: '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)': @@ -1006,8 +1008,6 @@ snapshots: dependencies: typescript: 5.5.4 - tsc@2.0.4: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -1036,3 +1036,5 @@ snapshots: word-wrap@1.2.5: {} yocto-queue@0.1.0: {} + + zod@3.23.8: {} diff --git a/libs/typescript/src/daletl/main.ts b/libs/typescript/src/daletl/main.ts index ff5f84e..352b245 100644 --- a/libs/typescript/src/daletl/main.ts +++ b/libs/typescript/src/daletl/main.ts @@ -1,5 +1,13 @@ import { encode, decode } from "@msgpack/msgpack"; -import { ParseError, RawTag, Tag, RawTagAsArray, RawBody, Body } from "./types"; +import { + ParseError, + RawTag, + Tag, + RawTagAsArray, + RawBody, + Body, + RootRaw, +} from "./types"; import El from "./tags/el"; import { TagNormalizers } from "./normalizers"; @@ -39,7 +47,7 @@ export function parseBody(body: RawBody): Body { if (Array.isArray(body)) { if (Array.isArray(body[0])) { - return body.map(parseTag); + return body.map((t) => parseTag(t as RawTag)); } if (typeof body[0] === "number") { @@ -50,14 +58,14 @@ export function parseBody(body: RawBody): Body { throw new ParseError("Invalid tag body"); } -export function parse(root_data: Uint8Array): Tag[] { +export function parse(root_data: Uint8Array): Root { let root = decode(root_data); if (!Array.isArray(root)) { throw new ParseError("Daletl root must be array"); } - return root.map(parseTag); + return new Root(root.map(parseTag)); } export class Root { @@ -66,8 +74,12 @@ export class Root { this.root = root; } + get raw(): RootRaw { + return this.root.map((t) => t.raw); + } + encode(): Uint8Array { - return encode(this.root.map((t) => t.encode())); + return encode(this.raw); } toHtml(classes?: boolean): string { diff --git a/libs/typescript/src/daletl/normalizers.ts b/libs/typescript/src/daletl/normalizers.ts index 7851ae0..99ffe2f 100644 --- a/libs/typescript/src/daletl/normalizers.ts +++ b/libs/typescript/src/daletl/normalizers.ts @@ -1,17 +1,30 @@ import { parseBody } from "./main"; import El from "./tags/el"; -import { ParseError, RawTagAsArray } from "./types"; +import Heading from "./tags/heading"; +import { RawTagAsArray } from "./types"; +import { z } from "zod"; -export function ElNormalizer(tag: RawTagAsArray): El { - let body = parseBody(tag[1]); - - if (body == null) { - throw new ParseError("Invalid tag body, must be not null"); - } - - return new El(body); -} - -const TagNormalizers = [ElNormalizer]; +const TagNormalizers = [ + n( + z.custom((b) => b !== null), + z.any(), + El + ), + n(z.string(), z.number().int().min(1).max(6), Heading), +]; export { TagNormalizers }; + +function n(body: z.ZodTypeAny, argument: z.ZodTypeAny, T: any) { + return (tag: RawTagAsArray) => { + let parsedBody = parseBody(tag[1]); + + z.tuple([z.number().int(), body, argument]).parse([ + tag[0], + parsedBody, + tag[2], + ]); + + return new T(parsedBody, tag[2]); + }; +} diff --git a/libs/typescript/src/daletl/tags/el.ts b/libs/typescript/src/daletl/tags/el.ts index 2727843..0df97b7 100644 --- a/libs/typescript/src/daletl/tags/el.ts +++ b/libs/typescript/src/daletl/tags/el.ts @@ -1,4 +1,4 @@ -import { bodyToRaw } from "../../utils"; +import { bodyToRaw, chtml } from "../../utils"; import { RawTag, Tag, Body } from "../types"; export default class El extends Tag { @@ -6,11 +6,11 @@ export default class El extends Tag { super(0, body, null); } - public get raw(): RawTag { - return bodyToRaw(this.body); + get raw(): RawTag { + return bodyToRaw(this.body)!; } - public toHtml(classes?: boolean): string { - return ""; + toHtml(classes?: boolean): string { + return chtml("section", "el", classes, this.body); } } diff --git a/libs/typescript/src/daletl/tags/heading.ts b/libs/typescript/src/daletl/tags/heading.ts new file mode 100644 index 0000000..34d9c95 --- /dev/null +++ b/libs/typescript/src/daletl/tags/heading.ts @@ -0,0 +1,17 @@ +import { chtml } from "../../utils"; +import { Tag } from "../types"; + +export default class Heading extends Tag { + constructor(body: string, argument: number) { + super(1, body, argument); + } + + toHtml(classes?: boolean): string { + return chtml( + `h${this.argument}`, + `h hl${this.argument}`, + classes, + this.body + ); + } +} diff --git a/libs/typescript/src/index.ts b/libs/typescript/src/index.ts new file mode 100644 index 0000000..a698685 --- /dev/null +++ b/libs/typescript/src/index.ts @@ -0,0 +1,12 @@ +import { parse, Root, El, Heading } from "./lib"; + +let data = new Root([ + new El("I am Element"), + new Heading("I am heading", 1), +]).encode(); + +let root = parse(data); + +console.log(root.raw, "\n"); +console.log(root.toHtml()); +console.log(root.toHtml(false)); diff --git a/libs/typescript/src/lib.ts b/libs/typescript/src/lib.ts index fc6d03a..304e9da 100644 --- a/libs/typescript/src/lib.ts +++ b/libs/typescript/src/lib.ts @@ -1,2 +1,5 @@ -export { parse } from "./daletl/main"; -export * as converters from "./converters/main"; +import El from "./daletl/tags/el"; +import Heading from "./daletl/tags/heading"; + +export { parse, Root } from "./daletl/main"; +export { El, Heading }; diff --git a/libs/typescript/src/utils.ts b/libs/typescript/src/utils.ts index 4d68340..317653c 100644 --- a/libs/typescript/src/utils.ts +++ b/libs/typescript/src/utils.ts @@ -14,20 +14,45 @@ export function bodyToRaw(body: Body): RawBody { return null; } +export function bodyToHtml(body: Body): string { + if (typeof body === "string") { + return body; + } + + if (Array.isArray(body)) { + return body.map((t) => t.toHtml()).join(""); + } + + return ""; +} + export function getRaw(t: Tag): RawTag { return t.raw; } interface Props { - [key: string]: string; + [key: string]: string | undefined; } -function hy(tag: string, body?: string, props?: Props) { - return `<${tag} ${ - props - ? Object.entries(props) - .map(([key, value]) => `${key}="${value}"`) - .join(" ") - : "" - }>${body}`; +export function chtml( + tag: string, + classNames: string, + classes: boolean = true, + body?: Body, + props?: Props +) { + let classProp = classes ? { class: classNames } : {}; + return html(tag, body, { ...props, ...classProp }); +} + +function html(tag: string, body?: Body, props?: Props) { + let pr = Object.entries(props || {}) + .map(([key, value]) => `${key}="${value}"`) + .join(" "); + + if (!body) { + return `<${tag}${pr ? " " + pr : ""}/>`; + } + + return `<${tag}${pr ? " " + pr : ""}>${bodyToHtml(body)}`; } diff --git a/libs/typescript/tsconfig.json b/libs/typescript/tsconfig.json index 59c6c79..686a262 100644 --- a/libs/typescript/tsconfig.json +++ b/libs/typescript/tsconfig.json @@ -3,7 +3,8 @@ "module": "commonjs", "target": "es2019", "declaration": true, - "outDir": "./dist" + "outDir": "./dist", + "strict": true }, "include": ["src/**/*"] }