Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,572 changes: 1,572 additions & 0 deletions lcov.info

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions src/block/CodeBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Row } from "./Row.ts";

export interface CodeBlockPack {
type: "codeBlock";
rows: Row[];
rows: [Row, ...Row[]];
}

/**
Expand All @@ -17,9 +17,8 @@ export interface CodeBlock {

export const convertToCodeBlock = (pack: CodeBlockPack): CodeBlock => {
const {
rows: [head, ...body],
rows: [{ indent, text }, ...body],
} = pack;
const { indent = 0, text = "" } = head ?? {};
const fileName: string = text.replace(/^\s*code:/, "");

return {
Expand Down
34 changes: 19 additions & 15 deletions src/block/Pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,35 @@ import type { TitlePack } from "./Title.ts";

export type Pack = TitlePack | CodeBlockPack | TablePack | LinePack;

const isChildRowOfPack = (pack: Pack, row: Row): boolean =>
(pack.type === "codeBlock" || pack.type === "table") &&
row.indent > (pack.rows[0]?.indent ?? 0);
const isChildRowOfPack = (
{ type, rows: [firstRow] }: Pack,
row: Row,
): boolean =>
(type === "codeBlock" || type === "table") && row.indent > firstRow.indent;

const packing = (packs: Pack[], row: Row): Pack[] => {
const lastPack = packs[packs.length - 1];
if (lastPack !== undefined && isChildRowOfPack(lastPack, row)) {
lastPack.rows.push(row);
return packs;
} else {
packs.push({
type: /^\s*code:/.test(row.text)
? "codeBlock"
: /^\s*table:/.test(row.text)
? "table"
: "line",
rows: [row],
});
}

packs.push({
type: /^\s*code:/.test(row.text)
? "codeBlock"
: /^\s*table:/.test(row.text)
? "table"
: "line",
rows: [row],
});

return packs;
};

export const packRows = (rows: Row[], opts: ParserOption): Pack[] => {
if (opts.hasTitle ?? true) {
export const packRows = (
rows: Row[],
{ hasTitle = true }: ParserOption,
): Pack[] => {
if (hasTitle) {
const [title, ...body] = rows;
if (title === undefined) return [];
return [
Expand Down
2 changes: 1 addition & 1 deletion src/block/Row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export interface Row {

export const parseToRows = (input: string): Row[] =>
input.split("\n").map((text) => ({
indent: /^\s+/.exec(text)?.[0]?.length ?? 0,
indent: /^\s+/.exec(text)?.[0].length ?? 0,
text,
}));
5 changes: 2 additions & 3 deletions src/block/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Row } from "./Row.ts";

export interface TablePack {
type: "table";
rows: Row[];
rows: [Row, ...Row[]];
}

/**
Expand All @@ -19,9 +19,8 @@ export interface Table {

export const convertToTable = (pack: TablePack): Table => {
const {
rows: [head, ...body],
rows: [{ indent, text }, ...body],
} = pack;
const { indent = 0, text = "" } = head ?? {};
const fileName = text.replace(/^\s*table:/, "");

return {
Expand Down
2 changes: 1 addition & 1 deletion src/block/node/ExternalLinkNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const createExternalLinkNode: NodeCreator<LinkNode | PlainNode> = (
const match = (
isHrefFirst ? /^https?:\/\/[^\s\]]+/ : /https?:\/\/[^\s\]]+$/
).exec(inner);
if (match?.[0] === undefined) return [];
if (match === null) return [];

const content = isHrefFirst
? inner.substring(match[0].length)
Expand Down
9 changes: 2 additions & 7 deletions src/block/node/PlainNode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { NodeCreator } from "./creator.ts";
import { createNodeParser } from "./creator.ts";
import type { NodeParser } from "./index.ts";
import type { TerminateNodeParser } from "./index.ts";
import type { PlainNode } from "./type.ts";

export const createPlainNode: NodeCreator<PlainNode> = (raw) => [
Expand All @@ -11,8 +10,4 @@ export const createPlainNode: NodeCreator<PlainNode> = (raw) => [
},
];

export const PlainNodeParser: NodeParser = createNodeParser(createPlainNode, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [/^()(.*)()$/],
});
export const PlainNodeParser: TerminateNodeParser = createPlainNode;
18 changes: 12 additions & 6 deletions src/block/node/creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,40 @@ export type NodeCreator<T extends Node> = (
opts: NodeParserOption,
) => T[];

type NodeParserCreatorOptions = {
parseOnNested: boolean;
parseOnQuoted: boolean;
patterns: RegExp[];
};

type NodeParserCreator<T extends Node> = (
nodeCreator: NodeCreator<T>,
opts: { parseOnNested: boolean; parseOnQuoted: boolean; patterns: RegExp[] },
opts: NodeParserCreatorOptions,
) => NodeParser;

export const createNodeParser: NodeParserCreator<Node> = (
nodeCreator,
{ parseOnNested, parseOnQuoted, patterns },
) => {
return (text, opts, next) => {
if (!parseOnNested && opts.nested) return next?.() ?? [];
if (!parseOnQuoted && opts.quoted) return next?.() ?? [];
if (!parseOnNested && opts.nested) return next();
if (!parseOnQuoted && opts.quoted) return next();

for (const pattern of patterns) {
const match = pattern.exec(text);
if (match === null) continue;

const left = text.substring(0, match.index);
const right = text.substring(match.index + (match[0]?.length ?? 0));
const right = text.substring(match.index + match[0].length);

const node = nodeCreator(match[0] ?? "", opts);
const node = nodeCreator(match[0], opts);
return [
...convertToNodes(left, opts),
...node,
...convertToNodes(right, opts),
];
}

return next?.() ?? [];
return next();
};
};
12 changes: 7 additions & 5 deletions src/block/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ export type NextNodeParser = () => Node[];
export type NodeParser = (
text: string,
opts: NodeParserOption,
next?: NextNodeParser,
next: NextNodeParser,
) => Node[];
export type TerminateNodeParser = (
text: string,
opts: NodeParserOption,
) => Node[];

const FalsyEliminator: NodeParser = (text, _, next) => {
if (text === "") return [];
return next?.() ?? [];
};
const FalsyEliminator: NodeParser = (text, _, next) =>
text !== "" ? next() : [];

const combineNodeParsers =
(...parsers: NodeParser[]) =>
Expand Down
9 changes: 6 additions & 3 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ export type Page = Block[];
* @param opts parser options
* @returns syntax tree of parsed input
*/
export const parse = (input: string, opts?: ParserOption): Page => {
export const parse = (
input: string,
{ hasTitle = true }: ParserOption = {},
): Page => {
const rows = parseToRows(input);
const packs = packRows(rows, { hasTitle: opts?.hasTitle ?? true });
const packs = packRows(rows, { hasTitle });
return packs.map(convertToBlock);
};

Expand All @@ -37,5 +40,5 @@ export const parse = (input: string, opts?: ParserOption): Page => {
*/
export const getTitle = (input: string): string => {
const match = /^\s*\S.*$/m.exec(input);
return match?.[0]?.trim() ?? "Untitled";
return match?.[0].trim() ?? "Untitled";
};
Loading