This commit is contained in:
Chris Kruining 2025-02-13 17:18:03 +11:00
parent 69fd9a1753
commit 8e0eee5847
No known key found for this signature in database
GPG key ID: EB894A3560CCCAD2
8 changed files with 220 additions and 70 deletions

View file

@ -0,0 +1,6 @@
export type { Source } from './source';
export { createParser as createHtmlParser } from './parser/html';
export { createParser as createMarkdownParser } from './parser/markdown';
export { createSource } from './source';

View file

@ -0,0 +1,28 @@
enum Decoration {
None = 0,
Bold = 1,
Italic = 2,
Underline = 4,
StrikeThrough = 8,
}
interface TextNode {
type: 'text';
decoration: Decoration;
nodes: (string | Node)[];
}
interface HeaderNode {
type: 'header';
nodes: Node[];
}
type Node = TextNode | HeaderNode;
export interface RichTextAST {
nodes: Node[];
}
export interface Parser {
parse(source: string): RichTextAST;
}

View file

@ -0,0 +1,9 @@
import { Parser } from "../parser";
export function createParser(): Parser {
return {
parse(value) {
return {};
},
};
}

View file

@ -0,0 +1,80 @@
import { Parser } from "../parser";
export function createParser(): Parser {
return {
parse(source) {
// console.log(source);
for (const token of tokenize(source)) {
console.log(token);
}
return {
nodes: [],
};
},
};
}
// const states = {
// none(): State {
// },
// } as const;
type Token = { start: number, length: number } & (
| { kind: 'bold' }
| { kind: 'italic' }
| { kind: 'underline' }
| { kind: 'strikethrough' }
| { kind: 'header', level: number }
| { kind: 'text', value: string }
);
function* tokenize(characters: string): Generator<Token, void, unknown> {
let buffer: string = '';
let clearBuffer = false;
let start = 0;
let i = 0;
for (const character of characters) {
if (buffer.length === 0) {
start = i;
}
buffer += character;
const length = buffer.length;
if (buffer === '**') {
yield { kind: 'bold', start, length };
clearBuffer = true;
}
else if (buffer === '') {
yield { kind: 'italic', start, length };
clearBuffer = true;
}
else if (buffer === ':') {
yield { kind: 'underline', start, length };
clearBuffer = true;
}
else if (buffer === ':') {
yield { kind: 'strikethrough', start, length };
clearBuffer = true;
}
else if (buffer.length > 1 && buffer.startsWith('#') && buffer.endsWith(' ')) {
yield { kind: 'header', start, length, level: buffer.length - 1 };
clearBuffer = true;
}
else if (buffer.length > 1 && buffer.startsWith('"') && buffer.endsWith('"')) {
yield { kind: 'text', start, length, value: buffer.slice(1, buffer.length - 1) };
clearBuffer = true;
}
if (clearBuffer) {
buffer = '';
clearBuffer = false;
}
i++;
}
}

View file

@ -0,0 +1,31 @@
import { createEffect, createSignal, Signal } from "solid-js";
import { Parser, RichTextAST } from "./parser";
export interface Source<TIn extends Parser, TOut extends Parser> {
readonly in: Signal<string>;
readonly out: Signal<string>;
}
export function createSource<TIn extends Parser, TOut extends Parser>(inParser: TIn, outParser: TOut, initalValue: string): Source<TIn, TOut> {
const [inValue, setIn] = createSignal<string>(initalValue);
const [outValue, setOut] = createSignal<string>('');
const [ast, setAst] = createSignal<RichTextAST>();
createEffect(() => {
setAst(inParser.parse(inValue()));
});
createEffect(() => {
setAst(outParser.parse(outValue()));
});
return {
get in() {
return [inValue, setIn] as Signal<string>;
},
get out() {
return [outValue, setOut] as Signal<string>;
},
};
}