| 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 | 1x
1x
1x
1x
1x
28x
1x
7x
7x
7x
7x
7x
50x
50x
28x
28x
15x
28x
7x
21x
28x
28x
22x
21x
1x
1x
50x
50x
15x
15x
15x
15x
43x
15x
7x
21x
1x
74x
15x
59x
59x
21x
21x
21x
21x
25x
25x
21x
21x
| import {
ParseSourceSpan,
splitNsName,
Element,
Comment,
Text,
Node
} 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 default function(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
})
Iif (options.documentMode === true) {
result.children.unshift({
type: 'doctype',
name: 'html',
public: null,
system: null
})
}
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 Eif (ast instanceof Comment) {
node = comment(ast)
}
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) {
if (name[0] === ':') {
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
}
|