All files / hast-util-from-webparser index.ts

100% Statements 50/50
96.3% Branches 26/27
100% Functions 9/9
100% Lines 50/50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 1521x                   1x 1x 1x 1x     38x                                             1x 12x 12x 12x           12x         64x     64x   38x 38x 22x     38x 12x   26x     38x 38x       26x 22x 4x 1x 3x 3x               64x   64x         22x 22x 22x   22x 52x     22x       12x         22x         1x           91x 1x     90x 90x                 26x 26x 26x     26x 27x 27x       26x   26x    
import {
  ParseSourceSpan,
  splitNsName,
  Element,
  Comment,
  Text,
  Node,
  Doctype
} from 'webparser'
 
let htmlSchema = require('property-information/html')
let svgSchema = require('property-information/svg')
let hastSvg = require('@starptech/prettyhtml-hastscript/svg')
let hast = require('@starptech/prettyhtml-hastscript')
 
function isFakeRoot(obj: Element): boolean {
  return obj.name === ':webparser:root'
}
 
type Options = {
  file?: string
  verbose?: boolean
  schema?: { space: string }
  documentMode?: boolean
}
 
type HastNode = {
  name?: string
  type: string
  tagName?: string
  properties?: Array<Object>
  children?: HastNode[]
  public?: string
  system?: string
  value?: string
  data?: { [name: string]: any }
}
 
/* Wrapper to normalise options. */
export = function from(rootNodes: Node[], options: Options) {
  const sourceSpan = new ParseSourceSpan(null, null)
  const fakeRoot = new Element(':webparser:root', [], rootNodes, sourceSpan)
  const result = transform(fakeRoot, {
    schema: htmlSchema,
    file: options.file,
    verbose: options.verbose
  })
 
  return result
}
 
/* Transform a node. */
function transform(ast: Node, config: Options): HastNode {
  let schema = config.schema
  let node: HastNode
 
  if (ast instanceof Element) {
    let children: HastNode[]
    config.schema = getNameAndNS(ast.name).ns === 'svg' ? svgSchema : htmlSchema
    if (ast.children && ast.children.length) {
      children = nodes(ast.children, config)
    }
 
    if (isFakeRoot(ast)) {
      node = root(ast, children)
    } else {
      node = element(ast, children, config)
    }
 
    node.data = node.data || {}
    node.data.selfClosing =
      ast.startSourceSpan === ast.endSourceSpan &&
      ast.startSourceSpan !== null &&
      ast.endSourceSpan !== null
  } else if (ast instanceof Text) {
    node = text(ast)
  } else if (ast instanceof Comment) {
    node = comment(ast)
  } else Eif (ast instanceof Doctype) {
    node = {
      type: 'doctype',
      name: 'html',
      public: null,
      system: null
    }
  }
 
  config.schema = schema
 
  return node
}
 
/* Transform children. */
function nodes(children: Node[], config: Options): HastNode[] {
  let length = children.length
  let index = -1
  let result: HastNode[] = []
 
  while (++index < length) {
    result[index] = transform(children[index], config)
  }
 
  return result
}
 
function root(ast: Node, children: HastNode[]): HastNode {
  return { type: 'root', children, data: {} }
}
 
/* Transform a text. */
function text(ast: Text): HastNode {
  return { type: 'text', value: ast.value }
}
 
/* Transform a comment. */
function comment(ast: Comment): HastNode {
  return { type: 'comment', value: ast.value }
}
 
function getNameAndNS(name: string) {
  // support vue :foo attributes but respect
  // namepsace syntax from webparser like :ns:attribute
  if (name.split(':').length === 2) {
    return { ns: null, name: name }
  }
 
  const info = splitNsName(name)
  return { ns: info[0], name: info[1] }
}
 
/* Transform an element. */
function element(
  ast: Element,
  children: HastNode[],
  config: Options
): HastNode {
  let fn = config.schema.space === 'svg' ? hastSvg : hast
  let name = getNameAndNS(ast.name).name
  let props: { [name: string]: string } = {}
  let node
 
  for (const attr of ast.attrs) {
    const attrInfo = getNameAndNS(attr.name)
    props[attrInfo.ns ? attrInfo.ns + ':' + attrInfo.name : attrInfo.name] =
      attr.value
  }
 
  node = fn(name, props, children)
 
  return node
}