From 099378aedd7ef52b6fcc604c87933cb481fc847e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=87=E5=A4=A9?= Date: Mon, 17 Aug 2020 19:04:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E9=83=A8=E5=88=86=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E5=A4=84=E7=90=86;=E7=A7=BB=E9=99=A4=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E9=AA=8C=E8=AF=81=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/directives/{attr.modern.js => attr.js} | 0 src/directives/duplex/{modern.js => index.js} | 0 src/directives/modern.js | 8 +- src/filters/array.js | 17 +- src/renders/domRender.js | 55 +++--- src/seed/cache.js | 180 +++++++++--------- src/seed/core.js | 7 +- src/seed/lang.js | 24 ++- src/vmodel/Mutation.js | 73 +++---- src/vtree/fromDOM.js | 128 ++++++------- src/vtree/orphanTag.js | 14 +- src/vtree/validateDOMNesting.js | 65 +++---- 12 files changed, 273 insertions(+), 298 deletions(-) rename src/directives/{attr.modern.js => attr.js} (100%) rename src/directives/duplex/{modern.js => index.js} (100%) diff --git a/src/directives/attr.modern.js b/src/directives/attr.js similarity index 100% rename from src/directives/attr.modern.js rename to src/directives/attr.js diff --git a/src/directives/duplex/modern.js b/src/directives/duplex/index.js similarity index 100% rename from src/directives/duplex/modern.js rename to src/directives/duplex/index.js diff --git a/src/directives/modern.js b/src/directives/modern.js index 68aaf77..b22eb94 100644 --- a/src/directives/modern.js +++ b/src/directives/modern.js @@ -8,13 +8,13 @@ import './text' import './css' import './expr' -import './attr.modern' +import './attr' import './html' import './if' import './on' import './for' import './class.hover.active' -import './duplex/modern' -import './rules' -import './validate' +import './duplex/index' +// import './rules' +// import './validate' diff --git a/src/filters/array.js b/src/filters/array.js index de7fd7e..e3d87e2 100644 --- a/src/filters/array.js +++ b/src/filters/array.js @@ -1,10 +1,6 @@ import { Anot, escapeRegExp } from '../seed/core' import { $$skipArray } from '../vmodel/reserved' -/* -https://github.com/hufyhang/orderBy/blob/master/index.js -*/ - export function orderBy(array, by, decend) { var type = Anot.type(array) if (type !== 'array' && type !== 'object') throw 'orderBy只能处理对象或数组' @@ -88,14 +84,7 @@ export function filterBy(array, search, ...args) { var target = isArray ? [] : {} __repeat(array, isArray, function(key) { var val = array[key] - if ( - criteria.apply( - { - key: key - }, - [val, key].concat(args) - ) - ) { + if (criteria.apply({ key }, [val, key].concat(args))) { if (isArray) { target.push(val) } else { @@ -121,7 +110,9 @@ export function selectBy(data, array, defaults) { export function limitBy(input, limit, begin) { var type = Anot.type(input) - if (type !== 'array' && type !== 'object') throw 'limitBy只能处理对象或数组' + if (type !== 'array' && type !== 'object') { + throw 'limitBy只能处理对象或数组' + } //必须是数值 if (typeof limit !== 'number') { return input diff --git a/src/renders/domRender.js b/src/renders/domRender.js index bdc9d75..de1a69f 100644 --- a/src/renders/domRender.js +++ b/src/renders/domRender.js @@ -3,7 +3,7 @@ import { fromDOM } from '../vtree/fromDOM' import { fromString } from '../vtree/fromString' import { VFragment } from '../vdom/VFragment' -import { Directive } from './Directive' +import { Directive } from './directive' import { orphanTag } from '../vtree/orphanTag' import { parseAttributes, eventMap } from '../parser/attributes' @@ -11,6 +11,8 @@ import { parseInterpolate } from '../parser/interpolate' import { startWith, groupTree, dumpTree, getRange } from './share' +var viewID + /** * 生成一个渲染器,并作为它第一个遇到的ms-controller对应的VM的$render属性 * @param {String|DOM} node @@ -25,17 +27,18 @@ Anot.scan = function(node, vm, beforeReady) { /** * Anot.scan 的内部实现 */ -function Render(node, vm, beforeReady) { - this.root = node //如果传入的字符串,确保只有一个标签作为根节点 - this.vm = vm - this.beforeReady = beforeReady - this.bindings = [] //收集待加工的绑定属性 - this.callbacks = [] - this.directives = [] - this.init() -} -Render.prototype = { +class Render { + constructor(node, vm, beforeReady) { + this.root = node //如果传入的字符串,确保只有一个标签作为根节点 + this.vm = vm + this.beforeReady = beforeReady + this.bindings = [] //收集待加工的绑定属性 + this.callbacks = [] + this.directives = [] + this.init() + } + /** * 开始扫描指定区域 * 收集绑定属性 @@ -50,15 +53,13 @@ Render.prototype = { } else if (typeof this.root === 'string') { vnodes = fromString(this.root) //转换虚拟DOM } else { - return console.warn( - 'Anot.scan first argument must element or HTML string' - ) + return console.warn('Anot.scan()第1个参数,只能是节点对象或节点字符串') } this.root = vnodes[0] this.vnodes = vnodes this.scanChildren(vnodes, this.vm, true) - }, + } scanChildren(children, scope, isRoot) { for (var i = 0; i < children.length; i++) { @@ -81,7 +82,7 @@ Render.prototype = { if (isRoot) { this.complete() } - }, + } /** * 从文本节点获取指令 @@ -99,7 +100,7 @@ Render.prototype = { } ]) } - }, + } /** * 从注释节点获取指令 @@ -112,7 +113,7 @@ Render.prototype = { if (startWith(vdom.nodeValue, 'ms-for:')) { this.getForBinding(vdom, scope, parentChildren) } - }, + } /** * 从元素节点的nodeName与属性中获取指令 @@ -223,7 +224,7 @@ Render.prototype = { ) { this.scanChildren(children, scope, false) } - }, + } /** * 将绑定属性转换为指令 @@ -245,7 +246,7 @@ Render.prototype = { fn() } this.optimizeDirectives() - }, + } /** * 将收集到的绑定属性进行深加工,最后转换指令 @@ -276,7 +277,7 @@ Render.prototype = { this.directives.push(directive) } } - }, + } /** * 修改指令的update与callback方法,让它们以后执行时更加高效 @@ -288,12 +289,13 @@ Render.prototype = { el.update = newUpdate el._isScheduled = false } - }, - update: function() { + } + + update() { for (var i = 0, el; (el = this.directives[i++]); ) { el.update() } - }, + } /** * 销毁所有指令 @@ -308,7 +310,7 @@ Render.prototype = { for (let i in this) { if (i !== 'dispose') delete this[i] } - }, + } /** * 将循环区域转换为for指令 @@ -341,7 +343,7 @@ Render.prototype = { parentChildren } ]) - }, + } /** * 在带ms-for元素节点旁添加两个注释节点,组成循环区域 @@ -370,7 +372,6 @@ Render.prototype = { this.getForBinding(begin, scope, parentChildren, props['data-for-rendered']) } } -var viewID function newUpdate() { var oldVal = this.beforeUpdate() diff --git a/src/seed/cache.js b/src/seed/cache.js index 6e1045e..1b6a75d 100644 --- a/src/seed/cache.js +++ b/src/seed/cache.js @@ -8,104 +8,98 @@ removed <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- added */ -export function Cache(maxLength) { + +export class Cache { + constructor(maxLength) { // 标识当前缓存数组的大小 this.size = 0 - // 标识缓存数组能达到的最大长度 + // 标识缓存数组能达到的最大长度 this.limit = maxLength - // head(最不常用的项),tail(最常用的项)全部初始化为undefined + // head(最不常用的项),tail(最常用的项)全部初始化为undefined this.head = this.tail = void 0 this._keymap = {} -} + } -Cache.prototype = { - - put(key, value) { - var entry = { - key: key, - value: value - } - this._keymap[key] = entry - if (this.tail) { - // 如果存在tail(缓存数组的长度不为0),将tail指向新的 entry - this.tail.newer = entry - entry.older = this.tail - } else { - // 如果缓存数组的长度为0,将head指向新的entry - this.head = entry - } - this.tail = entry - // 如果缓存数组达到上限,则先删除 head 指向的缓存对象 - /* istanbul ignore if */ - if (this.size === this.limit) { - this.shift() - } else { - this.size++ - } - return value - }, - - shift() { - /* istanbul ignore next */ - var entry = this.head - /* istanbul ignore if */ - if (entry) { - // 删除 head ,并改变指向 - this.head = this.head.newer - // 同步更新 _keymap 里面的属性值 - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = - void 0 - delete this._keymap[entry.key] //#1029 - // 同步更新 缓存数组的长度 - this.size-- - } - }, - - get(key) { - var entry = this._keymap[key] - // 如果查找不到含有`key`这个属性的缓存对象 - if (entry === void 0) - return - // 如果查找到的缓存对象已经是 tail (最近使用过的) - /* istanbul ignore if */ - if (entry === this.tail) { - return entry.value - } - // HEAD--------------TAIL - // <.older .newer> - // <--- add direction -- - // A B C E - if (entry.newer) { - // 处理 newer 指向 - if (entry === this.head) { - // 如果查找到的缓存对象是 head (最近最少使用过的) - // 则将 head 指向原 head 的 newer 所指向的缓存对象 - this.head = entry.newer - } - // 将所查找的缓存对象的下一级的 older 指向所查找的缓存对象的older所指向的值 - // 例如:A B C D E - // 如果查找到的是D,那么将E指向C,不再指向D - entry.newer.older = entry.older // C <-- E. - } - if (entry.older) { - // 处理 older 指向 - // 如果查找到的是D,那么C指向E,不再指向D - entry.older.newer = entry.newer // C. --> E - } - // 处理所查找到的对象的 newer 以及 older 指向 - entry.newer = void 0 // D --x - // older指向之前使用过的变量,即D指向E - entry.older = this.tail // D. --> E - if (this.tail) { - // 将E的newer指向D - this.tail.newer = entry // E. <-- D - } - // 改变 tail 为D - this.tail = entry - return entry.value + put(key, value) { + var entry = { key, value } + this._keymap[key] = entry + if (this.tail) { + // 如果存在tail(缓存数组的长度不为0),将tail指向新的 entry + this.tail.newer = entry + entry.older = this.tail + } else { + // 如果缓存数组的长度为0,将head指向新的entry + this.head = entry } -} \ No newline at end of file + this.tail = entry + // 如果缓存数组达到上限,则先删除 head 指向的缓存对象 + /* istanbul ignore if */ + if (this.size === this.limit) { + this.shift() + } else { + this.size++ + } + return value + } + + shift() { + /* istanbul ignore next */ + var entry = this.head + /* istanbul ignore if */ + if (entry) { + // 删除 head ,并改变指向 + this.head = this.head.newer + // 同步更新 _keymap 里面的属性值 + this.head.older = entry.newer = entry.older = this._keymap[ + entry.key + ] = void 0 + delete this._keymap[entry.key] //#1029 + // 同步更新 缓存数组的长度 + this.size-- + } + } + + get(key) { + var entry = this._keymap[key] + // 如果查找不到含有`key`这个属性的缓存对象 + if (entry === void 0) return + // 如果查找到的缓存对象已经是 tail (最近使用过的) + /* istanbul ignore if */ + if (entry === this.tail) { + return entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + // 处理 newer 指向 + if (entry === this.head) { + // 如果查找到的缓存对象是 head (最近最少使用过的) + // 则将 head 指向原 head 的 newer 所指向的缓存对象 + this.head = entry.newer + } + // 将所查找的缓存对象的下一级的 older 指向所查找的缓存对象的older所指向的值 + // 例如:A B C D E + // 如果查找到的是D,那么将E指向C,不再指向D + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + // 处理 older 指向 + // 如果查找到的是D,那么C指向E,不再指向D + entry.older.newer = entry.newer // C. --> E + } + // 处理所查找到的对象的 newer 以及 older 指向 + entry.newer = void 0 // D --x + // older指向之前使用过的变量,即D指向E + entry.older = this.tail // D. --> E + if (this.tail) { + // 将E的newer指向D + this.tail.newer = entry // E. <-- D + } + // 改变 tail 为D + this.tail = entry + return entry.value + } +} diff --git a/src/seed/core.js b/src/seed/core.js index 59fb13e..f3be7f5 100644 --- a/src/seed/core.js +++ b/src/seed/core.js @@ -24,8 +24,8 @@ export function oneObject(array, val) { if (typeof array === 'string') { array = array.match(rword) || [] } - var result = {}, - value = val !== void 0 ? val : 1 + var result = {} + var value = val !== void 0 ? val : 1 for (var i = 0, n = array.length; i < n; i++) { result[array[i]] = value } @@ -114,9 +114,10 @@ export var validators = {} export var cssHooks = {} window.Anot = Anot +Anot.platform = platform +/* istanbul ignore next */ export function createFragment() { - /* istanbul ignore next */ return document.createDocumentFragment() } diff --git a/src/seed/lang.js b/src/seed/lang.js index eac7f3d..0ae7fa3 100644 --- a/src/seed/lang.js +++ b/src/seed/lang.js @@ -6,22 +6,20 @@ var rarraylike = /(Array|List|Collection|Map|Arguments|Set)\]$/ // Anot.type var class2type = {} -'Boolean Number String Function Array Date RegExp Object Error'.replace( - Anot.rword, - function(name) { +'Boolean,Number,String,Function,Array,Date,RegExp,Object,Error,AsyncFunction,Promise,Generator,GeneratorFunction' + .split(',') + .forEach(function(name) { class2type['[object ' + name + ']'] = name.toLowerCase() - } -) + }) Anot.type = function(obj) { - //取得目标的类型 - if (obj == null) { - return String(obj) + if (obj) { + // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[inspect.call(obj)] || 'object' + : typeof obj } - // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function - return typeof obj === 'object' || typeof obj === 'function' - ? class2type[inspect.call(obj)] || 'object' - : typeof obj + return String(obj) } Anot.isFunction = function(fn) { @@ -123,8 +121,8 @@ export function isArrayLike(obj) { } Anot.each = function(obj, fn) { + //排除null, undefined if (obj) { - //排除null, undefined var i = 0 if (isArrayLike(obj)) { for (var n = obj.length; i < n; i++) { diff --git a/src/vmodel/Mutation.js b/src/vmodel/Mutation.js index 7806b16..1367a96 100644 --- a/src/vmodel/Mutation.js +++ b/src/vmodel/Mutation.js @@ -5,32 +5,34 @@ import { propagateChanged } from './transaction' import { Anot, platform } from '../seed/core' + /** * 与Computed等共享UUID */ export let obid = 1 -export function Mutation(expr, value, vm) { - //构造函数 - this.expr = expr - if (value) { - var childVm = platform.createProxy(value, this) - if (childVm) { - value = childVm - } - } - this.value = value - this.vm = vm - try { - vm.$mutations[expr] = this - } catch (ignoreIE) {} - this.uuid = ++obid - this.updateVersion() - this.mapIDs = {} - this.observers = [] -} -Mutation.prototype = { +export class Mutation { + constructor(expr, value, vm) { + //构造函数 + this.expr = expr + if (value) { + var childVm = platform.createProxy(value, this) + if (childVm) { + value = childVm + } + } + this.value = value + this.vm = vm + try { + vm.$mutations[expr] = this + } catch (ignoreIE) {} + this.uuid = ++obid + this.updateVersion() + this.mapIDs = {} + this.observers = [] + } + get() { if (Anot.trackingAction) { this.collect() //被收集 @@ -52,22 +54,7 @@ Mutation.prototype = { } } return this.value - }, - - collect() { - // Anot.track(name, '被收集') - reportObserved(this) - }, - - updateVersion() { - this.version = Math.random() + Math.random() - }, - - notify() { - transactionStart() - propagateChanged(this) - transactionEnd() - }, + } set(newValue) { var oldValue = this.value @@ -87,4 +74,18 @@ Mutation.prototype = { this.notify() } } + collect() { + // Anot.track(name, '被收集') + reportObserved(this) + } + + updateVersion() { + this.version = Math.random() + Math.random() + } + + notify() { + transactionStart() + propagateChanged(this) + transactionEnd() + } } diff --git a/src/vtree/fromDOM.js b/src/vtree/fromDOM.js index d527681..84ecd48 100644 --- a/src/vtree/fromDOM.js +++ b/src/vtree/fromDOM.js @@ -3,76 +3,76 @@ import { voidTag } from './voidTag' import { makeOrphan } from './makeOrphan' export function fromDOM(dom) { - return [from(dom)] + return [_from(dom)] } -export function from(node) { - var type = node.nodeName.toLowerCase() - switch (type) { - case '#text': - case '#comment': - return { - nodeName: type, - dom: node, - nodeValue: node.nodeValue - } - default: - var props = markProps(node, node.attributes || []) - var vnode = { - nodeName: type, - dom: node, - isVoidTag: !!voidTag[type], - props: props - } - if(type === 'option'){ - //即便你设置了option.selected = true, - //option.attributes也找不到selected属性 - props.selected = node.selected - } - if (orphanTag[type] || type === 'option') { - makeOrphan(vnode, type, node.text || node.innerHTML) - if (node.childNodes.length === 1) { - vnode.children[0].dom = node.firstChild - } - } else if (!vnode.isVoidTag) { - vnode.children = [] - for (var i = 0, el; el = node.childNodes[i++];) { - var child = from(el) - if (/\S/.test(child.nodeValue)) { - vnode.children.push(child) - } - } - } - return vnode - } +export function _from(node) { + var type = node.nodeName.toLowerCase() + switch (type) { + case '#text': + case '#comment': + return { + nodeName: type, + dom: node, + nodeValue: node.nodeValue + } + default: + var props = markProps(node, node.attributes || []) + var vnode = { + nodeName: type, + dom: node, + isVoidTag: !!voidTag[type], + props: props + } + if (type === 'option') { + //即便你设置了option.selected = true, + //option.attributes也找不到selected属性 + props.selected = node.selected + } + if (orphanTag[type] || type === 'option') { + makeOrphan(vnode, type, node.text || node.innerHTML) + if (node.childNodes.length === 1) { + vnode.children[0].dom = node.firstChild + } + } else if (!vnode.isVoidTag) { + vnode.children = [] + for (var i = 0, el; (el = node.childNodes[i++]); ) { + var child = _from(el) + if (/\S/.test(child.nodeValue)) { + vnode.children.push(child) + } + } + } + return vnode + } } var rformElement = /input|textarea|select/i function markProps(node, attrs) { - var ret = {} - for (var i = 0, n = attrs.length; i < n; i++) { - var attr = attrs[i] - if (attr.specified) { - //IE6-9不会将属性名变小写,比如它会将用户的contenteditable变成contentEditable - ret[attr.name.toLowerCase()] = attr.value - } + var ret = {} + for (var i = 0, n = attrs.length; i < n; i++) { + var attr = attrs[i] + if (attr.specified) { + //IE6-9不会将属性名变小写,比如它会将用户的contenteditable变成contentEditable + ret[attr.name.toLowerCase()] = attr.value } - if (rformElement.test(node.nodeName)) { - ret.type = node.type - var a = node.getAttributeNode('value') - if (a && /\S/.test(a.value)) { //IE6,7中无法取得checkbox,radio的value - ret.value = a.value - } - + } + if (rformElement.test(node.nodeName)) { + ret.type = node.type + var a = node.getAttributeNode('value') + if (a && /\S/.test(a.value)) { + //IE6,7中无法取得checkbox,radio的value + ret.value = a.value } - var style = node.style.cssText - if (style) { - ret.style = style - } - //类名 = 去重(静态类名+动态类名+ hover类名? + active类名) - if (ret.type === 'select-one') { - ret.selectedIndex = node.selectedIndex - } - return ret -} \ No newline at end of file + } + var style = node.style.cssText + if (style) { + ret.style = style + } + //类名 = 去重(静态类名+动态类名+ hover类名? + active类名) + if (ret.type === 'select-one') { + ret.selectedIndex = node.selectedIndex + } + return ret +} diff --git a/src/vtree/orphanTag.js b/src/vtree/orphanTag.js index 6dc7138..113f88b 100644 --- a/src/vtree/orphanTag.js +++ b/src/vtree/orphanTag.js @@ -1,8 +1,8 @@ export var orphanTag = { - script: 1, - style: 1, - textarea: 1, - xmp: 1, - noscript: 1, - template: 1 -} \ No newline at end of file + script: 1, + style: 1, + textarea: 1, + xmp: 1, + noscript: 1, + template: 1 +} diff --git a/src/vtree/validateDOMNesting.js b/src/vtree/validateDOMNesting.js index b44ae96..55b70a8 100644 --- a/src/vtree/validateDOMNesting.js +++ b/src/vtree/validateDOMNesting.js @@ -1,5 +1,29 @@ import { Anot, oneObject } from '../seed/core' +var pNestChild = oneObject('div,ul,ol,dl,table,h1,h2,h3,h4,h5,h6,form,fieldset') +var tNestChild = makeObject('tr,style,script') +var nestObject = { + p: pNestChild, + select: makeObject('option,optgroup,#text'), + optgroup: makeObject('option,#text'), + option: makeObject('#text'), + tr: makeObject('th,td,style,script'), + + tbody: tNestChild, + tfoot: tNestChild, + thead: tNestChild, + colgroup: makeObject('col'), + // table: oneObject('caption,colgroup,tbody,thead,tfoot,style,script,template,#document-fragment'), + head: makeObject( + 'base,basefont,bgsound,link,style,script,meta,title,noscript,noframes' + ), + html: oneObject('head,body') +} + +function makeObject(str) { + return oneObject(str + ',template,#document-fragment,#comment') +} + export function validateDOMNesting(parent, child) { var parentTag = parent.nodeName var tag = child.nodeName @@ -8,16 +32,16 @@ export function validateDOMNesting(parent, child) { if (parentTag === 'p') { if (pNestChild[tag]) { console.warn( - 'P element can not add these childlren:\n' + Object.keys(pNestChild) + 'P标签节点不允许以下类型的子节点:\n' + Object.keys(pNestChild) ) return false } } else if (!parentChild[tag]) { console.warn( parentTag.toUpperCase() + - 'element only add these children:\n' + + '标签节点只能增加以下子节点:\n' + Object.keys(parentChild) + - '\nbut you add ' + + '\n当前子节点为:' + tag.toUpperCase() + ' !!' ) @@ -26,38 +50,3 @@ export function validateDOMNesting(parent, child) { } return true } - -function makeObject(str) { - return oneObject(str + ',template,#document-fragment,#comment') -} -var pNestChild = oneObject('div,ul,ol,dl,table,h1,h2,h3,h4,h5,h6,form,fieldset') -var tNestChild = makeObject('tr,style,script') -var nestObject = { - p: pNestChild, - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect - select: makeObject('option,optgroup,#text'), - optgroup: makeObject('option,#text'), - option: makeObject('#text'), - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption - // No special behavior since these rules fall back to "in body" mode for - // all except special table nodes which cause bad parsing behavior anyway. - - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr - tr: makeObject('th,td,style,script'), - - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody - tbody: tNestChild, - tfoot: tNestChild, - thead: tNestChild, - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup - colgroup: makeObject('col'), - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable - // table: oneObject('caption,colgroup,tbody,thead,tfoot,style,script,template,#document-fragment'), - // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead - head: makeObject( - 'base,basefont,bgsound,link,style,script,meta,title,noscript,noframes' - ), - // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element - html: oneObject('head,body') -}