article-content-renderer-vue2 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,8 @@
10
10
  - 使用 Vue 2 `CreateElement` 和 `VNodeData`,不是 Vue 3 兼容层。
11
11
  - 支持严格模式和非严格容错渲染。
12
12
  - 拦截危险链接和图片 URL。
13
- - articleButton 的完整 href 由使用者回调生成。
13
+ - articleButton text/button 完整 href 由使用者回调生成。
14
+ - articleButton 的 link 样式直接使用协议节点中的 href,不调用 resolver。
14
15
  - 支持 Vue 2 SSR。
15
16
  - 提供 TypeScript 类型、结构化错误和 CSS Variables。
16
17
  - Vue 作为 peer dependency,不会打入组件包。
@@ -173,24 +174,40 @@ export default Vue.extend({
173
174
  `imageBaseUrl` 默认为 `https://www.doitme.link/`;传入新地址时,只替换文档图片中该默认前缀,其他图片 URL 保持不变。
174
175
  ## articleButton 链接
175
176
 
176
- `style: "button"` 和 `style: "text"` 都使用 `<a>` 渲染,只改变视觉样式。resolver 接收当前节点的完整只读属性:
177
-
178
- ```ts
179
- interface ArticleButtonAttrs {
180
- id: string
181
- title?: string
182
- text: string
183
- style: 'text' | 'button'
184
- }
185
- ```
186
-
187
- resolver 类型:
188
-
189
- ```ts
190
- type ResolveArticleButtonLink = (
191
- attrs: Readonly<ArticleButtonAttrs>,
192
- node: Readonly<ArticleButtonNode>,
193
- ) =>
177
+ `style: "button"`、`style: "text"` 和 `style: "link"` 都使用 `<a>` 渲染。它们的链接来源不同:
178
+
179
+ - text/button:必须提供 `id`,通过 `resolveArticleButtonLink` 生成完整 `href`。
180
+ - link:`id` 可省略,直接使用节点的 `href`,不会调用 `resolveArticleButtonLink`。
181
+
182
+ 对应的 TypeScript 类型是可辨识联合:
183
+
184
+ ```ts
185
+ interface ArticleButtonActionAttrs {
186
+ id: string
187
+ title?: string
188
+ text: string
189
+ style: 'text' | 'button'
190
+ href?: never
191
+ }
192
+
193
+ interface ArticleButtonLinkAttrs {
194
+ id?: string
195
+ title?: string
196
+ text: string
197
+ style: 'link'
198
+ href?: string
199
+ }
200
+
201
+ type ArticleButtonAttrs = ArticleButtonActionAttrs | ArticleButtonLinkAttrs
202
+ ```
203
+
204
+ resolver 只处理 text/button,因此回调中的 `attrs.id` 始终是 `string`:
205
+
206
+ ```ts
207
+ type ResolveArticleButtonLink = (
208
+ attrs: Readonly<ArticleButtonActionAttrs>,
209
+ node: Readonly<ArticleButtonActionNode>,
210
+ ) =>
194
211
  | string
195
212
  | {
196
213
  href: string
@@ -214,7 +231,35 @@ const resolveArticleButtonLink: ResolveArticleButtonLink = (attrs) => {
214
231
  <a href="/detail/view-more">...</a>
215
232
  ```
216
233
 
217
- 组件不会自动添加 `?`,也不会自动把节点属性转换成查询参数。
234
+ 组件不会自动添加 `?`,也不会自动把节点属性转换成查询参数。
235
+
236
+ ### link 样式直接使用 href
237
+
238
+ link 类型的地址完整写在协议节点中,不经过 resolver,也不会被自动改写:
239
+
240
+ ```ts
241
+ const article: ArticleDocument = {
242
+ type: 'doc',
243
+ content: [
244
+ {
245
+ type: 'articleButton',
246
+ attrs: {
247
+ text: '查看协议说明',
248
+ style: 'link',
249
+ href: '/docs/article-content-protocol#article-button',
250
+ },
251
+ },
252
+ ],
253
+ }
254
+ ```
255
+
256
+ 最终 DOM:
257
+
258
+ ```html
259
+ <a href="/docs/article-content-protocol#article-button">查看协议说明</a>
260
+ ```
261
+
262
+ 协议允许 link 类型省略 `href`;此时会渲染不带 `href` 的禁用态 `<a>`。`javascript:`、`data:` 等不安全地址也会被拦截,并通过 `render-error` 事件报告 `UNSAFE_URL`。
218
263
 
219
264
  ### 使用闭包
220
265
 
@@ -254,7 +299,7 @@ function handleArticleButtonClick(payload: ArticleButtonClickPayload): void {
254
299
  | `strict` | `boolean` | `false` | 校验失败时是否停止整篇正文渲染 |
255
300
  | `customSlots` | `CustomSlot[]` | `[]` | 配置一个或多个具名插槽的顶层正文插入位置 |
256
301
  | `imageBaseUrl` | `string` | `"https://www.doitme.link/"` | 替换文档图片的默认地址前缀 |
257
- | `resolveArticleButtonLink` | `ResolveArticleButtonLink` | `undefined` | 由使用者生成 articleButton 完整链接 |
302
+ | `resolveArticleButtonLink` | `ResolveArticleButtonLink` | `undefined` | text/button 生成完整链接;link 类型不调用 |
258
303
 
259
304
  ## Events
260
305
 
@@ -269,7 +314,7 @@ interface ArticleButtonClickPayload {
269
314
  }
270
315
  ```
271
316
 
272
- 事件在原生跳转前同步触发。调用 `payload.event.preventDefault()` 可以由 Vue Router 3 接管跳转。
317
+ 三种样式都会在原生跳转前同步触发事件。调用 `payload.event.preventDefault()` 可以由 Vue Router 3 接管跳转。
273
318
 
274
319
  ### render-error
275
320
 
@@ -293,23 +338,18 @@ interface RenderIssue {
293
338
 
294
339
  普通链接和 articleButton 允许 `http:`、`https:`、`mailto:`、`tel:`、相对路径和页面锚点。图片允许 `http:`、`https:`、`blob:` 和相对路径。危险协议会被拦截。
295
340
 
296
- ## Vue 2 根节点说明
297
-
298
- Vue 2 状态组件要求单一根节点,因此该版本会输出:
299
-
300
- ```html
301
- <div class="acp-document" data-node-type="doc">...</div>
302
- ```
303
-
304
- 默认样式为:
305
-
306
- ```css
307
- .acp-document {
308
- display: contents;
309
- }
310
- ```
311
-
312
- 它不会增加额外布局盒。Vue 3 版本使用 Fragment,不需要此兼容根节点。
341
+ ## Vue 2 顶层渲染结构
342
+
343
+ 组件使用 Vue 2 函数式多根渲染,正文节点会直接进入使用方已有的容器,不会额外输出 `.acp-document`、`data-node-type="doc"` 或 `data-protocol-version`:
344
+
345
+ ```html
346
+ <article class="article-content">
347
+ <h1 class="acp-heading">...</h1>
348
+ <p class="acp-paragraph">...</p>
349
+ </article>
350
+ ```
351
+
352
+ Vue 2 应用本身仍要求单一根节点。因此,不要把包含多个正文节点的 `ArticleContentRenderer` 直接作为整个 Vue 实例 render 函数的唯一根;请像上例一样放入页面已有的 `<main>`、`<article>` 或其他业务容器中。这个容器由使用方控制,不属于组件输出。
313
353
 
314
354
  ## 样式覆盖
315
355
 
@@ -1 +1 @@
1
- :root{--acp-color-text: inherit;--acp-color-muted: #667085;--acp-color-border: #d0d5dd;--acp-color-surface: #f8fafc;--acp-color-accent: #2563eb;--acp-color-accent-hover: #1d4ed8;--acp-color-on-accent: #ffffff;--acp-radius: .375rem;--acp-spacing-block: 1rem;--acp-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace}.acp-document{display:contents}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-article-button,.acp-table-wrapper{box-sizing:border-box}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-table-wrapper{margin-block:0 var(--acp-spacing-block)}.acp-paragraph:first-child,.acp-heading:first-child,.acp-blockquote:first-child,.acp-list:first-child,.acp-code-block:first-child,.acp-horizontal-rule:first-child,.acp-image:first-child,.acp-table-wrapper:first-child{margin-block-start:0}.acp-paragraph{color:var(--acp-color-text)}.acp-blockquote{margin-inline:0;padding-inline-start:1rem;border-inline-start:.25rem solid var(--acp-color-border);color:var(--acp-color-muted)}.acp-list{padding-inline-start:1.5rem}.acp-list-item>:last-child{margin-block-end:0}.acp-code-block{overflow-x:auto;padding:1rem;border-radius:var(--acp-radius);background:var(--acp-color-surface);font-family:var(--acp-font-mono);white-space:pre}.acp-mark--code{padding:.1em .25em;border-radius:calc(var(--acp-radius) / 2);background:var(--acp-color-surface);font-family:var(--acp-font-mono)}.acp-horizontal-rule{border:0;border-block-start:1px solid var(--acp-color-border)}.acp-image{display:flex;width:100%}.acp-image--left{justify-content:flex-start}.acp-image--center{justify-content:center}.acp-image--right{justify-content:flex-end}.acp-image__element{display:block;max-width:100%;height:auto}.acp-link,.acp-article-button--text{color:var(--acp-color-accent);text-decoration:underline;text-underline-offset:.15em}.acp-link:hover,.acp-article-button--text:hover{color:var(--acp-color-accent-hover)}.acp-article-button{display:inline-flex;align-items:center;justify-content:center;margin-block:0 var(--acp-spacing-block);cursor:pointer}.acp-article-button--button{min-height:2.5rem;padding:.5rem 1rem;border-radius:var(--acp-radius);background:var(--acp-color-accent);color:var(--acp-color-on-accent);text-decoration:none}.acp-article-button--button:hover{background:var(--acp-color-accent-hover)}.acp-article-button--disabled{cursor:not-allowed;opacity:.55}.acp-table-wrapper{width:100%;overflow-x:auto}.acp-table{width:100%;border-collapse:collapse}.acp-table-cell{padding:.625rem .75rem;border:1px solid var(--acp-color-border);vertical-align:top}.acp-table-cell>:last-child{margin-block-end:0}.acp-render-error{padding:.75rem 1rem;border:1px solid #fda29b;border-radius:var(--acp-radius);background:#fffbfa;color:#b42318}
1
+ :root{--acp-color-text: inherit;--acp-color-muted: #667085;--acp-color-border: #d0d5dd;--acp-color-surface: #f8fafc;--acp-color-accent: #2563eb;--acp-color-accent-hover: #1d4ed8;--acp-color-on-accent: #ffffff;--acp-radius: .375rem;--acp-spacing-block: 1rem;--acp-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-article-button,.acp-table-wrapper{box-sizing:border-box}.acp-paragraph,.acp-heading,.acp-blockquote,.acp-list,.acp-code-block,.acp-horizontal-rule,.acp-image,.acp-table-wrapper{margin-block:0 var(--acp-spacing-block)}.acp-paragraph:first-child,.acp-heading:first-child,.acp-blockquote:first-child,.acp-list:first-child,.acp-code-block:first-child,.acp-horizontal-rule:first-child,.acp-image:first-child,.acp-table-wrapper:first-child{margin-block-start:0}.acp-paragraph{color:var(--acp-color-text)}.acp-blockquote{margin-inline:0;padding-inline-start:1rem;border-inline-start:.25rem solid var(--acp-color-border);color:var(--acp-color-muted)}.acp-list{padding-inline-start:1.5rem}.acp-list-item>:last-child{margin-block-end:0}.acp-code-block{overflow-x:auto;padding:1rem;border-radius:var(--acp-radius);background:var(--acp-color-surface);font-family:var(--acp-font-mono);white-space:pre}.acp-mark--code{padding:.1em .25em;border-radius:calc(var(--acp-radius) / 2);background:var(--acp-color-surface);font-family:var(--acp-font-mono)}.acp-horizontal-rule{border:0;border-block-start:1px solid var(--acp-color-border)}.acp-image{display:flex;width:100%}.acp-image--left{justify-content:flex-start}.acp-image--center{justify-content:center}.acp-image--right{justify-content:flex-end}.acp-image__element{display:block;max-width:100%;height:auto}.acp-link,.acp-article-button--text,.acp-article-button--link{color:var(--acp-color-accent);text-decoration:underline;text-underline-offset:.15em}.acp-link:hover,.acp-article-button--text:hover,.acp-article-button--link:hover{color:var(--acp-color-accent-hover)}.acp-article-button{display:inline-flex;align-items:center;justify-content:center;margin-block:0 var(--acp-spacing-block);cursor:pointer}.acp-article-button--button{min-height:2.5rem;padding:.5rem 1rem;border-radius:var(--acp-radius);background:var(--acp-color-accent);color:var(--acp-color-on-accent);text-decoration:none}.acp-article-button--button:hover{background:var(--acp-color-accent-hover)}.acp-article-button--disabled{cursor:not-allowed;opacity:.55}.acp-table-wrapper{width:100%;overflow-x:auto}.acp-table{width:100%;border-collapse:collapse}.acp-table-cell{padding:.625rem .75rem;border:1px solid var(--acp-color-border);vertical-align:top}.acp-table-cell>:last-child{margin-block-end:0}.acp-render-error{padding:.75rem 1rem;border:1px solid #fda29b;border-radius:var(--acp-radius);background:#fffbfa;color:#b42318}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var j=Object.defineProperty,M=Object.defineProperties;var z=Object.getOwnPropertyDescriptors;var O=Object.getOwnPropertySymbols;var Y=Object.prototype.hasOwnProperty,F=Object.prototype.propertyIsEnumerable;var L=(n,r,t)=>r in n?j(n,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[r]=t,m=(n,r)=>{for(var t in r||(r={}))Y.call(r,t)&&L(n,t,r[t]);if(O)for(var t of O(r))F.call(r,t)&&L(n,t,r[t]);return n},A=(n,r)=>M(n,z(r));var S=(n,r,t)=>L(n,typeof r!="symbol"?r+"":r,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const K=require("vue"),G=new Set(["http:","https:","mailto:","tel:"]),W=new Set(["http:","https:","blob:"]),H="https://article-content-renderer.invalid/",I="https://www.doitme.link/";function X(n,r){if(typeof n!="string")return n;const t=n.trim();if(!t.startsWith(I))return t;const i=(r.trim()||I).replace(/\/+$/u,""),s=t.slice(I.length).replace(/^\/+/,"");return`${i}/${s}`}function E(n,r){if(typeof n!="string")return null;const t=n.trim();if(!t||/[\u0000-\u001F\u007F]/u.test(t))return null;try{const e=new URL(t,H);return(r==="link"?G:W).has(e.protocol)?t:null}catch(e){return null}}function q(n,r){const t=new Set(typeof n=="string"?n.trim().split(/\s+/u).filter(Boolean):[]);return r==="_blank"&&(t.add("noopener"),t.add("noreferrer")),t.size>0?[...t].join(" "):void 0}const J=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]);function h(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function R(n){return h(n)?n:{}}function u(n,r,t,e){var f;const i=h(t)?t:{},s=h(t)?e:t,o={},a={};for(const[l,p]of Object.entries(i))if(l==="class")o.class=p;else if(l==="style")o.style=p;else if(l.startsWith("on")&&typeof p=="function"){const x=l.slice(2).toLowerCase();o.on=A(m({},(f=o.on)!=null?f:{}),{[x]:p})}else p!==void 0&&p!==!1&&(a[l]=p);return Object.keys(a).length>0&&(o.attrs=a),n.createElement(r,o,s)}function y(n){return Array.isArray(n)?n:[]}function g(n,...r){return`${n}/${r.map(String).join("/")}`}function B(n){return n==="left"||n==="center"||n==="right"||n==="justify"}function Q(n){return n==="left"||n==="center"||n==="right"}function N(n){return n==="_blank"||n==="_self"}function b(n,r){n.reportIssue(r)}function Z(n,r,t){if(!h(n)||n.type!=="text"||typeof n.text!="string"||!n.text)return null;let e=n.text;const i=y(n.marks);for(let s=0;s<i.length;s+=1){const o=i[s];if(!h(o)||typeof o.type!="string")continue;const a=g(r,"marks",s);switch(o.type){case"bold":e=u(t,"strong",{class:"acp-mark acp-mark--bold"},[e]);break;case"italic":e=u(t,"em",{class:"acp-mark acp-mark--italic"},[e]);break;case"strike":e=u(t,"s",{class:"acp-mark acp-mark--strike"},[e]);break;case"underline":e=u(t,"u",{class:"acp-mark acp-mark--underline"},[e]);break;case"code":e=u(t,"code",{class:"acp-mark acp-mark--code"},[e]);break;case"link":{const f=R(o.attrs),l=E(f.href,"link");if(!l){b(t,{code:"UNSAFE_URL",path:g(a,"attrs","href"),message:"The link URL is empty, malformed, or uses a disallowed protocol.",nodeType:"link"});break}const p=N(f.target)?f.target:"_blank";e=u(t,"a",{class:"acp-link",href:l,target:p,rel:q(void 0,p)},[e]);break}}}return e}function w(n,r,t){return y(n).map((e,i)=>Z(e,g(r,i),t)).filter(e=>e!==null)}function V(n,r,t){return!h(n)||n.type!=="listItem"?null:u(t,"li",{class:"acp-list-item","data-node-type":"listItem"},T(n.content,g(r,"content"),t))}function tt(n,r,t){return!h(n)||n.type!=="tableCell"?null:u(t,"td",{class:"acp-table-cell","data-node-type":"tableCell"},T(n.content,g(r,"content"),t))}function et(n,r,t){if(!h(n)||n.type!=="tableRow")return null;const e=y(n.content).map((i,s)=>tt(i,g(r,"content",s),t)).filter(i=>i!==null);return u(t,"tr",{class:"acp-table-row","data-node-type":"tableRow"},e)}function rt(n){var i;if(h(n)&&n.target!==void 0&&!N(n.target)||h(n)&&n.rel!==void 0&&typeof n.rel!="string")return null;const r=typeof n=="string"?{href:n}:h(n)&&typeof n.href=="string"?m(m({href:n.href},N(n.target)?{target:n.target}:{}),typeof n.rel=="string"?{rel:n.rel}:{}):null;if(!r)return null;const t=E(r.href,"link");if(!t)return null;const e=(i=r.target)!=null?i:"_self";return{href:t,target:e,rel:q(r.rel,e)}}function nt(n,r,t){var f;const e=R(n.attrs);if(typeof e.id!="string"||!e.id||typeof e.text!="string"||!e.text||e.style!=="text"&&e.style!=="button")return null;const i=Object.freeze(A(m({id:e.id},typeof e.title=="string"?{title:e.title}:{}),{text:e.text,style:e.style})),s=Object.freeze({type:"articleButton",attrs:i});let o=null;if(!t.resolveArticleButtonLink)b(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:"No resolveArticleButtonLink callback was provided for an articleButton node.",nodeType:"articleButton"});else try{const l=t.resolveArticleButtonLink(i,s);o=rt(l),o||b(t,{code:typeof l=="string"||h(l)&&typeof l.href=="string"?"UNSAFE_URL":"LINK_RESOLUTION_FAILED",path:r,message:"The articleButton link resolver returned no usable safe URL.",nodeType:"articleButton"})}catch(l){b(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:`The articleButton link resolver threw an error: ${l instanceof Error?l.message:String(l)}`,nodeType:"articleButton"})}const a=(f=o==null?void 0:o.href)!=null?f:null;return u(t,"a",{class:["acp-article-button",`acp-article-button--${i.style}`,!a&&"acp-article-button--disabled"],href:a!=null?a:void 0,target:o==null?void 0:o.target,rel:o==null?void 0:o.rel,title:i.title,"data-node-type":"articleButton","data-article-button-id":i.id,"data-article-button-style":i.style,"aria-disabled":a?void 0:"true",onClick:l=>{a||l.preventDefault(),t.emitArticleButtonClick({attrs:i,node:s,href:a,event:l})}},i.text)}function U(n,r,t){if(!h(n)||typeof n.type!="string"||!J.has(n.type))return null;const e=R(n.attrs);switch(n.type){case"paragraph":{const i=B(e.textAlign)?e.textAlign:void 0;return u(t,"p",{class:"acp-paragraph","data-node-type":"paragraph",style:i?{textAlign:i}:void 0},w(n.content,g(r,"content"),t))}case"heading":{const i=Number.isInteger(e.level)&&Number(e.level)>=1&&Number(e.level)<=6?Number(e.level):1,s=B(e.textAlign)?e.textAlign:void 0;return u(t,`h${i}`,{class:["acp-heading",`acp-heading--${i}`],"data-node-type":"heading",style:s?{textAlign:s}:void 0},w(n.content,g(r,"content"),t))}case"blockquote":return u(t,"blockquote",{class:"acp-blockquote","data-node-type":"blockquote"},T(n.content,g(r,"content"),t));case"bulletList":{const i=y(n.content).map((s,o)=>V(s,g(r,"content",o),t)).filter(s=>s!==null);return u(t,"ul",{class:"acp-list acp-list--bullet","data-node-type":"bulletList"},i)}case"orderedList":{const i=Number.isInteger(e.start)&&Number(e.start)>=1?Number(e.start):1,s=y(n.content).map((o,a)=>V(o,g(r,"content",a),t)).filter(o=>o!==null);return u(t,"ol",{class:"acp-list acp-list--ordered","data-node-type":"orderedList",start:i},s)}case"codeBlock":{const i=typeof e.language=="string"&&e.language?e.language:void 0,s=y(n.content).filter(o=>h(o)&&o.type==="text"&&typeof o.text=="string").map(o=>o.text).join("");return u(t,"pre",{class:"acp-code-block","data-node-type":"codeBlock","data-language":i},[u(t,"code",{class:i?`language-${i}`:void 0},s)])}case"horizontalRule":return u(t,"hr",{class:"acp-horizontal-rule","data-node-type":"horizontalRule"});case"image":{const i=E(X(e.src,t.imageBaseUrl),"image");if(!i)return b(t,{code:"UNSAFE_URL",path:g(r,"attrs","src"),message:"The image URL is empty, malformed, or uses a disallowed protocol.",nodeType:"image"}),null;const s=Q(e.imageAlign)?e.imageAlign:"center",o=Number.isInteger(e.width)&&Number(e.width)>=1&&Number(e.width)<=1e4?Number(e.width):void 0,a=Number.isInteger(e.height)&&Number(e.height)>=1&&Number(e.height)<=1e4?Number(e.height):void 0;return u(t,"div",{class:["acp-image",`acp-image--${s}`],"data-node-type":"image","data-image-align":s},[u(t,"img",{class:"acp-image__element",src:i,alt:typeof e.alt=="string"?e.alt:"",title:typeof e.title=="string"?e.title:void 0,width:o,height:a,"data-image-align":s})])}case"articleButton":return nt(n,r,t);case"table":{const i=y(n.content).map((s,o)=>et(s,g(r,"content",o),t)).filter(s=>s!==null);return u(t,"div",{class:"acp-table-wrapper","data-node-type":"table"},[u(t,"table",{class:"acp-table"},[u(t,"tbody",i)])])}}return null}function T(n,r,t){return y(n).map((e,i)=>U(e,g(r,i),t)).filter(e=>e!==null)}function it(n,r){const t=y(n.content),e=new Map;r.customSlots.forEach(s=>{var a;if(!Number.isInteger(s.location)||s.location<1||s.location>t.length)return;const o=(a=e.get(s.location))!=null?a:[];o.push(s),e.set(s.location,o)});const i=[];return t.forEach((s,o)=>{var l;const a=o+1;(l=e.get(a))==null||l.forEach(p=>i.push(...p.content));const f=U(s,g("/content",o),r);f&&typeof f!="string"&&i.push(f)}),i}function st(n,r){return!h(n)||n.type!=="doc"?[]:it(n,r)}const ot=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]),at=new Set(["left","center","right","justify"]),ct=new Set(["left","center","right"]),lt=new Set(["bold","italic","strike","underline","code"]);function k(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function c(n,r){return`${n}/${String(r).replaceAll("~","~0").replaceAll("/","~1")}`}function d(n,...r){let t=n;for(const e of r)t=c(t,e);return t}class dt{constructor(){S(this,"issues",[])}validate(r){if(!k(r))return this.add("INVALID_ROOT","","The document must be an object."),this.result();this.checkProperties(r,"",["type","content"],["type","content"]),r.type!=="doc"&&this.add("INVALID_ROOT","/type",'The root node type must be "doc".');const t=this.requireArray(r.content,"/content");return t==null||t.forEach((e,i)=>this.validateBlock(e,c("/content",i))),this.result()}result(){return{valid:this.issues.length===0,issues:this.issues}}add(r,t,e,i){this.issues.push(m({code:r,path:t,message:e},i?{nodeType:i}:{}))}checkProperties(r,t,e,i=[],s){const o=new Set(e);for(const a of Object.keys(r))o.has(a)||this.add("UNKNOWN_PROPERTY",c(t,a),`Property "${a}" is not allowed.`,s);for(const a of i)a in r||this.add("MISSING_PROPERTY",c(t,a),`Required property "${a}" is missing.`,s)}requireArray(r,t,e){return Array.isArray(r)?r:(this.add("INVALID_TYPE",t,"Expected an array.",e),null)}optionalArray(r,t,e){return r===void 0?[]:this.requireArray(r,t,e)}requireNonEmptyArray(r,t,e){const i=this.requireArray(r,t,e);return i&&i.length===0&&this.add("INVALID_CONTENT",t,`Node "${e}" must contain at least one child.`,e),i}requireRecord(r,t,e){return k(r)?r:(this.add("INVALID_TYPE",t,"Expected an object.",e),null)}optionalRecord(r,t,e){return r===void 0?{}:this.requireRecord(r,t,e)}requireString(r,t,e,i={}){return typeof r!="string"?(this.add("INVALID_TYPE",t,"Expected a string.",e),!1):!i.allowEmpty&&r.length===0?(this.add("INVALID_VALUE",t,"The string must not be empty.",e),!1):i.maxLength!==void 0&&r.length>i.maxLength?(this.add("INVALID_VALUE",t,`The string must contain at most ${i.maxLength} characters.`,e),!1):!0}optionalString(r,t,e,i={}){r!==void 0&&this.requireString(r,t,e,i)}requireInteger(r,t,e,i,s){if(!Number.isInteger(r))return this.add("INVALID_TYPE",t,"Expected an integer.",e),!1;const o=r;return i!==void 0&&o<i?(this.add("INVALID_VALUE",t,`Value must be at least ${i}.`,e),!1):s!==void 0&&o>s?(this.add("INVALID_VALUE",t,`Value must be at most ${s}.`,e),!1):!0}validateBlock(r,t){if(!k(r)){this.add("INVALID_TYPE",t,"A block node must be an object.");return}const e=r.type;if(typeof e!="string"){this.add("MISSING_PROPERTY",c(t,"type"),"A block node requires a type.");return}if(!ot.has(e)){this.add("UNKNOWN_NODE",c(t,"type"),`Unknown block node "${e}".`,e);return}switch(e){case"paragraph":this.validateParagraph(r,t);break;case"heading":this.validateHeading(r,t);break;case"blockquote":this.validateBlockquote(r,t);break;case"bulletList":this.validateBulletList(r,t);break;case"orderedList":this.validateOrderedList(r,t);break;case"codeBlock":this.validateCodeBlock(r,t);break;case"horizontalRule":this.checkProperties(r,t,["type"],["type"],e);break;case"image":this.validateImage(r,t);break;case"articleButton":this.validateArticleButton(r,t);break;case"table":this.validateTable(r,t);break}}validateParagraph(r,t){const e="paragraph";this.checkProperties(r,t,["type","attrs","content"],["type"],e),this.validateTextAlignAttrs(r.attrs,c(t,"attrs"),e,!1),this.validateInlineContent(r.content,c(t,"content"),e)}validateHeading(r,t){const e="heading";this.checkProperties(r,t,["type","attrs","content"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["level","textAlign"],["level"],e),this.requireInteger(i.level,d(t,"attrs","level"),e,1,6),this.validateTextAlign(i.textAlign,d(t,"attrs","textAlign"),e)),this.validateInlineContent(r.content,c(t,"content"),e)}validateTextAlignAttrs(r,t,e,i){const s=i?this.requireRecord(r,t,e):this.optionalRecord(r,t,e);s&&(this.checkProperties(s,t,["textAlign"],[],e),this.validateTextAlign(s.textAlign,c(t,"textAlign"),e))}validateTextAlign(r,t,e){r!==void 0&&(typeof r!="string"?this.add("INVALID_TYPE",t,"Text alignment must be a string.",e):at.has(r)||this.add("INVALID_VALUE",t,`Unsupported text alignment "${r}".`,e))}validateInlineContent(r,t,e){const i=this.optionalArray(r,t,e);i==null||i.forEach((s,o)=>this.validateText(s,c(t,o),!0))}validateText(r,t,e){if(!k(r)){this.add("INVALID_TYPE",t,"A text node must be an object.","text");return}const i=e?["type","text","marks"]:["type","text"];if(this.checkProperties(r,t,i,["type","text"],"text"),r.type!=="text"&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a text node.","text"),this.requireString(r.text,c(t,"text"),"text"),e&&r.marks!==void 0){const s=this.requireArray(r.marks,c(t,"marks"),"text");s==null||s.forEach((o,a)=>this.validateMark(o,d(t,"marks",a)))}}validateMark(r,t){if(!k(r)){this.add("INVALID_TYPE",t,"A mark must be an object.");return}if(typeof r.type!="string"){this.add("MISSING_PROPERTY",c(t,"type"),"A mark requires a type.");return}if(lt.has(r.type)){this.checkProperties(r,t,["type"],["type"],r.type);return}if(r.type!=="link"){this.add("UNKNOWN_MARK",c(t,"type"),`Unknown mark "${r.type}".`,r.type);return}this.checkProperties(r,t,["type","attrs"],["type","attrs"],"link");const e=this.requireRecord(r.attrs,c(t,"attrs"),"link");e&&(this.checkProperties(e,c(t,"attrs"),["href","target"],["href"],"link"),this.requireString(e.href,d(t,"attrs","href"),"link"),e.target!==void 0&&e.target!=="_blank"&&e.target!=="_self"&&this.add("INVALID_VALUE",d(t,"attrs","target"),'Link target must be "_blank" or "_self".',"link"))}validateBlockquote(r,t){const e="blockquote";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);i==null||i.forEach((s,o)=>this.validateBlock(s,d(t,"content",o)))}validateBulletList(r,t){const e="bulletList";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);i==null||i.forEach((s,o)=>this.validateListItem(s,d(t,"content",o)))}validateOrderedList(r,t){const e="orderedList";this.checkProperties(r,t,["type","attrs","content"],["type","content"],e);const i=this.optionalRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["start"],[],e),i.start!==void 0&&this.requireInteger(i.start,d(t,"attrs","start"),e,1));const s=this.requireNonEmptyArray(r.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateListItem(o,d(t,"content",a)))}validateListItem(r,t){const e="listItem",i=this.requireRecord(r,t,e);if(!i)return;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a listItem node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateBlock(o,d(t,"content",a)))}validateCodeBlock(r,t){const e="codeBlock";this.checkProperties(r,t,["type","attrs","content"],["type"],e);const i=this.optionalRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["language"],[],e),this.optionalString(i.language,d(t,"attrs","language"),e,{maxLength:32}));const s=this.optionalArray(r.content,c(t,"content"),e);s&&(s.length>1&&this.add("INVALID_CONTENT",c(t,"content"),"A codeBlock may contain at most one text node.",e),s.forEach((o,a)=>this.validateText(o,d(t,"content",a),!1)))}validateImage(r,t){const e="image";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["src","alt","title","width","height","imageAlign"],["src"],e),this.requireString(i.src,d(t,"attrs","src"),e),this.optionalString(i.alt,d(t,"attrs","alt"),e,{allowEmpty:!0}),this.optionalString(i.title,d(t,"attrs","title"),e,{allowEmpty:!0}),i.width!==void 0&&this.requireInteger(i.width,d(t,"attrs","width"),e,1,1e4),i.height!==void 0&&this.requireInteger(i.height,d(t,"attrs","height"),e,1,1e4),i.imageAlign!==void 0&&(typeof i.imageAlign!="string"?this.add("INVALID_TYPE",d(t,"attrs","imageAlign"),"Image alignment must be a string.",e):ct.has(i.imageAlign)||this.add("INVALID_VALUE",d(t,"attrs","imageAlign"),`Unsupported image alignment "${i.imageAlign}".`,e)))}validateArticleButton(r,t){const e="articleButton";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["id","title","text","style"],["id","text","style"],e),this.requireString(i.id,d(t,"attrs","id"),e),this.optionalString(i.title,d(t,"attrs","title"),e),this.requireString(i.text,d(t,"attrs","text"),e),i.style!=="text"&&i.style!=="button"&&this.add("INVALID_VALUE",d(t,"attrs","style"),'Article button style must be "text" or "button".',e))}validateTable(r,t){const e="table";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);if(!i)return;let s=null;i.forEach((o,a)=>{const f=d(t,"content",a),l=this.validateTableRow(o,f);l!==null&&(s===null?s=l:l!==s&&this.add("TABLE_COLUMN_MISMATCH",c(f,"content"),`Expected ${s} table cells but received ${l}.`,"tableRow"))})}validateTableRow(r,t){var o;const e="tableRow",i=this.requireRecord(r,t,e);if(!i)return null;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a tableRow node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);return s==null||s.forEach((a,f)=>this.validateTableCell(a,d(t,"content",f))),(o=s==null?void 0:s.length)!=null?o:null}validateTableCell(r,t){const e="tableCell",i=this.requireRecord(r,t,e);if(!i)return;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a tableCell node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateBlock(o,d(t,"content",a)))}}function ut(n){return new dt().validate(n)}const C=Object.freeze({version:1,validate:ut,render:st}),D=new Map([[C.version,C]]),ft=Object.freeze([...D.keys()]),_=1;function v(n){return D.get(n)}function $(n,r={}){var s;const t=(s=r.protocolVersion)!=null?s:_,e=v(t);return e?e.validate(n):{valid:!1,issues:[{code:"UNSUPPORTED_PROTOCOL",path:"",message:`Article Content Protocol version ${t} is not supported.`}]}}function gt(){return[]}function ht(n){return`${n.code}:${n.path}:${n.message}`}const pt=K.extend({name:"ArticleContentRenderer",props:{document:{type:null,required:!0},protocolVersion:{type:Number,default:_},strict:{type:Boolean,default:!1},customSlots:{type:Array,default:gt},imageBaseUrl:{type:String,default:I},resolveArticleButtonLink:{type:Function,default:void 0}},data(){return{reportedRuntimeIssues:new Set}},computed:{validation(){return $(this.document,{protocolVersion:this.protocolVersion})}},watch:{validation:{immediate:!0,deep:!0,handler(n){n.issues.forEach(r=>this.$emit("render-error",r))}},document:{deep:!0,handler(){this.reportedRuntimeIssues.clear()}},protocolVersion(){this.reportedRuntimeIssues.clear()},resolveArticleButtonLink(){this.reportedRuntimeIssues.clear()},imageBaseUrl(){this.reportedRuntimeIssues.clear()}},methods:{resolveCustomSlots(){return this.customSlots.map(n=>{var e,i,s,o;const r={id:n.id,location:n.location},t=(o=(s=(i=(e=this.$scopedSlots)[n.id])==null?void 0:i.call(e,r))!=null?s:this.$slots[n.id])!=null?o:[];return A(m({},n),{content:t})})},reportRuntimeIssue(n){const r=ht(n);this.reportedRuntimeIssues.has(r)||(this.reportedRuntimeIssues.add(r),this.$nextTick(()=>this.$emit("render-error",n)))}},render(n){const r=v(this.protocolVersion);if(!r||this.strict&&!this.validation.valid)return n("div",{class:"acp-render-error",attrs:{role:"alert","data-render-error":"true"}},"Invalid article content");const t=r.render(this.document,{createElement:n,customSlots:this.resolveCustomSlots(),imageBaseUrl:this.imageBaseUrl,resolveArticleButtonLink:this.resolveArticleButtonLink,emitArticleButtonClick:e=>this.$emit("article-button-click",e),reportIssue:this.reportRuntimeIssue});return n("div",{class:"acp-document",attrs:{"data-node-type":"doc","data-protocol-version":this.protocolVersion}},t)}});function yt(n,r,t,e,i,s,o,a){var f=typeof n=="function"?n.options:n;return{exports:n,options:f}}var mt=yt(pt);const P=mt.exports,kt=Object.freeze({fileFormat:"article-content-protocol",fileFormatVersion:1,mediaType:"application/vnd.article-content-protocol+json",id:"article-content-v1",version:1,name:"Article Content Protocol v1",status:"draft",rootNode:"doc",nodeTypes:Object.freeze(["doc","paragraph","heading","blockquote","bulletList","orderedList","listItem","codeBlock","horizontalRule","image","articleButton","table","tableRow","tableCell","text"]),markTypes:Object.freeze(["bold","italic","strike","underline","code","link"])}),bt={install(n){n.component("ArticleContentRenderer",P)}};exports.ARTICLE_CONTENT_PROTOCOL_V1=kt;exports.ArticleContentRenderer=P;exports.ArticleContentRendererPlugin=bt;exports.CURRENT_PROTOCOL_VERSION=_;exports.SUPPORTED_PROTOCOL_VERSIONS=ft;exports.default=P;exports.validateArticleDocument=$;
1
+ "use strict";var K=Object.defineProperty,G=Object.defineProperties;var W=Object.getOwnPropertyDescriptors;var w=Object.getOwnPropertySymbols;var H=Object.prototype.hasOwnProperty,X=Object.prototype.propertyIsEnumerable;var E=(n,r,t)=>r in n?K(n,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[r]=t,m=(n,r)=>{for(var t in r||(r={}))H.call(r,t)&&E(n,t,r[t]);if(w)for(var t of w(r))X.call(r,t)&&E(n,t,r[t]);return n},b=(n,r)=>G(n,W(r));var C=(n,r,t)=>E(n,typeof r!="symbol"?r+"":r,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const x=require("vue"),J=new Set(["http:","https:","mailto:","tel:"]),Q=new Set(["http:","https:","blob:"]),Z="https://article-content-renderer.invalid/",N="https://www.doitme.link/";function tt(n,r){if(typeof n!="string")return n;const t=n.trim();if(!t.startsWith(N))return t;const i=(r.trim()||N).replace(/\/+$/u,""),s=t.slice(N.length).replace(/^\/+/,"");return`${i}/${s}`}function _(n,r){if(typeof n!="string")return null;const t=n.trim();if(!t||/[\u0000-\u001F\u007F]/u.test(t))return null;try{const e=new URL(t,Z);return(r==="link"?J:Q).has(e.protocol)?t:null}catch(e){return null}}function j(n,r){const t=new Set(typeof n=="string"?n.trim().split(/\s+/u).filter(Boolean):[]);return r==="_blank"&&(t.add("noopener"),t.add("noreferrer")),t.size>0?[...t].join(" "):void 0}const et=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]);function y(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function P(n){return y(n)?n:{}}function f(n,r,t,e){var l;const i=y(t)?t:{},s=y(t)?e:t,o={},a={};for(const[u,g]of Object.entries(i))if(u==="class")o.class=g;else if(u==="style")o.style=g;else if(u.startsWith("on")&&typeof g=="function"){const h=u.slice(2).toLowerCase();o.on=b(m({},(l=o.on)!=null?l:{}),{[h]:g})}else g!==void 0&&g!==!1&&(a[u]=g);return Object.keys(a).length>0&&(o.attrs=a),n.createElement(r,o,s)}function k(n){return Array.isArray(n)?n:[]}function p(n,...r){return`${n}/${r.map(String).join("/")}`}function V(n){return n==="left"||n==="center"||n==="right"||n==="justify"}function rt(n){return n==="left"||n==="center"||n==="right"}function R(n){return n==="_blank"||n==="_self"}function A(n,r){n.reportIssue(r)}function nt(n,r,t){if(!y(n)||n.type!=="text"||typeof n.text!="string"||!n.text)return null;let e=n.text;const i=k(n.marks);for(let s=0;s<i.length;s+=1){const o=i[s];if(!y(o)||typeof o.type!="string")continue;const a=p(r,"marks",s);switch(o.type){case"bold":e=f(t,"strong",{class:"acp-mark acp-mark--bold"},[e]);break;case"italic":e=f(t,"em",{class:"acp-mark acp-mark--italic"},[e]);break;case"strike":e=f(t,"s",{class:"acp-mark acp-mark--strike"},[e]);break;case"underline":e=f(t,"u",{class:"acp-mark acp-mark--underline"},[e]);break;case"code":e=f(t,"code",{class:"acp-mark acp-mark--code"},[e]);break;case"link":{const l=P(o.attrs),u=_(l.href,"link");if(!u){A(t,{code:"UNSAFE_URL",path:p(a,"attrs","href"),message:"The link URL is empty, malformed, or uses a disallowed protocol.",nodeType:"link"});break}const g=R(l.target)?l.target:"_blank";e=f(t,"a",{class:"acp-link",href:u,target:g,rel:j(void 0,g)},[e]);break}}}return e}function q(n,r,t){return k(n).map((e,i)=>nt(e,p(r,i),t)).filter(e=>e!==null)}function U(n,r,t){return!y(n)||n.type!=="listItem"?null:f(t,"li",{class:"acp-list-item","data-node-type":"listItem"},S(n.content,p(r,"content"),t))}function it(n,r,t){return!y(n)||n.type!=="tableCell"?null:f(t,"td",{class:"acp-table-cell","data-node-type":"tableCell"},S(n.content,p(r,"content"),t))}function st(n,r,t){if(!y(n)||n.type!=="tableRow")return null;const e=k(n.content).map((i,s)=>it(i,p(r,"content",s),t)).filter(i=>i!==null);return f(t,"tr",{class:"acp-table-row","data-node-type":"tableRow"},e)}function D(n){var i;if(y(n)&&n.target!==void 0&&!R(n.target)||y(n)&&n.rel!==void 0&&typeof n.rel!="string")return null;const r=typeof n=="string"?{href:n}:y(n)&&typeof n.href=="string"?m(m({href:n.href},R(n.target)?{target:n.target}:{}),typeof n.rel=="string"?{rel:n.rel}:{}):null;if(!r)return null;const t=_(r.href,"link");if(!t)return null;const e=(i=r.target)!=null?i:"_self";return{href:t,target:e,rel:j(r.rel,e)}}function ot(n,r,t){var g;const e=P(n.attrs),i=e.style==="text"||e.style==="button",s=e.style==="link";if(typeof e.text!="string"||!e.text||!i&&!s||i&&(typeof e.id!="string"||!e.id)||s&&e.id!==void 0&&(typeof e.id!="string"||!e.id))return null;const o=Object.freeze(s?m(b(m(m({},typeof e.id=="string"?{id:e.id}:{}),typeof e.title=="string"?{title:e.title}:{}),{text:e.text,style:"link"}),typeof e.href=="string"?{href:e.href}:{}):b(m({id:e.id},typeof e.title=="string"?{title:e.title}:{}),{text:e.text,style:e.style})),a=Object.freeze({type:"articleButton",attrs:o});let l=null;if(o.style==="link")o.href!==void 0&&(l=D(o.href),l||A(t,{code:"UNSAFE_URL",path:`${r}/attrs/href`,message:"The articleButton link href is not a usable safe URL.",nodeType:"articleButton"}));else if(!t.resolveArticleButtonLink)A(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:"No resolveArticleButtonLink callback was provided for an articleButton node.",nodeType:"articleButton"});else try{const h=Object.freeze({type:"articleButton",attrs:o}),L=t.resolveArticleButtonLink(o,h);l=D(L),l||A(t,{code:typeof L=="string"||y(L)&&typeof L.href=="string"?"UNSAFE_URL":"LINK_RESOLUTION_FAILED",path:r,message:"The articleButton link resolver returned no usable safe URL.",nodeType:"articleButton"})}catch(h){A(t,{code:"LINK_RESOLUTION_FAILED",path:r,message:`The articleButton link resolver threw an error: ${h instanceof Error?h.message:String(h)}`,nodeType:"articleButton"})}const u=(g=l==null?void 0:l.href)!=null?g:null;return f(t,"a",{class:["acp-article-button",`acp-article-button--${o.style}`,!u&&"acp-article-button--disabled"],href:u!=null?u:void 0,target:l==null?void 0:l.target,rel:l==null?void 0:l.rel,title:o.title,"data-node-type":"articleButton","data-article-button-id":o.id,"data-article-button-style":o.style,"aria-disabled":u?void 0:"true",onClick:h=>{u||h.preventDefault(),t.emitArticleButtonClick({attrs:o,node:a,href:u,event:h})}},o.text)}function z(n,r,t){if(!y(n)||typeof n.type!="string"||!et.has(n.type))return null;const e=P(n.attrs);switch(n.type){case"paragraph":{const i=V(e.textAlign)?e.textAlign:void 0;return f(t,"p",{class:"acp-paragraph","data-node-type":"paragraph",style:i?{textAlign:i}:void 0},q(n.content,p(r,"content"),t))}case"heading":{const i=Number.isInteger(e.level)&&Number(e.level)>=1&&Number(e.level)<=6?Number(e.level):1,s=V(e.textAlign)?e.textAlign:void 0;return f(t,`h${i}`,{class:["acp-heading",`acp-heading--${i}`],"data-node-type":"heading",style:s?{textAlign:s}:void 0},q(n.content,p(r,"content"),t))}case"blockquote":return f(t,"blockquote",{class:"acp-blockquote","data-node-type":"blockquote"},S(n.content,p(r,"content"),t));case"bulletList":{const i=k(n.content).map((s,o)=>U(s,p(r,"content",o),t)).filter(s=>s!==null);return f(t,"ul",{class:"acp-list acp-list--bullet","data-node-type":"bulletList"},i)}case"orderedList":{const i=Number.isInteger(e.start)&&Number(e.start)>=1?Number(e.start):1,s=k(n.content).map((o,a)=>U(o,p(r,"content",a),t)).filter(o=>o!==null);return f(t,"ol",{class:"acp-list acp-list--ordered","data-node-type":"orderedList",start:i},s)}case"codeBlock":{const i=typeof e.language=="string"&&e.language?e.language:void 0,s=k(n.content).filter(o=>y(o)&&o.type==="text"&&typeof o.text=="string").map(o=>o.text).join("");return f(t,"pre",{class:"acp-code-block","data-node-type":"codeBlock","data-language":i},[f(t,"code",{class:i?`language-${i}`:void 0},s)])}case"horizontalRule":return f(t,"hr",{class:"acp-horizontal-rule","data-node-type":"horizontalRule"});case"image":{const i=_(tt(e.src,t.imageBaseUrl),"image");if(!i)return A(t,{code:"UNSAFE_URL",path:p(r,"attrs","src"),message:"The image URL is empty, malformed, or uses a disallowed protocol.",nodeType:"image"}),null;const s=rt(e.imageAlign)?e.imageAlign:"center",o=Number.isInteger(e.width)&&Number(e.width)>=1&&Number(e.width)<=1e4?Number(e.width):void 0,a=Number.isInteger(e.height)&&Number(e.height)>=1&&Number(e.height)<=1e4?Number(e.height):void 0;return f(t,"div",{class:["acp-image",`acp-image--${s}`],"data-node-type":"image","data-image-align":s},[f(t,"img",{class:"acp-image__element",src:i,alt:typeof e.alt=="string"?e.alt:"",title:typeof e.title=="string"?e.title:void 0,width:o,height:a,"data-image-align":s})])}case"articleButton":return ot(n,r,t);case"table":{const i=k(n.content).map((s,o)=>st(s,p(r,"content",o),t)).filter(s=>s!==null);return f(t,"div",{class:"acp-table-wrapper","data-node-type":"table"},[f(t,"table",{class:"acp-table"},[f(t,"tbody",i)])])}}return null}function S(n,r,t){return k(n).map((e,i)=>z(e,p(r,i),t)).filter(e=>e!==null)}function at(n,r){const t=k(n.content),e=new Map;r.customSlots.forEach(s=>{var a;if(!Number.isInteger(s.location)||s.location<1||s.location>t.length)return;const o=(a=e.get(s.location))!=null?a:[];o.push(s),e.set(s.location,o)});const i=[];return t.forEach((s,o)=>{var u;const a=o+1;(u=e.get(a))==null||u.forEach(g=>i.push(...g.content));const l=z(s,p("/content",o),r);l&&typeof l!="string"&&i.push(l)}),i}function ct(n,r){return!y(n)||n.type!=="doc"?[]:at(n,r)}const lt=new Set(["paragraph","heading","blockquote","bulletList","orderedList","codeBlock","horizontalRule","image","articleButton","table"]),dt=new Set(["left","center","right","justify"]),ut=new Set(["left","center","right"]),ft=new Set(["bold","italic","strike","underline","code"]);function I(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function c(n,r){return`${n}/${String(r).replaceAll("~","~0").replaceAll("/","~1")}`}function d(n,...r){let t=n;for(const e of r)t=c(t,e);return t}class gt{constructor(){C(this,"issues",[])}validate(r){if(!I(r))return this.add("INVALID_ROOT","","The document must be an object."),this.result();this.checkProperties(r,"",["type","content"],["type","content"]),r.type!=="doc"&&this.add("INVALID_ROOT","/type",'The root node type must be "doc".');const t=this.requireArray(r.content,"/content");return t==null||t.forEach((e,i)=>this.validateBlock(e,c("/content",i))),this.result()}result(){return{valid:this.issues.length===0,issues:this.issues}}add(r,t,e,i){this.issues.push(m({code:r,path:t,message:e},i?{nodeType:i}:{}))}checkProperties(r,t,e,i=[],s){const o=new Set(e);for(const a of Object.keys(r))o.has(a)||this.add("UNKNOWN_PROPERTY",c(t,a),`Property "${a}" is not allowed.`,s);for(const a of i)a in r||this.add("MISSING_PROPERTY",c(t,a),`Required property "${a}" is missing.`,s)}requireArray(r,t,e){return Array.isArray(r)?r:(this.add("INVALID_TYPE",t,"Expected an array.",e),null)}optionalArray(r,t,e){return r===void 0?[]:this.requireArray(r,t,e)}requireNonEmptyArray(r,t,e){const i=this.requireArray(r,t,e);return i&&i.length===0&&this.add("INVALID_CONTENT",t,`Node "${e}" must contain at least one child.`,e),i}requireRecord(r,t,e){return I(r)?r:(this.add("INVALID_TYPE",t,"Expected an object.",e),null)}optionalRecord(r,t,e){return r===void 0?{}:this.requireRecord(r,t,e)}requireString(r,t,e,i={}){return typeof r!="string"?(this.add("INVALID_TYPE",t,"Expected a string.",e),!1):!i.allowEmpty&&r.length===0?(this.add("INVALID_VALUE",t,"The string must not be empty.",e),!1):i.maxLength!==void 0&&r.length>i.maxLength?(this.add("INVALID_VALUE",t,`The string must contain at most ${i.maxLength} characters.`,e),!1):!0}optionalString(r,t,e,i={}){r!==void 0&&this.requireString(r,t,e,i)}requireInteger(r,t,e,i,s){if(!Number.isInteger(r))return this.add("INVALID_TYPE",t,"Expected an integer.",e),!1;const o=r;return i!==void 0&&o<i?(this.add("INVALID_VALUE",t,`Value must be at least ${i}.`,e),!1):s!==void 0&&o>s?(this.add("INVALID_VALUE",t,`Value must be at most ${s}.`,e),!1):!0}validateBlock(r,t){if(!I(r)){this.add("INVALID_TYPE",t,"A block node must be an object.");return}const e=r.type;if(typeof e!="string"){this.add("MISSING_PROPERTY",c(t,"type"),"A block node requires a type.");return}if(!lt.has(e)){this.add("UNKNOWN_NODE",c(t,"type"),`Unknown block node "${e}".`,e);return}switch(e){case"paragraph":this.validateParagraph(r,t);break;case"heading":this.validateHeading(r,t);break;case"blockquote":this.validateBlockquote(r,t);break;case"bulletList":this.validateBulletList(r,t);break;case"orderedList":this.validateOrderedList(r,t);break;case"codeBlock":this.validateCodeBlock(r,t);break;case"horizontalRule":this.checkProperties(r,t,["type"],["type"],e);break;case"image":this.validateImage(r,t);break;case"articleButton":this.validateArticleButton(r,t);break;case"table":this.validateTable(r,t);break}}validateParagraph(r,t){const e="paragraph";this.checkProperties(r,t,["type","attrs","content"],["type"],e),this.validateTextAlignAttrs(r.attrs,c(t,"attrs"),e,!1),this.validateInlineContent(r.content,c(t,"content"),e)}validateHeading(r,t){const e="heading";this.checkProperties(r,t,["type","attrs","content"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["level","textAlign"],["level"],e),this.requireInteger(i.level,d(t,"attrs","level"),e,1,6),this.validateTextAlign(i.textAlign,d(t,"attrs","textAlign"),e)),this.validateInlineContent(r.content,c(t,"content"),e)}validateTextAlignAttrs(r,t,e,i){const s=i?this.requireRecord(r,t,e):this.optionalRecord(r,t,e);s&&(this.checkProperties(s,t,["textAlign"],[],e),this.validateTextAlign(s.textAlign,c(t,"textAlign"),e))}validateTextAlign(r,t,e){r!==void 0&&(typeof r!="string"?this.add("INVALID_TYPE",t,"Text alignment must be a string.",e):dt.has(r)||this.add("INVALID_VALUE",t,`Unsupported text alignment "${r}".`,e))}validateInlineContent(r,t,e){const i=this.optionalArray(r,t,e);i==null||i.forEach((s,o)=>this.validateText(s,c(t,o),!0))}validateText(r,t,e){if(!I(r)){this.add("INVALID_TYPE",t,"A text node must be an object.","text");return}const i=e?["type","text","marks"]:["type","text"];if(this.checkProperties(r,t,i,["type","text"],"text"),r.type!=="text"&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a text node.","text"),this.requireString(r.text,c(t,"text"),"text"),e&&r.marks!==void 0){const s=this.requireArray(r.marks,c(t,"marks"),"text");s==null||s.forEach((o,a)=>this.validateMark(o,d(t,"marks",a)))}}validateMark(r,t){if(!I(r)){this.add("INVALID_TYPE",t,"A mark must be an object.");return}if(typeof r.type!="string"){this.add("MISSING_PROPERTY",c(t,"type"),"A mark requires a type.");return}if(ft.has(r.type)){this.checkProperties(r,t,["type"],["type"],r.type);return}if(r.type!=="link"){this.add("UNKNOWN_MARK",c(t,"type"),`Unknown mark "${r.type}".`,r.type);return}this.checkProperties(r,t,["type","attrs"],["type","attrs"],"link");const e=this.requireRecord(r.attrs,c(t,"attrs"),"link");e&&(this.checkProperties(e,c(t,"attrs"),["href","target"],["href"],"link"),this.requireString(e.href,d(t,"attrs","href"),"link"),e.target!==void 0&&e.target!=="_blank"&&e.target!=="_self"&&this.add("INVALID_VALUE",d(t,"attrs","target"),'Link target must be "_blank" or "_self".',"link"))}validateBlockquote(r,t){const e="blockquote";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);i==null||i.forEach((s,o)=>this.validateBlock(s,d(t,"content",o)))}validateBulletList(r,t){const e="bulletList";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);i==null||i.forEach((s,o)=>this.validateListItem(s,d(t,"content",o)))}validateOrderedList(r,t){const e="orderedList";this.checkProperties(r,t,["type","attrs","content"],["type","content"],e);const i=this.optionalRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["start"],[],e),i.start!==void 0&&this.requireInteger(i.start,d(t,"attrs","start"),e,1));const s=this.requireNonEmptyArray(r.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateListItem(o,d(t,"content",a)))}validateListItem(r,t){const e="listItem",i=this.requireRecord(r,t,e);if(!i)return;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a listItem node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateBlock(o,d(t,"content",a)))}validateCodeBlock(r,t){const e="codeBlock";this.checkProperties(r,t,["type","attrs","content"],["type"],e);const i=this.optionalRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["language"],[],e),this.optionalString(i.language,d(t,"attrs","language"),e,{maxLength:32}));const s=this.optionalArray(r.content,c(t,"content"),e);s&&(s.length>1&&this.add("INVALID_CONTENT",c(t,"content"),"A codeBlock may contain at most one text node.",e),s.forEach((o,a)=>this.validateText(o,d(t,"content",a),!1)))}validateImage(r,t){const e="image";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["src","alt","title","width","height","imageAlign"],["src"],e),this.requireString(i.src,d(t,"attrs","src"),e),this.optionalString(i.alt,d(t,"attrs","alt"),e,{allowEmpty:!0}),this.optionalString(i.title,d(t,"attrs","title"),e,{allowEmpty:!0}),i.width!==void 0&&this.requireInteger(i.width,d(t,"attrs","width"),e,1,1e4),i.height!==void 0&&this.requireInteger(i.height,d(t,"attrs","height"),e,1,1e4),i.imageAlign!==void 0&&(typeof i.imageAlign!="string"?this.add("INVALID_TYPE",d(t,"attrs","imageAlign"),"Image alignment must be a string.",e):ut.has(i.imageAlign)||this.add("INVALID_VALUE",d(t,"attrs","imageAlign"),`Unsupported image alignment "${i.imageAlign}".`,e)))}validateArticleButton(r,t){const e="articleButton";this.checkProperties(r,t,["type","attrs"],["type","attrs"],e);const i=this.requireRecord(r.attrs,c(t,"attrs"),e);i&&(this.checkProperties(i,c(t,"attrs"),["id","title","text","style","href"],["text","style"],e),i.style==="text"||i.style==="button"?"id"in i?this.requireString(i.id,d(t,"attrs","id"),e):this.add("MISSING_PROPERTY",d(t,"attrs","id"),'Required property "id" is missing for an articleButton with text or button style.',e):this.optionalString(i.id,d(t,"attrs","id"),e),this.optionalString(i.title,d(t,"attrs","title"),e),this.requireString(i.text,d(t,"attrs","text"),e),this.optionalString(i.href,d(t,"attrs","href"),e),i.style!=="text"&&i.style!=="button"&&i.style!=="link"&&this.add("INVALID_VALUE",d(t,"attrs","style"),'Article button style must be "text", "button", or "link".',e),i.href!==void 0&&i.style!=="link"&&this.add("INVALID_VALUE",d(t,"attrs","href"),'Article button href may only be present when style is "link".',e))}validateTable(r,t){const e="table";this.checkProperties(r,t,["type","content"],["type","content"],e);const i=this.requireNonEmptyArray(r.content,c(t,"content"),e);if(!i)return;let s=null;i.forEach((o,a)=>{const l=d(t,"content",a),u=this.validateTableRow(o,l);u!==null&&(s===null?s=u:u!==s&&this.add("TABLE_COLUMN_MISMATCH",c(l,"content"),`Expected ${s} table cells but received ${u}.`,"tableRow"))})}validateTableRow(r,t){var o;const e="tableRow",i=this.requireRecord(r,t,e);if(!i)return null;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a tableRow node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);return s==null||s.forEach((a,l)=>this.validateTableCell(a,d(t,"content",l))),(o=s==null?void 0:s.length)!=null?o:null}validateTableCell(r,t){const e="tableCell",i=this.requireRecord(r,t,e);if(!i)return;this.checkProperties(i,t,["type","content"],["type","content"],e),i.type!==e&&this.add("INVALID_CONTENT",c(t,"type"),"Expected a tableCell node.",e);const s=this.requireNonEmptyArray(i.content,c(t,"content"),e);s==null||s.forEach((o,a)=>this.validateBlock(o,d(t,"content",a)))}}function pt(n){return new gt().validate(n)}const $=Object.freeze({version:1,validate:pt,render:ct}),M=new Map([[$.version,$]]),yt=Object.freeze([...M.keys()]),O=1;function F(n){return M.get(n)}function Y(n,r={}){var s;const t=(s=r.protocolVersion)!=null?s:O,e=F(t);return e?e.validate(n):{valid:!1,issues:[{code:"UNSUPPORTED_PROTOCOL",path:"",message:`Article Content Protocol version ${t} is not supported.`}]}}function ht(){return[]}function T(n){return`${n.code}:${n.path}:${n.message}`}function mt(n){const r=n.slots();return n.props.customSlots.map(t=>{var s,o,a,l;const e={id:t.id,location:t.location},i=(l=(a=(o=(s=n.scopedSlots)[t.id])==null?void 0:o.call(s,e))!=null?a:r[t.id])!=null?l:[];return b(m({},t),{content:i})})}function kt(n,r){Array.isArray(n)?n.forEach(t=>t(r)):n==null||n(r)}const At=x.extend({name:"ArticleContentRenderIssueReporter",props:{issues:{type:Array,required:!0}},data(){return{reportedFingerprint:""}},watch:{issues:{immediate:!0,deep:!0,handler(n){const r=n.map(T).join("|");r!==this.reportedFingerprint&&(this.reportedFingerprint=r,this.$nextTick(()=>n.forEach(t=>this.$emit("render-error",t))))}}},render(n){var r,t;return(t=(r=this.$slots.default)==null?void 0:r[0])!=null?t:n()}});function v(n,r,t,e){var a;const i=(a=t[0])!=null?a:n(),s=r.listeners["render-error"],o=n(At,{props:{issues:e},on:s?{"render-error":s}:void 0},[i]);return t.length>1?[o,...t.slice(1)]:o}const bt={name:"ArticleContentRenderer",functional:!0,props:{document:{type:null,required:!0},protocolVersion:{type:Number,default:O},strict:{type:Boolean,default:!1},customSlots:{type:Array,default:ht},imageBaseUrl:{type:String,default:N},resolveArticleButtonLink:{type:Function,default:void 0}},render(n,r){const{props:t}=r,e=Y(t.document,{protocolVersion:t.protocolVersion}),i=F(t.protocolVersion),s=[];if(!i||t.strict&&!e.valid){const a=n("div",{class:"acp-render-error",attrs:{role:"alert","data-render-error":"true"}},"Invalid article content");return v(n,r,[a],e.issues)}const o=i.render(t.document,{createElement:n,customSlots:mt(r),imageBaseUrl:t.imageBaseUrl,resolveArticleButtonLink:t.resolveArticleButtonLink,emitArticleButtonClick:a=>kt(r.listeners["article-button-click"],a),reportIssue:a=>s.push(a)});return v(n,r,o,[...e.issues,...s.filter((a,l,u)=>u.findIndex(g=>T(g)===T(a))===l)])}},It=x.extend(bt);function Lt(n,r,t,e,i,s,o,a){var l=typeof n=="function"?n.options:n;return{exports:n,options:l}}var Nt=Lt(It);const B=Nt.exports,Et=Object.freeze({fileFormat:"article-content-protocol",fileFormatVersion:1,mediaType:"application/vnd.article-content-protocol+json",id:"article-content-v1",version:1,name:"Article Content Protocol v1",status:"draft",rootNode:"doc",nodeTypes:Object.freeze(["doc","paragraph","heading","blockquote","bulletList","orderedList","listItem","codeBlock","horizontalRule","image","articleButton","table","tableRow","tableCell","text"]),markTypes:Object.freeze(["bold","italic","strike","underline","code","link"])}),Rt={install(n){n.component("ArticleContentRenderer",B)}};exports.ARTICLE_CONTENT_PROTOCOL_V1=Et;exports.ArticleContentRenderer=B;exports.ArticleContentRendererPlugin=Rt;exports.CURRENT_PROTOCOL_VERSION=O;exports.SUPPORTED_PROTOCOL_VERSIONS=yt;exports.default=B;exports.validateArticleDocument=Y;