lint: updates lint rules for no-unused-vars

This commit is contained in:
Emmaline Autumn 2024-03-16 02:12:20 -06:00
parent 16497edd46
commit 2e7eaccde8
10 changed files with 453 additions and 415 deletions

View File

@ -1,3 +1,23 @@
{
"extends": "next/core-web-vitals"
}
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"next/core-web-vitals"
],
"rules": {
"@typescript-eslint/no-unused-vars": [
"error",
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
]
}
}

View File

@ -2,7 +2,6 @@
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;

View File

@ -1,6 +1,4 @@
import { readMD } from "@/actions/readMD";
import { TTCMD } from "@/components/ttcmd";
import { readFile } from "fs/promises";
import { Suspense } from "react";
import { HomeClient } from "./client";
import { MDSkeletonLoader } from "@/components/loader";

BIN
bun.lockb

Binary file not shown.

View File

@ -4,7 +4,6 @@ import {
PropsWithChildren,
SetStateAction,
useCallback,
useEffect,
useState,
} from "react";
import { bulkRound } from "../../utils/bulkRound";
@ -24,7 +23,7 @@ interface IProps {
setHover: Dispatch<SetStateAction<boolean>>;
}
type position = { top: number; left: number; width?: number };
type position = { top: number; left: number; width?: number; };
export const PoppableContent: FC<PropsWithChildren<IProps>> = (
{
@ -35,7 +34,6 @@ export const PoppableContent: FC<PropsWithChildren<IProps>> = (
spacing = 10,
setHover,
isClosing,
isClosed,
},
) => {
const [popRef, setPopRef] = useState<HTMLDivElement>();
@ -52,7 +50,7 @@ export const PoppableContent: FC<PropsWithChildren<IProps>> = (
relHeight: number,
popWidth: number,
popHeight: number,
edge: edge,
_edge: edge,
align: alignment,
): position => {
const pos = {

View File

@ -1,13 +1,6 @@
"use client";
import {
FC,
PropsWithChildren,
ReactNode,
useCallback,
useEffect,
useState,
} from "react";
import { FC, PropsWithChildren, ReactNode, useCallback, useState } from "react";
import { PoppableContent } from "./poppable-content";
import { useDebounce } from "../../../hooks/useDebounce";

View File

@ -3,48 +3,14 @@ import Link from "next/link";
import { Fragment } from "react";
import { Poppable } from "../poppables/components/poppable";
import { Accordion, AccordionContent } from "../accordion";
import { metadata } from "@/app/layout";
type SearchFunction = (s: string, start: number, end: number) => {
start: number;
end: number;
text: string;
lastIndex: number;
};
type TokenIdentifier<M> = {
rx: RegExp;
parse: (s: string) => Token<M>;
search?: SearchFunction;
};
type TokenIdentifierMap = Map<
string,
TokenIdentifier<any>
>;
export const TokenRenderers = new Map<
string,
TokenRenderer<any>
>();
type IdentifierRegistration = <N = Record<string, string>>(
type: string,
match: RegExp,
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
renderFunction: TokenRenderer<N>,
openTagRx?: RegExp,
closeTagRx?: RegExp,
) => void;
export const TokenRenderers = new Map<string, TokenRenderer<any>>();
export function buildIdentifierMap(): [
TokenIdentifierMap,
IdentifierRegistration,
] {
const TokenIdentifiers = new Map<
string,
TokenIdentifier<any>
>();
const TokenIdentifiers = new Map<string, TokenIdentifier<any>>();
function registerIdentifier<M>(
type: string,
@ -79,7 +45,7 @@ export function buildIdentifierMap(): [
return { ...token, ...identifiedToken } as Token<M>;
},
search: (openTagRx && closeTagRx)
search: openTagRx && closeTagRx
? (s, start, end) => {
return search(
s,
@ -120,8 +86,11 @@ export const buildOnlyDefaultElements = () => {
/(?<!\/)(?:\[\])+\n+((?:.|\n)*?)\n+\/\[\]/g,
(s) => {
const rx = /((?:\[\])+)\n+([\s\S]*)\n+\/\[\]/;
const [_, columns, content] = s.match(rx) ||
["", "..", "Unable to parse grid"];
const [_, columns, content] = s.match(rx) || [
"",
"..",
"Unable to parse grid",
];
return {
content,
raw: s,
@ -133,7 +102,7 @@ export const buildOnlyDefaultElements = () => {
};
},
(token) => {
const { content, children, metadata, uuid } = token;
const { children, metadata } = token;
return (
<div
style={{
@ -141,11 +110,7 @@ export const buildOnlyDefaultElements = () => {
} as React.CSSProperties}
className="grid grid-cols-dynamic gap-x-8 gap-y-6 mb-6"
>
{children?.map((c) => (
<div key={c.uuid}>
{c.render(c)}
</div>
))}
{children?.map((c) => <div key={c.uuid}>{c.render(c)}</div>)}
</div>
);
},
@ -173,17 +138,14 @@ export const buildOnlyDefaultElements = () => {
};
},
(token) => {
const { children, metadata, uuid } = token;
const { children, metadata } = token;
return (
<div
data-block={!!metadata.isBlock}
className="data-[block=false]:card mb-6"
>
{children?.map((e) => (
<Fragment key={e.uuid}>
{e.render(e)}
</Fragment>
))}
{children?.map((e) => <Fragment key={e.uuid}>{e.render(e)}
</Fragment>)}
</div>
);
},
@ -192,22 +154,26 @@ export const buildOnlyDefaultElements = () => {
);
// fenced code block
registerIdentifier("code", /`{3}\n+((?:.|\n)*?)\n+`{3}/g, (s, rx) => {
return {
content: s.match(new RegExp(rx, ""))?.at(1) ||
"Unable to parse code",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return (
<pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
{token.content}
</pre>
);
});
registerIdentifier(
"code",
/`{3}\n+((?:.|\n)*?)\n+`{3}/g,
(s, rx) => {
return {
content: s.match(new RegExp(rx, ""))?.at(1) || "Unable to parse code",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
return (
<pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
{token.content}
</pre>
);
},
);
// list
registerIdentifier(
@ -215,20 +181,18 @@ export const buildOnlyDefaultElements = () => {
/^\s*-\s([\s\S]*?)\n\n/gm,
(s, rx) => {
return {
content: s.match(new RegExp(rx, ""))?.at(1) ||
"Unable to parse list",
content: s.match(new RegExp(rx, ""))?.at(1) || "Unable to parse list",
raw: s,
metadata: {
initialDepth:
s.replace("\n", "").split("-").at(0)?.length.toString() ||
"1",
s.replace("\n", "").split("-").at(0)?.length.toString() || "1",
},
uuid: crypto.randomUUID(),
rendersChildrenOnly,
};
},
(token) => {
const { children, metadata, uuid } = token;
const { children, metadata } = token;
return (
<>
<ul
@ -237,10 +201,7 @@ export const buildOnlyDefaultElements = () => {
>
{children?.map((c) => {
return (
<li
key={c.uuid}
data-depth={metadata.initialDepth}
>
<li key={c.uuid} data-depth={metadata.initialDepth}>
{c.children?.map((c: Token<any>) => (
<Fragment key={c.uuid}>{c.render(c)}</Fragment>
))}
@ -264,19 +225,15 @@ export const buildOnlyDefaultElements = () => {
raw: s,
metadata: {
initialDepth:
s.replace("\n", "").split("-").at(0)?.length.toString() ||
"1",
s.replace("\n", "").split("-").at(0)?.length.toString() || "1",
},
uuid: crypto.randomUUID(),
};
},
(token) => {
const { children, metadata, uuid } = token;
const { children, metadata } = token;
return (
<li
data-depth={metadata.initialDepth}
className="ml-2"
>
<li data-depth={metadata.initialDepth} className="ml-2">
{children?.map((c) => (
<Fragment key={c.uuid}>
(c.render(c))
@ -288,104 +245,120 @@ export const buildOnlyDefaultElements = () => {
);
// heading
registerIdentifier("heading", /^#+\s(.*?)$/gm, (s, rx) => {
const content = s.match(new RegExp(rx, ""))?.at(1) ||
"Unable to parse heading";
return {
content: content,
raw: s,
metadata: {
strength: s.match(/#/g)?.length.toString() || "1",
id: generateId(content, usedIds),
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return (
<div
// id={generateId(token.raw, usedIds)}
data-strength={token.metadata.strength}
className={`
registerIdentifier(
"heading",
/^#+\s(.*?)$/gm,
(s, rx) => {
const content = s.match(new RegExp(rx, ""))?.at(1) ||
"Unable to parse heading";
return {
content: content,
raw: s,
metadata: {
strength: s.match(/#/g)?.length.toString() || "1",
id: generateId(content, usedIds),
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
return (
<div
// id={generateId(token.raw, usedIds)}
data-strength={token.metadata.strength}
className={`
font-bold
data-[strength="1"]:text-4xl
data-[strength="2"]:text-3xl
data-[strength="3"]:text-2xl
`}
>
{token.content}
</div>
);
});
// image
registerIdentifier("image", /\!\[(.*?)\]\((.*?)\)/g, (s, rx) => {
const [_, title, src] = s.match(new RegExp(rx, ""))!;
return {
// content: inline,
content: title.trim(),
raw: s,
metadata: {
src,
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
const { metadata } = token;
metadata.src = metadata.src as string;
if (metadata.src.startsWith("<svg")) {
return (
<div
dangerouslySetInnerHTML={{
__html: sanitize(metadata.src, {
USE_PROFILES: { svg: true },
}),
}}
>
{token.content}
</div>
);
}
// eslint-disable-next-line @next/next/no-img-element
return <img src={metadata.src} alt={token.content} />;
});
},
);
// image
registerIdentifier(
"image",
/\!\[(.*?)\]\((.*?)\)/g,
(s, rx) => {
const [_, title, src] = s.match(new RegExp(rx, ""))!;
return {
// content: inline,
content: title.trim(),
raw: s,
metadata: {
src,
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
const { metadata } = token;
metadata.src = metadata.src as string;
if (metadata.src.startsWith("<svg")) {
return (
<div
dangerouslySetInnerHTML={{
__html: sanitize(metadata.src, {
USE_PROFILES: { svg: true },
}),
}}
>
</div>
);
}
// eslint-disable-next-line @next/next/no-img-element
return <img src={metadata.src} alt={token.content} />;
},
);
// anchor
registerIdentifier("anchor", /(?<![\!^])\[(.*?)\]\((.*?)\)/g, (s, rx) => {
let preset, [_, title, href] = s.match(new RegExp(rx, ""))!;
const match = title.match(/`{3}(cta|button)?(.*)/);
registerIdentifier(
"anchor",
/(?<![\!^])\[(.*?)\]\((.*?)\)/g,
(s, rx) => {
let preset,
[_, title, href] = s.match(new RegExp(rx, ""))!;
const match = title.match(/`{3}(cta|button)?(.*)/);
if (match) {
[_, preset, title] = match;
}
if (match) {
[_, preset, title] = match;
}
const classes = {
button: "btn-primary inline-block",
cta: "btn-secondary inline-block uppercase",
};
return {
content: title.trim(),
raw: s,
metadata: {
href,
classes: classes[preset as keyof typeof classes],
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
const { metadata } = token;
return (
<Link
className={metadata.classes ||
"dark:text-primary-600 underline dark:no-underline"}
href={metadata.href}
>
{token.content}
</Link>
);
});
const classes = {
button: "btn-primary inline-block",
cta: "btn-secondary inline-block uppercase",
};
return {
content: title.trim(),
raw: s,
metadata: {
href,
classes: classes[preset as keyof typeof classes],
},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
const { metadata } = token;
return (
<Link
className={metadata.classes ||
"dark:text-primary-600 underline dark:no-underline"}
href={metadata.href}
>
{token.content}
</Link>
);
},
);
// inline-code
registerIdentifier(
@ -411,70 +384,75 @@ export const buildOnlyDefaultElements = () => {
);
// bold
registerIdentifier("bold", /\*{2}(.*?)\*{2}/g, (s, rx) => {
return {
content: s.match(new RegExp(rx, "i"))?.at(1) ||
"Unable to parse bold",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return (
<span className="font-bold">
{token.content}
</span>
);
});
registerIdentifier(
"bold",
/\*{2}(.*?)\*{2}/g,
(s, rx) => {
return {
content: s.match(new RegExp(rx, "i"))?.at(1) || "Unable to parse bold",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
return <span className="font-bold">{token.content}</span>;
},
);
// italic
registerIdentifier("italic", /(?<!\*)\*([^\*]+?)\*(?!\*)/g, (s, rx) => {
return {
content: s.match(new RegExp(rx, "i"))?.at(1) ||
"Unable to parse italic",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return (
<span className="italic">
{token.content}
</span>
);
});
registerIdentifier(
"italic",
/(?<!\*)\*([^\*]+?)\*(?!\*)/g,
(s, rx) => {
return {
content: s.match(new RegExp(rx, "i"))?.at(1) ||
"Unable to parse italic",
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
return <span className="italic">{token.content}</span>;
},
);
// popover
registerIdentifier("popover", /\^\[(.*?)\]\<<(.*?)\>>/g, (s, rx) => {
const [_, title, content] = s.match(new RegExp(rx, ""))!;
registerIdentifier(
"popover",
/\^\[(.*?)\]\<<(.*?)\>>/g,
(s, rx) => {
const [_, title, content] = s.match(new RegExp(rx, ""))!;
return {
content,
raw: s,
metadata: { title },
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
const { children, metadata, uuid } = token;
return (
<Poppable
content={children?.map((c) => (
<Fragment key={uuid}>{c.render(c)}</Fragment>
)) ||
token.content}
preferredAlign="centered"
preferredEdge="bottom"
className="cursor-pointer mx-2"
>
<span className="border-b-2 border-dotted border-white">
{metadata.title}
</span>
</Poppable>
);
});
return {
content,
raw: s,
metadata: { title },
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
(token) => {
const { children, metadata, uuid } = token;
return (
<Poppable
content={children?.map((c) => (
<Fragment key={uuid}>{c.render(c)}</Fragment>
)) || token.content}
preferredAlign="centered"
preferredEdge="bottom"
className="cursor-pointer mx-2"
>
<span className="border-b-2 border-dotted border-white">
{metadata.title}
</span>
</Poppable>
);
},
);
registerIdentifier(
"accordion",
@ -490,17 +468,13 @@ export const buildOnlyDefaultElements = () => {
};
},
(token) => {
const { children, metadata, uuid } = token;
const { children, metadata } = token;
return (
<div className="bg-black/20 p-1 accordion">
<Accordion
title={metadata.title || "Expand"}
>
<Accordion title={metadata.title || "Expand"}>
<AccordionContent>
{children?.map((e, i) => (
<Fragment key={e.uuid}>
{e.render(e)}
</Fragment>
{children?.map((e) => (
<Fragment key={e.uuid}>{e.render(e)}</Fragment>
))}
</AccordionContent>
</Accordion>
@ -509,169 +483,193 @@ export const buildOnlyDefaultElements = () => {
},
);
registerIdentifier("p", /(?<=\n\n)([\s\S]*?)(?=\n\n)/g, (s) => {
return {
content: s.replace("\n", " "),
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
};
}, (token) => {
const { children, uuid } = token;
registerIdentifier(
"p",
/(?<=\n\n)([\s\S]*?)(?=\n\n)/g,
(s) => {
return {
content: s.replace("\n", " "),
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
};
},
(token) => {
const { children } = token;
debugger;
debugger;
return (
<div className="p">
{children?.map((e) => {
console.log(e);
return (
<Fragment key={e.uuid}>
{e.render(e)}
</Fragment>
);
})}
</div>
);
});
return (
<div className="p">
{children?.map((e) => {
console.log(e);
return <Fragment key={e.uuid}>{e.render(e)}</Fragment>;
})}
</div>
);
},
);
registerIdentifier("hr", /^-{3,}$/gm, (s, rx) => {
return {
content: s,
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return <div className="w-full border-b border-mixed-500 my-3"></div>;
});
registerIdentifier(
"hr",
/^-{3,}$/gm,
(s) => {
return {
content: s,
raw: s,
metadata: {},
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
() => {
return <div className="w-full border-b border-mixed-500 my-3"></div>;
},
);
registerIdentifier("comment", /<!--[\s\S]+?-->/g, (s, rx) => {
return {
content: "",
metadata: { comment: s },
raw: "",
uuid: crypto.randomUUID(),
rendersContentOnly,
};
}, (token) => {
return <></>;
});
registerIdentifier(
"comment",
/<!--[\s\S]+?-->/g,
(s) => {
return {
content: "",
metadata: { comment: s },
raw: "",
uuid: crypto.randomUUID(),
rendersContentOnly,
};
},
() => {
return <></>;
},
);
registerIdentifier("frontmatter", /^---([\s\S]*?)---/g, (s, rx) => {
return {
content: "",
metadata: {
frontmatterString: s.match(rx)?.at(0) || "",
},
raw: "",
uuid: "frontmatter",
};
}, (token) => {
return <>{token.raw}</>;
});
registerIdentifier(
"frontmatter",
/^---([\s\S]*?)---/g,
(s, rx) => {
return {
content: "",
metadata: {
frontmatterString: s.match(rx)?.at(0) || "",
},
raw: "",
uuid: "frontmatter",
};
},
(token) => {
return <>{token.raw}</>;
},
);
registerIdentifier("table", /^\|\s[\s\S]*?\|(?=(\n\n)|$)/g, (s, rx) => {
const rowSections = s.split(/^\|[|-\s]+\|$/gm).map((s) =>
s.split("\n").filter((r) => !!r).map((r) =>
r.split("|").map((c) => c.trim()).filter((c) => !!c)
)
);
registerIdentifier(
"table",
/^\|\s[\s\S]*?\|(?=(\n\n)|$)/g,
(s) => {
const rowSections = s.split(/^\|[|-\s]+\|$/gm).map((s) =>
s
.split("\n")
.filter((r) => !!r)
.map((r) =>
r
.split("|")
.map((c) => c.trim())
.filter((c) => !!c)
)
);
let headerRows: string[][] = [],
bodyRows: string[][] = [],
footerRows: string[][] = [];
let headerRows: string[][] = [],
bodyRows: string[][] = [],
footerRows: string[][] = [];
switch (rowSections.length) {
case 1:
bodyRows = rowSections[0];
break;
case 2:
headerRows = rowSections[0];
bodyRows = rowSections[1];
break;
case 3:
headerRows = rowSections[0];
bodyRows = rowSections[1];
footerRows = rowSections[3];
break;
}
switch (rowSections.length) {
case 1:
bodyRows = rowSections[0];
break;
case 2:
headerRows = rowSections[0];
bodyRows = rowSections[1];
break;
case 3:
headerRows = rowSections[0];
bodyRows = rowSections[1];
footerRows = rowSections[3];
break;
}
const maxColumns = Math.max(
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
);
const maxColumns = Math.max(
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
);
return {
content: s,
raw: s,
metadata: {
headerRows: headerRows,
bodyRows: bodyRows,
footerRows: footerRows,
columns: maxColumns,
},
uuid: crypto.randomUUID(),
};
}, (t) => {
const { headerRows, bodyRows, footerRows, columns } = t.metadata;
return {
content: s,
raw: s,
metadata: {
headerRows: headerRows,
bodyRows: bodyRows,
footerRows: footerRows,
columns: maxColumns,
},
uuid: crypto.randomUUID(),
};
},
(t) => {
const { headerRows, bodyRows, footerRows, columns } = t.metadata;
return (
<table className="md-table">
{!!headerRows && (
<thead>
{headerRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<th key={r.join() + i + c}>
{child?.render(child) ||
c}
</th>
);
})}
</tr>
))}
</thead>
)}
{!!bodyRows && (
<tbody>
{bodyRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<td key={r.join() + i + c}>
{child?.render(child) ||
c}
</td>
);
})}
</tr>
))}
</tbody>
)}
{!!footerRows && (
<tfoot>
{footerRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<td key={r.join() + i + c}>
{child?.render(child) ||
c}
</td>
);
})}
</tr>
))}
</tfoot>
)}
</table>
);
});
return (
<table className="md-table">
{!!headerRows && (
<thead>
{headerRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<th key={r.join() + i + c}>
{child?.render(child) || c}
</th>
);
})}
</tr>
))}
</thead>
)}
{!!bodyRows && (
<tbody>
{bodyRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<td key={r.join() + i + c}>
{child?.render(child) || c}
</td>
);
})}
</tr>
))}
</tbody>
)}
{!!footerRows && (
<tfoot>
{footerRows.map((r, i) => (
<tr key={r.join() + i}>
{r.concat(Array(columns - r.length).fill("")).map((c) => {
const child = t.children?.find((child) => child.raw === c);
return (
<td key={r.join() + i + c}>
{child?.render(child) || c}
</td>
);
})}
</tr>
))}
</tfoot>
)}
</table>
);
},
);
return TokenIdentifiers;
};
@ -694,14 +692,16 @@ function findMatchingClosedParenthesis(
const openingMatch = openRegex.exec(str);
const closingMatch = closedRegex.exec(str);
if ((openingMatch && !closingMatch)) {
if (openingMatch && !closingMatch) {
throw Error("Things have gone horribly wrong");
}
// if ((!openingMatch && closingMatch) || (!openingMatch && !closingMatch)) break;
if (
openingMatch && closingMatch && openingMatch.index < closingMatch.index
openingMatch &&
closingMatch &&
openingMatch.index < closingMatch.index
) {
openings++;
lastOpeningSuccessIndex = openingMatch.index + openingMatch[0].length;
@ -758,10 +758,11 @@ function search(
// Finds a unique id for things like headings
function generateId(t: string, usedIds: string[]) {
let id = t.toLowerCase().replace(/[^a-z\s]/ig, "").trim().replaceAll(
" ",
"-",
);
let id = t
.toLowerCase()
.replace(/[^a-z\s]/gi, "")
.trim()
.replaceAll(" ", "-");
let idNum = 1;
while (usedIds.includes(id)) {
id = id.replace(/-[0-9]+$/g, "");

View File

@ -118,7 +118,7 @@ function isAcceptableChild(parentType: string, childType: string): boolean {
return acceptableChildren ? acceptableChildren.includes(childType) : true;
}
// Occasionally, some P blocks start exactly at the same point as another block (a side effect of needing to exclude preceding linebreaks from the regex while also having the only clear delineation being those linebreaks) so we just remove those P blocks so that when searching for a parent, it doesn't need to figure out if the P block is valid or not. This doesn't cause issues during rendering since each block handles its own container element
// Occasionally, some P blocks start exactly at the same point as another block (a side effect of needing to exclude preceding line-breaks from the regex while also having the only clear delineation being those line-breaks) so we just remove those P blocks so that when searching for a parent, it doesn't need to figure out if the P block is valid or not. This doesn't cause issues during rendering since each block handles its own container element
function filterOverlappingPBlocks(blocks: TokenMarker[]): TokenMarker[] {
return blocks.filter((block) => {
if (block.type !== "p") {

View File

@ -16,14 +16,15 @@
"react-dom": "^18"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.1.0",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"eslint": "^8",
"eslint-config-next": "14.1.0"
"typescript": "^5",
"typescript-eslint": "^7.2.0"
}
}

28
types.d.ts vendored
View File

@ -26,3 +26,31 @@ type TokenMarker<M = Record<string, string>> = {
};
type FrontMatter = Record<string, string>;
type SearchFunction = (
s: string,
start: number,
end: number,
) => {
start: number;
end: number;
text: string;
lastIndex: number;
};
type TokenIdentifier<M> = {
rx: RegExp;
parse: (s: string) => Token<M>;
search?: SearchFunction;
};
type TokenIdentifierMap = Map<string, TokenIdentifier<any>>;
type IdentifierRegistration = <N = Record<string, string>>(
type: string,
match: RegExp,
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
renderFunction: TokenRenderer<N>,
openTagRx?: RegExp,
closeTagRx?: RegExp,
) => void;