UNPKG

@humanspeak/svelte-markdown

Version:

Fast, customizable markdown renderer for Svelte with built-in caching, TypeScript support, and Svelte 5 runes

127 lines (126 loc) 4.19 kB
/** * Creates a set of filter utility functions for renderer maps. * This factory generates three functions: buildUnsupported, allowOnly, and excludeOnly. * * Used to eliminate code duplication between unsupportedRenderers.ts and unsupportedHtmlRenderers.ts. * * @template TKey - The string literal type for valid keys * @template TResult - The result map type (e.g., Partial<Renderers> or HtmlRenderers) * * @param keys - Array of valid keys for this renderer type * @param unsupportedComponent - The component to use for unsupported/disabled renderers * @param defaultsMap - Map of keys to their default component implementations * * @returns Object containing buildUnsupported, allowOnly, and excludeOnly functions * * @example * ```typescript * import { createFilterUtilities } from './createFilterUtilities' * * type MyKey = 'foo' | 'bar' | 'baz' * const keys: readonly MyKey[] = ['foo', 'bar', 'baz'] as const * const UnsupportedComponent = () => null * const defaults = { foo: FooComponent, bar: BarComponent, baz: BazComponent } * * const { buildUnsupported, allowOnly, excludeOnly } = createFilterUtilities<MyKey, Record<MyKey, Component>>( * keys, * UnsupportedComponent, * defaults * ) * * // Block all renderers * const allUnsupported = buildUnsupported() * * // Allow only 'foo' and 'bar', block 'baz' * const allowList = allowOnly(['foo', 'bar']) * * // Block only 'baz', allow others with defaults * const denyList = excludeOnly(['baz']) * ``` */ export const createFilterUtilities = (keys, unsupportedComponent, defaultsMap) => { /** * Checks if a key is valid for this renderer type. */ const hasKey = (key) => keys.includes(key); /** * Builds a map where every key is set to the unsupported component. * Useful for starting with a "deny all" approach. */ const buildUnsupported = () => { const result = {}; for (const key of keys) { ; result[key] = unsupportedComponent; } return result; }; /** * Produces a renderer map that allows only the specified keys. * All non-listed keys are set to the unsupported component. * * Each entry can be either: * - A key string (to use the default component for that key) * - A tuple [key, component] to specify a custom component */ const allowOnly = (allowed) => { const result = buildUnsupported(); for (const entry of allowed) { if (Array.isArray(entry)) { const [key, component] = entry; if (hasKey(key)) { ; result[key] = component; } } else { const key = entry; if (hasKey(key)) { ; result[key] = defaultsMap[key]; } } } return result; }; /** * Produces a renderer map that excludes only the specified keys. * Excluded keys are set to the unsupported component. * All other keys use the default components. * * Optionally, specific non-excluded keys can be overridden with custom components. * Exclusions take precedence over overrides. */ const excludeOnly = (excluded, overrides) => { const result = {}; // Start with all defaults for (const key of keys) { ; result[key] = defaultsMap[key]; } // Mark excluded keys as unsupported for (const key of excluded) { if (hasKey(key)) { ; result[key] = unsupportedComponent; } } // Apply overrides (exclusions take precedence) if (overrides) { for (const [key, component] of overrides) { if (excluded.includes(key)) continue; if (hasKey(key)) { ; result[key] = component; } } } return result; }; return { buildUnsupported, allowOnly, excludeOnly }; };