Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 88 additions & 28 deletions lib/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,32 @@ var isHTMLVoidElement = conventions.isHTMLVoidElement;
var MIME_TYPE = conventions.MIME_TYPE;
var NAMESPACE = conventions.NAMESPACE;

/**
* Private DOM Constructor symbol
*
* Internal symbol used for construction of all classes whose constructors should be private.
* Currently used for checks in `Node`, `Document`, `Element`, `Attr`, `CharacterData`, `Text`, `Comment`,
* `CDATASection`, `DocumentType`, `Notation`, `Entity`, `EntityReference`, `DocumentFragment`, `ProcessingInstruction`
* so the constructor can't be used from outside the module.
*/
var PDC = Symbol();

var errors = require('./errors');
var DOMException = errors.DOMException;

var g = require('./grammar');

/**
* Checks if the given symbol equals the Private DOM Constructor symbol (PDC)
* and throws an Illegal constructor exception when the symbols don't match.
* This ensures that the constructor remains private and can't be used outside this module.
*/
function checkSymbol(symbol) {
if (symbol !== PDC) {
throw new TypeError('Illegal constructor');
}
}

/**
* A prerequisite for `[].filter`, to drop elements that are empty.
*
Expand Down Expand Up @@ -830,7 +851,7 @@ DOMImplementation.prototype = {
} else if (namespaceURI === NAMESPACE.SVG) {
contentType = MIME_TYPE.XML_SVG_IMAGE;
}
var doc = new Document({ contentType: contentType });
var doc = new Document(PDC, { contentType: contentType });
doc.implementation = this;
doc.childNodes = new NodeList();
doc.doctype = doctype || null;
Expand Down Expand Up @@ -890,7 +911,7 @@ DOMImplementation.prototype = {
*/
createDocumentType: function (qualifiedName, publicId, systemId, internalSubset) {
validateQualifiedName(qualifiedName);
var node = new DocumentType();
var node = new DocumentType(PDC);
node.name = qualifiedName;
node.nodeName = qualifiedName;
node.publicId = publicId || '';
Expand All @@ -917,7 +938,7 @@ DOMImplementation.prototype = {
* @see https://dom.spec.whatwg.org/#html-document
*/
createHTMLDocument: function (title) {
var doc = new Document({ contentType: MIME_TYPE.HTML });
var doc = new Document(PDC, { contentType: MIME_TYPE.HTML });
doc.implementation = this;
doc.childNodes = new NodeList();
if (title !== false) {
Expand Down Expand Up @@ -961,11 +982,14 @@ DOMImplementation.prototype = {
*
* @class
* @abstract
* @param {Symbol} symbol
* @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
* @see https://dom.spec.whatwg.org/#node
* @prettierignore
*/
function Node() {}
function Node(symbol) {
checkSymbol(symbol);
}

Node.prototype = {
/**
Expand Down Expand Up @@ -1405,13 +1429,16 @@ function _visitNode(node, callback) {
* property via it's options parameter.
*
* @class
* @param {Symbol} symbol
* @param {DocumentOptions} [options]
* @augments Node
* @private
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document
* @see https://dom.spec.whatwg.org/#interface-document
*/
function Document(options) {
function Document(symbol, options) {
checkSymbol(symbol);

var opt = options || {};
this.ownerDocument = this;
/**
Expand Down Expand Up @@ -2054,7 +2081,7 @@ Document.prototype = {
* @see https://dom.spec.whatwg.org/#concept-create-element
*/
createElement: function (tagName) {
var node = new Element();
var node = new Element(PDC);
node.ownerDocument = this;
if (this.type === 'html') {
tagName = tagName.toLowerCase();
Expand All @@ -2071,31 +2098,31 @@ Document.prototype = {
return node;
},
createDocumentFragment: function () {
var node = new DocumentFragment();
var node = new DocumentFragment(PDC);
node.ownerDocument = this;
node.childNodes = new NodeList();
return node;
},
createTextNode: function (data) {
var node = new Text();
var node = new Text(PDC);
node.ownerDocument = this;
node.appendData(data);
return node;
},
createComment: function (data) {
var node = new Comment();
var node = new Comment(PDC);
node.ownerDocument = this;
node.appendData(data);
return node;
},
createCDATASection: function (data) {
var node = new CDATASection();
var node = new CDATASection(PDC);
node.ownerDocument = this;
node.appendData(data);
return node;
},
createProcessingInstruction: function (target, data) {
var node = new ProcessingInstruction();
var node = new ProcessingInstruction(PDC);
node.ownerDocument = this;
node.nodeName = node.target = target;
node.nodeValue = node.data = data;
Expand Down Expand Up @@ -2125,7 +2152,7 @@ Document.prototype = {
return this._createAttribute(name);
},
_createAttribute: function (name) {
var node = new Attr();
var node = new Attr(PDC);
node.ownerDocument = this;
node.name = name;
node.nodeName = name;
Expand All @@ -2134,15 +2161,15 @@ Document.prototype = {
return node;
},
createEntityReference: function (name) {
var node = new EntityReference();
var node = new EntityReference(PDC);
node.ownerDocument = this;
node.nodeName = name;
return node;
},
// Introduced in DOM Level 2:
createElementNS: function (namespaceURI, qualifiedName) {
var validated = validateAndExtract(namespaceURI, qualifiedName);
var node = new Element();
var node = new Element(PDC);
var attrs = (node.attributes = new NamedNodeMap());
node.childNodes = new NodeList();
node.ownerDocument = this;
Expand All @@ -2157,7 +2184,7 @@ Document.prototype = {
// Introduced in DOM Level 2:
createAttributeNS: function (namespaceURI, qualifiedName) {
var validated = validateAndExtract(namespaceURI, qualifiedName);
var node = new Attr();
var node = new Attr(PDC);
node.ownerDocument = this;
node.nodeName = qualifiedName;
node.name = qualifiedName;
Expand All @@ -2170,7 +2197,9 @@ Document.prototype = {
};
_extends(Document, Node);

function Element() {
function Element(symbol) {
checkSymbol(symbol);

this._nsMap = Object.create(null);
}
Element.prototype = {
Expand Down Expand Up @@ -2348,15 +2377,19 @@ Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName
Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;

_extends(Element, Node);
function Attr() {
function Attr(symbol) {
checkSymbol(symbol);

this.namespaceURI = null;
this.prefix = null;
this.ownerElement = null;
}
Attr.prototype.nodeType = ATTRIBUTE_NODE;
_extends(Attr, Node);

function CharacterData() {}
function CharacterData(symbol) {
checkSymbol(symbol);
}
CharacterData.prototype = {
data: '',
substringData: function (offset, count) {
Expand All @@ -2382,7 +2415,9 @@ CharacterData.prototype = {
},
};
_extends(CharacterData, Node);
function Text() {}
function Text(symbol) {
checkSymbol(symbol);
}
Text.prototype = {
nodeName: '#text',
nodeType: TEXT_NODE,
Expand All @@ -2400,42 +2435,58 @@ Text.prototype = {
},
};
_extends(Text, CharacterData);
function Comment() {}
function Comment(symbol) {
checkSymbol(symbol);
}
Comment.prototype = {
nodeName: '#comment',
nodeType: COMMENT_NODE,
};
_extends(Comment, CharacterData);

function CDATASection() {}
function CDATASection(symbol) {
checkSymbol(symbol);
}
CDATASection.prototype = {
nodeName: '#cdata-section',
nodeType: CDATA_SECTION_NODE,
};
_extends(CDATASection, CharacterData);

function DocumentType() {}
function DocumentType(symbol) {
checkSymbol(symbol);
}
DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
_extends(DocumentType, Node);

function Notation() {}
function Notation(symbol) {
checkSymbol(symbol);
}
Notation.prototype.nodeType = NOTATION_NODE;
_extends(Notation, Node);

function Entity() {}
function Entity(symbol) {
checkSymbol(symbol);
}
Entity.prototype.nodeType = ENTITY_NODE;
_extends(Entity, Node);

function EntityReference() {}
function EntityReference(symbol) {
checkSymbol(symbol);
}
EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
_extends(EntityReference, Node);

function DocumentFragment() {}
function DocumentFragment(symbol) {
checkSymbol(symbol);
}
DocumentFragment.prototype.nodeName = '#document-fragment';
DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
_extends(DocumentFragment, Node);

function ProcessingInstruction() {}
function ProcessingInstruction(symbol) {
checkSymbol(symbol);
}
ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
_extends(ProcessingInstruction, Node);
function XMLSerializer() {}
Expand Down Expand Up @@ -2756,7 +2807,7 @@ function importNode(doc, node, deep) {
* potentially invoked in this function) do not meet their specific constraints.
*/
function cloneNode(doc, node, deep) {
var node2 = new node.constructor();
var node2 = new node.constructor(PDC);
for (var n in node) {
if (hasOwn(node, n)) {
var v = node[n];
Expand Down Expand Up @@ -2861,12 +2912,21 @@ try {

exports._updateLiveList = _updateLiveList;
exports.Attr = Attr;
exports.CDATASection = CDATASection;
exports.CharacterData = CharacterData;
exports.Comment = Comment;
exports.Document = Document;
exports.DocumentFragment = DocumentFragment;
exports.DocumentType = DocumentType;
exports.DOMImplementation = DOMImplementation;
exports.Element = Element;
exports.Entity = Entity;
exports.EntityReference = EntityReference;
exports.LiveNodeList = LiveNodeList;
exports.NamedNodeMap = NamedNodeMap;
exports.Node = Node;
exports.NodeList = NodeList;
exports.Notation = Notation;
exports.Text = Text;
exports.XMLSerializer = XMLSerializer;
exports.ProcessingInstruction = ProcessingInstruction;
60 changes: 35 additions & 25 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,31 +148,40 @@ Object.defineProperties(DOMException.prototype, {
},
});

DOMException.INDEX_SIZE_ERR = 1;
DOMException.DOMSTRING_SIZE_ERR = 2;
DOMException.HIERARCHY_REQUEST_ERR = 3;
DOMException.WRONG_DOCUMENT_ERR = 4;
DOMException.INVALID_CHARACTER_ERR = 5;
DOMException.NO_DATA_ALLOWED_ERR = 6;
DOMException.NO_MODIFICATION_ALLOWED_ERR = 7;
DOMException.NOT_FOUND_ERR = 8;
DOMException.NOT_SUPPORTED_ERR = 9;
DOMException.INUSE_ATTRIBUTE_ERR = 10;
DOMException.INVALID_STATE_ERR = 11;
DOMException.SYNTAX_ERR = 12;
DOMException.INVALID_MODIFICATION_ERR = 13;
DOMException.NAMESPACE_ERR = 14;
DOMException.INVALID_ACCESS_ERR = 15;
DOMException.VALIDATION_ERR = 16;
DOMException.TYPE_MISMATCH_ERR = 17;
DOMException.SECURITY_ERR = 18;
DOMException.NETWORK_ERR = 19;
DOMException.ABORT_ERR = 20;
DOMException.URL_MISMATCH_ERR = 21;
DOMException.QUOTA_EXCEEDED_ERR = 22;
DOMException.TIMEOUT_ERR = 23;
DOMException.INVALID_NODE_TYPE_ERR = 24;
DOMException.DATA_CLONE_ERR = 25;
var ExceptionCode = {
INDEX_SIZE_ERR: 1,
DOMSTRING_SIZE_ERR: 2,
HIERARCHY_REQUEST_ERR: 3,
WRONG_DOCUMENT_ERR: 4,
INVALID_CHARACTER_ERR: 5,
NO_DATA_ALLOWED_ERR: 6,
NO_MODIFICATION_ALLOWED_ERR: 7,
NOT_FOUND_ERR: 8,
NOT_SUPPORTED_ERR: 9,
INUSE_ATTRIBUTE_ERR: 10,
INVALID_STATE_ERR: 11,
SYNTAX_ERR: 12,
INVALID_MODIFICATION_ERR: 13,
NAMESPACE_ERR: 14,
INVALID_ACCESS_ERR: 15,
VALIDATION_ERR: 16,
TYPE_MISMATCH_ERR: 17,
SECURITY_ERR: 18,
NETWORK_ERR: 19,
ABORT_ERR: 20,
URL_MISMATCH_ERR: 21,
QUOTA_EXCEEDED_ERR: 22,
TIMEOUT_ERR: 23,
INVALID_NODE_TYPE_ERR: 24,
DATA_CLONE_ERR: 25,
};

var entries = Object.entries(ExceptionCode);
for (var i = 0; i < entries.length; i++) {
var key = entries[i][0];
var value = entries[i][1];
DOMException[key] = value;
}

/**
* Creates an error that will not be caught by XMLReader aka the SAX parser.
Expand All @@ -194,3 +203,4 @@ extendError(ParseError);
exports.DOMException = DOMException;
exports.DOMExceptionName = DOMExceptionName;
exports.ParseError = ParseError;
exports.ExceptionCode = ExceptionCode;
Loading