parse_html_to_node 0.0.3 → 0.0.5

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
@@ -1,19 +1,21 @@
1
- # parse_html
1
+ # parse_html_to_node
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/parse_html_to_node)](https://www.npmjs.com/package/parse_html_to_node)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
+ [![Tests](https://img.shields.io/badge/tests-44_passed,_1_skipped-green.svg)](https://vitest.dev/)
6
7
 
7
8
  一个不依赖浏览器环境的HTML字符串解析器,可将HTML转换为可操作的对象树,支持完整的DOM操作、属性管理和样式处理。
8
9
 
9
10
  ## 特性
10
11
 
11
- - 🚀 **零依赖**:纯JavaScript实现,无需浏览器环境
12
+ - 🚀 **零依赖**:纯JavaScript实现,无需浏览器环境,支持浏览器、Nodejs、小程序等运行环境
12
13
  - 🔧 **完整DOM操作**:支持`before`、`after`、`insert`等DOM操作方法
13
14
  - 🏷️ **属性管理**:提供`getAttr`、`setAttr`、`setAttrs`等方法
14
15
  - 🎨 **样式处理**:支持`getStyle`、`setStyle`、`setStyles`等方法
15
16
  - 🌳 **多根节点支持**:可解析HTML片段(多个根节点)
16
17
  - 📦 **TypeScript支持**:完整的类型定义
18
+ - 🧪 **完整测试覆盖**:包含45个单元测试,确保代码质量
17
19
  - ⚡ **高性能**:轻量级实现,快速解析
18
20
 
19
21
  ## 安装
@@ -265,6 +267,35 @@ console.log(node.child()[0].textContent); // "Hello "
265
267
  3. **样式格式**:内部使用驼峰格式,但解析时支持短横线格式。
266
268
  4. **错误处理**:无效HTML会抛出错误,请确保HTML格式正确。
267
269
 
270
+ ## 测试
271
+
272
+ 项目包含完整的单元测试套件,使用 [Vitest](https://vitest.dev/) 测试框架。
273
+
274
+ ### 测试覆盖率
275
+ - **45个测试用例**,覆盖所有核心功能
276
+ - **44个通过**,1个跳过(无效HTML解析测试)
277
+ - **测试覆盖率**:包括构造函数、DOM操作、属性管理、样式处理、HTML生成等
278
+
279
+ ### 运行测试
280
+ ```bash
281
+ # 运行所有测试
282
+ pnpm test
283
+
284
+ # 运行测试并打开UI界面
285
+ pnpm run test:ui
286
+
287
+ # 生成测试覆盖率报告
288
+ pnpm run coverage
289
+ ```
290
+
291
+ ### 测试结构
292
+ ```
293
+ __tests__/
294
+ └── parse_html.test.ts # 所有单元测试
295
+ ```
296
+
297
+ 测试文件包含了丰富的使用示例,可以作为API文档参考。
298
+
268
299
  ## 开发
269
300
 
270
301
  ### 构建项目
@@ -284,10 +315,12 @@ pnpm run build
284
315
 
285
316
  ```
286
317
  parse_html_to_node/
318
+ ├── __tests__/
319
+ │ └── parse_html.test.ts # 单元测试
287
320
  ├── lib/
288
- │ └── index.ts # 源代码
289
- ├── dist/ # 构建输出
290
- ├── text.ts # 使用示例
321
+ │ └── parse_html.ts # 源代码
322
+ ├── dist/ # 构建输出
323
+ ├── text.ts # 使用示例
291
324
  ├── package.json
292
325
  └── tsconfig.json
293
326
  ```
@@ -304,7 +337,7 @@ parse_html_to_node/
304
337
 
305
338
  ## 许可证
306
339
 
307
- [MIT](LICENSE) © Huang Jingjing
340
+ [MIT](LICENSE)
308
341
 
309
342
  ## 相关链接
310
343
 
@@ -1,2 +1,2 @@
1
- "use strict";const C=["img","br","input","meta","link","hr","area","base","col","embed","param","source","track","wbr"];function M(o){return o.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}function S(o){return o.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function A(o){const t={};if(!o)return t;const e=/([a-zA-Z0-9-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g;let n;for(;(n=e.exec(o))!==null;){const[,s,r,l,a]=n,h=r||l||a||"";t[s]=h}if(t.style){const s={},r=/([a-zA-Z0-9-]+)\s*:\s*([^;]+)/g;let l;for(;(l=r.exec(t.style))!==null;){const[,a,h]=l;s[S(a.trim())]=h.trim()}t.styleObj=s,delete t.style}return t}function g(o){if(o=o.trim(),!o)return null;if(!o.startsWith("<"))return{tagName:"#text",textContent:o,attributes:{},styles:{},children:[],parent:null};const t=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,e=o.match(t);if(e){const[,c,i]=e;if(C.includes(c.toLowerCase())){const N=A(i);return{tagName:c.toLowerCase(),attributes:N,styles:N.styleObj||{},textContent:"",children:[],parent:null}}}const n=/<([a-zA-Z0-9]+)\s*(.*?)>/,s=o.match(n);if(!s)return null;const[r,l,a]=s,h=l.toLowerCase(),u=`</${h}>`;let x=-1,d=1,m=r.length;for(;m<o.length&&d>0;){const c=o.indexOf(`<${h}`,m),i=o.indexOf(u,m);if(i===-1)break;c!==-1&&c<i?(d++,m=c+`<${h}`.length):(d--,d===0&&(x=i),m=i+u.length)}const L=x!==-1?o.slice(r.length,x).trim():o.slice(r.length).trim(),I=A(a),w={tagName:h,attributes:I,styles:I.styleObj||{},textContent:"",children:[],parent:null};if(L){const c=[];let i=L;for(;i;){const N=i.indexOf("<");if(N===-1){const p=g(i);p&&c.push(p),i=""}else if(N>0){const p=g(i.slice(0,N));p&&c.push(p),i=i.slice(N)}else{const p=i.match(n);if(!p){const f=g(i);f&&c.push(f),i="";continue}const E=p[1].toLowerCase(),$=`</${E}>`;if(C.includes(E)){const f=g(i.slice(0,p[0].length));f&&c.push(f),i=i.slice(p[0].length).trim();continue}let O=-1,j=1,T=p[0].length;for(;T<i.length&&j>0;){const f=i.indexOf(`<${E}`,T),y=i.indexOf($,T);if(y===-1)break;f!==-1&&f<y?(j++,T=f+`<${E}`.length):(j--,j===0&&(O=y),T=y+$.length)}if(O!==-1){const f=i.slice(0,O+$.length),y=g(f);y&&c.push(y),i=i.slice(O+$.length).trim()}else{const f=g(i);f&&c.push(f),i=""}}}w.children=c.filter(Boolean),w.children.length===1&&w.children[0].tagName==="#text"&&(w.textContent=w.children[0].textContent,w.children=[])}return w}function k(o){if(o=o.trim(),!o)return[];const t=[];let e=o;for(;e;){const n=e.indexOf("<");if(n===-1){const s=g(e);s&&t.push(s),e=""}else if(n>0){const s=g(e.slice(0,n));s&&t.push(s),e=e.slice(n)}else{const s=/<([a-zA-Z0-9]+)\s*(.*?)>/,r=e.match(s);if(!r){const a=g(e);a&&t.push(a),e="";continue}const l=r[1].toLowerCase();if(C.includes(l)){const a=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,h=e.match(a);if(h){const u=g(h[0]);u&&t.push(u),e=e.slice(h[0].length).trim()}else{const u=g(e);u&&t.push(u),e=""}}else{const a=`</${l}>`;let h=-1,u=1,x=r[0].length;for(;x<e.length&&u>0;){const d=e.indexOf(`<${l}`,x),m=e.indexOf(a,x);if(m===-1)break;d!==-1&&d<m?(u++,x=d+`<${l}`.length):(u--,u===0&&(h=m),x=m+a.length)}if(h!==-1){const d=e.slice(0,h+a.length),m=g(d);m&&t.push(m),e=e.slice(h+a.length).trim()}else{const d=g(e);d&&t.push(d),e=""}}}}return t.filter(Boolean)}class b{constructor(t){if(typeof t!="string")throw new Error("初始化Node必须传入HTML字符串");const e=t.trim();if(!e)throw new Error("无法解析空的HTML字符串");const n=g(e),s=k(e);if(this.tagName="",this.attributes={},this.styles={},this.textContent="",this.children=[],this.parent=null,n&&s.length===1)this.tagName=n.tagName,this.attributes={...n.attributes},this.styles={...n.styles},this.textContent=n.textContent||"",n.children.length>0&&(this.children=n.children.map(r=>{const l=new b(this.#t(r));return l.parent=this,l}));else if(s.length>0)this.tagName="#fragment",this.attributes={},this.styles={},this.textContent="",this.children=s.map(r=>{const l=new b(this.#t(r));return l.parent=this,l});else throw new Error("无法解析无效的HTML字符串")}#t(t){if(t.tagName==="#text")return t.textContent;let e=`<${t.tagName}`;const n={...t.attributes};if(Object.keys(t.styles).length>0){const r=Object.entries(t.styles).map(([l,a])=>`${M(l)}: ${a}`).join("; ");n.style=r}for(const[r,l]of Object.entries(n))r!=="styleObj"&&typeof l=="string"&&(e+=` ${r}="${l}"`);if(C.includes(t.tagName))return e+="/>",e;e+=">";let s=t.textContent;return t.children.length>0&&(s+=t.children.map(r=>this.#t(r)).join("")),`${e}${s}</${t.tagName}>`}child(){return[...this.children]}before(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行before操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n,0,e),e.parent=this.parent,this}after(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行after操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n+1,0,e),e.parent=this.parent,this}insert(t,e){if(typeof t!="number"||t<0||t>this.children.length)throw new Error(`插入位置${t}无效,必须是0到${this.children.length}之间的整数`);const n=this.#e(e);return n.tagName==="#fragment"?n.children.forEach((s,r)=>{s.parent=this,this.children.splice(t+r,0,s)}):(this.children.splice(t,0,n),n.parent=this),this}getAttr(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("属性名必须是字符串");return typeof this.attributes[t]=="string"?this.attributes[t]:null}setAttr(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="string")throw new Error("属性名必须是字符串");return e==null?delete this.attributes[t]:this.attributes[t]=String(e),this}setAttrs(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="object"||t===null)throw new Error("属性对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setAttr(e,n);return this}getStyle(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("样式属性名必须是字符串");const e=S(t);return this.styles[e]||this.styles[t]||null}setStyle(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="string")throw new Error("样式属性名必须是字符串");const n=S(t);return e==null?(delete this.styles[n],delete this.styles[t]):this.styles[n]=String(e),this}setStyles(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="object"||t===null)throw new Error("样式对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setStyle(e,n);return this}getHtml(){if(this.tagName==="#text")return this.textContent;if(this.tagName==="#fragment")return this.children.map(s=>s.getHtml()).join("");let t=`<${this.tagName}`;const e={...this.attributes};if(Object.keys(this.styles).length>0){const s=Object.entries(this.styles).map(([r,l])=>`${M(r)}: ${l}`).join("; ");e.style=s}for(const[s,r]of Object.entries(e))if(s!=="styleObj"&&typeof r=="string"){const l=r.replace(/"/g,"&quot;");t+=` ${s}="${l}"`}if(C.includes(this.tagName))return t+="/>",t;t+=">";let n=this.textContent;return this.children.length>0&&(n+=this.children.map(s=>s.getHtml()).join("")),`${t}${n}</${this.tagName}>`}#e(t){if(t instanceof b)return t;if(typeof t=="string")return new b(t);throw new Error("插入的节点必须是HTML字符串或Node实例")}}module.exports=b;
1
+ "use strict";const C=["img","br","input","meta","link","hr","area","base","col","embed","param","source","track","wbr"];function M(o){return o.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}function S(o){return o.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function A(o){const t={};if(!o)return t;const e=/([a-zA-Z0-9-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g;let n;for(;(n=e.exec(o))!==null;){const[,s,r,l,a]=n,h=r||l||a||"";t[s]=h}if(t.style){const s={},r=/([a-zA-Z0-9-]+)\s*:\s*([^;]+)/g;let l;for(;(l=r.exec(t.style))!==null;){const[,a,h]=l;s[S(a.trim())]=h.trim()}t.styleObj=s,delete t.style}return t}function g(o){if(o=o,!o)return null;if(!o.startsWith("<"))return{tagName:"#text",textContent:o,attributes:{},styles:{},children:[],parent:null};const t=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,e=o.match(t);if(e){const[,c,i]=e;if(C.includes(c.toLowerCase())){const N=A(i);return{tagName:c.toLowerCase(),attributes:N,styles:N.styleObj||{},textContent:"",children:[],parent:null}}}const n=/<([a-zA-Z0-9]+)\s*(.*?)>/,s=o.match(n);if(!s)return null;const[r,l,a]=s,h=l.toLowerCase(),u=`</${h}>`;let x=-1,d=1,m=r.length;for(;m<o.length&&d>0;){const c=o.indexOf(`<${h}`,m),i=o.indexOf(u,m);if(i===-1)break;c!==-1&&c<i?(d++,m=c+`<${h}`.length):(d--,d===0&&(x=i),m=i+u.length)}const L=x!==-1?o.slice(r.length,x):o.slice(r.length),I=A(a),w={tagName:h,attributes:I,styles:I.styleObj||{},textContent:"",children:[],parent:null};if(L){const c=[];let i=L;for(;i;){const N=i.indexOf("<");if(N===-1){const p=g(i);p&&c.push(p),i=""}else if(N>0){const p=g(i.slice(0,N));p&&c.push(p),i=i.slice(N)}else{const p=i.match(n);if(!p){const f=g(i);f&&c.push(f),i="";continue}const E=p[1].toLowerCase(),$=`</${E}>`;if(C.includes(E)){const f=g(i.slice(0,p[0].length));f&&c.push(f),i=i.slice(p[0].length);continue}let O=-1,j=1,T=p[0].length;for(;T<i.length&&j>0;){const f=i.indexOf(`<${E}`,T),y=i.indexOf($,T);if(y===-1)break;f!==-1&&f<y?(j++,T=f+`<${E}`.length):(j--,j===0&&(O=y),T=y+$.length)}if(O!==-1){const f=i.slice(0,O+$.length),y=g(f);y&&c.push(y),i=i.slice(O+$.length)}else{const f=g(i);f&&c.push(f),i=""}}}w.children=c.filter(Boolean),w.children.length===1&&w.children[0].tagName==="#text"&&(w.textContent=w.children[0].textContent,w.children=[])}return w}function k(o){if(o=o,!o)return[];const t=[];let e=o;for(;e;){const n=e.indexOf("<");if(n===-1){const s=g(e);s&&t.push(s),e=""}else if(n>0){const s=g(e.slice(0,n));s&&t.push(s),e=e.slice(n)}else{const s=/<([a-zA-Z0-9]+)\s*(.*?)>/,r=e.match(s);if(!r){const a=g(e);a&&t.push(a),e="";continue}const l=r[1].toLowerCase();if(C.includes(l)){const a=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,h=e.match(a);if(h){const u=g(h[0]);u&&t.push(u),e=e.slice(h[0].length)}else{const u=g(e);u&&t.push(u),e=""}}else{const a=`</${l}>`;let h=-1,u=1,x=r[0].length;for(;x<e.length&&u>0;){const d=e.indexOf(`<${l}`,x),m=e.indexOf(a,x);if(m===-1)break;d!==-1&&d<m?(u++,x=d+`<${l}`.length):(u--,u===0&&(h=m),x=m+a.length)}if(h!==-1){const d=e.slice(0,h+a.length),m=g(d);m&&t.push(m),e=e.slice(h+a.length)}else{const d=g(e);d&&t.push(d),e=""}}}}return t.filter(Boolean)}class b{constructor(t){if(typeof t!="string")throw new Error("初始化Node必须传入HTML字符串");const e=t;if(!e)throw new Error("无法解析空的HTML字符串");const n=g(e),s=k(e);if(this.tagName="",this.attributes={},this.styles={},this.textContent="",this.children=[],this.parent=null,n&&s.length===1)this.tagName=n.tagName,this.attributes={...n.attributes},this.styles={...n.styles},this.textContent=n.textContent||"",n.children.length>0&&(this.children=n.children.map(r=>{const l=new b(this.#t(r));return l.parent=this,l}));else if(s.length>0)this.tagName="#fragment",this.attributes={},this.styles={},this.textContent="",this.children=s.map(r=>{const l=new b(this.#t(r));return l.parent=this,l});else throw new Error("无法解析无效的HTML字符串")}#t(t){if(t.tagName==="#text")return t.textContent;let e=`<${t.tagName}`;const n={...t.attributes};if(Object.keys(t.styles).length>0){const r=Object.entries(t.styles).map(([l,a])=>`${M(l)}: ${a}`).join("; ");n.style=r}for(const[r,l]of Object.entries(n))r!=="styleObj"&&typeof l=="string"&&(e+=` ${r}="${l}"`);if(C.includes(t.tagName))return e+="/>",e;e+=">";let s=t.textContent;return t.children.length>0&&(s+=t.children.map(r=>this.#t(r)).join("")),`${e}${s}</${t.tagName}>`}child(){return[...this.children]}before(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行before操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n,0,e),e.parent=this.parent,this}after(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行after操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n+1,0,e),e.parent=this.parent,this}insert(t,e){if(typeof t!="number"||t<0||t>this.children.length)throw new Error(`插入位置${t}无效,必须是0到${this.children.length}之间的整数`);const n=this.#e(e);return n.tagName==="#fragment"?n.children.forEach((s,r)=>{s.parent=this,this.children.splice(t+r,0,s)}):(this.children.splice(t,0,n),n.parent=this),this}getAttr(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("属性名必须是字符串");return typeof this.attributes[t]=="string"?this.attributes[t]:null}setAttr(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="string")throw new Error("属性名必须是字符串");return e==null?delete this.attributes[t]:this.attributes[t]=String(e),this}setAttrs(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="object"||t===null)throw new Error("属性对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setAttr(e,n);return this}getStyle(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("样式属性名必须是字符串");const e=S(t);return this.styles[e]||this.styles[t]||null}setStyle(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="string")throw new Error("样式属性名必须是字符串");const n=S(t);return e==null?(delete this.styles[n],delete this.styles[t]):this.styles[n]=String(e),this}setStyles(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="object"||t===null)throw new Error("样式对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setStyle(e,n);return this}getHtml(){if(this.tagName==="#text")return this.textContent;if(this.tagName==="#fragment")return this.children.map(s=>s.getHtml()).join("");let t=`<${this.tagName}`;const e={...this.attributes};if(Object.keys(this.styles).length>0){const s=Object.entries(this.styles).map(([r,l])=>`${M(r)}: ${l}`).join("; ");e.style=s}for(const[s,r]of Object.entries(e))if(s!=="styleObj"&&typeof r=="string"){const l=r.replace(/"/g,"&quot;");t+=` ${s}="${l}"`}if(C.includes(this.tagName))return t+="/>",t;t+=">";let n=this.textContent;return this.children.length>0&&(n+=this.children.map(s=>s.getHtml()).join("")),`${t}${n}</${this.tagName}>`}#e(t){if(t instanceof b)return t;if(typeof t=="string")return new b(t);throw new Error("插入的节点必须是HTML字符串或Node实例")}}module.exports=b;
2
2
  //# sourceMappingURL=parse_html.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse_html.cjs.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html.trim();\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex).trim() : html.slice(startTag.length).trim();\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length).trim();\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html.trim();\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length).trim();\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html.trim();\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
1
+ {"version":3,"file":"parse_html.cjs.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html;\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex) : html.slice(startTag.length);\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length);\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html;\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length);\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html;\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
@@ -26,7 +26,7 @@ function A(o) {
26
26
  return t;
27
27
  }
28
28
  function g(o) {
29
- if (o = o.trim(), !o) return null;
29
+ if (o = o, !o) return null;
30
30
  if (!o.startsWith("<"))
31
31
  return {
32
32
  tagName: "#text",
@@ -63,7 +63,7 @@ function g(o) {
63
63
  if (i === -1) break;
64
64
  c !== -1 && c < i ? (d++, m = c + `<${h}`.length) : (d--, d === 0 && (x = i), m = i + u.length);
65
65
  }
66
- const L = x !== -1 ? o.slice(r.length, x).trim() : o.slice(r.length).trim(), I = A(a), w = {
66
+ const L = x !== -1 ? o.slice(r.length, x) : o.slice(r.length), I = A(a), w = {
67
67
  tagName: h,
68
68
  attributes: I,
69
69
  // 类型匹配
@@ -94,7 +94,7 @@ function g(o) {
94
94
  const E = p[1].toLowerCase(), $ = `</${E}>`;
95
95
  if (C.includes(E)) {
96
96
  const f = g(i.slice(0, p[0].length));
97
- f && c.push(f), i = i.slice(p[0].length).trim();
97
+ f && c.push(f), i = i.slice(p[0].length);
98
98
  continue;
99
99
  }
100
100
  let O = -1, j = 1, b = p[0].length;
@@ -105,7 +105,7 @@ function g(o) {
105
105
  }
106
106
  if (O !== -1) {
107
107
  const f = i.slice(0, O + $.length), y = g(f);
108
- y && c.push(y), i = i.slice(O + $.length).trim();
108
+ y && c.push(y), i = i.slice(O + $.length);
109
109
  } else {
110
110
  const f = g(i);
111
111
  f && c.push(f), i = "";
@@ -117,7 +117,7 @@ function g(o) {
117
117
  return w;
118
118
  }
119
119
  function k(o) {
120
- if (o = o.trim(), !o) return [];
120
+ if (o = o, !o) return [];
121
121
  const t = [];
122
122
  let e = o;
123
123
  for (; e; ) {
@@ -140,7 +140,7 @@ function k(o) {
140
140
  const a = /<([a-zA-Z0-9]+)\s*(.*?)\/?>/, h = e.match(a);
141
141
  if (h) {
142
142
  const u = g(h[0]);
143
- u && t.push(u), e = e.slice(h[0].length).trim();
143
+ u && t.push(u), e = e.slice(h[0].length);
144
144
  } else {
145
145
  const u = g(e);
146
146
  u && t.push(u), e = "";
@@ -155,7 +155,7 @@ function k(o) {
155
155
  }
156
156
  if (h !== -1) {
157
157
  const d = e.slice(0, h + a.length), m = g(d);
158
- m && t.push(m), e = e.slice(h + a.length).trim();
158
+ m && t.push(m), e = e.slice(h + a.length);
159
159
  } else {
160
160
  const d = g(e);
161
161
  d && t.push(d), e = "";
@@ -173,7 +173,7 @@ class T {
173
173
  constructor(t) {
174
174
  if (typeof t != "string")
175
175
  throw new Error("初始化Node必须传入HTML字符串");
176
- const e = t.trim();
176
+ const e = t;
177
177
  if (!e)
178
178
  throw new Error("无法解析空的HTML字符串");
179
179
  const n = g(e), s = k(e);
@@ -1 +1 @@
1
- {"version":3,"file":"parse_html.es.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html.trim();\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex).trim() : html.slice(startTag.length).trim();\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length).trim();\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html.trim();\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length).trim();\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html.trim();\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
1
+ {"version":3,"file":"parse_html.es.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html;\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex) : html.slice(startTag.length);\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length);\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html;\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length);\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html;\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- (function(x,T){typeof exports=="object"&&typeof module<"u"?module.exports=T():typeof define=="function"&&define.amd?define(T):(x=typeof globalThis<"u"?globalThis:x||self,x.parse_html=T())})(this,(function(){"use strict";const x=["img","br","input","meta","link","hr","area","base","col","embed","param","source","track","wbr"];function T(o){return o.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}function L(o){return o.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function I(o){const t={};if(!o)return t;const e=/([a-zA-Z0-9-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g;let n;for(;(n=e.exec(o))!==null;){const[,s,r,l,a]=n,h=r||l||a||"";t[s]=h}if(t.style){const s={},r=/([a-zA-Z0-9-]+)\s*:\s*([^;]+)/g;let l;for(;(l=r.exec(t.style))!==null;){const[,a,h]=l;s[L(a.trim())]=h.trim()}t.styleObj=s,delete t.style}return t}function c(o){if(o=o.trim(),!o)return null;if(!o.startsWith("<"))return{tagName:"#text",textContent:o,attributes:{},styles:{},children:[],parent:null};const t=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,e=o.match(t);if(e){const[,f,i]=e;if(x.includes(f.toLowerCase())){const y=I(i);return{tagName:f.toLowerCase(),attributes:y,styles:y.styleObj||{},textContent:"",children:[],parent:null}}}const n=/<([a-zA-Z0-9]+)\s*(.*?)>/,s=o.match(n);if(!s)return null;const[r,l,a]=s,h=l.toLowerCase(),u=`</${h}>`;let w=-1,d=1,m=r.length;for(;m<o.length&&d>0;){const f=o.indexOf(`<${h}`,m),i=o.indexOf(u,m);if(i===-1)break;f!==-1&&f<i?(d++,m=f+`<${h}`.length):(d--,d===0&&(w=i),m=i+u.length)}const M=w!==-1?o.slice(r.length,w).trim():o.slice(r.length).trim(),A=I(a),N={tagName:h,attributes:A,styles:A.styleObj||{},textContent:"",children:[],parent:null};if(M){const f=[];let i=M;for(;i;){const y=i.indexOf("<");if(y===-1){const p=c(i);p&&f.push(p),i=""}else if(y>0){const p=c(i.slice(0,y));p&&f.push(p),i=i.slice(y)}else{const p=i.match(n);if(!p){const g=c(i);g&&f.push(g),i="";continue}const $=p[1].toLowerCase(),O=`</${$}>`;if(x.includes($)){const g=c(i.slice(0,p[0].length));g&&f.push(g),i=i.slice(p[0].length).trim();continue}let j=-1,S=1,E=p[0].length;for(;E<i.length&&S>0;){const g=i.indexOf(`<${$}`,E),b=i.indexOf(O,E);if(b===-1)break;g!==-1&&g<b?(S++,E=g+`<${$}`.length):(S--,S===0&&(j=b),E=b+O.length)}if(j!==-1){const g=i.slice(0,j+O.length),b=c(g);b&&f.push(b),i=i.slice(j+O.length).trim()}else{const g=c(i);g&&f.push(g),i=""}}}N.children=f.filter(Boolean),N.children.length===1&&N.children[0].tagName==="#text"&&(N.textContent=N.children[0].textContent,N.children=[])}return N}function k(o){if(o=o.trim(),!o)return[];const t=[];let e=o;for(;e;){const n=e.indexOf("<");if(n===-1){const s=c(e);s&&t.push(s),e=""}else if(n>0){const s=c(e.slice(0,n));s&&t.push(s),e=e.slice(n)}else{const s=/<([a-zA-Z0-9]+)\s*(.*?)>/,r=e.match(s);if(!r){const a=c(e);a&&t.push(a),e="";continue}const l=r[1].toLowerCase();if(x.includes(l)){const a=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,h=e.match(a);if(h){const u=c(h[0]);u&&t.push(u),e=e.slice(h[0].length).trim()}else{const u=c(e);u&&t.push(u),e=""}}else{const a=`</${l}>`;let h=-1,u=1,w=r[0].length;for(;w<e.length&&u>0;){const d=e.indexOf(`<${l}`,w),m=e.indexOf(a,w);if(m===-1)break;d!==-1&&d<m?(u++,w=d+`<${l}`.length):(u--,u===0&&(h=m),w=m+a.length)}if(h!==-1){const d=e.slice(0,h+a.length),m=c(d);m&&t.push(m),e=e.slice(h+a.length).trim()}else{const d=c(e);d&&t.push(d),e=""}}}}return t.filter(Boolean)}class C{constructor(t){if(typeof t!="string")throw new Error("初始化Node必须传入HTML字符串");const e=t.trim();if(!e)throw new Error("无法解析空的HTML字符串");const n=c(e),s=k(e);if(this.tagName="",this.attributes={},this.styles={},this.textContent="",this.children=[],this.parent=null,n&&s.length===1)this.tagName=n.tagName,this.attributes={...n.attributes},this.styles={...n.styles},this.textContent=n.textContent||"",n.children.length>0&&(this.children=n.children.map(r=>{const l=new C(this.#t(r));return l.parent=this,l}));else if(s.length>0)this.tagName="#fragment",this.attributes={},this.styles={},this.textContent="",this.children=s.map(r=>{const l=new C(this.#t(r));return l.parent=this,l});else throw new Error("无法解析无效的HTML字符串")}#t(t){if(t.tagName==="#text")return t.textContent;let e=`<${t.tagName}`;const n={...t.attributes};if(Object.keys(t.styles).length>0){const r=Object.entries(t.styles).map(([l,a])=>`${T(l)}: ${a}`).join("; ");n.style=r}for(const[r,l]of Object.entries(n))r!=="styleObj"&&typeof l=="string"&&(e+=` ${r}="${l}"`);if(x.includes(t.tagName))return e+="/>",e;e+=">";let s=t.textContent;return t.children.length>0&&(s+=t.children.map(r=>this.#t(r)).join("")),`${e}${s}</${t.tagName}>`}child(){return[...this.children]}before(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行before操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n,0,e),e.parent=this.parent,this}after(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行after操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n+1,0,e),e.parent=this.parent,this}insert(t,e){if(typeof t!="number"||t<0||t>this.children.length)throw new Error(`插入位置${t}无效,必须是0到${this.children.length}之间的整数`);const n=this.#e(e);return n.tagName==="#fragment"?n.children.forEach((s,r)=>{s.parent=this,this.children.splice(t+r,0,s)}):(this.children.splice(t,0,n),n.parent=this),this}getAttr(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("属性名必须是字符串");return typeof this.attributes[t]=="string"?this.attributes[t]:null}setAttr(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="string")throw new Error("属性名必须是字符串");return e==null?delete this.attributes[t]:this.attributes[t]=String(e),this}setAttrs(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="object"||t===null)throw new Error("属性对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setAttr(e,n);return this}getStyle(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("样式属性名必须是字符串");const e=L(t);return this.styles[e]||this.styles[t]||null}setStyle(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="string")throw new Error("样式属性名必须是字符串");const n=L(t);return e==null?(delete this.styles[n],delete this.styles[t]):this.styles[n]=String(e),this}setStyles(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="object"||t===null)throw new Error("样式对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setStyle(e,n);return this}getHtml(){if(this.tagName==="#text")return this.textContent;if(this.tagName==="#fragment")return this.children.map(s=>s.getHtml()).join("");let t=`<${this.tagName}`;const e={...this.attributes};if(Object.keys(this.styles).length>0){const s=Object.entries(this.styles).map(([r,l])=>`${T(r)}: ${l}`).join("; ");e.style=s}for(const[s,r]of Object.entries(e))if(s!=="styleObj"&&typeof r=="string"){const l=r.replace(/"/g,"&quot;");t+=` ${s}="${l}"`}if(x.includes(this.tagName))return t+="/>",t;t+=">";let n=this.textContent;return this.children.length>0&&(n+=this.children.map(s=>s.getHtml()).join("")),`${t}${n}</${this.tagName}>`}#e(t){if(t instanceof C)return t;if(typeof t=="string")return new C(t);throw new Error("插入的节点必须是HTML字符串或Node实例")}}return C}));
1
+ (function(x,T){typeof exports=="object"&&typeof module<"u"?module.exports=T():typeof define=="function"&&define.amd?define(T):(x=typeof globalThis<"u"?globalThis:x||self,x.parse_html=T())})(this,(function(){"use strict";const x=["img","br","input","meta","link","hr","area","base","col","embed","param","source","track","wbr"];function T(o){return o.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}function L(o){return o.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function I(o){const t={};if(!o)return t;const e=/([a-zA-Z0-9-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g;let n;for(;(n=e.exec(o))!==null;){const[,s,r,l,a]=n,h=r||l||a||"";t[s]=h}if(t.style){const s={},r=/([a-zA-Z0-9-]+)\s*:\s*([^;]+)/g;let l;for(;(l=r.exec(t.style))!==null;){const[,a,h]=l;s[L(a.trim())]=h.trim()}t.styleObj=s,delete t.style}return t}function c(o){if(o=o,!o)return null;if(!o.startsWith("<"))return{tagName:"#text",textContent:o,attributes:{},styles:{},children:[],parent:null};const t=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,e=o.match(t);if(e){const[,f,i]=e;if(x.includes(f.toLowerCase())){const y=I(i);return{tagName:f.toLowerCase(),attributes:y,styles:y.styleObj||{},textContent:"",children:[],parent:null}}}const n=/<([a-zA-Z0-9]+)\s*(.*?)>/,s=o.match(n);if(!s)return null;const[r,l,a]=s,h=l.toLowerCase(),u=`</${h}>`;let w=-1,d=1,p=r.length;for(;p<o.length&&d>0;){const f=o.indexOf(`<${h}`,p),i=o.indexOf(u,p);if(i===-1)break;f!==-1&&f<i?(d++,p=f+`<${h}`.length):(d--,d===0&&(w=i),p=i+u.length)}const M=w!==-1?o.slice(r.length,w):o.slice(r.length),A=I(a),N={tagName:h,attributes:A,styles:A.styleObj||{},textContent:"",children:[],parent:null};if(M){const f=[];let i=M;for(;i;){const y=i.indexOf("<");if(y===-1){const m=c(i);m&&f.push(m),i=""}else if(y>0){const m=c(i.slice(0,y));m&&f.push(m),i=i.slice(y)}else{const m=i.match(n);if(!m){const g=c(i);g&&f.push(g),i="";continue}const $=m[1].toLowerCase(),O=`</${$}>`;if(x.includes($)){const g=c(i.slice(0,m[0].length));g&&f.push(g),i=i.slice(m[0].length);continue}let j=-1,S=1,E=m[0].length;for(;E<i.length&&S>0;){const g=i.indexOf(`<${$}`,E),b=i.indexOf(O,E);if(b===-1)break;g!==-1&&g<b?(S++,E=g+`<${$}`.length):(S--,S===0&&(j=b),E=b+O.length)}if(j!==-1){const g=i.slice(0,j+O.length),b=c(g);b&&f.push(b),i=i.slice(j+O.length)}else{const g=c(i);g&&f.push(g),i=""}}}N.children=f.filter(Boolean),N.children.length===1&&N.children[0].tagName==="#text"&&(N.textContent=N.children[0].textContent,N.children=[])}return N}function k(o){if(o=o,!o)return[];const t=[];let e=o;for(;e;){const n=e.indexOf("<");if(n===-1){const s=c(e);s&&t.push(s),e=""}else if(n>0){const s=c(e.slice(0,n));s&&t.push(s),e=e.slice(n)}else{const s=/<([a-zA-Z0-9]+)\s*(.*?)>/,r=e.match(s);if(!r){const a=c(e);a&&t.push(a),e="";continue}const l=r[1].toLowerCase();if(x.includes(l)){const a=/<([a-zA-Z0-9]+)\s*(.*?)\/?>/,h=e.match(a);if(h){const u=c(h[0]);u&&t.push(u),e=e.slice(h[0].length)}else{const u=c(e);u&&t.push(u),e=""}}else{const a=`</${l}>`;let h=-1,u=1,w=r[0].length;for(;w<e.length&&u>0;){const d=e.indexOf(`<${l}`,w),p=e.indexOf(a,w);if(p===-1)break;d!==-1&&d<p?(u++,w=d+`<${l}`.length):(u--,u===0&&(h=p),w=p+a.length)}if(h!==-1){const d=e.slice(0,h+a.length),p=c(d);p&&t.push(p),e=e.slice(h+a.length)}else{const d=c(e);d&&t.push(d),e=""}}}}return t.filter(Boolean)}class C{constructor(t){if(typeof t!="string")throw new Error("初始化Node必须传入HTML字符串");const e=t;if(!e)throw new Error("无法解析空的HTML字符串");const n=c(e),s=k(e);if(this.tagName="",this.attributes={},this.styles={},this.textContent="",this.children=[],this.parent=null,n&&s.length===1)this.tagName=n.tagName,this.attributes={...n.attributes},this.styles={...n.styles},this.textContent=n.textContent||"",n.children.length>0&&(this.children=n.children.map(r=>{const l=new C(this.#t(r));return l.parent=this,l}));else if(s.length>0)this.tagName="#fragment",this.attributes={},this.styles={},this.textContent="",this.children=s.map(r=>{const l=new C(this.#t(r));return l.parent=this,l});else throw new Error("无法解析无效的HTML字符串")}#t(t){if(t.tagName==="#text")return t.textContent;let e=`<${t.tagName}`;const n={...t.attributes};if(Object.keys(t.styles).length>0){const r=Object.entries(t.styles).map(([l,a])=>`${T(l)}: ${a}`).join("; ");n.style=r}for(const[r,l]of Object.entries(n))r!=="styleObj"&&typeof l=="string"&&(e+=` ${r}="${l}"`);if(x.includes(t.tagName))return e+="/>",e;e+=">";let s=t.textContent;return t.children.length>0&&(s+=t.children.map(r=>this.#t(r)).join("")),`${e}${s}</${t.tagName}>`}child(){return[...this.children]}before(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行before操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n,0,e),e.parent=this.parent,this}after(t){if(!this.parent)throw new Error("当前节点没有父节点,无法执行after操作");const e=this.#e(t),n=this.parent.children.findIndex(s=>s===this);if(n===-1)throw new Error("当前节点不在父节点的子节点列表中");return this.parent.children.splice(n+1,0,e),e.parent=this.parent,this}insert(t,e){if(typeof t!="number"||t<0||t>this.children.length)throw new Error(`插入位置${t}无效,必须是0到${this.children.length}之间的整数`);const n=this.#e(e);return n.tagName==="#fragment"?n.children.forEach((s,r)=>{s.parent=this,this.children.splice(t+r,0,s)}):(this.children.splice(t,0,n),n.parent=this),this}getAttr(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("属性名必须是字符串");return typeof this.attributes[t]=="string"?this.attributes[t]:null}setAttr(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="string")throw new Error("属性名必须是字符串");return e==null?delete this.attributes[t]:this.attributes[t]=String(e),this}setAttrs(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置属性");if(typeof t!="object"||t===null)throw new Error("属性对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setAttr(e,n);return this}getStyle(t){if(this.tagName==="#fragment"||this.tagName==="#text")return null;if(typeof t!="string")throw new Error("样式属性名必须是字符串");const e=L(t);return this.styles[e]||this.styles[t]||null}setStyle(t,e){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="string")throw new Error("样式属性名必须是字符串");const n=L(t);return e==null?(delete this.styles[n],delete this.styles[t]):this.styles[n]=String(e),this}setStyles(t){if(this.tagName==="#fragment"||this.tagName==="#text")throw new Error("片段/文本节点不支持设置样式");if(typeof t!="object"||t===null)throw new Error("样式对象必须是非空对象");for(const[e,n]of Object.entries(t))this.setStyle(e,n);return this}getHtml(){if(this.tagName==="#text")return this.textContent;if(this.tagName==="#fragment")return this.children.map(s=>s.getHtml()).join("");let t=`<${this.tagName}`;const e={...this.attributes};if(Object.keys(this.styles).length>0){const s=Object.entries(this.styles).map(([r,l])=>`${T(r)}: ${l}`).join("; ");e.style=s}for(const[s,r]of Object.entries(e))if(s!=="styleObj"&&typeof r=="string"){const l=r.replace(/"/g,"&quot;");t+=` ${s}="${l}"`}if(x.includes(this.tagName))return t+="/>",t;t+=">";let n=this.textContent;return this.children.length>0&&(n+=this.children.map(s=>s.getHtml()).join("")),`${t}${n}</${this.tagName}>`}#e(t){if(t instanceof C)return t;if(typeof t=="string")return new C(t);throw new Error("插入的节点必须是HTML字符串或Node实例")}}return C}));
2
2
  //# sourceMappingURL=parse_html.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse_html.umd.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html.trim();\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex).trim() : html.slice(startTag.length).trim();\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length).trim();\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html.trim();\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length).trim();\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length).trim();\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html.trim();\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
1
+ {"version":3,"file":"parse_html.umd.js","sources":["../lib/parse_html.ts"],"sourcesContent":["// 定义核心接口:扩展属性对象(包含内部使用的styleObj)\ninterface IAttributeData {\n [key: string]: string | Record<string, string> | undefined; // 允许值是字符串、样式对象或undefined\n styleObj?: Record<string, string>; // 新增:显式声明styleObj属性(可选)\n}\n\n// 定义核心接口:节点数据结构(解析后的原始数据)\ninterface INodeData {\n tagName: string; // #text | #fragment | 标签名(如div/p)\n textContent: string;\n attributes: IAttributeData; // 修改:使用扩展后的属性接口\n styles: Record<string, string>; // 样式键值对(驼峰格式)\n children: INodeData[];\n parent: INodeData | null;\n}\n\n// 自闭合标签常量(只读数组)\nconst SELF_CLOSING_TAGS: readonly string[] = [\"img\", \"br\", \"input\", \"meta\", \"link\", \"hr\", \"area\", \"base\", \"col\", \"embed\", \"param\", \"source\", \"track\", \"wbr\"];\n\n// 工具函数:驼峰转短横线(用于样式属性)\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n}\n\n// 工具函数:短横线转驼峰(用于样式属性)\nfunction kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_: string, match: string) => match.toUpperCase());\n}\n\n// 工具函数:解析属性字符串为属性对象(修改返回类型为IAttributeData)\nfunction parseAttributes(attrStr: string): IAttributeData {\n const attrs: IAttributeData = {}; // 修改:使用扩展后的属性接口\n if (!attrStr) return attrs;\n\n // 匹配属性键值对:key=\"value\" / key='value' / key=value\n const attrRegex = /([a-zA-Z0-9-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrStr)) !== null) {\n const [, key, doubleVal, singleVal, noQuoteVal] = match;\n const value = doubleVal || singleVal || noQuoteVal || \"\";\n attrs[key] = value;\n }\n\n // 解析style属性为样式对象(内部属性,不对外输出)\n if (attrs.style) {\n const styleObj: Record<string, string> = {};\n const styleRegex = /([a-zA-Z0-9-]+)\\s*:\\s*([^;]+)/g;\n let styleMatch: RegExpExecArray | null;\n\n while ((styleMatch = styleRegex.exec(attrs.style as string)) !== null) {\n const [, prop, val] = styleMatch;\n styleObj[kebabToCamel(prop.trim())] = val.trim();\n }\n\n attrs.styleObj = styleObj; // 现在类型匹配,无TS错误\n delete attrs.style; // 替换为结构化的样式对象\n }\n\n return attrs;\n}\n\n// 核心工具函数:解析单个节点(内部使用)\nfunction parseSingleNode(html: string): INodeData | null {\n html = html;\n if (!html) return null;\n\n // 文本节点(非标签内容)\n if (!html.startsWith(\"<\")) {\n return {\n tagName: \"#text\",\n textContent: html,\n attributes: {}, // 符合IAttributeData类型\n styles: {},\n children: [],\n parent: null,\n };\n }\n\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = html.match(selfClosingRegex);\n\n // 处理自闭合标签\n if (selfClosingMatch) {\n const [, tagName, attrStr] = selfClosingMatch;\n if (SELF_CLOSING_TAGS.includes(tagName.toLowerCase())) {\n const attrs = parseAttributes(attrStr);\n return {\n tagName: tagName.toLowerCase(),\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // styleObj是Record<string, string>,符合styles类型\n textContent: \"\",\n children: [],\n parent: null,\n };\n }\n }\n\n // 匹配开始标签\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const startTagMatch = html.match(startTagRegex);\n if (!startTagMatch) return null;\n\n const [startTag, tagName, attrStr] = startTagMatch;\n const lowerTagName = tagName.toLowerCase();\n const endTag = `</${lowerTagName}>`;\n\n // 查找匹配的结束标签(处理嵌套)\n let endTagIndex = -1;\n let tagCount = 1;\n let currentIndex = startTag.length;\n\n while (currentIndex < html.length && tagCount > 0) {\n const nextStart = html.indexOf(`<${lowerTagName}`, currentIndex);\n const nextEnd = html.indexOf(endTag, currentIndex);\n\n if (nextEnd === -1) break;\n if (nextStart !== -1 && nextStart < nextEnd) {\n tagCount++;\n currentIndex = nextStart + `<${lowerTagName}`.length;\n } else {\n tagCount--;\n if (tagCount === 0) endTagIndex = nextEnd;\n currentIndex = nextEnd + endTag.length;\n }\n }\n\n // 提取标签内容(开始标签和结束标签之间)\n const content = endTagIndex !== -1 ? html.slice(startTag.length, endTagIndex) : html.slice(startTag.length);\n\n // 构建基础节点数据\n const attrs = parseAttributes(attrStr);\n const nodeData: INodeData = {\n tagName: lowerTagName,\n attributes: attrs, // 类型匹配\n styles: attrs.styleObj || {}, // 类型匹配\n textContent: \"\",\n children: [],\n parent: null,\n };\n\n // 解析子节点\n if (content) {\n const childNodes: INodeData[] = [];\n let remaining = content;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 纯文本内容\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) childNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析嵌套标签\n const tempTagMatch = remaining.match(startTagRegex);\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) childNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n const tempEndTag = `</${tempTagName}>`;\n\n // 自闭合标签直接处理\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfNode = parseSingleNode(remaining.slice(0, tempTagMatch[0].length));\n if (selfNode) childNodes.push(selfNode);\n remaining = remaining.slice(tempTagMatch[0].length);\n continue;\n }\n\n // 查找嵌套标签的结束位置\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n // 提取子节点HTML并递归解析\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) childNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) childNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n\n // 过滤无效节点并赋值\n nodeData.children = childNodes.filter(Boolean);\n // 单一文本子节点直接合并到textContent\n if (nodeData.children.length === 1 && nodeData.children[0].tagName === \"#text\") {\n nodeData.textContent = nodeData.children[0].textContent;\n nodeData.children = [];\n }\n }\n\n return nodeData;\n}\n\n// 新增:解析HTML片段(支持多根节点)\nfunction parseHTMLFragment(html: string): INodeData[] {\n html = html;\n if (!html) return [];\n\n const fragmentNodes: INodeData[] = [];\n let remaining = html;\n\n while (remaining) {\n const tagStart = remaining.indexOf(\"<\");\n if (tagStart === -1) {\n // 剩余纯文本\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n } else {\n if (tagStart > 0) {\n // 标签前的文本节点\n const textNode = parseSingleNode(remaining.slice(0, tagStart));\n if (textNode) fragmentNodes.push(textNode);\n remaining = remaining.slice(tagStart);\n } else {\n // 解析单个标签节点\n const startTagRegex = /<([a-zA-Z0-9]+)\\s*(.*?)>/;\n const tempTagMatch = remaining.match(startTagRegex);\n\n if (!tempTagMatch) {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n continue;\n }\n\n const tempTagName = tempTagMatch[1].toLowerCase();\n\n // 自闭合标签\n if (SELF_CLOSING_TAGS.includes(tempTagName)) {\n const selfClosingRegex = /<([a-zA-Z0-9]+)\\s*(.*?)\\/?>/;\n const selfClosingMatch = remaining.match(selfClosingRegex);\n\n if (selfClosingMatch) {\n const selfNode = parseSingleNode(selfClosingMatch[0]);\n if (selfNode) fragmentNodes.push(selfNode);\n remaining = remaining.slice(selfClosingMatch[0].length);\n } else {\n const textNode = parseSingleNode(remaining);\n if (textNode) fragmentNodes.push(textNode);\n remaining = \"\";\n }\n } else {\n // 非自闭合标签,找匹配的结束标签\n const tempEndTag = `</${tempTagName}>`;\n let tempEndIndex = -1;\n let tempTagCount = 1;\n let tempCurrentIndex = tempTagMatch[0].length;\n\n while (tempCurrentIndex < remaining.length && tempTagCount > 0) {\n const nextTempStart = remaining.indexOf(`<${tempTagName}`, tempCurrentIndex);\n const nextTempEnd = remaining.indexOf(tempEndTag, tempCurrentIndex);\n\n if (nextTempEnd === -1) break;\n if (nextTempStart !== -1 && nextTempStart < nextTempEnd) {\n tempTagCount++;\n tempCurrentIndex = nextTempStart + `<${tempTagName}`.length;\n } else {\n tempTagCount--;\n if (tempTagCount === 0) tempEndIndex = nextTempEnd;\n tempCurrentIndex = nextTempEnd + tempEndTag.length;\n }\n }\n\n if (tempEndIndex !== -1) {\n const childHTML = remaining.slice(0, tempEndIndex + tempEndTag.length);\n const childNode = parseSingleNode(childHTML);\n if (childNode) fragmentNodes.push(childNode);\n remaining = remaining.slice(tempEndIndex + tempEndTag.length);\n } else {\n const childNode = parseSingleNode(remaining);\n if (childNode) fragmentNodes.push(childNode);\n remaining = \"\";\n }\n }\n }\n }\n }\n\n // 过滤无效节点\n return fragmentNodes.filter(Boolean);\n}\n\n// 核心Node类实现(支持片段/多根节点)\nclass Node {\n public tagName: string;\n public attributes: IAttributeData; // 修改:使用扩展后的属性接口\n public styles: Record<string, string>;\n public textContent: string;\n public children: Node[];\n public parent: Node | null;\n\n /**\n * 构造函数:通过HTML字符串初始化节点(支持单根/多根)\n * @param {string} html - HTML字符串(单根/多根均可)\n */\n constructor(html: string) {\n if (typeof html !== \"string\") {\n throw new Error(\"初始化Node必须传入HTML字符串\");\n }\n\n const htmlTrimmed = html;\n if (!htmlTrimmed) {\n throw new Error(\"无法解析空的HTML字符串\");\n }\n\n // 尝试解析为单一节点\n const singleNodeData = parseSingleNode(htmlTrimmed);\n // 解析为片段(多根节点)\n const fragmentNodeData = parseHTMLFragment(htmlTrimmed);\n\n // 初始化默认属性\n this.tagName = \"\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n this.children = [];\n this.parent = null;\n\n // 节点核心属性赋值\n if (singleNodeData && fragmentNodeData.length === 1) {\n // 单根节点\n this.tagName = singleNodeData.tagName;\n this.attributes = { ...singleNodeData.attributes };\n this.styles = { ...singleNodeData.styles };\n this.textContent = singleNodeData.textContent || \"\";\n\n // 子节点转换为Node实例\n if (singleNodeData.children.length > 0) {\n this.children = singleNodeData.children.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n }\n } else if (fragmentNodeData.length > 0) {\n // 多根节点 → 标记为片段节点\n this.tagName = \"#fragment\";\n this.attributes = {}; // 符合IAttributeData类型\n this.styles = {};\n this.textContent = \"\";\n\n // 片段的子节点是多个根节点\n this.children = fragmentNodeData.map((childData) => {\n const childNode = new Node(this.#generateHTMLFromData(childData));\n childNode.parent = this;\n return childNode;\n });\n } else {\n throw new Error(\"无法解析无效的HTML字符串\");\n }\n }\n\n /**\n * 私有方法:从节点数据生成HTML字符串(用于子节点初始化)\n * @param {INodeData} nodeData - 节点数据\n * @returns {string} HTML字符串\n */\n #generateHTMLFromData(nodeData: INodeData): string {\n if (nodeData.tagName === \"#text\") return nodeData.textContent;\n\n // 构建开始标签\n let startTag = `<${nodeData.tagName}`;\n const attrs = { ...nodeData.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(nodeData.styles).length > 0) {\n const styleStr = Object.entries(nodeData.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n // 确保val是字符串(IAttributeData中除了styleObj都是string)\n if (typeof val === \"string\") {\n startTag += ` ${key}=\"${val}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(nodeData.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点)\n let content = nodeData.textContent;\n if (nodeData.children.length > 0) {\n content += nodeData.children.map((child) => this.#generateHTMLFromData(child)).join(\"\");\n }\n\n return `${startTag}${content}</${nodeData.tagName}>`;\n }\n\n /**\n * 子集管理:获取当前节点的所有子节点\n * @returns {Node[]} 子节点数组(浅拷贝)\n */\n child(): Node[] {\n return [...this.children];\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n before(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行before操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点前一个位置\n this.parent.children.splice(currentIndex, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在当前节点之后插入新元素\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n after(newNode: string | Node): Node {\n if (!this.parent) {\n throw new Error(\"当前节点没有父节点,无法执行after操作\");\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n const currentIndex = this.parent.children.findIndex((child) => child === this);\n\n if (currentIndex === -1) {\n throw new Error(\"当前节点不在父节点的子节点列表中\");\n }\n\n // 插入到当前节点下一个位置\n this.parent.children.splice(currentIndex + 1, 0, nodeToInsert);\n nodeToInsert.parent = this.parent;\n\n return this;\n }\n\n /**\n * DOM操作:在指定位置插入新元素\n * @param {number} position - 插入位置(0 ~ children.length)\n * @param {string|Node} newNode - 要插入的HTML字符串或Node实例\n * @returns {Node} 当前节点(链式调用)\n */\n insert(position: number, newNode: string | Node): Node {\n if (typeof position !== \"number\" || position < 0 || position > this.children.length) {\n throw new Error(`插入位置${position}无效,必须是0到${this.children.length}之间的整数`);\n }\n\n const nodeToInsert = this.#convertToNode(newNode);\n // 如果插入的是片段节点,展开其所有子节点(符合DOM标准)\n if (nodeToInsert.tagName === \"#fragment\") {\n nodeToInsert.children.forEach((child, index) => {\n child.parent = this;\n this.children.splice(position + index, 0, child);\n });\n } else {\n this.children.splice(position, 0, nodeToInsert);\n nodeToInsert.parent = this;\n }\n\n return this;\n }\n\n /**\n * 属性操作:获取指定属性的值\n * @param {string} attrName - 属性名\n * @returns {string|null} 属性值(不存在返回null)\n */\n getAttr(attrName: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无属性\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n // 只返回字符串类型的属性(排除styleObj)\n return typeof this.attributes[attrName] === \"string\" ? this.attributes[attrName] : null;\n }\n\n /**\n * 属性操作:设置指定属性的值\n * @param {string} attrName - 属性名\n * @param {string|null|undefined} value - 属性值(null/undefined删除属性)\n * @returns {Node} 当前节点(链式调用)\n */\n setAttr(attrName: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrName !== \"string\") {\n throw new Error(\"属性名必须是字符串\");\n }\n\n if (value === null || value === undefined) {\n delete this.attributes[attrName];\n } else {\n // 确保属性值是字符串(符合IAttributeData的基础约束)\n this.attributes[attrName] = String(value);\n }\n\n return this;\n }\n\n /**\n * 属性操作:批量设置多个属性\n * @param {Record<string, string | null | undefined>} attrs - 包含属性名-属性值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setAttrs(attrs: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置属性\");\n }\n if (typeof attrs !== \"object\" || attrs === null) {\n throw new Error(\"属性对象必须是非空对象\");\n }\n\n for (const [attrName, value] of Object.entries(attrs)) {\n this.setAttr(attrName, value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:获取指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @returns {string|null} 样式值(不存在返回null)\n */\n getStyle(styleProp: string): string | null {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n return null; // 片段/文本节点无样式\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n return this.styles[camelProp] || this.styles[styleProp] || null;\n }\n\n /**\n * 样式操作:设置指定样式属性的值\n * @param {string} styleProp - 样式属性名(支持驼峰/短横线)\n * @param {string|null|undefined} value - 样式值(null/undefined删除样式)\n * @returns {Node} 当前节点(链式调用)\n */\n setStyle(styleProp: string, value: string | null | undefined): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styleProp !== \"string\") {\n throw new Error(\"样式属性名必须是字符串\");\n }\n\n const camelProp = kebabToCamel(styleProp);\n if (value === null || value === undefined) {\n delete this.styles[camelProp];\n delete this.styles[styleProp];\n } else {\n this.styles[camelProp] = String(value);\n }\n\n return this;\n }\n\n /**\n * 样式操作:批量设置多个样式属性\n * @param {Record<string, string | null | undefined>} styles - 包含样式属性名-样式值键值对的对象\n * @returns {Node} 当前节点(链式调用)\n */\n setStyles(styles: Record<string, string | null | undefined>): Node {\n if (this.tagName === \"#fragment\" || this.tagName === \"#text\") {\n throw new Error(\"片段/文本节点不支持设置样式\");\n }\n if (typeof styles !== \"object\" || styles === null) {\n throw new Error(\"样式对象必须是非空对象\");\n }\n\n for (const [styleProp, value] of Object.entries(styles)) {\n this.setStyle(styleProp, value);\n }\n\n return this;\n }\n\n /**\n * 获取当前节点的完整HTML文本\n * @returns {string} HTML字符串\n */\n getHtml(): string {\n // 文本节点直接返回文本\n if (this.tagName === \"#text\") {\n return this.textContent;\n }\n\n // 片段节点返回所有子节点的HTML拼接\n if (this.tagName === \"#fragment\") {\n return this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n // 普通元素节点\n let startTag = `<${this.tagName}`;\n const attrs = { ...this.attributes };\n\n // 拼接样式属性(覆盖原始style)\n if (Object.keys(this.styles).length > 0) {\n const styleStr = Object.entries(this.styles)\n .map(([key, val]) => `${camelToKebab(key)}: ${val}`)\n .join(\"; \");\n attrs.style = styleStr;\n }\n\n // 拼接所有属性:过滤内部属性styleObj,确保值是字符串\n for (const [key, val] of Object.entries(attrs)) {\n if (key === \"styleObj\") continue; // 核心修复:跳过内部样式对象属性\n if (typeof val === \"string\") {\n const safeVal = val.replace(/\"/g, \"&quot;\");\n startTag += ` ${key}=\"${safeVal}\"`;\n }\n }\n\n // 自闭合标签处理\n if (SELF_CLOSING_TAGS.includes(this.tagName)) {\n startTag += \"/>\";\n return startTag;\n }\n\n startTag += \">\";\n\n // 拼接内容(文本+子节点HTML)\n let content = this.textContent;\n if (this.children.length > 0) {\n content += this.children.map((child) => child.getHtml()).join(\"\");\n }\n\n return `${startTag}${content}</${this.tagName}>`;\n }\n\n /**\n * 私有辅助方法:统一转换插入的节点为Node实例\n * @param {string|Node} node - HTML字符串或Node实例\n * @returns {Node} Node实例\n */\n #convertToNode(node: string | Node): Node {\n if (node instanceof Node) return node;\n if (typeof node === \"string\") return new Node(node);\n throw new Error(\"插入的节点必须是HTML字符串或Node实例\");\n }\n}\n\nexport default Node;\n"],"names":["SELF_CLOSING_TAGS","camelToKebab","str","match","kebabToCamel","_","parseAttributes","attrStr","attrs","attrRegex","key","doubleVal","singleVal","noQuoteVal","value","styleObj","styleRegex","styleMatch","prop","val","parseSingleNode","html","selfClosingRegex","selfClosingMatch","tagName","startTagRegex","startTagMatch","startTag","lowerTagName","endTag","endTagIndex","tagCount","currentIndex","nextStart","nextEnd","content","nodeData","childNodes","remaining","tagStart","textNode","tempTagMatch","tempTagName","tempEndTag","selfNode","tempEndIndex","tempTagCount","tempCurrentIndex","nextTempStart","nextTempEnd","childHTML","childNode","parseHTMLFragment","fragmentNodes","Node","htmlTrimmed","singleNodeData","fragmentNodeData","childData","#generateHTMLFromData","styleStr","child","newNode","nodeToInsert","#convertToNode","position","index","attrName","styleProp","camelProp","styles","safeVal","node"],"mappings":"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"}
package/package.json CHANGED
@@ -1,17 +1,19 @@
1
1
  {
2
2
  "name": "parse_html_to_node",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "This is an HTML string parsed into an object, which does not depend on a browser environment and can be used in any JavaScript runtime.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.js",
7
- "types": "dist/index.d.ts",
5
+ "main": "dist/parse_html.umd.js",
6
+ "module": "dist/parse_html.es.js",
7
+ "types": "dist/parse_html.d.ts",
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
11
  "scripts": {
12
12
  "dev": "tsc --watch",
13
13
  "build": "vite build",
14
- "test": "echo \"Error: no test specified\" && exit 1"
14
+ "test": "vitest",
15
+ "test:ui": "vitest --ui",
16
+ "coverage": "vitest run --coverage"
15
17
  },
16
18
  "publishConfig": {
17
19
  "registry": "https://registry.npmjs.org/"
@@ -33,9 +35,12 @@
33
35
  "license": "MIT",
34
36
  "devDependencies": {
35
37
  "@types/node": "^25.2.0",
38
+ "@vitest/coverage-v8": "4.0.18",
39
+ "@vitest/ui": "^4.0.18",
36
40
  "tslib": "^2.8.1",
37
41
  "typescript": "^5.9.3",
38
42
  "vite": "^7.3.1",
39
- "vite-plugin-dts": "^4.5.4"
43
+ "vite-plugin-dts": "^4.5.4",
44
+ "vitest": "^4.0.18"
40
45
  }
41
46
  }