File size: 1,290 Bytes
c20f20c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import type { HTMLNode, CommentOrTextAST, ElementAST, AST } from './types';

export const splitHead = (str: string, sep: string) => {
  const idx = str.indexOf(sep);
  if (idx === -1) return [str];
  return [str.slice(0, idx), str.slice(idx + sep.length)];
};

const unquote = (str: string) => {
  const car = str.charAt(0);
  const end = str.length - 1;
  const isQuoteStart = car === '"' || car === "'";
  if (isQuoteStart && car === str.charAt(end)) {
    return str.slice(1, end);
  }
  return str;
};

const formatAttributes = (attributes: string[]) => {
  return attributes.map((attribute) => {
    const parts = splitHead(attribute.trim(), '=');
    const key = parts[0];
    const value = typeof parts[1] === 'string' ? unquote(parts[1]) : null;
    return { key, value };
  });
};

export const format = (nodes: HTMLNode[]): AST[] => {
  return nodes.map((node) => {
    if (node.type === 'element') {
      const children = format(node.children);
      const item: ElementAST = {
        type: 'element',
        tagName: node.tagName.toLowerCase(),
        attributes: formatAttributes(node.attributes),
        children,
      };
      return item;
    }

    const item: CommentOrTextAST = {
      type: node.type,
      content: node.content,
    };
    return item;
  });
};