| import { Line } from '../primitives.js'; | |
| const reTag = /^@[^\s/]+(?=\s|$)/; | |
| /** | |
| * Groups source lines in sections representing tags. | |
| * First section is a block description if present. Last section captures lines starting with | |
| * the last tag to the end of the block, including dangling closing marker. | |
| * @param {Line[]} block source lines making a single comment block | |
| */ | |
| export type Parser = (block: Line[]) => Line[][]; | |
| /** | |
| * Predicate telling if string contains opening/closing escaping sequence | |
| * @param {string} source raw source line | |
| */ | |
| export type Fencer = (source: string) => boolean; | |
| /** | |
| * `Parser` configuration options | |
| */ | |
| export interface Options { | |
| // escaping sequence or predicate | |
| fence: string | Fencer; | |
| } | |
| /** | |
| * Creates configured `Parser` | |
| * @param {Partial<Options>} options | |
| */ | |
| export default function getParser({ | |
| fence = '```', | |
| }: Partial<Options> = {}): Parser { | |
| const fencer = getFencer(fence); | |
| const toggleFence = (source: string, isFenced: boolean): boolean => | |
| fencer(source) ? !isFenced : isFenced; | |
| return function parseBlock(source: Line[]): Line[][] { | |
| // start with description section | |
| const sections: Line[][] = [[]]; | |
| let isFenced = false; | |
| for (const line of source) { | |
| if (reTag.test(line.tokens.description) && !isFenced) { | |
| sections.push([line]); | |
| } else { | |
| sections[sections.length - 1].push(line); | |
| } | |
| isFenced = toggleFence(line.tokens.description, isFenced); | |
| } | |
| return sections; | |
| }; | |
| } | |
| function getFencer(fence: string | Fencer): Fencer { | |
| if (typeof fence === 'string') | |
| return (source: string) => source.split(fence).length % 2 === 0; | |
| return fence; | |
| } |