interface cleanup

This commit is contained in:
evilchili committed 2026-10-16 13:27:47 -07:00
1 parent 965fc09d99
commit 9a2ba8c330
8 files changed
+18 -76

No files matched your search

+1 -1
View File
@@ -7,6 +7,7 @@ export declare class Tag implements TagType {
precedence: number; precedence: number;
isBlock: boolean; isBlock: boolean;
showDelimitersInEditorNodes: boolean; showDelimitersInEditorNodes: boolean;
template: string;
childNodesToMarkdown(element: HTMLElement, callback: Function): string; childNodesToMarkdown(element: HTMLElement, callback: Function): string;
tokenize(role: TokenRole, sequence: string, source: string): Token | null; tokenize(role: TokenRole, sequence: string, source: string): Token | null;
toHTML(token: Token, callback: Function): string; toHTML(token: Token, callback: Function): string;
@@ -19,6 +20,5 @@ export declare class TagCollection implements TagCollectionType {
ordered: TagType[]; ordered: TagType[];
map: Map<string, TagType[]>; map: Map<string, TagType[]>;
constructor(tags: TagType[]); constructor(tags: TagType[]);
private validate;
getByElementName(element: string): TagType | undefined; getByElementName(element: string): TagType | undefined;
} }
+2 -28
View File
@@ -9,6 +9,7 @@ class Tag {
precedence = 50; precedence = 50;
isBlock = false; isBlock = false;
showDelimitersInEditorNodes = true; showDelimitersInEditorNodes = true;
template = '';
childNodesToMarkdown(element, callback) { childNodesToMarkdown(element, callback) {
return Array.from(element.childNodes) return Array.from(element.childNodes)
.map(child => callback(child)) .map(child => callback(child))
@@ -98,7 +99,6 @@ class TagCollection {
tags = {}; tags = {};
ordered; ordered;
map; map;
//openers: RegExp[];
constructor(tags) { constructor(tags) {
for (const tag of tags) { for (const tag of tags) {
if (tag.constructor.name in this.tags) { if (tag.constructor.name in this.tags) {
@@ -111,7 +111,6 @@ class TagCollection {
const p2 = b.precedence - (b.isBlock ? 100 : 0); const p2 = b.precedence - (b.isBlock ? 100 : 0);
return p1 < p2 ? -1 : 1; return p1 < p2 ? -1 : 1;
}); });
//this.validate();
this.map = new Map(); this.map = new Map();
for (const tag of this.ordered) { for (const tag of this.ordered) {
for (const key of tag.opener) { for (const key of tag.opener) {
@@ -122,35 +121,10 @@ class TagCollection {
} }
} }
} }
validate() {
const inline = this.ordered.filter(t => { return !t.opener; });
for (let outer = 0; outer < inline.length; outer++) {
for (let inner = outer + 1; inner < inline.length; inner++) {
const first = this.ordered[outer];
const second = this.ordered[inner];
if (!(first.opener && second.opener)) {
continue;
}
const firstIsPrefix = second.opener[0].startsWith(first.opener[0]);
const secondIsPrefix = first.opener[0].startsWith(second.opener[0]);
if (!firstIsPrefix && !secondIsPrefix) {
continue;
}
const longer = first.opener.length > second.opener.length ? first : second;
const shorter = first.opener.length > second.opener.length ? second : first;
if (longer.precedence >= shorter.precedence) {
throw new Error(`Tag "${longer.constructor.name}" (opener "${longer.opener}") must have ` +
`lower precedence than "${shorter.constructor.name}" (opener "${shorter.opener}") ` +
`because its opener is a prefix match. ` +
`Got ${longer.constructor.name}=${longer.precedence}, ${shorter.constructor.name}=${shorter.precedence}.`);
}
}
}
}
getByElementName(element) { getByElementName(element) {
const el = element.toUpperCase(); const el = element.toUpperCase();
return this.ordered.filter(t => { return this.ordered.filter(t => {
return [...t.element, ...t.aliases ?? []].includes(el); return t.element.includes(el);
})[0] || undefined; })[0] || undefined;
} }
} }
-3
View File
@@ -1,13 +1,11 @@
import { Tag } from "./base"; import { Tag } from "./base";
export declare class Bold extends Tag { export declare class Bold extends Tag {
element: string[]; element: string[];
aliases: string[];
opener: string[]; opener: string[];
precedence: number; precedence: number;
} }
export declare class Italic extends Tag { export declare class Italic extends Tag {
element: string[]; element: string[];
aliases: string[];
opener: string[]; opener: string[];
precedence: number; precedence: number;
} }
@@ -18,7 +16,6 @@ export declare class BoldItalic extends Tag {
} }
export declare class Strikethrough extends Tag { export declare class Strikethrough extends Tag {
element: string[]; element: string[];
aliases: string[];
opener: string[]; opener: string[];
} }
export declare class Code extends Tag { export declare class Code extends Tag {
+3 -6
View File
@@ -3,15 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.Code = exports.Strikethrough = exports.BoldItalic = exports.Italic = exports.Bold = void 0; exports.Code = exports.Strikethrough = exports.BoldItalic = exports.Italic = exports.Bold = void 0;
const base_1 = require("./base"); const base_1 = require("./base");
class Bold extends base_1.Tag { class Bold extends base_1.Tag {
element = ['STRONG']; element = ['STRONG', 'B'];
aliases = ['B'];
opener = ['**', '__']; opener = ['**', '__'];
precedence = 40; precedence = 40;
} }
exports.Bold = Bold; exports.Bold = Bold;
class Italic extends base_1.Tag { class Italic extends base_1.Tag {
element = ['EM']; element = ['EM', 'I'];
aliases = ['I'];
opener = ['*', '_']; opener = ['*', '_'];
precedence = 30; precedence = 30;
} }
@@ -23,8 +21,7 @@ class BoldItalic extends base_1.Tag {
} }
exports.BoldItalic = BoldItalic; exports.BoldItalic = BoldItalic;
class Strikethrough extends base_1.Tag { class Strikethrough extends base_1.Tag {
element = ['DEL']; element = ['DEL', 'S', 'STRIKE'];
aliases = ['S', 'STRIKE'];
opener = ['~~']; opener = ['~~'];
} }
exports.Strikethrough = Strikethrough; exports.Strikethrough = Strikethrough;
+3 -13
View File
@@ -7,27 +7,17 @@ export interface Token {
groups?: { groups?: {
[key: string]: string; [key: string]: string;
}; };
/** For link tokens: the href and optional title. */
href?: string;
title?: string;
meta?: Record<string, string>; meta?: Record<string, string>;
} }
/**
* A Tag is the core abstraction: it knows how to match markdown syntax,
* convert it to HTML, and convert the HTML back to markdown. Tags are
* registered by HTML selector (e.g. 'STRONG,B') so the converter can
* look them up during HTML→markdown conversion.
*/
export interface TagType { export interface TagType {
element: string[]; element: string[];
opener: string[]; opener: string[];
closer: string | null; closer: string | null;
precedence: number; precedence: number;
isBlock: boolean; isBlock: boolean;
template?: string; showDelimitersInEditorNodes: boolean;
pattern?: RegExp | null; template: string;
showDelimitersInEditorNodes?: boolean; pattern: RegExp | null;
aliases?: string[];
tokenize(role: TokenRole, sequence: string, value: string): Token | null; tokenize(role: TokenRole, sequence: string, value: string): Token | null;
toHTML: (token: Token, callback: Function) => string; toHTML: (token: Token, callback: Function) => string;
toMarkdown: (element: HTMLElement, callback: Function) => string; toMarkdown: (element: HTMLElement, callback: Function) => string;
+3 -2
View File
@@ -9,6 +9,8 @@ export class Tag implements TagType {
isBlock: boolean = false; isBlock: boolean = false;
showDelimitersInEditorNodes: boolean = true; showDelimitersInEditorNodes: boolean = true;
template = '';
childNodesToMarkdown(element: HTMLElement, callback: Function): string { childNodesToMarkdown(element: HTMLElement, callback: Function): string {
return Array.from(element.childNodes) return Array.from(element.childNodes)
.map(child => callback(child)) .map(child => callback(child))
@@ -102,7 +104,6 @@ export class TagCollection implements TagCollectionType {
tags: Record<string, TagType> = {}; tags: Record<string, TagType> = {};
ordered: TagType[]; ordered: TagType[];
map: Map<string, TagType[]>; map: Map<string, TagType[]>;
//openers: RegExp[];
constructor(tags: TagType[]) { constructor(tags: TagType[]) {
for (const tag of tags) { for (const tag of tags) {
@@ -131,7 +132,7 @@ export class TagCollection implements TagCollectionType {
getByElementName(element: string): TagType | undefined { getByElementName(element: string): TagType | undefined {
const el = element.toUpperCase(); const el = element.toUpperCase();
return this.ordered.filter(t => { return this.ordered.filter(t => {
return [...t.element, ...t.aliases ?? []].includes(el); return t.element.includes(el);
})[0] || undefined; })[0] || undefined;
} }
} }
+3 -6
View File
@@ -1,15 +1,13 @@
import { Tag } from "./base"; import { Tag } from "./base";
export class Bold extends Tag { export class Bold extends Tag {
element = ['STRONG']; element = ['STRONG', 'B'];
aliases = ['B'];
opener = ['**', '__']; opener = ['**', '__'];
precedence = 40; precedence = 40;
} }
export class Italic extends Tag { export class Italic extends Tag {
element = ['EM']; element = ['EM', 'I'];
aliases = ['I'];
opener = ['*', '_']; opener = ['*', '_'];
precedence = 30; precedence = 30;
} }
@@ -21,8 +19,7 @@ export class BoldItalic extends Tag {
} }
export class Strikethrough extends Tag { export class Strikethrough extends Tag {
element = ['DEL']; element = ['DEL', 'S', 'STRIKE'];
aliases = ['S', 'STRIKE'];
opener = ['~~']; opener = ['~~'];
} }
+3 -17
View File
@@ -3,35 +3,21 @@ export type TokenRole = 'open' | 'close' | 'block';
export interface Token { export interface Token {
role: TokenRole; role: TokenRole;
value: string; value: string;
sequence?: string; sequence?: string;
tag?: TagType; tag?: TagType;
groups?: { [key: string]: string; }; groups?: { [key: string]: string; };
/** For link tokens: the href and optional title. */
href?: string;
title?: string;
meta?: Record<string, string>; meta?: Record<string, string>;
} }
/**
* A Tag is the core abstraction: it knows how to match markdown syntax,
* convert it to HTML, and convert the HTML back to markdown. Tags are
* registered by HTML selector (e.g. 'STRONG,B') so the converter can
* look them up during HTML→markdown conversion.
*/
export interface TagType { export interface TagType {
element: string[]; element: string[];
opener: string[]; opener: string[];
closer: string | null; closer: string | null;
precedence: number; precedence: number;
isBlock: boolean; isBlock: boolean;
template?: string; showDelimitersInEditorNodes: boolean;
pattern?: RegExp | null; template: string;
showDelimitersInEditorNodes?: boolean; pattern: RegExp | null;
aliases?: string[];
tokenize(role: TokenRole, sequence: string, value: string): Token | null; tokenize(role: TokenRole, sequence: string, value: string): Token | null;
toHTML: (token: Token, callback: Function) => string; toHTML: (token: Token, callback: Function) => string;