Skip to content

Commit

Permalink
Refactor build script
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Nov 16, 2022
1 parent 4d22180 commit 7d26299
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 92 deletions.
165 changes: 78 additions & 87 deletions build.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import fs from 'node:fs'
import https from 'node:https'
import concatStream from 'concat-stream'
import {bail} from 'bail'
import {unified} from 'unified'
import rehypeParse from 'rehype-parse'
import fs from 'node:fs/promises'
import fetch from 'node-fetch'
import {fromHtml} from 'hast-util-from-html'
import {selectAll} from 'hast-util-select'
import {toString} from 'hast-util-to-string'
import {htmlElementAttributes} from './index.js'

const own = {}.hasOwnProperty

const processor = unified().use(rehypeParse)

if (!('*' in htmlElementAttributes)) {
htmlElementAttributes['*'] = []
}
Expand All @@ -20,83 +15,79 @@ if (!('*' in htmlElementAttributes)) {
const globals = htmlElementAttributes['*']

// Crawl WHATWG HTML.
https.get('https://html.spec.whatwg.org/multipage/indices.html', (response) => {
response
.pipe(
concatStream((buf) => {
const nodes = selectAll('#attributes-1 tbody tr', processor.parse(buf))
/** @type {Record<string, Array<string>>} */
const result = {}
let index = -1

// Throw if we didn’t match, e.g., when the spec updates.
if (nodes.length === 0) {
throw new Error('Missing results in html')
}

while (++index < nodes.length) {
const name = toString(nodes[index].children[0]).trim()
const value = toString(nodes[index].children[1]).trim()

if (/custom elements/i.test(value)) {
continue
}

const elements = /HTML elements/.test(value)
? ['*']
: value.split(/;/g).map((d) => d.replace(/\([^)]+\)/g, '').trim())
let offset = -1

while (++offset < elements.length) {
const tagName = elements[offset].toLowerCase().trim()

if (!own.call(htmlElementAttributes, tagName)) {
htmlElementAttributes[tagName] = []
}

/** @type {string[]} */
const attributes = htmlElementAttributes[tagName]

if (!attributes.includes(name)) {
attributes.push(name)
}
}
}

const keys = Object.keys(htmlElementAttributes).sort()
index = -1

while (++index < keys.length) {
const key = keys[index]

htmlElementAttributes[key].sort()

if (key !== '*') {
htmlElementAttributes[key] = htmlElementAttributes[key].filter(
(/** @type {string} */ d) => !globals.includes(d)
)
}

if (htmlElementAttributes[key].length > 0) {
result[key] = htmlElementAttributes[key]
}
}

fs.writeFile(
'index.js',
[
'/**',
' * Map of HTML elements to allowed attributes.',
' *',
' * @type {Record<string, Array<string>>}',
' */',
'export const htmlElementAttributes = ' +
JSON.stringify(result, null, 2),
''
].join('\n'),
bail
)
})
const response = await fetch(
'https://html.spec.whatwg.org/multipage/indices.html'
)
const text = await response.text()

const nodes = selectAll('#attributes-1 tbody tr', fromHtml(text))

// Throw if we didn’t match, e.g., when the spec updates.
if (nodes.length === 0) {
throw new Error('Missing results in html')
}

/** @type {Record<string, Array<string>>} */
const result = {}
let index = -1

while (++index < nodes.length) {
const name = toString(nodes[index].children[0]).trim()
const value = toString(nodes[index].children[1]).trim()

if (/custom elements/i.test(value)) {
continue
}

const elements = /HTML elements/.test(value)
? ['*']
: value.split(/;/g).map((d) => d.replace(/\([^)]+\)/g, '').trim())
let offset = -1

while (++offset < elements.length) {
const tagName = elements[offset].toLowerCase().trim()

if (!own.call(htmlElementAttributes, tagName)) {
htmlElementAttributes[tagName] = []
}

/** @type {string[]} */
const attributes = htmlElementAttributes[tagName]

if (!attributes.includes(name)) {
attributes.push(name)
}
}
}

const keys = Object.keys(htmlElementAttributes).sort()
index = -1

while (++index < keys.length) {
const key = keys[index]

htmlElementAttributes[key].sort()

if (key !== '*') {
htmlElementAttributes[key] = htmlElementAttributes[key].filter(
(/** @type {string} */ d) => !globals.includes(d)
)
.on('error', bail)
})
}

if (htmlElementAttributes[key].length > 0) {
result[key] = htmlElementAttributes[key]
}
}

await fs.writeFile(
'index.js',
[
'/**',
' * Map of HTML elements to allowed attributes.',
' *',
' * @type {Record<string, Array<string>>}',
' */',
'export const htmlElementAttributes = ' + JSON.stringify(result, null, 2),
''
].join('\n')
)
7 changes: 2 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,17 @@
"index.js"
],
"devDependencies": {
"@types/concat-stream": "^2.0.0",
"@types/node": "^18.0.0",
"bail": "^2.0.0",
"c8": "^7.0.0",
"concat-stream": "^2.0.0",
"hast-util-from-html": "^1.0.0",
"hast-util-select": "^5.0.0",
"hast-util-to-string": "^2.0.0",
"node-fetch": "^3.0.0",
"prettier": "^2.0.0",
"rehype-parse": "^8.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"unified": "^10.0.0",
"xo": "^0.52.0"
},
"scripts": {
Expand Down

0 comments on commit 7d26299

Please sign in to comment.