@mdit/plugin-embed
Advanced tools
| (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.mdItPluginEmbed={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=/\\{%/g,n=/%\\}/g,r=(e,t)=>{if(e.charCodeAt(t)!==123||e.charCodeAt(t+1)!==37)return!1;let n=t-1,r=0;for(;n>=0&&e.charCodeAt(n)===92;)r++,n--;return r%2!=1},i=(e,t)=>e.charCodeAt(t)===37&&e.charCodeAt(t+1)===125,a=e=>(a,o)=>{let s=a.md.utils.isSpace,c=a.pos,l=a.src.length;if(l-c<5||!r(a.src,c))return!1;let u=c+2;for(;u<l&&s(a.src.charCodeAt(u));)u++;let d=u,f=!1;for(;d+1<l;d++){if(r(a.src,d))return!1;if(i(a.src,d)){f=!0;break}}if(!f)return!1;let p=u+1;for(;p<d&&!s(a.src.charCodeAt(p));)p++;let m=a.src.slice(u,p);if(!e.has(m))return!1;if(!o){let e=a.push(`embed_inline`,`embed`,0),r=p<d?a.src.slice(p+1,d).trim().replaceAll(t,`{%`).replaceAll(n,`%}`):``;e.markup=`{% %}`,e.info=m,e.content=r}return a.pos=d+2,!0},o=e=>(a,o,s,c)=>{let l=a.md.utils.isSpace,u=a.bMarks[o]+a.tShift[o],d=a.eMarks[o],f=a.src;if(d-u<5||a.src.charCodeAt(u)!==123||a.src.charCodeAt(u+1)!==37)return!1;d=a.skipSpacesBack(d,u);let p=d-2;if(!i(f,p))return!1;let m=u+2;for(;m<p&&l(a.src.charCodeAt(m));)m++;let h=-1;for(let e=m;e+1<p;e++){if(r(a.src,e)||i(a.src,e))return!1;h===-1&&l(a.src.charCodeAt(e))&&(h=e)}let g=h===-1?a.src.slice(m,p).trimEnd():a.src.slice(m,h);if(!e.has(g)||h===-1&&e.get(g).allowInline)return!1;if(c)return!0;let _=h===-1?``:a.src.slice(h+1,p).trim().replaceAll(t,`{%`).replaceAll(n,`%}`),v=a.push(`embed_block`,`embed`,0);return v.block=!0,v.info=g,v.content=_,v.map=[o,o+1],v.markup=`{% %}`,a.line=o+1,!0};e.embed=(e,t)=>{if(typeof t!=`object`||!Array.isArray(t.config))throw TypeError(`[@mdit/plugin-embed]: config is required and must be an array.`);let n=e,r=n.__embedMap??=new Map,i=n.__inlineEmbedMap??=new Map;t.config.forEach(e=>{r.set(e.name,e),e.allowInline&&i.set(e.name,e)}),`embed_block`in e.renderer.rules||(e.block.ruler.before(`paragraph`,`embed_block`,o(r),{alt:[`paragraph`,`reference`,`blockquote`,`list`]}),e.renderer.rules.embed_block=(e,t)=>{let n=e[t];return r.get(n.info).setup(n.content,!1)}),i.size>0&&!(`embed_inline`in e.renderer.rules)&&(e.inline.ruler.before(`emphasis`,`embed_inline`,a(i)),e.renderer.rules.embed_inline=(e,t)=>{let n=e[t];return i.get(n.info).setup(n.content,!0)})}}); | ||
| //# sourceMappingURL=cdn.umd.js.map |
| {"version":3,"file":"cdn.umd.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type MarkdownIt from \"markdown-it\";\nimport type { PluginWithOptions } from \"markdown-it\";\nimport type { RuleBlock } from \"markdown-it/lib/parser_block.mjs\";\nimport type { RuleInline } from \"markdown-it/lib/parser_inline.mjs\";\nimport type Token from \"markdown-it/lib/token.mjs\";\n\nimport type { EmbedConfig, MarkdownItEmbedOptions } from \"./options.js\";\n\nconst ESCAPED_OPENING_MARKER_REGEXP = /\\\\{%/g;\nconst ESCAPED_CLOSING_MARKER_REGEXP = /%\\\\}/g;\n\nconst checkInlineOpeningMarker = (src: string, current: number): boolean => {\n if (src.charCodeAt(current) !== 123 /* { */ || src.charCodeAt(current + 1) !== 37 /* % */)\n return false;\n\n // Check if the opening marker was escaped\n let pos = current - 1;\n let backslashCount = 0;\n\n while (pos >= 0 && src.charCodeAt(pos) === 92 /* \\ */) {\n backslashCount++;\n pos--;\n }\n\n // If opening {% is escaped (odd number of preceding backslashes), don't parse\n if (backslashCount % 2 === 1) return false;\n\n return true;\n};\n\nconst checkClosingMarker = (src: string, current: number): boolean =>\n src.charCodeAt(current) === 37 /* % */ && src.charCodeAt(current + 1) === 125; /* } */\n\n/*\n * Parse inline embed with bracket syntax: {%...%}\n */\nconst createInlineEmbedRule =\n (inlineEmbedMap: Map<string, EmbedConfig>): RuleInline =>\n (state, silent) => {\n const isSpace = state.md.utils.isSpace;\n const start = state.pos;\n const max = state.src.length;\n\n // minimum length check for inline embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (!checkInlineOpeningMarker(state.src, start)) return false;\n\n let contentStart = start + 2; // Move past the opening {% marker\n\n // skip spaces\n while (contentStart < max) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let contentEnd = contentStart;\n let found = false;\n\n for (; contentEnd + 1 < max; contentEnd++) {\n // must not include opening marker\n if (checkInlineOpeningMarker(state.src, contentEnd)) return false;\n\n if (checkClosingMarker(state.src, contentEnd)) {\n found = true;\n break;\n }\n }\n\n // No closing marker found\n if (!found) return false;\n\n // get first space\n let spacer = contentStart + 1;\n\n while (spacer < contentEnd) {\n if (isSpace(state.src.charCodeAt(spacer))) break;\n\n spacer++;\n }\n\n // Extract embed name\n const name = state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!inlineEmbedMap.has(name)) return false;\n\n if (!silent) {\n const token = state.push(\"embed_inline\", \"embed\", 0);\n const params =\n spacer < contentEnd\n ? state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\")\n : \"\";\n\n token.markup = \"{% %}\";\n token.info = name;\n token.content = params;\n }\n // Move past the closing %} marker\n state.pos = contentEnd + 2;\n\n return true;\n };\n\n/*\n * Parse block embed with syntax: {% ... %}\n */\nconst createBlockEmbedRule =\n (embedMap: Map<string, EmbedConfig>): RuleBlock =>\n (state, startLine, _, silent) => {\n const isSpace = state.md.utils.isSpace;\n const start = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n const src = state.src;\n\n // minimum length check for block embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (\n state.src.charCodeAt(start) !== 123 /* { */ ||\n state.src.charCodeAt(start + 1) !== 37 /* % */\n )\n return false;\n\n max = state.skipSpacesBack(max, start);\n\n const contentEnd = max - 2;\n\n if (!checkClosingMarker(src, contentEnd)) return false;\n\n let contentStart = start + 2;\n\n // skip spaces\n while (contentStart < contentEnd) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let spacer = -1;\n\n for (let pos = contentStart; pos + 1 < contentEnd; pos++) {\n // must not include unescaped opening marker or closing marker\n if (checkInlineOpeningMarker(state.src, pos)) return false;\n\n if (checkClosingMarker(state.src, pos)) return false;\n\n if (spacer !== -1) continue;\n\n if (isSpace(state.src.charCodeAt(pos))) spacer = pos;\n }\n\n // Extract content between {% and %}\n const name =\n spacer === -1\n ? state.src.slice(contentStart, contentEnd).trimEnd()\n : state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!embedMap.has(name)) return false;\n\n // Fallback to inline if it's an inline-allowed embed without params\n // oxlint-disable-next-line typescript/no-non-null-assertion\n if (spacer === -1 && embedMap.get(name)!.allowInline) return false;\n\n if (silent) return true;\n\n const params =\n spacer === -1\n ? \"\"\n : state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\");\n\n const token = state.push(\"embed_block\", \"embed\", 0);\n\n token.block = true;\n token.info = name;\n token.content = params;\n token.map = [startLine, startLine + 1];\n token.markup = \"{% %}\";\n\n // Advance to the next line\n state.line = startLine + 1;\n\n return true;\n };\n\nexport const embed: PluginWithOptions<MarkdownItEmbedOptions> = (md, options) => {\n if (typeof options !== \"object\" || !Array.isArray(options.config))\n throw new TypeError(\"[@mdit/plugin-embed]: config is required and must be an array.\");\n\n // Get existing maps or create new ones to support multiple plugin instances\n const mdWithMaps = md as MarkdownIt & {\n __embedMap?: Map<string, EmbedConfig>;\n __inlineEmbedMap?: Map<string, EmbedConfig>;\n };\n\n const embedMap = (mdWithMaps.__embedMap ??= new Map<string, EmbedConfig>());\n const inlineEmbedMap = (mdWithMaps.__inlineEmbedMap ??= new Map<string, EmbedConfig>());\n\n options.config.forEach((item) => {\n embedMap.set(item.name, item);\n // Inline embeds are only supported when allowInline is true\n if (item.allowInline) inlineEmbedMap.set(item.name, item);\n });\n\n // Only register rules if not already registered\n // check embed_block rules here\n if (!(\"embed_block\" in md.renderer.rules)) {\n // Register the block rule\n md.block.ruler.before(\"paragraph\", \"embed_block\", createBlockEmbedRule(embedMap), {\n alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"],\n });\n\n // Register the renderers\n md.renderer.rules.embed_block = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return embedMap.get(token.info)!.setup(token.content, false);\n };\n }\n\n // only register embed_inline rules if inline embeds are allowed\n if (inlineEmbedMap.size > 0 && !(\"embed_inline\" in md.renderer.rules)) {\n // Register the inline rule\n md.inline.ruler.before(\"emphasis\", \"embed_inline\", createInlineEmbedRule(inlineEmbedMap));\n\n md.renderer.rules.embed_inline = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return inlineEmbedMap.get(token.info)!.setup(token.content, true);\n };\n }\n};\n"],"mappings":"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"} |
| import { PluginWithOptions } from "markdown-it"; | ||
| //#region src/options.d.ts | ||
| interface EmbedConfig { | ||
| /** | ||
| * Embed token name | ||
| * | ||
| * 嵌入令牌名称 | ||
| */ | ||
| name: string; | ||
| /** | ||
| * Setup function to generate embed HTML | ||
| * | ||
| * 生成嵌入 HTML 的设置函数 | ||
| */ | ||
| setup: (ref: string, isInline: boolean) => string; | ||
| /** | ||
| * Whether the embed can be used inline | ||
| * | ||
| * 是否允许在行内使用 | ||
| * | ||
| * @default false | ||
| */ | ||
| allowInline?: boolean; | ||
| } | ||
| interface MarkdownItEmbedOptions { | ||
| /** | ||
| * Embed configurations | ||
| * | ||
| * 嵌入配置 | ||
| */ | ||
| config?: EmbedConfig[]; | ||
| } | ||
| //#endregion | ||
| //#region src/plugin.d.ts | ||
| declare const embed: PluginWithOptions<MarkdownItEmbedOptions>; | ||
| //#endregion | ||
| export { EmbedConfig, MarkdownItEmbedOptions, embed }; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/options.ts","../src/plugin.ts"],"mappings":";;;UAAiB,WAAA;;;AAAjB;;;EAME,IAAA;;;;;;EAOA,KAAA,GAAQ,GAAA,UAAa,QAAA;EASrB;AAGF;;;;;;EAHE,WAAA;AAAA;AAAA,UAGe,sBAAA;EC4KqB;;;;;EDtKpC,MAAA,GAAS,WAAA;AAAA;;;cCsKE,KAAA,EAAO,iBAAA,CAAkB,sBAAA"} |
| const e=/\\{%/g,t=/%\\}/g,n=(e,t)=>{if(e.charCodeAt(t)!==123||e.charCodeAt(t+1)!==37)return!1;let n=t-1,r=0;for(;n>=0&&e.charCodeAt(n)===92;)r++,n--;return r%2!=1},r=(e,t)=>e.charCodeAt(t)===37&&e.charCodeAt(t+1)===125,i=i=>(a,o)=>{let s=a.md.utils.isSpace,c=a.pos,l=a.src.length;if(l-c<5||!n(a.src,c))return!1;let u=c+2;for(;u<l&&s(a.src.charCodeAt(u));)u++;let d=u,f=!1;for(;d+1<l;d++){if(n(a.src,d))return!1;if(r(a.src,d)){f=!0;break}}if(!f)return!1;let p=u+1;for(;p<d&&!s(a.src.charCodeAt(p));)p++;let m=a.src.slice(u,p);if(!i.has(m))return!1;if(!o){let n=a.push(`embed_inline`,`embed`,0),r=p<d?a.src.slice(p+1,d).trim().replaceAll(e,`{%`).replaceAll(t,`%}`):``;n.markup=`{% %}`,n.info=m,n.content=r}return a.pos=d+2,!0},a=i=>(a,o,s,c)=>{let l=a.md.utils.isSpace,u=a.bMarks[o]+a.tShift[o],d=a.eMarks[o],f=a.src;if(d-u<5||a.src.charCodeAt(u)!==123||a.src.charCodeAt(u+1)!==37)return!1;d=a.skipSpacesBack(d,u);let p=d-2;if(!r(f,p))return!1;let m=u+2;for(;m<p&&l(a.src.charCodeAt(m));)m++;let h=-1;for(let e=m;e+1<p;e++){if(n(a.src,e)||r(a.src,e))return!1;h===-1&&l(a.src.charCodeAt(e))&&(h=e)}let g=h===-1?a.src.slice(m,p).trimEnd():a.src.slice(m,h);if(!i.has(g)||h===-1&&i.get(g).allowInline)return!1;if(c)return!0;let _=h===-1?``:a.src.slice(h+1,p).trim().replaceAll(e,`{%`).replaceAll(t,`%}`),v=a.push(`embed_block`,`embed`,0);return v.block=!0,v.info=g,v.content=_,v.map=[o,o+1],v.markup=`{% %}`,a.line=o+1,!0},o=(e,t)=>{if(typeof t!=`object`||!Array.isArray(t.config))throw TypeError(`[@mdit/plugin-embed]: config is required and must be an array.`);let n=e,r=n.__embedMap??=new Map,o=n.__inlineEmbedMap??=new Map;t.config.forEach(e=>{r.set(e.name,e),e.allowInline&&o.set(e.name,e)}),`embed_block`in e.renderer.rules||(e.block.ruler.before(`paragraph`,`embed_block`,a(r),{alt:[`paragraph`,`reference`,`blockquote`,`list`]}),e.renderer.rules.embed_block=(e,t)=>{let n=e[t];return r.get(n.info).setup(n.content,!1)}),o.size>0&&!(`embed_inline`in e.renderer.rules)&&(e.inline.ruler.before(`emphasis`,`embed_inline`,i(o)),e.renderer.rules.embed_inline=(e,t)=>{let n=e[t];return o.get(n.info).setup(n.content,!0)})};export{o as embed}; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type MarkdownIt from \"markdown-it\";\nimport type { PluginWithOptions } from \"markdown-it\";\nimport type { RuleBlock } from \"markdown-it/lib/parser_block.mjs\";\nimport type { RuleInline } from \"markdown-it/lib/parser_inline.mjs\";\nimport type Token from \"markdown-it/lib/token.mjs\";\n\nimport type { EmbedConfig, MarkdownItEmbedOptions } from \"./options.js\";\n\nconst ESCAPED_OPENING_MARKER_REGEXP = /\\\\{%/g;\nconst ESCAPED_CLOSING_MARKER_REGEXP = /%\\\\}/g;\n\nconst checkInlineOpeningMarker = (src: string, current: number): boolean => {\n if (src.charCodeAt(current) !== 123 /* { */ || src.charCodeAt(current + 1) !== 37 /* % */)\n return false;\n\n // Check if the opening marker was escaped\n let pos = current - 1;\n let backslashCount = 0;\n\n while (pos >= 0 && src.charCodeAt(pos) === 92 /* \\ */) {\n backslashCount++;\n pos--;\n }\n\n // If opening {% is escaped (odd number of preceding backslashes), don't parse\n if (backslashCount % 2 === 1) return false;\n\n return true;\n};\n\nconst checkClosingMarker = (src: string, current: number): boolean =>\n src.charCodeAt(current) === 37 /* % */ && src.charCodeAt(current + 1) === 125; /* } */\n\n/*\n * Parse inline embed with bracket syntax: {%...%}\n */\nconst createInlineEmbedRule =\n (inlineEmbedMap: Map<string, EmbedConfig>): RuleInline =>\n (state, silent) => {\n const isSpace = state.md.utils.isSpace;\n const start = state.pos;\n const max = state.src.length;\n\n // minimum length check for inline embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (!checkInlineOpeningMarker(state.src, start)) return false;\n\n let contentStart = start + 2; // Move past the opening {% marker\n\n // skip spaces\n while (contentStart < max) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let contentEnd = contentStart;\n let found = false;\n\n for (; contentEnd + 1 < max; contentEnd++) {\n // must not include opening marker\n if (checkInlineOpeningMarker(state.src, contentEnd)) return false;\n\n if (checkClosingMarker(state.src, contentEnd)) {\n found = true;\n break;\n }\n }\n\n // No closing marker found\n if (!found) return false;\n\n // get first space\n let spacer = contentStart + 1;\n\n while (spacer < contentEnd) {\n if (isSpace(state.src.charCodeAt(spacer))) break;\n\n spacer++;\n }\n\n // Extract embed name\n const name = state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!inlineEmbedMap.has(name)) return false;\n\n if (!silent) {\n const token = state.push(\"embed_inline\", \"embed\", 0);\n const params =\n spacer < contentEnd\n ? state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\")\n : \"\";\n\n token.markup = \"{% %}\";\n token.info = name;\n token.content = params;\n }\n // Move past the closing %} marker\n state.pos = contentEnd + 2;\n\n return true;\n };\n\n/*\n * Parse block embed with syntax: {% ... %}\n */\nconst createBlockEmbedRule =\n (embedMap: Map<string, EmbedConfig>): RuleBlock =>\n (state, startLine, _, silent) => {\n const isSpace = state.md.utils.isSpace;\n const start = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n const src = state.src;\n\n // minimum length check for block embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (\n state.src.charCodeAt(start) !== 123 /* { */ ||\n state.src.charCodeAt(start + 1) !== 37 /* % */\n )\n return false;\n\n max = state.skipSpacesBack(max, start);\n\n const contentEnd = max - 2;\n\n if (!checkClosingMarker(src, contentEnd)) return false;\n\n let contentStart = start + 2;\n\n // skip spaces\n while (contentStart < contentEnd) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let spacer = -1;\n\n for (let pos = contentStart; pos + 1 < contentEnd; pos++) {\n // must not include unescaped opening marker or closing marker\n if (checkInlineOpeningMarker(state.src, pos)) return false;\n\n if (checkClosingMarker(state.src, pos)) return false;\n\n if (spacer !== -1) continue;\n\n if (isSpace(state.src.charCodeAt(pos))) spacer = pos;\n }\n\n // Extract content between {% and %}\n const name =\n spacer === -1\n ? state.src.slice(contentStart, contentEnd).trimEnd()\n : state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!embedMap.has(name)) return false;\n\n // Fallback to inline if it's an inline-allowed embed without params\n // oxlint-disable-next-line typescript/no-non-null-assertion\n if (spacer === -1 && embedMap.get(name)!.allowInline) return false;\n\n if (silent) return true;\n\n const params =\n spacer === -1\n ? \"\"\n : state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\");\n\n const token = state.push(\"embed_block\", \"embed\", 0);\n\n token.block = true;\n token.info = name;\n token.content = params;\n token.map = [startLine, startLine + 1];\n token.markup = \"{% %}\";\n\n // Advance to the next line\n state.line = startLine + 1;\n\n return true;\n };\n\nexport const embed: PluginWithOptions<MarkdownItEmbedOptions> = (md, options) => {\n if (typeof options !== \"object\" || !Array.isArray(options.config))\n throw new TypeError(\"[@mdit/plugin-embed]: config is required and must be an array.\");\n\n // Get existing maps or create new ones to support multiple plugin instances\n const mdWithMaps = md as MarkdownIt & {\n __embedMap?: Map<string, EmbedConfig>;\n __inlineEmbedMap?: Map<string, EmbedConfig>;\n };\n\n const embedMap = (mdWithMaps.__embedMap ??= new Map<string, EmbedConfig>());\n const inlineEmbedMap = (mdWithMaps.__inlineEmbedMap ??= new Map<string, EmbedConfig>());\n\n options.config.forEach((item) => {\n embedMap.set(item.name, item);\n // Inline embeds are only supported when allowInline is true\n if (item.allowInline) inlineEmbedMap.set(item.name, item);\n });\n\n // Only register rules if not already registered\n // check embed_block rules here\n if (!(\"embed_block\" in md.renderer.rules)) {\n // Register the block rule\n md.block.ruler.before(\"paragraph\", \"embed_block\", createBlockEmbedRule(embedMap), {\n alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"],\n });\n\n // Register the renderers\n md.renderer.rules.embed_block = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return embedMap.get(token.info)!.setup(token.content, false);\n };\n }\n\n // only register embed_inline rules if inline embeds are allowed\n if (inlineEmbedMap.size > 0 && !(\"embed_inline\" in md.renderer.rules)) {\n // Register the inline rule\n md.inline.ruler.before(\"emphasis\", \"embed_inline\", createInlineEmbedRule(inlineEmbedMap));\n\n md.renderer.rules.embed_inline = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return inlineEmbedMap.get(token.info)!.setup(token.content, true);\n };\n }\n};\n"],"mappings":"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"} |
+8
-8
| { | ||
| "name": "@mdit/plugin-embed", | ||
| "version": "0.24.1", | ||
| "version": "0.25.0", | ||
| "description": "embed plugin for MarkdownIt", | ||
@@ -26,11 +26,11 @@ "keywords": [ | ||
| "files": [ | ||
| "lib" | ||
| "dist" | ||
| ], | ||
| "type": "module", | ||
| "browser": "./lib/browser.js", | ||
| "types": "./lib/index.d.ts", | ||
| "unpkg": "./dist/cdn.umd.js", | ||
| "jsdelivr": "./dist/cdn.umd.js", | ||
| "exports": { | ||
| ".": { | ||
| "type": "./lib/index.d.ts", | ||
| "default": "./lib/index.js" | ||
| "types": "./dist/index.d.ts", | ||
| "default": "./dist/index.js" | ||
| }, | ||
@@ -54,8 +54,8 @@ "./package.json": "./package.json" | ||
| "engines": { | ||
| "node": ">= 18" | ||
| "node": ">= 20" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsdown --config-loader unrun", | ||
| "clean": "rimraf ./lib" | ||
| "clean": "rimraf ./dist" | ||
| } | ||
| } |
| function e(e){switch(e){case 9:case 32:return!0}return!1}const t=/\\{%/g,n=/%\\}/g,r=(e,t)=>{if(e.charCodeAt(t)!==123||e.charCodeAt(t+1)!==37)return!1;let n=t-1,r=0;for(;n>=0&&e.charCodeAt(n)===92;)r++,n--;return r%2!=1},i=(e,t)=>e.charCodeAt(t)===37&&e.charCodeAt(t+1)===125,a=a=>(o,s)=>{let c=o.pos,l=o.src.length;if(l-c<5||!r(o.src,c))return!1;let u=c+2;for(;u<l&&e(o.src.charCodeAt(u));)u++;let d=u,f=!1;for(;d+1<l;d++){if(r(o.src,d))return!1;if(i(o.src,d)){f=!0;break}}if(!f)return!1;let p=u+1;for(;p<d&&!e(o.src.charCodeAt(p));)p++;let m=o.src.slice(u,p);if(!a.has(m))return!1;if(!s){let e=o.push(`embed_inline`,`embed`,0),r=p?o.src.slice(p+1,d).trim().replaceAll(t,`{%`).replaceAll(n,`%}`):``;e.markup=`{% %}`,e.info=m,e.content=r}return o.pos=d+2,!0},o=a=>(o,s,c,l)=>{let u=o.bMarks[s]+o.tShift[s],d=o.eMarks[s],f=o.src;if(d-u<5||o.src.charCodeAt(u)!==123||o.src.charCodeAt(u+1)!==37)return!1;d=o.skipSpacesBack(d,u);let p=d-2;if(!i(f,p))return!1;let m=u+2;for(;m<p&&e(o.src.charCodeAt(m));)m++;let h=-1;for(let t=m;t+1<p;t++){if(r(o.src,t)||i(o.src,t))return!1;h===-1&&e(o.src.charCodeAt(t))&&(h=t)}let g=h===-1?o.src.slice(m,p+1).trimEnd():o.src.slice(m,h);if(!a.has(g))return!1;if(l)return!0;let _=h===-1?``:o.src.slice(h+1,p).trim().replaceAll(t,`{%`).replaceAll(n,`%}`),v=o.push(`embed_block`,`embed`,0);return v.block=!0,v.info=g,v.content=_,v.map=[s,s+1],v.markup=`{% %}`,o.line=s+1,!0},s=(e,t)=>{if(typeof t!=`object`||!Array.isArray(t.config))throw TypeError(`[@mdit/plugin-embed]: config is required and must be an array.`);let n=e,r=n.__embedMap??=new Map,i=n.__inlineEmbedMap??=new Map;t.config.forEach(e=>{r.set(e.name,e),e.allowInline&&i.set(e.name,e)}),`embed_block`in e.renderer.rules||(e.block.ruler.before(`paragraph`,`embed_block`,o(r),{alt:[`paragraph`,`reference`,`blockquote`,`list`]}),e.renderer.rules.embed_block=(e,t)=>{let n=e[t];return r.get(n.info).setup(n.content,!1)}),i.size>0&&!(`embed_inline`in e.renderer.rules)&&(e.inline.ruler.before(`emphasis`,`embed_inline`,a(i)),e.renderer.rules.embed_inline=(e,t)=>{let n=e[t];return i.get(n.info).setup(n.content,!0)})};export{s as embed}; | ||
| //# sourceMappingURL=browser.js.map |
| {"version":3,"file":"browser.js","names":[],"sources":["../../../node_modules/.pnpm/markdown-it@14.1.0/node_modules/markdown-it/lib/common/utils.mjs","../src/plugin.ts"],"sourcesContent":["// Utilities\n//\n\nimport * as mdurl from 'mdurl'\nimport * as ucmicro from 'uc.micro'\nimport { decodeHTML } from 'entities'\n\nfunction _class (obj) { return Object.prototype.toString.call(obj) }\n\nfunction isString (obj) { return _class(obj) === '[object String]' }\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty\n\nfunction has (object, key) {\n return _hasOwnProperty.call(object, key)\n}\n\n// Merge objects\n//\nfunction assign (obj /* from1, from2, from3, ... */) {\n const sources = Array.prototype.slice.call(arguments, 1)\n\n sources.forEach(function (source) {\n if (!source) { return }\n\n if (typeof source !== 'object') {\n throw new TypeError(source + 'must be object')\n }\n\n Object.keys(source).forEach(function (key) {\n obj[key] = source[key]\n })\n })\n\n return obj\n}\n\n// Remove element from array and put another array at those position.\n// Useful for some operations with tokens\nfunction arrayReplaceAt (src, pos, newElements) {\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1))\n}\n\nfunction isValidEntityCode (c) {\n /* eslint no-bitwise:0 */\n // broken sequence\n if (c >= 0xD800 && c <= 0xDFFF) { return false }\n // never used\n if (c >= 0xFDD0 && c <= 0xFDEF) { return false }\n if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false }\n // control codes\n if (c >= 0x00 && c <= 0x08) { return false }\n if (c === 0x0B) { return false }\n if (c >= 0x0E && c <= 0x1F) { return false }\n if (c >= 0x7F && c <= 0x9F) { return false }\n // out of range\n if (c > 0x10FFFF) { return false }\n return true\n}\n\nfunction fromCodePoint (c) {\n /* eslint no-bitwise:0 */\n if (c > 0xffff) {\n c -= 0x10000\n const surrogate1 = 0xd800 + (c >> 10)\n const surrogate2 = 0xdc00 + (c & 0x3ff)\n\n return String.fromCharCode(surrogate1, surrogate2)\n }\n return String.fromCharCode(c)\n}\n\nconst UNESCAPE_MD_RE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g\nconst ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi\nconst UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi')\n\nconst DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))$/i\n\nfunction replaceEntityPattern (match, name) {\n if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {\n const code = name[1].toLowerCase() === 'x'\n ? parseInt(name.slice(2), 16)\n : parseInt(name.slice(1), 10)\n\n if (isValidEntityCode(code)) {\n return fromCodePoint(code)\n }\n\n return match\n }\n\n const decoded = decodeHTML(match)\n if (decoded !== match) {\n return decoded\n }\n\n return match\n}\n\n/* function replaceEntities(str) {\n if (str.indexOf('&') < 0) { return str; }\n\n return str.replace(ENTITY_RE, replaceEntityPattern);\n} */\n\nfunction unescapeMd (str) {\n if (str.indexOf('\\\\') < 0) { return str }\n return str.replace(UNESCAPE_MD_RE, '$1')\n}\n\nfunction unescapeAll (str) {\n if (str.indexOf('\\\\') < 0 && str.indexOf('&') < 0) { return str }\n\n return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {\n if (escaped) { return escaped }\n return replaceEntityPattern(match, entity)\n })\n}\n\nconst HTML_ESCAPE_TEST_RE = /[&<>\"]/\nconst HTML_ESCAPE_REPLACE_RE = /[&<>\"]/g\nconst HTML_REPLACEMENTS = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"'\n}\n\nfunction replaceUnsafeChar (ch) {\n return HTML_REPLACEMENTS[ch]\n}\n\nfunction escapeHtml (str) {\n if (HTML_ESCAPE_TEST_RE.test(str)) {\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar)\n }\n return str\n}\n\nconst REGEXP_ESCAPE_RE = /[.?*+^$[\\]\\\\(){}|-]/g\n\nfunction escapeRE (str) {\n return str.replace(REGEXP_ESCAPE_RE, '\\\\$&')\n}\n\nfunction isSpace (code) {\n switch (code) {\n case 0x09:\n case 0x20:\n return true\n }\n return false\n}\n\n// Zs (unicode class) || [\\t\\f\\v\\r\\n]\nfunction isWhiteSpace (code) {\n if (code >= 0x2000 && code <= 0x200A) { return true }\n switch (code) {\n case 0x09: // \\t\n case 0x0A: // \\n\n case 0x0B: // \\v\n case 0x0C: // \\f\n case 0x0D: // \\r\n case 0x20:\n case 0xA0:\n case 0x1680:\n case 0x202F:\n case 0x205F:\n case 0x3000:\n return true\n }\n return false\n}\n\n/* eslint-disable max-len */\n\n// Currently without astral characters support.\nfunction isPunctChar (ch) {\n return ucmicro.P.test(ch) || ucmicro.S.test(ch)\n}\n\n// Markdown ASCII punctuation characters.\n//\n// !, \", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\, ], ^, _, `, {, |, }, or ~\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\n//\n// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.\n//\nfunction isMdAsciiPunct (ch) {\n switch (ch) {\n case 0x21/* ! */:\n case 0x22/* \" */:\n case 0x23/* # */:\n case 0x24/* $ */:\n case 0x25/* % */:\n case 0x26/* & */:\n case 0x27/* ' */:\n case 0x28/* ( */:\n case 0x29/* ) */:\n case 0x2A/* * */:\n case 0x2B/* + */:\n case 0x2C/* , */:\n case 0x2D/* - */:\n case 0x2E/* . */:\n case 0x2F/* / */:\n case 0x3A/* : */:\n case 0x3B/* ; */:\n case 0x3C/* < */:\n case 0x3D/* = */:\n case 0x3E/* > */:\n case 0x3F/* ? */:\n case 0x40/* @ */:\n case 0x5B/* [ */:\n case 0x5C/* \\ */:\n case 0x5D/* ] */:\n case 0x5E/* ^ */:\n case 0x5F/* _ */:\n case 0x60/* ` */:\n case 0x7B/* { */:\n case 0x7C/* | */:\n case 0x7D/* } */:\n case 0x7E/* ~ */:\n return true\n default:\n return false\n }\n}\n\n// Hepler to unify [reference labels].\n//\nfunction normalizeReference (str) {\n // Trim and collapse whitespace\n //\n str = str.trim().replace(/\\s+/g, ' ')\n\n // In node v10 'ẞ'.toLowerCase() === 'Ṿ', which is presumed to be a bug\n // fixed in v12 (couldn't find any details).\n //\n // So treat this one as a special case\n // (remove this when node v10 is no longer supported).\n //\n if ('ẞ'.toLowerCase() === 'Ṿ') {\n str = str.replace(/ẞ/g, 'ß')\n }\n\n // .toLowerCase().toUpperCase() should get rid of all differences\n // between letter variants.\n //\n // Simple .toLowerCase() doesn't normalize 125 code points correctly,\n // and .toUpperCase doesn't normalize 6 of them (list of exceptions:\n // İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently\n // uppercased versions).\n //\n // Here's an example showing how it happens. Lets take greek letter omega:\n // uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)\n //\n // Unicode entries:\n // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\n // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\n // 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\n // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;\n //\n // Case-insensitive comparison should treat all of them as equivalent.\n //\n // But .toLowerCase() doesn't change ϑ (it's already lowercase),\n // and .toUpperCase() doesn't change ϴ (already uppercase).\n //\n // Applying first lower then upper case normalizes any character:\n // '\\u0398\\u03f4\\u03b8\\u03d1'.toLowerCase().toUpperCase() === '\\u0398\\u0398\\u0398\\u0398'\n //\n // Note: this is equivalent to unicode case folding; unicode normalization\n // is a different step that is not required here.\n //\n // Final result should be uppercased, because it's later stored in an object\n // (this avoid a conflict with Object.prototype members,\n // most notably, `__proto__`)\n //\n return str.toLowerCase().toUpperCase()\n}\n\n// Re-export libraries commonly used in both markdown-it and its plugins,\n// so plugins won't have to depend on them explicitly, which reduces their\n// bundled size (e.g. a browser build).\n//\nconst lib = { mdurl, ucmicro }\n\nexport {\n lib,\n assign,\n isString,\n has,\n unescapeMd,\n unescapeAll,\n isValidEntityCode,\n fromCodePoint,\n escapeHtml,\n arrayReplaceAt,\n isSpace,\n isWhiteSpace,\n isMdAsciiPunct,\n isPunctChar,\n escapeRE,\n normalizeReference\n}\n","import type MarkdownIt from \"markdown-it\";\nimport type { PluginWithOptions } from \"markdown-it\";\nimport { isSpace } from \"markdown-it/lib/common/utils.mjs\";\nimport type { RuleBlock } from \"markdown-it/lib/parser_block.mjs\";\nimport type { RuleInline } from \"markdown-it/lib/parser_inline.mjs\";\nimport type Token from \"markdown-it/lib/token.mjs\";\n\nimport type { EmbedConfig, MarkdownItEmbedOptions } from \"./options.js\";\n\nconst ESCAPED_OPENING_MARKER_REGEXP = /\\\\{%/g;\nconst ESCAPED_CLOSING_MARKER_REGEXP = /%\\\\}/g;\n\nconst checkInlineOpeningMarker = (src: string, current: number): boolean => {\n if (src.charCodeAt(current) !== 123 /* { */ || src.charCodeAt(current + 1) !== 37 /* % */)\n return false;\n\n // Check if the opening marker was escaped\n let pos = current - 1;\n let backslashCount = 0;\n\n while (pos >= 0 && src.charCodeAt(pos) === 92 /* \\ */) {\n backslashCount++;\n pos--;\n }\n\n // If opening {% is escaped (odd number of preceding backslashes), don't parse\n if (backslashCount % 2 === 1) return false;\n\n return true;\n};\n\nconst checkClosingMarker = (src: string, current: number): boolean =>\n src.charCodeAt(current) === 37 /* % */ && src.charCodeAt(current + 1) === 125; /* } */\n\n/*\n * Parse inline embed with bracket syntax: {%...%}\n */\nconst getEmbedInline =\n (inlineEmbedMap: Map<string, EmbedConfig>): RuleInline =>\n (state, silent) => {\n const start = state.pos;\n const max = state.src.length;\n\n // minimum length check for inline embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (!checkInlineOpeningMarker(state.src, start)) return false;\n\n let contentStart = start + 2; // Move past the opening {% marker\n\n // skip spaces\n while (contentStart < max) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let contentEnd = contentStart;\n let found = false;\n\n for (; contentEnd + 1 < max; contentEnd++) {\n // must not include opening marker\n if (checkInlineOpeningMarker(state.src, contentEnd)) return false;\n\n if (checkClosingMarker(state.src, contentEnd)) {\n found = true;\n break;\n }\n }\n\n // No closing marker found\n if (!found) return false;\n\n // get first space\n let spacer = contentStart + 1;\n\n while (spacer < contentEnd) {\n if (isSpace(state.src.charCodeAt(spacer))) break;\n\n spacer++;\n }\n\n // Extract embed name\n const name = state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!inlineEmbedMap.has(name)) return false;\n\n if (!silent) {\n const token = state.push(\"embed_inline\", \"embed\", 0);\n const params = spacer\n ? state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\")\n : \"\";\n\n token.markup = \"{% %}\";\n token.info = name;\n token.content = params;\n }\n\n // Move past the closing %} marker\n state.pos = contentEnd + 2;\n\n return true;\n };\n\n/*\n * Parse block embed with syntax: {% ... %}\n */\nconst getEmbedBlock =\n (embedMap: Map<string, EmbedConfig>): RuleBlock =>\n (state, startLine, _, silent) => {\n const start = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n const src = state.src;\n\n // minimum length check for block embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (\n state.src.charCodeAt(start) !== 123 /* { */ ||\n state.src.charCodeAt(start + 1) !== 37 /* % */\n )\n return false;\n\n max = state.skipSpacesBack(max, start);\n\n const contentEnd = max - 2;\n\n if (!checkClosingMarker(src, contentEnd)) return false;\n\n let contentStart = start + 2;\n\n // skip spaces\n while (contentStart < contentEnd) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let spacer = -1;\n\n for (let pos = contentStart; pos + 1 < contentEnd; pos++) {\n // must not include unescaped opening marker or closing marker\n if (checkInlineOpeningMarker(state.src, pos)) return false;\n\n if (checkClosingMarker(state.src, pos)) return false;\n\n if (spacer !== -1) continue;\n\n if (isSpace(state.src.charCodeAt(pos))) spacer = pos;\n }\n\n // Extract content between {% and %}\n const name =\n spacer === -1\n ? state.src.slice(contentStart, contentEnd + 1).trimEnd()\n : state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!embedMap.has(name)) return false;\n\n if (silent) return true;\n\n const params =\n spacer === -1\n ? \"\"\n : state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\");\n\n const token = state.push(\"embed_block\", \"embed\", 0);\n\n token.block = true;\n token.info = name;\n token.content = params;\n token.map = [startLine, startLine + 1];\n token.markup = \"{% %}\";\n\n // Advance to the next line\n state.line = startLine + 1;\n\n return true;\n };\n\nexport const embed: PluginWithOptions<MarkdownItEmbedOptions> = (md, options) => {\n if (typeof options !== \"object\" || !Array.isArray(options.config))\n throw new TypeError(\"[@mdit/plugin-embed]: config is required and must be an array.\");\n\n // Get existing maps or create new ones to support multiple plugin instances\n const mdWithMaps = md as MarkdownIt & {\n // oxlint-disable-next-line typescript/naming-convention\n __embedMap?: Map<string, EmbedConfig>;\n // oxlint-disable-next-line typescript/naming-convention\n __inlineEmbedMap?: Map<string, EmbedConfig>;\n };\n\n const embedMap = (mdWithMaps.__embedMap ??= new Map<string, EmbedConfig>());\n const inlineEmbedMap = (mdWithMaps.__inlineEmbedMap ??= new Map<string, EmbedConfig>());\n\n options.config.forEach((item) => {\n embedMap.set(item.name, item);\n // Inline embeds are only supported when allowInline is true\n if (item.allowInline) inlineEmbedMap.set(item.name, item);\n });\n\n // Only register rules if not already registered\n // check embed_block rules here\n if (!(\"embed_block\" in md.renderer.rules)) {\n // Register the block rule\n md.block.ruler.before(\"paragraph\", \"embed_block\", getEmbedBlock(embedMap), {\n alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"],\n });\n\n // Register the renderers\n md.renderer.rules.embed_block = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return embedMap.get(token.info)!.setup(token.content, false);\n };\n }\n\n // only register embed_inline rules if inline embeds are allowed\n if (inlineEmbedMap.size > 0 && !(\"embed_inline\" in md.renderer.rules)) {\n // Register the inline rule\n md.inline.ruler.before(\"emphasis\", \"embed_inline\", getEmbedInline(inlineEmbedMap));\n\n md.renderer.rules.embed_inline = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return inlineEmbedMap.get(token.info)!.setup(token.content, true);\n };\n }\n};\n"],"x_google_ignoreList":[0],"mappings":"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"} |
| import { PluginWithOptions } from "markdown-it"; | ||
| //#region src/options.d.ts | ||
| interface EmbedConfig { | ||
| /** | ||
| * Embed token name | ||
| * | ||
| * 嵌入令牌名称 | ||
| */ | ||
| name: string; | ||
| /** | ||
| * Setup function to generate embed HTML | ||
| * | ||
| * 生成嵌入 HTML 的设置函数 | ||
| */ | ||
| setup: (ref: string, isInline: boolean) => string; | ||
| /** | ||
| * Whether the embed can be used inline | ||
| * | ||
| * 是否允许在行内使用 | ||
| * | ||
| * @default false | ||
| */ | ||
| allowInline?: boolean; | ||
| } | ||
| interface MarkdownItEmbedOptions { | ||
| /** | ||
| * Embed configurations | ||
| * | ||
| * 嵌入配置 | ||
| */ | ||
| config?: EmbedConfig[]; | ||
| } | ||
| //#endregion | ||
| //#region src/plugin.d.ts | ||
| declare const embed: PluginWithOptions<MarkdownItEmbedOptions>; | ||
| //#endregion | ||
| export { EmbedConfig, MarkdownItEmbedOptions, embed }; | ||
| //# sourceMappingURL=index.d.ts.map |
| import{isSpace as e}from"markdown-it/lib/common/utils.mjs";const t=/\\{%/g,n=/%\\}/g,r=(e,t)=>{if(e.charCodeAt(t)!==123||e.charCodeAt(t+1)!==37)return!1;let n=t-1,r=0;for(;n>=0&&e.charCodeAt(n)===92;)r++,n--;return r%2!=1},i=(e,t)=>e.charCodeAt(t)===37&&e.charCodeAt(t+1)===125,a=a=>(o,s)=>{let c=o.pos,l=o.src.length;if(l-c<5||!r(o.src,c))return!1;let u=c+2;for(;u<l&&e(o.src.charCodeAt(u));)u++;let d=u,f=!1;for(;d+1<l;d++){if(r(o.src,d))return!1;if(i(o.src,d)){f=!0;break}}if(!f)return!1;let p=u+1;for(;p<d&&!e(o.src.charCodeAt(p));)p++;let m=o.src.slice(u,p);if(!a.has(m))return!1;if(!s){let e=o.push(`embed_inline`,`embed`,0),r=p?o.src.slice(p+1,d).trim().replaceAll(t,`{%`).replaceAll(n,`%}`):``;e.markup=`{% %}`,e.info=m,e.content=r}return o.pos=d+2,!0},o=a=>(o,s,c,l)=>{let u=o.bMarks[s]+o.tShift[s],d=o.eMarks[s],f=o.src;if(d-u<5||o.src.charCodeAt(u)!==123||o.src.charCodeAt(u+1)!==37)return!1;d=o.skipSpacesBack(d,u);let p=d-2;if(!i(f,p))return!1;let m=u+2;for(;m<p&&e(o.src.charCodeAt(m));)m++;let h=-1;for(let t=m;t+1<p;t++){if(r(o.src,t)||i(o.src,t))return!1;h===-1&&e(o.src.charCodeAt(t))&&(h=t)}let g=h===-1?o.src.slice(m,p+1).trimEnd():o.src.slice(m,h);if(!a.has(g))return!1;if(l)return!0;let _=h===-1?``:o.src.slice(h+1,p).trim().replaceAll(t,`{%`).replaceAll(n,`%}`),v=o.push(`embed_block`,`embed`,0);return v.block=!0,v.info=g,v.content=_,v.map=[s,s+1],v.markup=`{% %}`,o.line=s+1,!0},s=(e,t)=>{if(typeof t!=`object`||!Array.isArray(t.config))throw TypeError(`[@mdit/plugin-embed]: config is required and must be an array.`);let n=e,r=n.__embedMap??=new Map,i=n.__inlineEmbedMap??=new Map;t.config.forEach(e=>{r.set(e.name,e),e.allowInline&&i.set(e.name,e)}),`embed_block`in e.renderer.rules||(e.block.ruler.before(`paragraph`,`embed_block`,o(r),{alt:[`paragraph`,`reference`,`blockquote`,`list`]}),e.renderer.rules.embed_block=(e,t)=>{let n=e[t];return r.get(n.info).setup(n.content,!1)}),i.size>0&&!(`embed_inline`in e.renderer.rules)&&(e.inline.ruler.before(`emphasis`,`embed_inline`,a(i)),e.renderer.rules.embed_inline=(e,t)=>{let n=e[t];return i.get(n.info).setup(n.content,!0)})};export{s as embed}; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import type MarkdownIt from \"markdown-it\";\nimport type { PluginWithOptions } from \"markdown-it\";\nimport { isSpace } from \"markdown-it/lib/common/utils.mjs\";\nimport type { RuleBlock } from \"markdown-it/lib/parser_block.mjs\";\nimport type { RuleInline } from \"markdown-it/lib/parser_inline.mjs\";\nimport type Token from \"markdown-it/lib/token.mjs\";\n\nimport type { EmbedConfig, MarkdownItEmbedOptions } from \"./options.js\";\n\nconst ESCAPED_OPENING_MARKER_REGEXP = /\\\\{%/g;\nconst ESCAPED_CLOSING_MARKER_REGEXP = /%\\\\}/g;\n\nconst checkInlineOpeningMarker = (src: string, current: number): boolean => {\n if (src.charCodeAt(current) !== 123 /* { */ || src.charCodeAt(current + 1) !== 37 /* % */)\n return false;\n\n // Check if the opening marker was escaped\n let pos = current - 1;\n let backslashCount = 0;\n\n while (pos >= 0 && src.charCodeAt(pos) === 92 /* \\ */) {\n backslashCount++;\n pos--;\n }\n\n // If opening {% is escaped (odd number of preceding backslashes), don't parse\n if (backslashCount % 2 === 1) return false;\n\n return true;\n};\n\nconst checkClosingMarker = (src: string, current: number): boolean =>\n src.charCodeAt(current) === 37 /* % */ && src.charCodeAt(current + 1) === 125; /* } */\n\n/*\n * Parse inline embed with bracket syntax: {%...%}\n */\nconst getEmbedInline =\n (inlineEmbedMap: Map<string, EmbedConfig>): RuleInline =>\n (state, silent) => {\n const start = state.pos;\n const max = state.src.length;\n\n // minimum length check for inline embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (!checkInlineOpeningMarker(state.src, start)) return false;\n\n let contentStart = start + 2; // Move past the opening {% marker\n\n // skip spaces\n while (contentStart < max) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let contentEnd = contentStart;\n let found = false;\n\n for (; contentEnd + 1 < max; contentEnd++) {\n // must not include opening marker\n if (checkInlineOpeningMarker(state.src, contentEnd)) return false;\n\n if (checkClosingMarker(state.src, contentEnd)) {\n found = true;\n break;\n }\n }\n\n // No closing marker found\n if (!found) return false;\n\n // get first space\n let spacer = contentStart + 1;\n\n while (spacer < contentEnd) {\n if (isSpace(state.src.charCodeAt(spacer))) break;\n\n spacer++;\n }\n\n // Extract embed name\n const name = state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!inlineEmbedMap.has(name)) return false;\n\n if (!silent) {\n const token = state.push(\"embed_inline\", \"embed\", 0);\n const params = spacer\n ? state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\")\n : \"\";\n\n token.markup = \"{% %}\";\n token.info = name;\n token.content = params;\n }\n\n // Move past the closing %} marker\n state.pos = contentEnd + 2;\n\n return true;\n };\n\n/*\n * Parse block embed with syntax: {% ... %}\n */\nconst getEmbedBlock =\n (embedMap: Map<string, EmbedConfig>): RuleBlock =>\n (state, startLine, _, silent) => {\n const start = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n const src = state.src;\n\n // minimum length check for block embed - at least 5 characters: {%x%}\n if (max - start < 5) return false;\n\n // check opening marker\n if (\n state.src.charCodeAt(start) !== 123 /* { */ ||\n state.src.charCodeAt(start + 1) !== 37 /* % */\n )\n return false;\n\n max = state.skipSpacesBack(max, start);\n\n const contentEnd = max - 2;\n\n if (!checkClosingMarker(src, contentEnd)) return false;\n\n let contentStart = start + 2;\n\n // skip spaces\n while (contentStart < contentEnd) {\n if (!isSpace(state.src.charCodeAt(contentStart))) break;\n\n contentStart++;\n }\n\n let spacer = -1;\n\n for (let pos = contentStart; pos + 1 < contentEnd; pos++) {\n // must not include unescaped opening marker or closing marker\n if (checkInlineOpeningMarker(state.src, pos)) return false;\n\n if (checkClosingMarker(state.src, pos)) return false;\n\n if (spacer !== -1) continue;\n\n if (isSpace(state.src.charCodeAt(pos))) spacer = pos;\n }\n\n // Extract content between {% and %}\n const name =\n spacer === -1\n ? state.src.slice(contentStart, contentEnd + 1).trimEnd()\n : state.src.slice(contentStart, spacer);\n\n // Check if embed name exists in the map\n if (!embedMap.has(name)) return false;\n\n if (silent) return true;\n\n const params =\n spacer === -1\n ? \"\"\n : state.src\n .slice(spacer + 1, contentEnd)\n .trim()\n .replaceAll(ESCAPED_OPENING_MARKER_REGEXP, \"{%\")\n .replaceAll(ESCAPED_CLOSING_MARKER_REGEXP, \"%}\");\n\n const token = state.push(\"embed_block\", \"embed\", 0);\n\n token.block = true;\n token.info = name;\n token.content = params;\n token.map = [startLine, startLine + 1];\n token.markup = \"{% %}\";\n\n // Advance to the next line\n state.line = startLine + 1;\n\n return true;\n };\n\nexport const embed: PluginWithOptions<MarkdownItEmbedOptions> = (md, options) => {\n if (typeof options !== \"object\" || !Array.isArray(options.config))\n throw new TypeError(\"[@mdit/plugin-embed]: config is required and must be an array.\");\n\n // Get existing maps or create new ones to support multiple plugin instances\n const mdWithMaps = md as MarkdownIt & {\n // oxlint-disable-next-line typescript/naming-convention\n __embedMap?: Map<string, EmbedConfig>;\n // oxlint-disable-next-line typescript/naming-convention\n __inlineEmbedMap?: Map<string, EmbedConfig>;\n };\n\n const embedMap = (mdWithMaps.__embedMap ??= new Map<string, EmbedConfig>());\n const inlineEmbedMap = (mdWithMaps.__inlineEmbedMap ??= new Map<string, EmbedConfig>());\n\n options.config.forEach((item) => {\n embedMap.set(item.name, item);\n // Inline embeds are only supported when allowInline is true\n if (item.allowInline) inlineEmbedMap.set(item.name, item);\n });\n\n // Only register rules if not already registered\n // check embed_block rules here\n if (!(\"embed_block\" in md.renderer.rules)) {\n // Register the block rule\n md.block.ruler.before(\"paragraph\", \"embed_block\", getEmbedBlock(embedMap), {\n alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"],\n });\n\n // Register the renderers\n md.renderer.rules.embed_block = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return embedMap.get(token.info)!.setup(token.content, false);\n };\n }\n\n // only register embed_inline rules if inline embeds are allowed\n if (inlineEmbedMap.size > 0 && !(\"embed_inline\" in md.renderer.rules)) {\n // Register the inline rule\n md.inline.ruler.before(\"emphasis\", \"embed_inline\", getEmbedInline(inlineEmbedMap));\n\n md.renderer.rules.embed_inline = (tokens: Token[], index: number): string => {\n const token = tokens[index];\n\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return inlineEmbedMap.get(token.info)!.setup(token.content, true);\n };\n }\n};\n"],"mappings":"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"} |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
9
12.5%56
1.82%30319
-19.49%