-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathadd-web-component-definitions.js
111 lines (95 loc) · 3.22 KB
/
add-web-component-definitions.js
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
const { parse } = require('parse5')
const toHast = require('hast-util-from-parse5')
const visit = require('unist-util-visit')
const h = require('hastscript')
const toHtml = require('hast-util-to-html')
const isWebComponent = tag => tag && (/(\w+(-\w+)+)/g).test(tag)
const logPrefix = '[add-web-component-definitions]'
const addChild = (body, child, position) => {
if (position === 'afterbegin') {
body.children.unshift(child)
} else {
body.children.push(child)
}
}
module.exports = function (options, content, outputPath) {
if (typeof outputPath !== 'string' || !outputPath || !content) { return content }
if (!!options.path && !!options.specifiers) {
throw new Error('You may configure a path function or import specifiers, but not both')
}
if (outputPath.endsWith('.html') || content.startsWith('<')) {
options = Object.assign(
{
path: tag => `/js/components/${tag}/${tag}.js`,
specifiers: {},
position: 'beforeend',
verbose: false,
quiet: false,
singleScript: false,
modulePreload: false
},
options)
if (typeof options.path !== 'function') {
throw new TypeError(`Path must be a function: ${options.path}?`)
}
if (Object.keys(options.specifiers).length !== 0) {
options.path = tag => {
if (!options.specifiers[tag]) {
return null
}
const typeOfSpecifier = typeof options.specifiers[tag]
if (!['string', 'function'].includes(typeOfSpecifier)) {
throw new TypeError(`Specifier must be either a function or a string: "${options.specifiers[tag]}" for tag "${tag}"?`)
}
return typeof options.specifiers[tag] === 'function'
? options.specifiers[tag](tag)
: options.specifiers[tag]
}
}
if (options.verbose) {
console.log(logPrefix, 'Examining', outputPath)
console.log(logPrefix, 'options', options)
}
const tags = new Set()
const tree = toHast(parse(content))
let body, head
visit(tree, 'element', (node) => {
if (!body && node.tagName === 'body') {
body = node
}
if (!head && node.tagName === 'head') {
head = node
}
if (isWebComponent(node.tagName)) {
tags.add(node.tagName)
}
return node
})
if (options.verbose) {
console.log(logPrefix, `Tags found in ${outputPath}:`, tags)
}
if (tags.size) {
const arrayOfValues = [...new Set([...tags].map(options.path))].filter(Boolean)
if (!options.quiet) {
arrayOfValues.forEach(value => console.log(logPrefix, value))
}
if (options.singleScript) {
const value = arrayOfValues.map(value => `import "${value}";`).join('\n')
const child = h('script', { type: 'module' }, [{ type: 'text', value }])
addChild(body, child, options.position)
} else {
arrayOfValues.forEach(src => {
const child = h('script', { type: 'module', src })
addChild(body, child, options.position)
if (options.modulePreload) {
head.children.push(h('link', { rel: 'modulepreload', href: src }))
}
})
}
} else {
return content
}
return toHtml(tree)
}
return content
}