forked from dequelabs/axe-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserial-virtual-node.js
More file actions
132 lines (116 loc) · 3.17 KB
/
serial-virtual-node.js
File metadata and controls
132 lines (116 loc) · 3.17 KB
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
import AbstractVirtualNode from './abstract-virtual-node';
import { assert, validInputTypes } from '../../utils';
class SerialVirtualNode extends AbstractVirtualNode {
/**
* Convert a serialised node into a VirtualNode object
* @param {Object} node Serialised node
*/
constructor(serialNode) {
super();
this._props = normaliseProps(serialNode);
this._attrs = normaliseAttrs(serialNode);
}
// Accessof for DOM node properties
get props() {
return this._props;
}
/**
* Get the value of the given attribute name.
* @param {String} attrName The name of the attribute.
* @return {String|null} The value of the attribute or null if the attribute does not exist
*/
attr(attrName) {
return this._attrs[attrName] ?? null;
}
/**
* Determine if the element has the given attribute.
* @param {String} attrName The name of the attribute
* @return {Boolean} True if the element has the attribute, false otherwise.
*/
hasAttr(attrName) {
return this._attrs[attrName] !== undefined;
}
/**
* Return a list of attribute names for the element.
* @return {String[]}
*/
get attrNames() {
return Object.keys(this._attrs);
}
}
const nodeNamesToTypes = {
'#cdata-section': 2,
'#text': 3,
'#comment': 8,
'#document': 9,
'#document-fragment': 11
};
const nodeTypeToName = {};
const nodeNames = Object.keys(nodeNamesToTypes);
nodeNames.forEach(nodeName => {
nodeTypeToName[nodeNamesToTypes[nodeName]] = nodeName;
});
/**
* Convert between serialised props and DOM-like properties
* @param {Object} serialNode
* @return {Object} normalProperties
*/
function normaliseProps(serialNode) {
let nodeName = serialNode.nodeName ?? nodeTypeToName[serialNode.nodeType];
const nodeType =
serialNode.nodeType ?? nodeNamesToTypes[serialNode.nodeName] ?? 1;
assert(
typeof nodeType === 'number',
`nodeType has to be a number, got '${nodeType}'`
);
assert(
typeof nodeName === 'string',
`nodeName has to be a string, got '${nodeName}'`
);
nodeName = nodeName.toLowerCase();
let type = null;
if (nodeName === 'input') {
type = (
serialNode.type ||
(serialNode.attributes && serialNode.attributes.type) ||
''
).toLowerCase();
if (!validInputTypes().includes(type)) {
type = 'text';
}
}
const props = {
...serialNode,
nodeType,
nodeName
};
if (type) {
props.type = type;
}
delete props.attributes;
return Object.freeze(props);
}
/**
* Convert between serialised attributes and DOM-like attributes
* @param {Object} serialNode
* @return {Object} normalAttributes
*/
function normaliseAttrs({ attributes = {} }) {
const attrMap = {
htmlFor: 'for',
className: 'class'
};
return Object.keys(attributes).reduce((attrs, attrName) => {
const value = attributes[attrName];
assert(
typeof value !== 'object' || value === null,
`expects attributes not to be an object, '${attrName}' was`
);
if (value !== undefined) {
const mappedName = attrMap[attrName] || attrName;
attrs[mappedName] = value !== null ? String(value) : null;
}
return attrs;
}, {});
}
export default SerialVirtualNode;