fix: refactor, tag classes, daletl add data type of tag

This commit is contained in:
Artemy Egorov 2024-07-25 15:55:09 +03:00
parent bc6b6a7db4
commit 599639dee6
12 changed files with 1178 additions and 99 deletions

View file

@ -1,14 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {}
}

View file

@ -0,0 +1,11 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
{files: ["**/*.{js,mjs,cjs,ts}"]},
{languageOptions: { globals: globals.browser }},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];

View file

@ -28,7 +28,11 @@
},
"homepage": "https://github.com/TxtDot/dalet#readme",
"devDependencies": {
"tsc": "^2.0.4"
"@eslint/js": "^9.7.0",
"eslint": "9.x",
"globals": "^15.8.0",
"tsc": "^2.0.4",
"typescript-eslint": "^7.17.0"
},
"dependencies": {
"@msgpack/msgpack": "3.0.0-beta2"

File diff suppressed because it is too large Load diff

View file

@ -1,51 +0,0 @@
import { Root, Tag } from "../daletl/types";
interface Props {
[key: string]: string;
}
function hy(tag: string, body?: string, props?: Props) {
return `<${tag} ${
props
? Object.entries(props)
.map(([key, value]) => `${key}="${value}"`)
.join(" ")
: ""
}>${body}</${tag}>`;
}
function comp(
name: string,
body: string | Tag[],
classNames: string,
classes: boolean,
props: Props = {}
): string {
let realBody = Array.isArray(body)
? body.map((b) => htmlTag(b, classes)).join("")
: body;
return hy(name, realBody, {
class: classes ? classNames : undefined,
...props,
});
}
function element(tag: Tag, classes: boolean): string {
return comp("section", tag.body, "el", classes);
}
function heading(tag: Tag, classes: boolean): string {
if (typeof tag.argument !== "number") {
return comp("h1", tag.body, "h", classes);
}
return comp(`h${tag.argument}`, tag.body, `h hl${tag.argument}`, classes);
}
function htmlTag(tag: Tag, classes: boolean): string {
return [element, heading][tag.id](tag, classes);
}
export function toHtml(root: Root, classes: boolean = true): string {
return root.map((t) => htmlTag(t, classes)).join("");
}

View file

@ -1 +0,0 @@
export { toHtml } from "./html";

View file

@ -1,37 +1,34 @@
import { encode, decode } from "@msgpack/msgpack";
import { ParseError, Root, Tag } from "./types";
import { ParseError, RawTag, Tag, RawTagAsArray, RawBody, Body } from "./types";
import El from "./tags/el";
import { TagNormalizers } from "./normalizers";
export function parseRawTag(raw_tag: any[] | string): Tag {
export function parseTag(raw_tag: RawTag): Tag {
if (typeof raw_tag === "string") {
return {
id: 0,
body: raw_tag,
argument: null,
};
return new El(raw_tag);
}
if (typeof raw_tag === "number") {
return TagNormalizers[raw_tag]([raw_tag, null]);
}
if (Array.isArray(raw_tag)) {
if (Array.isArray(raw_tag[0])) {
return {
id: 0,
body: parseRawTagBody(raw_tag),
argument: null,
};
raw_tag = raw_tag as RawTag[];
return new El(raw_tag.map(parseTag));
}
if (typeof raw_tag[0] === "number") {
return {
id: raw_tag[0],
body: parseRawTagBody(raw_tag[1]),
argument: raw_tag[3] || null,
};
return TagNormalizers[(raw_tag as RawTagAsArray)[0]](
raw_tag as RawTagAsArray
);
}
}
throw new ParseError("Invalid tag");
}
export function parseRawTagBody(body: string | null | any[]): Tag["body"] {
export function parseBody(body: RawBody): Body {
if (typeof body === "string") {
return body;
}
@ -42,23 +39,38 @@ export function parseRawTagBody(body: string | null | any[]): Tag["body"] {
if (Array.isArray(body)) {
if (Array.isArray(body[0])) {
return body.map(parseRawTag);
return body.map(parseTag);
}
if (typeof body[0] === "number") {
return [parseRawTag(body)];
return [parseTag(body)];
}
}
throw new ParseError("Invalid tag body");
}
export function parse(root_data?: Uint8Array): Root {
let root = root_data ? decode(root_data) : [];
export function parse(root_data: Uint8Array): Tag[] {
let root = decode(root_data);
if (!Array.isArray(root)) {
throw new ParseError("Daletl root must be array");
}
return root.map(parseRawTag);
return root.map(parseTag);
}
export class Root {
root: Tag[];
constructor(root: Tag[]) {
this.root = root;
}
encode(): Uint8Array {
return encode(this.root.map((t) => t.encode()));
}
toHtml(classes?: boolean): string {
return this.root.map((t) => t.toHtml(classes)).join("");
}
}

View file

@ -0,0 +1,17 @@
import { parseBody } from "./main";
import El from "./tags/el";
import { ParseError, RawTagAsArray } from "./types";
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];
export { TagNormalizers };

View file

@ -0,0 +1,16 @@
import { bodyToRaw } from "../../utils";
import { RawTag, Tag, Body } from "../types";
export default class El extends Tag {
constructor(body: string | Tag[]) {
super(0, body, null);
}
public get raw(): RawTag {
return bodyToRaw(this.body);
}
public toHtml(classes?: boolean): string {
return "";
}
}

View file

@ -1,10 +1,13 @@
export interface Tag {
id: number;
body: string | null | Tag[];
argument: number | string | null;
}
import { encode } from "@msgpack/msgpack";
import { bodyToRaw } from "../utils";
export type Root = Tag[];
export type RawBody = string | null | RawTag[] | RawTag;
export type RawId = number;
export type RawArgument = number | string | null;
export type RawTagAsArray = [RawId, RawBody, RawArgument] | [RawId, RawBody];
export type RawTag = RawTagAsArray | number | string | RawTag[];
export type RootRaw = RawTag[];
export class ParseError extends Error {
constructor(message: string = "Parse error") {
@ -12,3 +15,33 @@ export class ParseError extends Error {
this.name = "ParseError";
}
}
export abstract class Tag {
id: number;
body: Body;
argument: Argument;
constructor(id: number, body: Body, argument: Argument) {
this.id = id;
this.body = body;
this.argument = argument;
}
get raw(): RawTag {
if (this.argument == null) {
if (this.body == null) {
return this.id;
}
return [this.id, bodyToRaw(this.body)];
}
return [this.id, bodyToRaw(this.body), this.argument];
}
encode(): Uint8Array {
return encode(this.raw);
}
abstract toHtml(classes?: boolean): string;
}
export type Body = string | Tag[] | null;
export type Argument = RawArgument;
export type TagNormalizer = (tag: RawTagAsArray) => Tag;

View file

@ -0,0 +1,33 @@
import { Body, ParseError, RawBody, RawTag, Tag } from "./daletl/types";
export function bodyToRaw(body: Body): RawBody {
if (typeof body === "string") {
return body;
}
if (Array.isArray(body)) {
if (Array.isArray(body[0])) {
return body.map(getRaw);
}
}
return null;
}
export function getRaw(t: Tag): RawTag {
return t.raw;
}
interface Props {
[key: string]: string;
}
function hy(tag: string, body?: string, props?: Props) {
return `<${tag} ${
props
? Object.entries(props)
.map(([key, value]) => `${key}="${value}"`)
.join(" ")
: ""
}>${body}</${tag}>`;
}

View file

@ -16,14 +16,14 @@ Daletl root is array of tags. For convenience, we will use the json5 representat
All tags specification is in [Tags](./tags.md).
Each tag may be one of three types:
Each tag may be one of four types:
#### Data Representation
##### As array of 1-3 elements
##### As array of 2-3 elements
1. Tag id
2. Tag body (optional if argument not specified, if argument specified it must be null)
2. Tag body
3. Tag argument (optional)
Tag id is integer number.
@ -50,6 +50,20 @@ Argument can be number or string.
]
```
##### As number
Number becomes tag.
```json5
1
```
equals to
```json5
[1, null]
```
##### As string
String becomes element tag.