构建语法树和解析语法树

const domTags=['div','section','img','p','span']
//深度遍历html节点
function depthSearch(node,childProp='children'){
  const nodeList=[]
  const depthEach=function(item){
    nodeList.push(item);
    if(item[childProp]){
      for(let k in item[childProp]){
        depthEach(item[childProp][k]);
      }
    }
  }
  depthEach(node);
  return nodeList;
}

//模板转语法树
 function templateToAstData(template) {
  console.log(template)
  let deep=0;
  const astTree={
    node:{
      id:0,
      deep:0,
      child:[],
    },
    id:0,
    idMap:{},
    getNode(deep) {
      let node=this.node
      for(let i=1;i<deep+1;i++){
        node=node.child[node.child.length-1]
      }
      return node;
    },
    createNode(deep,propStr) {
      let node=this.node
      //创建空元素
      for(let i=1;i<deep+1;i++){
        if(!node.child){node.child=[]}
        if(i===deep){
          const nNode={
            id:++this.id,
            deep:deep,
          }
          this.idMap[nNode.id]=nNode
          node.child.push(nNode)
        }
        node=node.child[node.child.length-1]
      }

      const props={md5_id:node.id}
      if(propStr){
        propStr.replace(/(w+)=(['"])(.+?)2/g,function (m,p1,p2,p3) {
          props[p1]=p3
        })
      }
      node.props=props;
      return node;
    },
    createText(deep,text){
      const node=this.createNode(deep)
      node.tag='_text';
      node.text=text;
      return node;
    }
  };
  let pathArr=[]
  let preRange=[0,0];
  template.replace(/<([dD]+?)>/gi,function (m,p1,p2) {
    let curDeep=deep;
    //开头<div>
    if(/^([a-z]w*)/i.test(p1)){
      const tag=RegExp.$1.toLocaleLowerCase();
      let last=p1.replace(tag,'')
      if(tag==='br'||last[last.length-1]==='/'){
        if(pathArr[deep]===undefined){
          pathArr[deep]={
            startRange:[p2,p2+m.length],
            endRange:[p2,p2+m.length],
            isEnd:1,
            tag:tag,
          };
        }
      }else{
        pathArr[deep]={
          startRange:[p2,p2+m.length],
          isEnd:0,
          tag:tag,
        }
        deep++;
      }

    }else if(/^/([a-z]w*)$/i.test(p1)){ //结尾 </div>
      const tag=RegExp.$1.toLocaleLowerCase();
      if(pathArr[deep-1]&&tag===pathArr[deep-1].tag){
        deep--;
        curDeep=deep
        if(tag===pathArr[curDeep].tag){
          pathArr[curDeep].isEnd=2;
          pathArr[curDeep].endRange=[p2,p2+m.length];
        }
      }else{
        pathArr[deep]={
          startRange:[p2,p2+m.length],
          endRange:[p2,p2+m.length],
          isEnd:-1,
        };
      }
    }
    const isEnd=pathArr[curDeep].isEnd;
    const tag=pathArr[curDeep].tag;
    if(isEnd===0){
      if(preRange[1]<p2){
        const text=template.substring(preRange[1],p2)
        if(/S/.test(text)){
          //创建文字元素
          astTree.createText(curDeep,text)
        }
      }
      //创建空元素
      astTree.createNode(curDeep,p1.substring(tag.length,p1.length))
    }else if(isEnd===1){
      if(preRange[1]<p2){
        const text=template.substring(preRange[1],p2)
        if(/S/.test(text)){
          //创建文字元素
          astTree.createText(curDeep,text)
        }
      }
      //创建当前元素
      const node=astTree.createNode(curDeep,p1.substring(tag.length,p1.length))
      Object.assign(node,pathArr[curDeep])
    }else if(isEnd===2){
      if(preRange[1]<p2){
        const text=template.substring(preRange[1],p2)
        if(/S/.test(text)){
          //创建文字元素
          astTree.createText(curDeep+1,text)
        }
      }
      const node=astTree.getNode(curDeep)
      Object.assign(node,pathArr[curDeep])
    }

    preRange=[p2,p2+m.length]
  })
  return astTree;
}


//语法树转可编辑模板
function astDataToEditHtml(astTree) {
  const astData=astTree.node
  function getTextByNode(node) {
    //dom 对应的属性空间
    const props=node.props
    let pstr=''
    for(let name in props){
      pstr=pstr+` ${name}="${props[name]}"`;
    }

    if(node.tag==='_text'){
      return [node.text]
    }else if(node.isEnd===1){
      return [`<${node.tag}${pstr}/>`]
    }else if(node.isEnd===2){
      return [`<${node.tag}${pstr}>`,`</${node.tag}>`]
    }
    return ['']
  }

  const list=depthSearch(astData,'child')
  let preDeep=-1;
  const endCache=[]
  let html=''
  for(let i=0;i<list.length;i++){
    const node=list[i];
    const arr=getTextByNode(node)
    if(node.deep<=preDeep){
      for(let i=preDeep;i>=node.deep;i--){
        html=html+endCache[i]
      }
    }
    endCache[node.deep]=arr[1]||''
    html=html+arr[0]
    preDeep=node.deep;
  }
  for(let i=preDeep;i>=0;i--){
    html=html+endCache[i]
  }
  return html;
}
// const astData=templateToAstData('<section name="222" style=" 100px;">这是一<section>222<br>这是一个s<section>这是一个section</section>ection</section>个section</section>');
// const editHtml=astDataToEditHtml(astData)
// console.log(editHtml)
module.exports={
  templateToAstData,
  astDataToEditHtml
}