html-version
Version:
parse and modify html versions according to the html version spec
139 lines (123 loc) • 3.87 kB
JavaScript
var uniq = require('uniq')
var has = require('has')
var detect = require('detect-indent')
var copy = require('shallow-copy')
var indent = require('./lib/indent.js')
exports.parse = function (root) {
if (typeof root === 'string' || !/^html/i.test(root.constructor.name)) {
root = dom(root)
}
var info = { integrity: {} }
info.version = null
select('meta[name="version"]', function (link) {
var ver = link.getAttribute('content')
if (ver) info.version = ver
})
info.versions = {}
select('link[rel="version"]', function (link) {
var ver = link.getAttribute('version')
if (!ver) return
if (!info.versions[ver]) info.versions[ver] = []
var href = link.getAttribute('href')
if (href) info.versions[ver].push(href)
pushIntegrity(link)
})
Object.keys(info.versions).forEach(function (key) {
uniq(info.versions[key])
})
info.signature = []
select('link[rel="signature"]', function (link) {
var href = link.getAttribute('href')
if (href) info.signature.push(href)
pushIntegrity(link)
})
uniq(info.signature)
info.latest = []
select('link[rel="latest-version"]', function (link) {
var href = link.getAttribute('href')
if (href) info.latest.push(href)
})
uniq(info.latest)
info.predecessor = []
select('link[rel="predecessor-version"]', function (link) {
var href = link.getAttribute('href')
var ver = link.getAttribute('version')
if (href) info.predecessor.push(href)
if (ver && has(info.versions, ver)) {
info.predecessor.push.apply(info.predecessor, info.versions[ver])
}
pushIntegrity(link)
})
uniq(info.predecessor)
Object.keys(info.integrity).forEach(function (key) {
uniq(info.integrity[key])
})
return info
function select (q, f) {
var nodes = root.querySelectorAll(q)
for (var i = 0; i < nodes.length; i++) f(nodes[i])
}
function pushIntegrity (link) {
var href = link.getAttribute('href')
var grit = link.getAttribute('integrity')
if (href && grit) {
var grits = info.integrity[href]
if (!grits) grits = info.integrity[href] = []
grits.push.apply(grits, grit.split(/\s+/).filter(Boolean))
}
}
}
exports.meta = require('./meta.js')
exports.update = function (root, loc, prev) {
if (/^html/i.test(root.constructor.name)) {
root = root.cloneNode(true)
} else root = dom(root)
var src = root.outerHTML
prev = copy(prev)
if (prev.version) {
prev.versions[prev.version] = loc
prev.predecessor = loc
}
var meta = exports.meta(prev)
var head = root.querySelector('head')
var detected = detect(typeof src === 'string' ? src : src.toString())
.indent
if (head) {
var pre = head.innerHTML
var postdent = /(\s*)$/.exec(pre.split('\n').slice(-1)[0])[1].length
var dent = Array(
/^(\s*)/.exec(pre.split('\n').slice(-2,-1)[0])[1].length+1
).join(' ')
head.innerHTML = pre.replace(/\s*$/, '\n')
+ indent(meta, dent) + '\n'
+ Array(postdent + 1).join(' ')
return root.outerHTML
}
var html = root.querySelector('html')
if (html) {
html = select(html)
var post = html.html()
var dent = Array(/^[\r\n]*(\s*)/.exec(post)[1].length + 1).join(' ')
html.innerHTML = '\n' + dent + '<head>'
+ '\n' + indent(meta, dent + detected)
+ '\n' + dent + '</head>\n'
+ html.innerHTML
return root.outerHTML
} else {
var post = root.innerHTML
var dent = Array(/^[\r\n]*(\s*)/.exec(post)[1].length + 1).join(' ')
return dent + '<head>\n'
+ indent(meta, dent + detected)
+ '\n' + dent + '</head>\n'
+ post
}
function select (q, f) {
var nodes = root.querySelectorAll(q)
for (var i = 0; i < nodes.length; i++) f(nodes[i])
}
}
function dom (str) {
var div = document.createElement('html')
div.innerHTML = str
return div
}