feat: heading tag, new normalizers

This commit is contained in:
Artemy Egorov 2024-07-25 18:39:46 +03:00
parent 599639dee6
commit 8530f84830
10 changed files with 134 additions and 46 deletions

View file

@ -8,7 +8,9 @@
"/dist" "/dist"
], ],
"scripts": { "scripts": {
"build": "tsc" "build": "tsc",
"start": "node ./dist/index.js",
"bstart": "tsc && node ./dist/index.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -31,10 +33,11 @@
"@eslint/js": "^9.7.0", "@eslint/js": "^9.7.0",
"eslint": "9.x", "eslint": "9.x",
"globals": "^15.8.0", "globals": "^15.8.0",
"tsc": "^2.0.4", "typescript": "^5.5.4",
"typescript-eslint": "^7.17.0" "typescript-eslint": "^7.17.0"
}, },
"dependencies": { "dependencies": {
"@msgpack/msgpack": "3.0.0-beta2" "@msgpack/msgpack": "3.0.0-beta2",
"zod": "^3.23.8"
} }
} }

View file

@ -11,6 +11,9 @@ importers:
'@msgpack/msgpack': '@msgpack/msgpack':
specifier: 3.0.0-beta2 specifier: 3.0.0-beta2
version: 3.0.0-beta2 version: 3.0.0-beta2
zod:
specifier: ^3.23.8
version: 3.23.8
devDependencies: devDependencies:
'@eslint/js': '@eslint/js':
specifier: ^9.7.0 specifier: ^9.7.0
@ -21,9 +24,9 @@ importers:
globals: globals:
specifier: ^15.8.0 specifier: ^15.8.0
version: 15.8.0 version: 15.8.0
tsc: typescript:
specifier: ^2.0.4 specifier: ^5.5.4
version: 2.0.4 version: 5.5.4
typescript-eslint: typescript-eslint:
specifier: ^7.17.0 specifier: ^7.17.0
version: 7.17.0(eslint@9.7.0)(typescript@5.5.4) version: 7.17.0(eslint@9.7.0)(typescript@5.5.4)
@ -495,10 +498,6 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=4.2.0' typescript: '>=4.2.0'
tsc@2.0.4:
resolution: {integrity: sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q==}
hasBin: true
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@ -534,6 +533,9 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
zod@3.23.8:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
snapshots: snapshots:
'@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)': '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)':
@ -1006,8 +1008,6 @@ snapshots:
dependencies: dependencies:
typescript: 5.5.4 typescript: 5.5.4
tsc@2.0.4: {}
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
@ -1036,3 +1036,5 @@ snapshots:
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
yocto-queue@0.1.0: {} yocto-queue@0.1.0: {}
zod@3.23.8: {}

View file

@ -1,5 +1,13 @@
import { encode, decode } from "@msgpack/msgpack"; 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 El from "./tags/el";
import { TagNormalizers } from "./normalizers"; import { TagNormalizers } from "./normalizers";
@ -39,7 +47,7 @@ export function parseBody(body: RawBody): Body {
if (Array.isArray(body)) { if (Array.isArray(body)) {
if (Array.isArray(body[0])) { if (Array.isArray(body[0])) {
return body.map(parseTag); return body.map((t) => parseTag(t as RawTag));
} }
if (typeof body[0] === "number") { if (typeof body[0] === "number") {
@ -50,14 +58,14 @@ export function parseBody(body: RawBody): Body {
throw new ParseError("Invalid tag 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); let root = decode(root_data);
if (!Array.isArray(root)) { if (!Array.isArray(root)) {
throw new ParseError("Daletl root must be array"); throw new ParseError("Daletl root must be array");
} }
return root.map(parseTag); return new Root(root.map(parseTag));
} }
export class Root { export class Root {
@ -66,8 +74,12 @@ export class Root {
this.root = root; this.root = root;
} }
get raw(): RootRaw {
return this.root.map((t) => t.raw);
}
encode(): Uint8Array { encode(): Uint8Array {
return encode(this.root.map((t) => t.encode())); return encode(this.raw);
} }
toHtml(classes?: boolean): string { toHtml(classes?: boolean): string {

View file

@ -1,17 +1,30 @@
import { parseBody } from "./main"; import { parseBody } from "./main";
import El from "./tags/el"; 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 { const TagNormalizers = [
let body = parseBody(tag[1]); n(
z.custom((b) => b !== null),
if (body == null) { z.any(),
throw new ParseError("Invalid tag body, must be not null"); El
} ),
n(z.string(), z.number().int().min(1).max(6), Heading),
return new El(body); ];
}
const TagNormalizers = [ElNormalizer];
export { TagNormalizers }; 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]);
};
}

View file

@ -1,4 +1,4 @@
import { bodyToRaw } from "../../utils"; import { bodyToRaw, chtml } from "../../utils";
import { RawTag, Tag, Body } from "../types"; import { RawTag, Tag, Body } from "../types";
export default class El extends Tag { export default class El extends Tag {
@ -6,11 +6,11 @@ export default class El extends Tag {
super(0, body, null); super(0, body, null);
} }
public get raw(): RawTag { get raw(): RawTag {
return bodyToRaw(this.body); return bodyToRaw(this.body)!;
} }
public toHtml(classes?: boolean): string { toHtml(classes?: boolean): string {
return ""; return chtml("section", "el", classes, this.body);
} }
} }

View file

@ -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
);
}
}

View file

@ -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));

View file

@ -1,2 +1,5 @@
export { parse } from "./daletl/main"; import El from "./daletl/tags/el";
export * as converters from "./converters/main"; import Heading from "./daletl/tags/heading";
export { parse, Root } from "./daletl/main";
export { El, Heading };

View file

@ -14,20 +14,45 @@ export function bodyToRaw(body: Body): RawBody {
return null; 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 { export function getRaw(t: Tag): RawTag {
return t.raw; return t.raw;
} }
interface Props { interface Props {
[key: string]: string; [key: string]: string | undefined;
} }
function hy(tag: string, body?: string, props?: Props) { export function chtml(
return `<${tag} ${ tag: string,
props classNames: string,
? Object.entries(props) classes: boolean = true,
.map(([key, value]) => `${key}="${value}"`) body?: Body,
.join(" ") props?: Props
: "" ) {
}>${body}</${tag}>`; 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)}</${tag}>`;
} }

View file

@ -3,7 +3,8 @@
"module": "commonjs", "module": "commonjs",
"target": "es2019", "target": "es2019",
"declaration": true, "declaration": true,
"outDir": "./dist" "outDir": "./dist",
"strict": true
}, },
"include": ["src/**/*"] "include": ["src/**/*"]
} }