{"version":3,"sources":["../src/plugins/index.ts"],"names":[],"mappings":";;;AAwCO,SAAS,kBACX,IAAA,EACE;AACL,EAAA,MAAM,MAAW,EAAC;AAClB,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM,IAAI,GAAG,GAAA,CAAI,IAAA,CAAK,GAAG,CAAC,CAAA;AAC1C,EAAA,OAAO,GAAA;AACT;AAMO,SAAS,sBAAsB,IAAA,EAQrB;AACf,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,KAAA,CAAM,MAAM,GAAA,EAAK;AACf,MAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,KAAK,IAAA,EAAM,GAAG,GAAG,OAAO,IAAA;AAC7C,MAAA,MAAM,KAAA,GAAQ,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,MAAA;AAC9B,MAAA,IAAI,CAAA,GAAI,KAAA;AACR,MAAA,OAAO,CAAA,GAAI,KAAK,MAAA,EAAQ;AACtB,QAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,CAAK,CAAC,MAAM,IAAA,IAAQ,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ;AAChE,UAAA,CAAA,IAAK,CAAA;AACL,UAAA;AAAA,QACF;AACA,QAAA,IAAI,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,KAAA,EAAO,CAAC,CAAA,EAAG;AAClC,UAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO,CAAC,CAAA;AACjC,UAAA,OAAO;AAAA,YACL,QAAA,EAAU,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAA;AAAA,YAClC,OAAO,EAAE,IAAA,EAAM,IAAA,CAAK,SAAA,EAAW,SAAS,KAAA;AAAM,WAChD;AAAA,QACF;AACA,QAAA,IAAI,IAAA,CAAK,CAAC,CAAA,KAAM,IAAA,EAAM,OAAO,IAAA;AAC7B,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,GACF;AACA,EAAA,IAAI,IAAA,CAAK,QAAA,KAAa,MAAA,EAAW,MAAA,CAAO,WAAW,IAAA,CAAK,QAAA;AACxD,EAAA,OAAO,MAAA;AACT;AAMO,SAAS,kBAAkB,IAAA,EASlB;AACd,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,UAAU,IAAA,EAAM;AACd,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAClC,MAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,KAAK,SAAA,IAAa,QAAA;AAAA,QACxB,OAAA,EAAS,EAAA;AAAA,QACT,IAAA,EAAM,EAAE,UAAA,EAAY,IAAA,CAAK,IAAA,EAAM,GAAI,IAAA,CAAK,YAAA,GAAe,CAAC,CAAA,IAAK,EAAC;AAAG,OACnE;AAAA,IACF,CAAA;AAAA,IACA,QAAQ,IAAA,EAAM;AACZ,MAAA,MAAM,KAAK,IAAA,CAAK,SAAA;AAChB,MAAA,OAAO,KAAK,EAAA,CAAG,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA,CAAK,MAAK,KAAM,EAAA;AAAA,IAC9C,CAAA;AAAA,IACA,QAAQ,IAAA,CAAK;AAAA,GACf;AACF","file":"plugins.cjs","sourcesContent":["/**\n * stream-md/plugins — public plugin API.\n *\n * Plugins extend the parser with custom block types and inline tokens.\n * The built-in block/inline rules use the same data shape, so plugins\n * are first-class citizens (not \"second-class\" overlays).\n *\n * Block plugins:\n *   - `openMatch(line)` returns `{ type, content?, meta?, closeImmediately? }`\n *     when the line should start a new block of this plugin's type.\n *   - `isClose(line, content)` (optional) decides when the block should close.\n *     If absent, blank-line-closes-block applies.\n *   - `render(block)` is the React renderer (only used by the React entry).\n *\n * Inline plugins:\n *   - `triggers` (optional) is a string of leading characters that *might*\n *     trigger this plugin — used as a perf hint.\n *   - `match(text, pos)` returns `{ consumed, token }` or null.\n *   - `render(token)` (optional) is the React renderer.\n */\n\nexport type {\n  BlockPlugin,\n  BlockPluginOpenResult,\n  InlinePlugin,\n  InlinePluginMatchResult,\n  Block,\n  BlockMeta,\n  InlineToken,\n  InlineTokenType,\n} from \"../parser/types\";\n\nimport type {\n  BlockPlugin,\n  InlinePlugin,\n  Block,\n  InlineToken,\n} from \"../parser/types\";\n\n/** Compose multiple plugin sets into a single set. */\nexport function composePlugins<T extends BlockPlugin | InlinePlugin>(\n  ...sets: Array<readonly T[] | undefined>\n): T[] {\n  const out: T[] = [];\n  for (const s of sets) if (s) out.push(...s);\n  return out;\n}\n\n/**\n * Tiny helper for building inline plugins that match a fixed delimiter\n * (e.g. `$...$` for math). Handles backslash-escapes inside the delimiter.\n */\nexport function delimitedInlinePlugin(opts: {\n  name: string;\n  open: string;\n  close: string;\n  tokenType: InlineToken[\"type\"];\n  triggers?: string;\n  /** If true, escaping is handled (`\\$` inside math). */\n  allowEscapes?: boolean;\n}): InlinePlugin {\n  const plugin: InlinePlugin = {\n    name: opts.name,\n    match(text, pos) {\n      if (!text.startsWith(opts.open, pos)) return null;\n      const start = pos + opts.open.length;\n      let i = start;\n      while (i < text.length) {\n        if (opts.allowEscapes && text[i] === \"\\\\\" && i + 1 < text.length) {\n          i += 2;\n          continue;\n        }\n        if (text.startsWith(opts.close, i)) {\n          const inner = text.slice(start, i);\n          return {\n            consumed: i + opts.close.length - pos,\n            token: { type: opts.tokenType, content: inner },\n          };\n        }\n        if (text[i] === \"\\n\") return null;\n        i++;\n      }\n      return null;\n    },\n  };\n  if (opts.triggers !== undefined) plugin.triggers = opts.triggers;\n  return plugin;\n}\n\n/**\n * Tiny helper for building block plugins that match a fenced block of the\n * form `OPENER ... CLOSER` (e.g. ```mermaid).\n */\nexport function fencedBlockPlugin(opts: {\n  name: string;\n  /** Regex matched against a single line to detect open. */\n  openLine: RegExp;\n  /** Regex matched against a line to detect close (default: blank line). */\n  closeLine?: RegExp;\n  blockType?: Block[\"type\"];\n  metaFromOpen?: (m: RegExpMatchArray) => Block[\"meta\"];\n  render: (block: Block) => unknown;\n}): BlockPlugin {\n  return {\n    name: opts.name,\n    openMatch(line) {\n      const m = line.match(opts.openLine);\n      if (!m) return null;\n      return {\n        type: opts.blockType ?? \"custom\",\n        content: \"\",\n        meta: { pluginName: opts.name, ...(opts.metaFromOpen?.(m) ?? {}) },\n      };\n    },\n    isClose(line) {\n      const re = opts.closeLine;\n      return re ? re.test(line) : line.trim() === \"\";\n    },\n    render: opts.render as BlockPlugin[\"render\"],\n  };\n}\n"]}