/** * @typedef {'toml' | 'yaml'} Preset * Known name of a frontmatter style. * * @typedef Info * Sequence. * * Depending on how this structure is used, it reflects a marker or a fence. * @property {string} close * Closing. * @property {string} open * Opening. * * @typedef MatterProps * Fields describing a kind of matter. * @property {string} type * Node type to tokenize as. * @property {boolean | null | undefined} [anywhere=false] * Whether matter can be found anywhere in the document, normally, only matter * at the start of the document is recognized. * * > πŸ‘‰ **Note**: using this is a terrible idea. * > It’s called frontmatter, not matter-in-the-middle or so. * > This makes your markdown less portable. * * @typedef MarkerProps * Marker configuration. * @property {Info | string} marker * Character repeated 3 times, used as complete fences. * * For example the character `'-'` will result in `'---'` being used as the * fence * Pass `open` and `close` to specify different characters for opening and * closing fences. * @property {never} [fence] * If `marker` is set, `fence` must not be set. * * @typedef FenceProps * Fence configuration. * @property {Info | string} fence * Complete fences. * * This can be used when fences contain different characters or lengths * other than 3. * Pass `open` and `close` to interface to specify different characters for opening and * closing fences. * @property {never} [marker] * If `fence` is set, `marker` must not be set. * * @typedef {(MatterProps & FenceProps) | (MatterProps & MarkerProps)} Matter * Fields describing a kind of matter. * * > πŸ‘‰ **Note**: using `anywhere` is a terrible idea. * > It’s called frontmatter, not matter-in-the-middle or so. * > This makes your markdown less portable. * * > πŸ‘‰ **Note**: `marker` and `fence` are mutually exclusive. * > If `marker` is set, `fence` must not be set, and vice versa. * * @typedef {Matter | Preset | Array} Options * Configuration. */ import {fault} from 'fault' const own = {}.hasOwnProperty const markers = {yaml: '-', toml: '+'} /** * Simplify options by normalizing them to an array of matters. * * @param {Options | null | undefined} [options='yaml'] * Configuration (default: `'yaml'`). * @returns {Array} * List of matters. */ export function toMatters(options) { /** @type {Array} */ const result = [] let index = -1 /** @type {Array} */ const presetsOrMatters = Array.isArray(options) ? options : options ? [options] : ['yaml'] while (++index < presetsOrMatters.length) { result[index] = matter(presetsOrMatters[index]) } return result } /** * Simplify an option. * * @param {Matter | Preset} option * Configuration. * @returns {Matter} * Matter. */ function matter(option) { let result = option if (typeof result === 'string') { if (!own.call(markers, result)) { throw fault('Missing matter definition for `%s`', result) } result = {type: result, marker: markers[result]} } else if (typeof result !== 'object') { throw fault('Expected matter to be an object, not `%j`', result) } if (!own.call(result, 'type')) { throw fault('Missing `type` in matter `%j`', result) } if (!own.call(result, 'fence') && !own.call(result, 'marker')) { throw fault('Missing `marker` or `fence` in matter `%j`', result) } return result }