小程序支持主题管理

This commit is contained in:
devil
2020-11-21 16:42:35 +08:00
parent 3afb6cd3e7
commit 2a5c0cfba1
1748 changed files with 1343 additions and 172 deletions

View File

@ -0,0 +1,11 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,15 @@
//Types of elements found in the DOM
module.exports = {
Text: "text", //Text
Directive: "directive", //<? ... ?>
Comment: "comment", //<!-- ... -->
Script: "script", //<script> tags
Style: "style", //<style> tags
Tag: "tag", //Any tag
CDATA: "cdata", //<![CDATA[ ... ]]>
Doctype: "doctype",
isTag: function(elem){
return elem.type === "tag" || elem.type === "script" || elem.type === "style";
}
};

View File

@ -0,0 +1,90 @@
{
"_args": [
[
{
"raw": "domelementtype@1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "1",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"/data/www/project/shopxo/public/appmini/old/alipay/node_modules/domhandler"
]
],
"_from": "domelementtype@>=1.0.0 <2.0.0",
"_hasShrinkwrap": false,
"_id": "domelementtype@1.3.1",
"_inCache": true,
"_location": "/domelementtype",
"_nodeVersion": "11.3.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/domelementtype_1.3.1_1544088453224_0.16246904901637227"
},
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "6.4.1",
"_phantomChildren": {},
"_requested": {
"raw": "domelementtype@1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "1",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/domhandler"
],
"_resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"_shasum": "d048c44b37b0d10a7f2a3d5fee3f4333d790481f",
"_shrinkwrap": null,
"_spec": "domelementtype@1",
"_where": "/data/www/project/shopxo/public/appmini/old/alipay/node_modules/domhandler",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/domelementtype/issues"
},
"dependencies": {},
"description": "all the types of nodes in htmlparser2's dom",
"devDependencies": {},
"directories": {},
"dist": {
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"shasum": "d048c44b37b0d10a7f2a3d5fee3f4333d790481f",
"tarball": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"fileCount": 4,
"unpackedSize": 2072,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCOuGCRA9TVsSAnZWagAAyyEP/i0IsOJYtr7ACAsPru/T\nqUkPekzIRjgNhQj97Bx/qc1uV23hvvcIACqY8c7QX0X3xwxtrmC43TP5+eGD\neU1BasHGTPtdEFHGAd4hGxh02Mh+ABWPnxo3RTWBaMFSq72qqAuwr2RS+Cia\nEsI5zme0CdGfpnBUF2pAYChwbqPpLnVTGNC3HlakmV57h6OwzfrlyXG1SkhT\nYItha7gNbIv7AuydH44S3AHyyWsw4BQlWjmC+cuasfvrEVsarocYUqTLHWLO\nWpMu/NP2Jct4H8nQzNWCYSI5Hu5F7GDd3wmqBkPZ2Q/GzjQx5tQP7C6ynwGA\n+wA9jVw21xVVzXfRu8d4PBZURppnYSCph8AraccelSYNoqwFleFlP/6EE32b\nj0TLsR4yAQFOy7zqHTmh4ew6mkc7mJGg+lbOsAYSVl4GaVqBiVwqj0zW1CGX\nwj9MSmqBfmM7NIp4lb8oLk1/5D1mtpS5Ng4tyfCE5HK5XGsdVAYKqjamAsPY\n4/y7ZAE8Zb5rglkTJZk4TY8/+s6Wu8IAYyuTD25mLaRu1Z4Kx6uPnZXDZKKw\n2JjTszTpinpNQq50VuhJnQcEyEyNJBra/4aSKgay8LfVqXNUBl+sVBwPJ6l5\nN0e8Vna3pGbeizO4QKm/7mxZnIKAVMZHi7LZ2PFh3LJ0XHIeMuYOsrEF3SKv\ngm4Y\r\n=pGU3\r\n-----END PGP SIGNATURE-----\r\n"
},
"gitHead": "19b2491101a4de3679b59db8eb7fdd9aa0fbc60b",
"homepage": "https://github.com/fb55/domelementtype#readme",
"keywords": [
"dom",
"htmlparser2"
],
"license": "BSD-2-Clause",
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domelementtype",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/domelementtype.git"
},
"version": "1.3.1"
}

View File

@ -0,0 +1 @@
all the types of nodes in htmlparser2's dom

View File

@ -0,0 +1,6 @@
before_install:
- '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@1.4.28'
- npm install -g npm@latest
language: node_js
node_js:
- 8

View File

@ -0,0 +1,11 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,217 @@
var ElementType = require("domelementtype");
var re_whitespace = /\s+/g;
var NodePrototype = require("./lib/node");
var ElementPrototype = require("./lib/element");
function DomHandler(callback, options, elementCB){
if(typeof callback === "object"){
elementCB = options;
options = callback;
callback = null;
} else if(typeof options === "function"){
elementCB = options;
options = defaultOpts;
}
this._callback = callback;
this._options = options || defaultOpts;
this._elementCB = elementCB;
this.dom = [];
this._done = false;
this._tagStack = [];
this._parser = this._parser || null;
}
//default options
var defaultOpts = {
normalizeWhitespace: false, //Replace all whitespace with single spaces
withStartIndices: false, //Add startIndex properties to nodes
withEndIndices: false, //Add endIndex properties to nodes
};
DomHandler.prototype.onparserinit = function(parser){
this._parser = parser;
};
//Resets the handler back to starting state
DomHandler.prototype.onreset = function(){
DomHandler.call(this, this._callback, this._options, this._elementCB);
};
//Signals the handler that parsing is done
DomHandler.prototype.onend = function(){
if(this._done) return;
this._done = true;
this._parser = null;
this._handleCallback(null);
};
DomHandler.prototype._handleCallback =
DomHandler.prototype.onerror = function(error){
if(typeof this._callback === "function"){
this._callback(error, this.dom);
} else {
if(error) throw error;
}
};
DomHandler.prototype.onclosetag = function(){
//if(this._tagStack.pop().name !== name) this._handleCallback(Error("Tagname didn't match!"));
var elem = this._tagStack.pop();
if(this._options.withEndIndices && elem){
elem.endIndex = this._parser.endIndex;
}
if(this._elementCB) this._elementCB(elem);
};
DomHandler.prototype._createDomElement = function(properties){
if (!this._options.withDomLvl1) return properties;
var element;
if (properties.type === "tag") {
element = Object.create(ElementPrototype);
} else {
element = Object.create(NodePrototype);
}
for (var key in properties) {
if (properties.hasOwnProperty(key)) {
element[key] = properties[key];
}
}
return element;
};
DomHandler.prototype._addDomElement = function(element){
var parent = this._tagStack[this._tagStack.length - 1];
var siblings = parent ? parent.children : this.dom;
var previousSibling = siblings[siblings.length - 1];
element.next = null;
if(this._options.withStartIndices){
element.startIndex = this._parser.startIndex;
}
if(this._options.withEndIndices){
element.endIndex = this._parser.endIndex;
}
if(previousSibling){
element.prev = previousSibling;
previousSibling.next = element;
} else {
element.prev = null;
}
siblings.push(element);
element.parent = parent || null;
};
DomHandler.prototype.onopentag = function(name, attribs){
var properties = {
type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,
name: name,
attribs: attribs,
children: []
};
var element = this._createDomElement(properties);
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.ontext = function(data){
//the ignoreWhitespace is officially dropped, but for now,
//it's an alias for normalizeWhitespace
var normalize = this._options.normalizeWhitespace || this._options.ignoreWhitespace;
var lastTag;
if(!this._tagStack.length && this.dom.length && (lastTag = this.dom[this.dom.length-1]).type === ElementType.Text){
if(normalize){
lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");
} else {
lastTag.data += data;
}
} else {
if(
this._tagStack.length &&
(lastTag = this._tagStack[this._tagStack.length - 1]) &&
(lastTag = lastTag.children[lastTag.children.length - 1]) &&
lastTag.type === ElementType.Text
){
if(normalize){
lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");
} else {
lastTag.data += data;
}
} else {
if(normalize){
data = data.replace(re_whitespace, " ");
}
var element = this._createDomElement({
data: data,
type: ElementType.Text
});
this._addDomElement(element);
}
}
};
DomHandler.prototype.oncomment = function(data){
var lastTag = this._tagStack[this._tagStack.length - 1];
if(lastTag && lastTag.type === ElementType.Comment){
lastTag.data += data;
return;
}
var properties = {
data: data,
type: ElementType.Comment
};
var element = this._createDomElement(properties);
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.oncdatastart = function(){
var properties = {
children: [{
data: "",
type: ElementType.Text
}],
type: ElementType.CDATA
};
var element = this._createDomElement(properties);
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.oncommentend = DomHandler.prototype.oncdataend = function(){
this._tagStack.pop();
};
DomHandler.prototype.onprocessinginstruction = function(name, data){
var element = this._createDomElement({
name: name,
data: data,
type: ElementType.Directive
});
this._addDomElement(element);
};
module.exports = DomHandler;

View File

@ -0,0 +1,20 @@
// DOM-Level-1-compliant structure
var NodePrototype = require('./node');
var ElementPrototype = module.exports = Object.create(NodePrototype);
var domLvl1 = {
tagName: "name"
};
Object.keys(domLvl1).forEach(function(key) {
var shorthand = domLvl1[key];
Object.defineProperty(ElementPrototype, key, {
get: function() {
return this[shorthand] || null;
},
set: function(val) {
this[shorthand] = val;
return val;
}
});
});

View File

@ -0,0 +1,44 @@
// This object will be used as the prototype for Nodes when creating a
// DOM-Level-1-compliant structure.
var NodePrototype = module.exports = {
get firstChild() {
var children = this.children;
return children && children[0] || null;
},
get lastChild() {
var children = this.children;
return children && children[children.length - 1] || null;
},
get nodeType() {
return nodeTypes[this.type] || nodeTypes.element;
}
};
var domLvl1 = {
tagName: "name",
childNodes: "children",
parentNode: "parent",
previousSibling: "prev",
nextSibling: "next",
nodeValue: "data"
};
var nodeTypes = {
element: 1,
text: 3,
cdata: 4,
comment: 8
};
Object.keys(domLvl1).forEach(function(key) {
var shorthand = domLvl1[key];
Object.defineProperty(NodePrototype, key, {
get: function() {
return this[shorthand] || null;
},
set: function(val) {
this[shorthand] = val;
return val;
}
});
});

View File

@ -0,0 +1,111 @@
{
"_args": [
[
{
"raw": "domhandler@^2.4.2",
"scope": null,
"escapedName": "domhandler",
"name": "domhandler",
"rawSpec": "^2.4.2",
"spec": ">=2.4.2 <3.0.0",
"type": "range"
},
"/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2"
]
],
"_from": "domhandler@>=2.4.2 <3.0.0",
"_id": "domhandler@2.4.2",
"_inCache": true,
"_location": "/domhandler",
"_nodeVersion": "10.0.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/domhandler_2.4.2_1525892844640_0.057355339211383916"
},
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "5.6.0",
"_phantomChildren": {},
"_requested": {
"raw": "domhandler@^2.4.2",
"scope": null,
"escapedName": "domhandler",
"name": "domhandler",
"rawSpec": "^2.4.2",
"spec": ">=2.4.2 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/mini-html-parser2"
],
"_resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"_shasum": "8805097e933d65e85546f726d60f5eb88b44f803",
"_shrinkwrap": null,
"_spec": "domhandler@^2.4.2",
"_where": "/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/DomHandler/issues"
},
"dependencies": {
"domelementtype": "1"
},
"description": "handler for htmlparser2 that turns pages into a dom",
"devDependencies": {
"htmlparser2": "^3.9.0",
"jshint": "^2.9.1",
"mocha": "^3.0.2"
},
"directories": {
"test": "tests"
},
"dist": {
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"shasum": "8805097e933d65e85546f726d60f5eb88b44f803",
"tarball": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"fileCount": 33,
"unpackedSize": 29945,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa80btCRA9TVsSAnZWagAAhQ4P/A4+DwDYOfgcue03Fsa3\nI+WBrBPQev1+huy0IUPiY64Dt26kQu5tUYckGCg8aEn2aA2hZf9EmnIdwrqD\n0h75PwmD4hkhE8GfRG4ehPff3vv86Gx2lLfk6HtYCGtUrrxWqY/XYgaYgJM+\nZmWzGheOqgXrphgOf8JgbWL6uBN7zT1eOLafvskMuKIGkfs4YWwNiLypy8Ue\nzYhxf+gimANQ84EhUzlQevDMXktqWuakH2aEbuDV2DaelnOFibO15xqoRl2P\ng0npC5v37NB1hxOvch8zBUtJ4NUfA2eR7VQx5bX0s6SCTTTFUBrh/qRdVDcy\nvLPlRO5koNgi4y2rwrQxqPG/duI1qvPSftRVzowmpS51hUwDSbbVxcZCwWp4\nNtj9lGC2qL3GIl+RtM6l4dHG0Rh34DUXEj74XjRODNP1ttew0/lk2bRFqMfO\nQrqAJnHj9WPa24ps91JssrA31bRQex6qvwWwR11rJ2IAZVIyu9lzPV503zM3\nPv7edFmyBQ5nwiI6gDiZGg5J2JM1E44DZPtTR+RWf0VBcmdoh8z22BtpoWTE\np8eKewHJn7h4UfbwA+YEzOi9NfJhk3FKLmTZF65ltKwyOtorPSoPmbHQSl/P\nNhmY/6TLMvn+XJx6Hc9oPSOWH8QPSkKltdVaSViDpAJqmZwxfa5sPC1Tar3l\nc8a8\r\n=kEog\r\n-----END PGP SIGNATURE-----\r\n"
},
"gitHead": "045bd8d634dca30192fbd23fee0c530adc9c6f52",
"homepage": "https://github.com/fb55/DomHandler#readme",
"jshintConfig": {
"quotmark": "double",
"trailing": true,
"unused": true,
"undef": true,
"node": true,
"proto": true,
"globals": {
"it": true
}
},
"keywords": [
"dom",
"htmlparser2"
],
"license": "BSD-2-Clause",
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domhandler",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/DomHandler.git"
},
"scripts": {
"test": "mocha -R list && jshint index.js test/"
},
"version": "2.4.2"
}

View File

@ -0,0 +1,116 @@
# domhandler [![Build Status](https://travis-ci.org/fb55/domhandler.svg?branch=master)](https://travis-ci.org/fb55/domhandler)
The DOM handler (formally known as DefaultHandler) creates a tree containing all nodes of a page. The tree may be manipulated using the [domutils](https://github.com/fb55/domutils) library.
## Usage
```javascript
var handler = new DomHandler([ <func> callback(err, dom), ] [ <obj> options ]);
// var parser = new Parser(handler[, options]);
```
Available options are described below.
## Example
```javascript
var htmlparser = require("htmlparser2");
var rawHtml = "Xyz <script language= javascript>var foo = '<<bar>>';< / script><!--<!-- Waah! -- -->";
var handler = new htmlparser.DomHandler(function (error, dom) {
if (error)
[...do something for errors...]
else
[...parsing done, do something...]
console.log(dom);
});
var parser = new htmlparser.Parser(handler);
parser.write(rawHtml);
parser.end();
```
Output:
```javascript
[{
data: 'Xyz ',
type: 'text'
}, {
type: 'script',
name: 'script',
attribs: {
language: 'javascript'
},
children: [{
data: 'var foo = \'<bar>\';<',
type: 'text'
}]
}, {
data: '<!-- Waah! -- ',
type: 'comment'
}]
```
## Option: normalizeWhitespace
Indicates whether the whitespace in text nodes should be normalized (= all whitespace should be replaced with single spaces). The default value is "false".
The following HTML will be used:
```html
<font>
<br>this is the text
<font>
```
### Example: true
```javascript
[{
type: 'tag',
name: 'font',
children: [{
data: ' ',
type: 'text'
}, {
type: 'tag',
name: 'br'
}, {
data: 'this is the text ',
type: 'text'
}, {
type: 'tag',
name: 'font'
}]
}]
```
### Example: false
```javascript
[{
type: 'tag',
name: 'font',
children: [{
data: '\n\t',
type: 'text'
}, {
type: 'tag',
name: 'br'
}, {
data: 'this is the text\n',
type: 'text'
}, {
type: 'tag',
name: 'font'
}]
}]
```
## Option: withDomLvl1
Adds DOM level 1 properties to all elements.
<!-- TODO: description -->
## Option: withStartIndices
Indicates whether a `startIndex` property will be added to nodes. When the parser is used in a non-streaming fashion, `startIndex` is an integer indicating the position of the start of the node in the document. The default value is "false".
## Option: withEndIndices
Indicates whether a `endIndex` property will be added to nodes. When the parser is used in a non-streaming fashion, `endIndex` is an integer indicating the position of the end of the node in the document. The default value is "false".

View File

@ -0,0 +1,57 @@
{
"name": "Basic test",
"options": {},
"html": "<!DOCTYPE html><html><title>The Title</title><body>Hello world</body></html>",
"expected": [
{
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "tag",
"name": "html",
"attribs": {},
"parent": null,
"children": [
{
"type": "tag",
"name": "title",
"attribs": {},
"parent": {
"type": "tag",
"name": "html",
"attribs": {}
},
"children": [
{
"data": "The Title",
"type": "text",
"parent": {
"type": "tag",
"name": "title",
"attribs": {}
}
}
]
},
{
"type": "tag",
"name": "body",
"attribs": {},
"children": [
{
"data": "Hello world",
"type": "text"
}
],
"prev": {
"type": "tag",
"name": "title",
"attribs": {}
}
}
]
}
]
}

View File

@ -0,0 +1,21 @@
{
"name": "Single Tag 1",
"options": {},
"html": "<br>text</br>",
"expected": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": "text",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
}
]
}

View File

@ -0,0 +1,21 @@
{
"name": "Single Tag 2",
"options": {},
"html": "<br>text<br>",
"expected": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": "text",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
}
]
}

View File

@ -0,0 +1,27 @@
{
"name": "Unescaped chars in script",
"options": {},
"html": "<head><script language=\"Javascript\">var foo = \"<bar>\"; alert(2 > foo); var baz = 10 << 2; var zip = 10 >> 1; var yap = \"<<>>>><<\";</script></head>",
"expected": [
{
"type": "tag",
"name": "head",
"attribs": {},
"children": [
{
"type": "script",
"name": "script",
"attribs": {
"language": "Javascript"
},
"children": [
{
"data": "var foo = \"<bar>\"; alert(2 > foo); var baz = 10 << 2; var zip = 10 >> 1; var yap = \"<<>>>><<\";",
"type": "text"
}
]
}
]
}
]
}

View File

@ -0,0 +1,18 @@
{
"name": "Special char in comment",
"options": {},
"html": "<head><!-- commented out tags <title>Test</title>--></head>",
"expected": [
{
"type": "tag",
"name": "head",
"attribs": {},
"children": [
{
"data": " commented out tags <title>Test</title>",
"type": "comment"
}
]
}
]
}

View File

@ -0,0 +1,18 @@
{
"name": "Script source in comment",
"options": {},
"html": "<script><!--var foo = 1;--></script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {},
"children": [
{
"data": "<!--var foo = 1;-->",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,20 @@
{
"name": "Unescaped chars in style",
"options": {},
"html": "<style type=\"text/css\">\n body > p\n\t{ font-weight: bold; }</style>",
"expected": [
{
"type": "style",
"name": "style",
"attribs": {
"type": "text/css"
},
"children": [
{
"data": "\n body > p\n\t{ font-weight: bold; }",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,20 @@
{
"name": "Extra spaces in tag",
"options": {},
"html": "<font\t\n size='14' \n>the text</\t\nfont\t \n>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,20 @@
{
"name": "Unquoted attributes",
"options": {},
"html": "<font size= 14>the text</font>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,15 @@
{
"name": "Singular attribute",
"options": {},
"html": "<option value='foo' selected>",
"expected": [
{
"type": "tag",
"name": "option",
"attribs": {
"value": "foo",
"selected": ""
}
}
]
}

View File

@ -0,0 +1,40 @@
{
"name": "Text outside tags",
"options": {},
"html": "Line one\n<br>\nline two",
"expected": [
{
"data": "Line one\n",
"type": "text",
"prev": null,
"next": {
"type": "tag",
"name": "br",
"attribs": {}
}
},
{
"type": "tag",
"name": "br",
"attribs": {},
"prev": {
"data": "Line one\n",
"type": "text"
},
"next": {
"data": "\nline two",
"type": "text"
}
},
{
"data": "\nline two",
"type": "text",
"prev": {
"type": "tag",
"name": "br",
"attribs": {}
},
"next": null
}
]
}

View File

@ -0,0 +1,11 @@
{
"name": "Only text",
"options": {},
"html": "this is the text",
"expected": [
{
"data": "this is the text",
"type": "text"
}
]
}

View File

@ -0,0 +1,19 @@
{
"name": "Comment within text",
"options": {},
"html": "this is <!-- the comment --> the text",
"expected": [
{
"data": "this is ",
"type": "text"
},
{
"data": " the comment ",
"type": "comment"
},
{
"data": " the text",
"type": "text"
}
]
}

View File

@ -0,0 +1,18 @@
{
"name": "Comment within text within script",
"options": {},
"html": "<script>this is <!-- the comment --> the text</script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {},
"children": [
{
"data": "this is <!-- the comment --> the text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,22 @@
{
"name": "Option 'verbose' set to 'false'",
"options": {
"verbose": false
},
"html": "<font\t\n size='14' \n>the text</\t\nfont\t \n>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,47 @@
{
"name": "Normalize whitespace",
"options": {
"normalizeWhitespace": true
},
"html": "Line one\n<br>\t \r\n\f <br>\nline two<font><br> x </font>",
"expected": [
{
"data": "Line one ",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " ",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " line two",
"type": "text"
},
{
"type": "tag",
"name": "font",
"attribs": {},
"children": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " x ",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,18 @@
{
"name": "XML Namespace",
"options": {},
"html": "<ns:tag>text</ns:tag>",
"expected": [
{
"type": "tag",
"name": "ns:tag",
"attribs": {},
"children": [
{
"data": "text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,16 @@
{
"name": "Enforce empty tags",
"options": {},
"html": "<link>text</link>",
"expected": [
{
"type": "tag",
"name": "link",
"attribs": {}
},
{
"data": "text",
"type": "text"
}
]
}

View File

@ -0,0 +1,20 @@
{
"name": "Ignore empty tags (xml mode)",
"options": {
"xmlMode": true
},
"html": "<link>text</link>",
"expected": [
{
"type": "tag",
"name": "link",
"attribs": {},
"children": [
{
"data": "text",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,20 @@
{
"name": "Template script tags",
"options": {},
"html": "<script type=\"text/template\"><h1>Heading1</h1></script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {
"type": "text/template"
},
"children": [
{
"data": "<h1>Heading1</h1>",
"type": "text"
}
]
}
]
}

View File

@ -0,0 +1,15 @@
{
"name": "Conditional comments",
"options": {},
"html": "<!--[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]--><!--[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]-->",
"expected": [
{
"data": "[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]",
"type": "comment"
},
{
"data": "[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]",
"type": "comment"
}
]
}

View File

@ -0,0 +1,41 @@
{
"name": "lowercase tags",
"options": {},
"html": "<!DOCTYPE html><HTML><TITLE>The Title</title><BODY>Hello world</body></html>",
"expected": [
{
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "tag",
"name": "html",
"attribs": {},
"children": [
{
"type": "tag",
"name": "title",
"attribs": {},
"children": [
{
"data": "The Title",
"type": "text"
}
]
},
{
"type": "tag",
"name": "body",
"attribs": {},
"children": [
{
"data": "Hello world",
"type": "text"
}
]
}
]
}
]
}

View File

@ -0,0 +1,131 @@
{
"name": "DOM level 1",
"options": { "withDomLvl1": true },
"html": "<div>some stray text<h1>Hello, world.</h1><!-- comment node -->more stray text</div>",
"expected": [
{
"type": "tag",
"nodeType": 1,
"name": "div",
"tagName": "div",
"attribs": {},
"nodeValue": null,
"children": [
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "some stray text",
"nodeValue": "some stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
{
"type": "tag",
"nodeType": 1,
"name": "h1",
"tagName": "h1",
"nodeValue": null,
"attribs": {},
"children": [
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
],
"firstChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
"lastChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
},
{
"type": "comment",
"nodeType": 8,
"tagName": null,
"data": " comment node ",
"nodeValue": " comment node ",
"childNodes": null,
"firstChild": null,
"lastChild": null,
"prev": {
"type": "tag",
"name": "h1",
"nodeValue": null,
"attribs": {}
},
"previousSibling": {
"type": "tag",
"name": "h1",
"nodeValue": null,
"attribs": {}
},
"next": {
"type": "text",
"tagName": null,
"data": "more stray text"
},
"nextSibling": {
"type": "text",
"tagName": null,
"data": "more stray text"
}
},
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "more stray text",
"nodeValue": "more stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null,
"next": null,
"nextSibling": null
}
],
"firstChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "some stray text",
"nodeValue": "some stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
"lastChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "more stray text",
"nodeValue": "more stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
}
]
}

View File

@ -0,0 +1,85 @@
{
"name": "withStartIndices adds correct startIndex properties",
"options": {"withStartIndices": true},
"streaming": false,
"html": "<!DOCTYPE html> <html> <title>The Title</title> <body class='foo'>Hello world <p></p></body> <!-- the comment --> </html> ",
"expected": [
{
"startIndex": 0,
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "text",
"data": " "
},
{
"startIndex": 16,
"type": "tag",
"name": "html",
"attribs": {},
"parent": null,
"children": [
{
"startIndex": 22,
"type": "text",
"data": " "
},
{
"startIndex": 23,
"type": "tag",
"name": "title",
"attribs": {},
"children": [
{
"startIndex": 30,
"data": "The Title",
"type": "text"
}
]
},
{
"startIndex": 47,
"type": "text",
"data": " "
},
{
"startIndex": 48,
"type": "tag",
"name": "body",
"attribs": {"class": "foo"},
"children": [
{
"startIndex": 66,
"data": "Hello world ",
"type": "text"
},
{
"startIndex": 78,
"type": "tag",
"name": "p",
"attribs": {},
"children": []
}
]
},
{
"startIndex": 92,
"type": "text",
"data": " "
},
{
"startIndex": 93,
"type": "comment",
"data": " the comment "
},
{
"startIndex": 113,
"type": "text",
"data": " "
}
]
}
]
}

View File

@ -0,0 +1,86 @@
{
"name": "withEndIndices adds correct endIndex properties",
"options": {"withStartIndices": true,"withEndIndices": true},
"streaming": false,
"html": "<!DOCTYPE html> <html> <title>The Title</title> <body class='foo'>Hello world <p></p></body> <!-- the comment --> </html> ",
"expected": [
{
"endIndex": null,
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "text",
"data": " ",
"endIndex": 15
},
{
"endIndex": 120,
"type": "tag",
"name": "html",
"attribs": {},
"parent": null,
"children": [
{
"endIndex": 22,
"type": "text",
"data": " "
},
{
"endIndex": 46,
"type": "tag",
"name": "title",
"attribs": {},
"children": [
{
"endIndex": 38,
"data": "The Title",
"type": "text"
}
]
},
{
"endIndex": 47,
"type": "text",
"data": " "
},
{
"endIndex": 91,
"type": "tag",
"name": "body",
"attribs": {"class": "foo"},
"children": [
{
"endIndex": 77,
"data": "Hello world ",
"type": "text"
},
{
"endIndex": 84,
"type": "tag",
"name": "p",
"attribs": {},
"children": []
}
]
},
{
"endIndex": 92,
"type": "text",
"data": " "
},
{
"endIndex": 112,
"type": "comment",
"data": " the comment "
},
{
"endIndex": 113,
"type": "text",
"data": " "
}
]
}
]
}

View File

@ -0,0 +1,60 @@
var fs = require("fs"),
path = require("path"),
assert = require("assert"),
util = require("util"),
Parser = require("htmlparser2").Parser,
Handler = require("../");
var basePath = path.resolve(__dirname, "cases"),
inspectOpts = { showHidden: true, depth: null };
fs
.readdirSync(basePath)
.filter(RegExp.prototype.test, /\.json$/) //only allow .json files
.map(function(name){
return path.resolve(basePath, name);
})
.map(require)
.forEach(function(test){
it(test.name, function(){
var expected = test.expected;
var handler = new Handler(function(err, actual){
assert.ifError(err);
try {
compare(expected, actual);
} catch(e){
e.expected = util.inspect(expected, inspectOpts);
e.actual = util.inspect(actual, inspectOpts);
throw e;
}
}, test.options);
var data = test.html;
var parser = new Parser(handler, test.options);
//first, try to run the test via chunks
if (test.streaming || test.streaming === undefined){
for(var i = 0; i < data.length; i++){
parser.write(data.charAt(i));
}
parser.done();
}
//then parse everything
parser.parseComplete(data);
});
});
function compare(expected, result){
assert.equal(typeof expected, typeof result, "types didn't match");
if(typeof expected !== "object" || expected === null){
assert.strictEqual(expected, result, "result doesn't equal expected");
} else {
for(var prop in expected){
assert.ok(prop in result, "result didn't contain property " + prop);
compare(expected[prop], result[prop]);
}
}
}

View File

@ -0,0 +1,5 @@
sudo: true
language: node_js
node_js:
- 8
script: npm run coveralls

View File

@ -0,0 +1,11 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,26 @@
var encode = require("./lib/encode.js"),
decode = require("./lib/decode.js");
exports.decode = function(data, level) {
return (!level || level <= 0 ? decode.XML : decode.HTML)(data);
};
exports.decodeStrict = function(data, level) {
return (!level || level <= 0 ? decode.XML : decode.HTMLStrict)(data);
};
exports.encode = function(data, level) {
return (!level || level <= 0 ? encode.XML : encode.HTML)(data);
};
exports.encodeXML = encode.XML;
exports.encodeHTML4 = exports.encodeHTML5 = exports.encodeHTML = encode.HTML;
exports.decodeXML = exports.decodeXMLStrict = decode.XML;
exports.decodeHTML4 = exports.decodeHTML5 = exports.decodeHTML = decode.HTML;
exports.decodeHTML4Strict = exports.decodeHTML5Strict = exports.decodeHTMLStrict = decode.HTMLStrict;
exports.escape = encode.escape;

View File

@ -0,0 +1,70 @@
var entityMap = require("../maps/entities.json"),
legacyMap = require("../maps/legacy.json"),
xmlMap = require("../maps/xml.json"),
decodeCodePoint = require("./decode_codepoint.js");
var decodeXMLStrict = getStrictDecoder(xmlMap),
decodeHTMLStrict = getStrictDecoder(entityMap);
function getStrictDecoder(map) {
var keys = Object.keys(map).join("|"),
replace = getReplacer(map);
keys += "|#[xX][\\da-fA-F]+|#\\d+";
var re = new RegExp("&(?:" + keys + ");", "g");
return function(str) {
return String(str).replace(re, replace);
};
}
var decodeHTML = (function() {
var legacy = Object.keys(legacyMap).sort(sorter);
var keys = Object.keys(entityMap).sort(sorter);
for (var i = 0, j = 0; i < keys.length; i++) {
if (legacy[j] === keys[i]) {
keys[i] += ";?";
j++;
} else {
keys[i] += ";";
}
}
var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"),
replace = getReplacer(entityMap);
function replacer(str) {
if (str.substr(-1) !== ";") str += ";";
return replace(str);
}
//TODO consider creating a merged map
return function(str) {
return String(str).replace(re, replacer);
};
})();
function sorter(a, b) {
return a < b ? 1 : -1;
}
function getReplacer(map) {
return function replace(str) {
if (str.charAt(1) === "#") {
if (str.charAt(2) === "X" || str.charAt(2) === "x") {
return decodeCodePoint(parseInt(str.substr(3), 16));
}
return decodeCodePoint(parseInt(str.substr(2), 10));
}
return map[str.slice(1, -1)];
};
}
module.exports = {
XML: decodeXMLStrict,
HTML: decodeHTML,
HTMLStrict: decodeHTMLStrict
};

View File

@ -0,0 +1,25 @@
var decodeMap = require("../maps/decode.json");
module.exports = decodeCodePoint;
// modified version of https://github.com/mathiasbynens/he/blob/master/src/he.js#L94-L119
function decodeCodePoint(codePoint) {
if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) {
return "\uFFFD";
}
if (codePoint in decodeMap) {
codePoint = decodeMap[codePoint];
}
var output = "";
if (codePoint > 0xffff) {
codePoint -= 0x10000;
output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800);
codePoint = 0xdc00 | (codePoint & 0x3ff);
}
output += String.fromCharCode(codePoint);
return output;
}

View File

@ -0,0 +1,82 @@
var inverseXML = getInverseObj(require("../maps/xml.json")),
xmlReplacer = getInverseReplacer(inverseXML);
exports.XML = getInverse(inverseXML, xmlReplacer);
var inverseHTML = getInverseObj(require("../maps/entities.json")),
htmlReplacer = getInverseReplacer(inverseHTML);
exports.HTML = getInverse(inverseHTML, htmlReplacer);
function getInverseObj(obj) {
return Object.keys(obj)
.sort()
.reduce(function(inverse, name) {
inverse[obj[name]] = "&" + name + ";";
return inverse;
}, {});
}
function getInverseReplacer(inverse) {
var single = [],
multiple = [];
Object.keys(inverse).forEach(function(k) {
if (k.length === 1) {
single.push("\\" + k);
} else {
multiple.push(k);
}
});
//TODO add ranges
multiple.unshift("[" + single.join("") + "]");
return new RegExp(multiple.join("|"), "g");
}
var re_nonASCII = /[^\0-\x7F]/g,
re_astralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
function singleCharReplacer(c) {
return (
"&#x" +
c
.charCodeAt(0)
.toString(16)
.toUpperCase() +
";"
);
}
function astralReplacer(c) {
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
var high = c.charCodeAt(0);
var low = c.charCodeAt(1);
var codePoint = (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;
return "&#x" + codePoint.toString(16).toUpperCase() + ";";
}
function getInverse(inverse, re) {
function func(name) {
return inverse[name];
}
return function(data) {
return data
.replace(re, func)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
};
}
var re_xmlChars = getInverseReplacer(inverseXML);
function escapeXML(data) {
return data
.replace(re_xmlChars, singleCharReplacer)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
}
exports.escape = escapeXML;

View File

@ -0,0 +1 @@
{"0":65533,"128":8364,"130":8218,"131":402,"132":8222,"133":8230,"134":8224,"135":8225,"136":710,"137":8240,"138":352,"139":8249,"140":338,"142":381,"145":8216,"146":8217,"147":8220,"148":8221,"149":8226,"150":8211,"151":8212,"152":732,"153":8482,"154":353,"155":8250,"156":339,"158":382,"159":376}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"Aacute":"\u00C1","aacute":"\u00E1","Acirc":"\u00C2","acirc":"\u00E2","acute":"\u00B4","AElig":"\u00C6","aelig":"\u00E6","Agrave":"\u00C0","agrave":"\u00E0","amp":"&","AMP":"&","Aring":"\u00C5","aring":"\u00E5","Atilde":"\u00C3","atilde":"\u00E3","Auml":"\u00C4","auml":"\u00E4","brvbar":"\u00A6","Ccedil":"\u00C7","ccedil":"\u00E7","cedil":"\u00B8","cent":"\u00A2","copy":"\u00A9","COPY":"\u00A9","curren":"\u00A4","deg":"\u00B0","divide":"\u00F7","Eacute":"\u00C9","eacute":"\u00E9","Ecirc":"\u00CA","ecirc":"\u00EA","Egrave":"\u00C8","egrave":"\u00E8","ETH":"\u00D0","eth":"\u00F0","Euml":"\u00CB","euml":"\u00EB","frac12":"\u00BD","frac14":"\u00BC","frac34":"\u00BE","gt":">","GT":">","Iacute":"\u00CD","iacute":"\u00ED","Icirc":"\u00CE","icirc":"\u00EE","iexcl":"\u00A1","Igrave":"\u00CC","igrave":"\u00EC","iquest":"\u00BF","Iuml":"\u00CF","iuml":"\u00EF","laquo":"\u00AB","lt":"<","LT":"<","macr":"\u00AF","micro":"\u00B5","middot":"\u00B7","nbsp":"\u00A0","not":"\u00AC","Ntilde":"\u00D1","ntilde":"\u00F1","Oacute":"\u00D3","oacute":"\u00F3","Ocirc":"\u00D4","ocirc":"\u00F4","Ograve":"\u00D2","ograve":"\u00F2","ordf":"\u00AA","ordm":"\u00BA","Oslash":"\u00D8","oslash":"\u00F8","Otilde":"\u00D5","otilde":"\u00F5","Ouml":"\u00D6","ouml":"\u00F6","para":"\u00B6","plusmn":"\u00B1","pound":"\u00A3","quot":"\"","QUOT":"\"","raquo":"\u00BB","reg":"\u00AE","REG":"\u00AE","sect":"\u00A7","shy":"\u00AD","sup1":"\u00B9","sup2":"\u00B2","sup3":"\u00B3","szlig":"\u00DF","THORN":"\u00DE","thorn":"\u00FE","times":"\u00D7","Uacute":"\u00DA","uacute":"\u00FA","Ucirc":"\u00DB","ucirc":"\u00FB","Ugrave":"\u00D9","ugrave":"\u00F9","uml":"\u00A8","Uuml":"\u00DC","uuml":"\u00FC","Yacute":"\u00DD","yacute":"\u00FD","yen":"\u00A5","yuml":"\u00FF"}

View File

@ -0,0 +1 @@
{"amp":"&","apos":"'","gt":">","lt":"<","quot":"\""}

View File

@ -0,0 +1,129 @@
{
"_args": [
[
{
"raw": "entities@^1.1.1",
"scope": null,
"escapedName": "entities",
"name": "entities",
"rawSpec": "^1.1.1",
"spec": ">=1.1.1 <2.0.0",
"type": "range"
},
"/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2"
]
],
"_from": "entities@>=1.1.1 <2.0.0",
"_hasShrinkwrap": false,
"_id": "entities@1.1.2",
"_inCache": true,
"_location": "/entities",
"_nodeVersion": "10.11.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/entities_1.1.2_1540160822569_0.14727328761963432"
},
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "6.4.1",
"_phantomChildren": {},
"_requested": {
"raw": "entities@^1.1.1",
"scope": null,
"escapedName": "entities",
"name": "entities",
"rawSpec": "^1.1.1",
"spec": ">=1.1.1 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/mini-html-parser2"
],
"_resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"_shasum": "bdfa735299664dfafd34529ed4f8522a275fea56",
"_shrinkwrap": null,
"_spec": "entities@^1.1.1",
"_where": "/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/entities/issues"
},
"dependencies": {},
"description": "Encode & decode XML/HTML entities with ease",
"devDependencies": {
"coveralls": "*",
"istanbul": "*",
"jshint": "2",
"mocha": "^5.0.1",
"mocha-lcov-reporter": "*"
},
"directories": {
"test": "test"
},
"dist": {
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"shasum": "bdfa735299664dfafd34529ed4f8522a275fea56",
"tarball": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"fileCount": 14,
"unpackedSize": 57359,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbzP03CRA9TVsSAnZWagAAJBQP+wca0lyuDaPXh22c1FZ1\nCMsY1wnU6lg71osycf2M4dpV/Q4Mmd8n4kvAdsOG12EK0UrSfaJnC2xRiTcP\niC+rp9XO+AP3e+8V8EbnJhJHkeHEJBs9JMi5nOCehKNH1EUM/ZmCZ+WIDfii\nUVQ8WIoBmuvEdLydKqO9yQdv5KjZsfZyC0mi3MtcDPfJ2zTngfJ5OgaAkKzM\nJnjGjUvGbBBwwEm3eP7aJNGWMFRzVjOiFN6o5BcIbFBZ0dSIjZ9Fwlbj95yl\nWpCJoS/ayzfp+TJGySWkbFhGzXtrvn0vlky/7rfh7b4fZ5fcogdsWoIqtwO2\nJgcub34OdC+atMAX0bwkixV8qbtFfKB6wyWiE04xvBeop/RR9k8xgvUR/T+h\n/8w1PnuuFZLrqec6rkt+NqaYA4GBOl3FhzHy9vyW9Hjvsa3ZnfAxxaLm8xcH\nbCTtHprwhI/nYq6HEPqXd6XgRJ5v9s7uzasSX8PncV6H3TLF4dBfiWc9pt/e\n1T+L5BV+kYBImbefy0OjnmcryFZk2YqbBkyglC27J6DeGkZjq4vYQ8rqS2ee\nm69Q21fYmP+LkF5K0cdCo4hEFZw2smOMFjmP5JpOSZmKWfjJjrmRYTxQDSSx\nh2ptVmuE7BFC8/05KQ4miVVBTmHOUieC0nKvVNCQhs9USShr5ighrrrlCDZj\n6yp8\r\n=2vNQ\r\n-----END PGP SIGNATURE-----\r\n"
},
"gitHead": "54a5717d85d886c4aafa2ac5ff83d8d3d730337c",
"homepage": "https://github.com/fb55/entities#readme",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"keywords": [
"html",
"xml",
"entity",
"decoding",
"encoding"
],
"license": "BSD-2-Clause",
"main": "./index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "entities",
"optionalDependencies": {},
"prettier": {
"tabWidth": 4
},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/entities.git"
},
"scripts": {
"coveralls": "npm run lint && npm run lcov && (cat coverage/lcov.info | coveralls || exit 0)",
"lcov": "istanbul cover _mocha --report lcovonly -- -R spec",
"lint": "jshint index.js lib/*.js test/*.js",
"test": "mocha && npm run lint"
},
"version": "1.1.2"
}

View File

@ -0,0 +1,27 @@
# entities [![NPM version](http://img.shields.io/npm/v/entities.svg)](https://npmjs.org/package/entities) [![Downloads](https://img.shields.io/npm/dm/entities.svg)](https://npmjs.org/package/entities) [![Build Status](http://img.shields.io/travis/fb55/entities.svg)](http://travis-ci.org/fb55/entities) [![Coverage](http://img.shields.io/coveralls/fb55/entities.svg)](https://coveralls.io/r/fb55/entities)
En- & decoder for XML/HTML entities.
## How to…
### …install `entities`
npm i entities
### …use `entities`
```javascript
var entities = require("entities");
//encoding
entities.encodeXML("&#38;"); // "&amp;#38;"
entities.encodeHTML("&#38;"); // "&amp;&num;38&semi;"
//decoding
entities.decodeXML("asdf &amp; &#xFF; &#xFC; &apos;"); // "asdf & ÿ ü '"
entities.decodeHTML("asdf &amp; &yuml; &uuml; &apos;"); // "asdf & ÿ ü '"
```
<!-- TODO extend API -->
---
License: BSD-2-Clause

View File

@ -0,0 +1,2 @@
--check-leaks
--reporter spec

View File

@ -0,0 +1,170 @@
var assert = require("assert"),
path = require("path"),
entities = require("../");
describe("Encode->decode test", function() {
var testcases = [
{
input: "asdf & ÿ ü '",
xml: "asdf &amp; &#xFF; &#xFC; &apos;",
html: "asdf &amp; &yuml; &uuml; &apos;"
},
{
input: "&#38;",
xml: "&amp;#38;",
html: "&amp;&num;38&semi;"
}
];
testcases.forEach(function(tc) {
var encodedXML = entities.encodeXML(tc.input);
it("should XML encode " + tc.input, function() {
assert.equal(encodedXML, tc.xml);
});
it("should default to XML encode " + tc.input, function() {
assert.equal(entities.encode(tc.input), tc.xml);
});
it("should XML decode " + encodedXML, function() {
assert.equal(entities.decodeXML(encodedXML), tc.input);
});
it("should default to XML encode " + encodedXML, function() {
assert.equal(entities.decode(encodedXML), tc.input);
});
it("should default strict to XML encode " + encodedXML, function() {
assert.equal(entities.decodeStrict(encodedXML), tc.input);
});
var encodedHTML5 = entities.encodeHTML5(tc.input);
it("should HTML5 encode " + tc.input, function() {
assert.equal(encodedHTML5, tc.html);
});
it("should HTML5 decode " + encodedHTML5, function() {
assert.equal(entities.decodeHTML(encodedHTML5), tc.input);
});
});
it("should encode data URIs (issue 16)", function() {
var data = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAALAAABAAEAAAIBRAA7";
assert.equal(entities.decode(entities.encode(data)), data);
});
});
describe("Decode test", function() {
var testcases = [
{ input: "&amp;amp;", output: "&amp;" },
{ input: "&amp;#38;", output: "&#38;" },
{ input: "&amp;#x26;", output: "&#x26;" },
{ input: "&amp;#X26;", output: "&#X26;" },
{ input: "&#38;#38;", output: "&#38;" },
{ input: "&#x26;#38;", output: "&#38;" },
{ input: "&#X26;#38;", output: "&#38;" },
{ input: "&#x3a;", output: ":" },
{ input: "&#x3A;", output: ":" },
{ input: "&#X3a;", output: ":" },
{ input: "&#X3A;", output: ":" }
];
testcases.forEach(function(tc) {
it("should XML decode " + tc.input, function() {
assert.equal(entities.decodeXML(tc.input), tc.output);
});
it("should HTML4 decode " + tc.input, function() {
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
it("should HTML5 decode " + tc.input, function() {
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
});
});
var levels = ["xml", "entities"];
describe("Documents", function() {
levels
.map(function(n) {
return path.join("..", "maps", n);
})
.map(require)
.forEach(function(doc, i) {
describe("Decode", function() {
it(levels[i], function() {
Object.keys(doc).forEach(function(e) {
for (var l = i; l < levels.length; l++) {
assert.equal(entities.decode("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Decode strict", function() {
it(levels[i], function() {
Object.keys(doc).forEach(function(e) {
for (var l = i; l < levels.length; l++) {
assert.equal(entities.decodeStrict("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Encode", function() {
it(levels[i], function() {
Object.keys(doc).forEach(function(e) {
for (var l = i; l < levels.length; l++) {
assert.equal(entities.decode(entities.encode(doc[e], l), l), doc[e]);
}
});
});
});
});
var legacy = require("../maps/legacy.json");
describe("Legacy", function() {
it("should decode", runLegacy);
});
function runLegacy() {
Object.keys(legacy).forEach(function(e) {
assert.equal(entities.decodeHTML("&" + e), legacy[e]);
});
}
});
var astral = {
"1D306": "\uD834\uDF06",
"1D11E": "\uD834\uDD1E"
};
var astralSpecial = {
"80": "\u20AC",
"110000": "\uFFFD"
};
describe("Astral entities", function() {
Object.keys(astral).forEach(function(c) {
it("should decode " + astral[c], function() {
assert.equal(entities.decode("&#x" + c + ";"), astral[c]);
});
it("should encode " + astral[c], function() {
assert.equal(entities.encode(astral[c]), "&#x" + c + ";");
});
it("should escape " + astral[c], function() {
assert.equal(entities.escape(astral[c]), "&#x" + c + ";");
});
});
Object.keys(astralSpecial).forEach(function(c) {
it("special should decode \\u" + c, function() {
assert.equal(entities.decode("&#x" + c + ";"), astralSpecial[c]);
});
});
});
describe("Escape", function() {
it("should always decode ASCII chars", function() {
for (var i = 0; i < 0x7f; i++) {
var c = String.fromCharCode(i);
assert.equal(entities.decodeXML(entities.escape(c)), c);
}
});
});

View File

@ -0,0 +1,15 @@
sauce_connect: true
loopback: airtap.local
browsers:
- name: chrome
version: latest
- name: firefox
version: latest
- name: safari
version: 9..latest
# - name: iphone
# version: latest
- name: ie
version: 9..latest
- name: microsoftedge
version: 13..latest

View File

@ -0,0 +1,16 @@
sudo: false
language: node_js
node_js:
- stable
- '0.12'
script:
- npm test
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_NODE_VERSION}" = "stable" ]; then npm run test:browsers; fi
addons:
sauce_connect: true
hosts:
- airtap.local
env:
global:
- secure: XcBiD8yReflut9q7leKsigDZ0mI3qTKH+QrNVY8DaqlomJOZw8aOrVuX9Jz12l86ZJ41nbxmKnRNkFzcVr9mbP9YaeTb3DpeOBWmvaoSfud9Wnc16VfXtc1FCcwDhSVcSiM3UtnrmFU5cH+Dw1LPh5PbfylYOS/nJxUvG0FFLqI=
- secure: jNWtEbqhUdQ0xXDHvCYfUbKYeJCi6a7B4LsrcxYCyWWn4NIgncE5x2YbB+FSUUFVYfz0dsn5RKP1oHB99f0laUEo18HBNkrAS/rtyOdVzcpJjbQ6kgSILGjnJD/Ty1B57Rcz3iyev5Y7bLZ6Y1FbDnk/i9/l0faOGz8vTC3Vdkc=

View File

@ -0,0 +1,70 @@
# 3.0.0 (2018-05-25)
**This version drops support for IE8.** `events` no longer includes polyfills
for ES5 features. If you need to support older environments, use an ES5 shim
like [es5-shim](https://npmjs.com/package/es5-shim). Both the shim and sham
versions of es5-shim are necessary.
- Update to events code from Node.js 10.x
- (semver major) Adds `off()` method
- Port more tests from Node.js
- Switch browser tests to airtap, making things more reliable
# 2.1.0 (2018-05-25)
- add Emitter#rawListeners from Node.js v9.4
# 2.0.0 (2018-02-02)
- Update to events code from node.js 8.x
- Adds `prependListener()` and `prependOnceListener()`
- Adds `eventNames()` method
- (semver major) Unwrap `once()` listeners in `listeners()`
- copy tests from node.js
Note that this version doubles the gzipped size, jumping from 1.1KB to 2.1KB,
due to new methods and runtime performance improvements. Be aware of that when
upgrading.
# 1.1.1 (2016-06-22)
- add more context to errors if they are not instanceof Error
# 1.1.0 (2015-09-29)
- add Emitter#listerCount (to match node v4 api)
# 1.0.2 (2014-08-28)
- remove un-reachable code
- update devDeps
## 1.0.1 / 2014-05-11
- check for console.trace before using it
## 1.0.0 / 2013-12-10
- Update to latest events code from node.js 0.10
- copy tests from node.js
## 0.4.0 / 2011-07-03 ##
- Switching to graphquire@0.8.0
## 0.3.0 / 2011-07-03 ##
- Switching to URL based module require.
## 0.2.0 / 2011-06-10 ##
- Simplified package structure.
- Graphquire for dependency management.
## 0.1.1 / 2011-05-16 ##
- Unhandled errors are logged via console.error
## 0.1.0 / 2011-04-22 ##
- Initial release

22
sourcecode/alipay/default/node_modules/events/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT
Copyright Joyent, Inc. and other Node contributors.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,48 @@
# events [![Build Status](https://travis-ci.org/Gozala/events.png?branch=master)](https://travis-ci.org/Gozala/events)
> Node's event emitter for all engines.
This implements the Node.js [`events`](http://nodejs.org/api/events.html) module for environments that do not have it, like browsers.
> `events` currently matches the **Node.js 10.1** API.
Note that the `events` module uses ES5 features. If you need to support very old browsers like IE8, use a shim like [`es5-shim`](https://www.npmjs.com/package/es5-shim). You need both the shim and the sham versions of `es5-shim`.
This module is maintained, but only by very few people. If you'd like to help, let us know in the [Maintainer Needed](https://github.com/Gozala/events/issues/43) issue!
## Install
You usually do not have to install `events` yourself! If your code runs in Node.js, `events` is built in. If your code runs in the browser, bundlers like [browserify](https://github.com/browserify/browserify) or [webpack](https://github.com/webpack/webpack) also include the `events` module.
But if none of those apply, with npm do:
```
npm install events
```
## Usage
```javascript
var EventEmitter = require('events')
var ee = new EventEmitter()
ee.on('message', function (text) {
console.log(text)
})
ee.emit('message', 'hello world')
```
## API
See the [Node.js EventEmitter docs](http://nodejs.org/api/events.html). `events` currently matches the Node.js 10.1 API.
## Contributing
PRs are very welcome! The main way to contribute to `events` is by porting features, bugfixes and tests from Node.js. Ideally, code contributions to this module are copy-pasted from Node.js and transpiled to ES5, rather than reimplemented from scratch. Matching the Node.js code as closely as possible makes maintenance simpler when new changes land in Node.js.
This module intends to provide exactly the same API as Node.js, so features that are not available in the core `events` module will not be accepted. Feature requests should instead be directed at [nodejs/node](https://github.com/nodejs/node) and will be added to this module once they are implemented in Node.js.
If there is a difference in behaviour between Node.js's `events` module and this module, please open an issue!
## License
[MIT](./LICENSE)

448
sourcecode/alipay/default/node_modules/events/events.js generated vendored Normal file
View File

@ -0,0 +1,448 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
var R = typeof Reflect === 'object' ? Reflect : null
var ReflectApply = R && typeof R.apply === 'function'
? R.apply
: function ReflectApply(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
}
var ReflectOwnKeys
if (R && typeof R.ownKeys === 'function') {
ReflectOwnKeys = R.ownKeys
} else if (Object.getOwnPropertySymbols) {
ReflectOwnKeys = function ReflectOwnKeys(target) {
return Object.getOwnPropertyNames(target)
.concat(Object.getOwnPropertySymbols(target));
};
} else {
ReflectOwnKeys = function ReflectOwnKeys(target) {
return Object.getOwnPropertyNames(target);
};
}
function ProcessEmitWarning(warning) {
if (console && console.warn) console.warn(warning);
}
var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
return value !== value;
}
function EventEmitter() {
EventEmitter.init.call(this);
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
var defaultMaxListeners = 10;
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
enumerable: true,
get: function() {
return defaultMaxListeners;
},
set: function(arg) {
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
}
defaultMaxListeners = arg;
}
});
EventEmitter.init = function() {
if (this._events === undefined ||
this._events === Object.getPrototypeOf(this)._events) {
this._events = Object.create(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
}
this._maxListeners = n;
return this;
};
function $getMaxListeners(that) {
if (that._maxListeners === undefined)
return EventEmitter.defaultMaxListeners;
return that._maxListeners;
}
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return $getMaxListeners(this);
};
EventEmitter.prototype.emit = function emit(type) {
var args = [];
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
var doError = (type === 'error');
var events = this._events;
if (events !== undefined)
doError = (doError && events.error === undefined);
else if (!doError)
return false;
// If there is no 'error' event listener then throw.
if (doError) {
var er;
if (args.length > 0)
er = args[0];
if (er instanceof Error) {
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
// At least give some kind of context to the user
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
err.context = er;
throw err; // Unhandled 'error' event
}
var handler = events[type];
if (handler === undefined)
return false;
if (typeof handler === 'function') {
ReflectApply(handler, this, args);
} else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
ReflectApply(listeners[i], this, args);
}
return true;
};
function _addListener(target, type, listener, prepend) {
var m;
var events;
var existing;
if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
}
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit('newListener', type,
listener.listener ? listener.listener : listener);
// Re-assign `events` because a newListener handler could have caused the
// this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
if (existing === undefined) {
// Optimize the case of one listener. Don't need the extra array object.
existing = events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
existing = events[type] =
prepend ? [listener, existing] : [existing, listener];
// If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
// Check for listener leak
m = $getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
existing.warned = true;
// No error code for this since it is a Warning
// eslint-disable-next-line no-restricted-syntax
var w = new Error('Possible EventEmitter memory leak detected. ' +
existing.length + ' ' + String(type) + ' listeners ' +
'added. Use emitter.setMaxListeners() to ' +
'increase limit');
w.name = 'MaxListenersExceededWarning';
w.emitter = target;
w.type = type;
w.count = existing.length;
ProcessEmitWarning(w);
}
}
return target;
}
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.prependListener =
function prependListener(type, listener) {
return _addListener(this, type, listener, true);
};
function onceWrapper() {
var args = [];
for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
ReflectApply(this.listener, this.target, args);
}
}
function _onceWrap(target, type, listener) {
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
var wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
EventEmitter.prototype.once = function once(type, listener) {
if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
}
this.on(type, _onceWrap(this, type, listener));
return this;
};
EventEmitter.prototype.prependOnceListener =
function prependOnceListener(type, listener) {
if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
}
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
// Emits a 'removeListener' event if and only if the listener was removed.
EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
var list, events, position, i, originalListener;
if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
}
events = this._events;
if (events === undefined)
return this;
list = events[type];
if (list === undefined)
return this;
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = Object.create(null);
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
position = -1;
for (i = list.length - 1; i >= 0; i--) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0)
return this;
if (position === 0)
list.shift();
else {
spliceOne(list, position);
}
if (list.length === 1)
events[type] = list[0];
if (events.removeListener !== undefined)
this.emit('removeListener', type, originalListener || listener);
}
return this;
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.removeAllListeners =
function removeAllListeners(type) {
var listeners, events, i;
events = this._events;
if (events === undefined)
return this;
// not listening for removeListener, no need to emit
if (events.removeListener === undefined) {
if (arguments.length === 0) {
this._events = Object.create(null);
this._eventsCount = 0;
} else if (events[type] !== undefined) {
if (--this._eventsCount === 0)
this._events = Object.create(null);
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
var key;
for (i = 0; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = Object.create(null);
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners !== undefined) {
// LIFO order
for (i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
}
}
return this;
};
function _listeners(target, type, unwrap) {
var events = target._events;
if (events === undefined)
return [];
var evlistener = events[type];
if (evlistener === undefined)
return [];
if (typeof evlistener === 'function')
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
return unwrap ?
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
}
EventEmitter.prototype.listeners = function listeners(type) {
return _listeners(this, type, true);
};
EventEmitter.prototype.rawListeners = function rawListeners(type) {
return _listeners(this, type, false);
};
EventEmitter.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) {
var events = this._events;
if (events !== undefined) {
var evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener !== undefined) {
return evlistener.length;
}
}
return 0;
}
EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
}
function spliceOne(list, index) {
for (; index + 1 < list.length; index++)
list[index] = list[index + 1];
list.pop();
}
function unwrapListeners(arr) {
var ret = new Array(arr.length);
for (var i = 0; i < ret.length; ++i) {
ret[i] = arr[i].listener || arr[i];
}
return ret;
}

View File

@ -0,0 +1,114 @@
{
"_args": [
[
{
"raw": "events@^3.0.0",
"scope": null,
"escapedName": "events",
"name": "events",
"rawSpec": "^3.0.0",
"spec": ">=3.0.0 <4.0.0",
"type": "range"
},
"/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2"
]
],
"_from": "events@>=3.0.0 <4.0.0",
"_hasShrinkwrap": false,
"_id": "events@3.0.0",
"_inCache": true,
"_location": "/events",
"_nodeVersion": "10.2.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/events_3.0.0_1527242698947_0.5854518946832163"
},
"_npmUser": {
"name": "goto-bus-stop",
"email": "rene@kooi.me"
},
"_npmVersion": "6.0.1",
"_phantomChildren": {},
"_requested": {
"raw": "events@^3.0.0",
"scope": null,
"escapedName": "events",
"name": "events",
"rawSpec": "^3.0.0",
"spec": ">=3.0.0 <4.0.0",
"type": "range"
},
"_requiredBy": [
"/mini-html-parser2"
],
"_resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"_shasum": "9a0a0dfaf62893d92b875b8f2698ca4114973e88",
"_shrinkwrap": null,
"_spec": "events@^3.0.0",
"_where": "/data/www/project/shopxo/public/appmini/old/alipay/node_modules/mini-html-parser2",
"author": {
"name": "Irakli Gozalishvili",
"email": "rfobic@gmail.com",
"url": "http://jeditoolkit.com"
},
"bugs": {
"url": "http://github.com/Gozala/events/issues/"
},
"dependencies": {},
"description": "Node's event emitter for all engines.",
"devDependencies": {
"airtap": "0.0.6",
"isarray": "^2.0.2",
"tape": "^4.8.0"
},
"directories": {},
"dist": {
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==",
"shasum": "9a0a0dfaf62893d92b875b8f2698ca4114973e88",
"tarball": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
"fileCount": 29,
"unpackedSize": 71954,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbB9/MCRA9TVsSAnZWagAAMs8QAIT9CjOlShawwVkYExL4\n+ywcO87Ldn5FbS6Ysy8rN5jsbLc5zS3mC7euO0ewjUM0tvrYgEIN30a5520v\nveZyPwiYsKlWf2efxS6/+YuSqXKwnOUANeFJQf/DuKxDwaaqm+WEW6GP+aRS\nmizxq+ucQWWXxhLpvQDvqX+11HoHFXtzXJkG0NNggrqXFq9DY37xQaAwT/uN\nsZZqlJ/m8MZlBwcO9IT9an0lRGeUIHxRFjiRNclp2HSQE8+dsXjpkmWmWqAu\nUuCaej0QpADxibyjdwI9qw7Izoce9Vfrt3QfoVdUIo5Xs1aQ0wUX4zOQAjgZ\noMi3uOtdzJ5gEBW68y2Uan4EX4GTQa0b5GslU536/is/Oq67fq6rxllCEopq\nG94lf01njnK1C5wFWdNDR7pkogPLceqyHQlcNvQDQsH9WDXhAaxVjZ2ztZKV\n80xMvXWYNZdmuWj/hb354LpWbVAmbO795lok1NdcAbcYcfcR1cHjmoECII0G\nsXev7ZcTlGxrjjFxb0jF/Oe/boVAmEho5Suy992tBA1zHGIOgiHZqU8f2ete\nGIZi3p2+K6wG1n/vyKkrQW55VvkCaORk95O2YXSCQDUb+vT+s4ldDMvnK6dZ\nfZ1QJQ/OpNJ7ha2nCbyJ+wphvSbetT1b0rljIIijQp+q/0+sO/CHg8vI8kD8\nA1EP\r\n=hbXi\r\n-----END PGP SIGNATURE-----\r\n"
},
"engines": {
"node": ">=0.8.x"
},
"gitHead": "d0e217c21fbd5f26bbf0fe9982380e786759f817",
"homepage": "https://github.com/Gozala/events#readme",
"id": "events",
"keywords": [
"events",
"eventEmitter",
"eventDispatcher",
"listeners"
],
"license": "MIT",
"main": "./events.js",
"maintainers": [
{
"name": "defunctzombie",
"email": "shtylman@gmail.com"
},
{
"name": "goto-bus-stop",
"email": "rene@kooi.me"
},
{
"name": "gozala",
"email": "rfobic@gmail.com"
}
],
"name": "events",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/Gozala/events.git",
"web": "https://github.com/Gozala/events"
},
"scripts": {
"test": "node tests/index.js",
"test:browsers": "airtap -- tests/index.js"
},
"version": "3.0.0"
}

View File

@ -0,0 +1,111 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var EventEmitter = require('../');
{
var ee = new EventEmitter();
var events_new_listener_emitted = [];
var listeners_new_listener_emitted = [];
// Sanity check
assert.strictEqual(ee.addListener, ee.on);
ee.on('newListener', function(event, listener) {
// Don't track newListener listeners.
if (event === 'newListener')
return;
events_new_listener_emitted.push(event);
listeners_new_listener_emitted.push(listener);
});
var hello = common.mustCall(function(a, b) {
assert.strictEqual('a', a);
assert.strictEqual('b', b);
});
ee.once('newListener', function(name, listener) {
assert.strictEqual(name, 'hello');
assert.strictEqual(listener, hello);
var listeners = this.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
});
ee.on('hello', hello);
ee.once('foo', assert.fail);
assert.ok(Array.isArray(events_new_listener_emitted));
assert.strictEqual(events_new_listener_emitted.length, 2);
assert.strictEqual(events_new_listener_emitted[0], 'hello');
assert.strictEqual(events_new_listener_emitted[1], 'foo');
assert.ok(Array.isArray(listeners_new_listener_emitted));
assert.strictEqual(listeners_new_listener_emitted.length, 2);
assert.strictEqual(listeners_new_listener_emitted[0], hello);
assert.strictEqual(listeners_new_listener_emitted[1], assert.fail);
ee.emit('hello', 'a', 'b');
}
// just make sure that this doesn't throw:
{
var f = new EventEmitter();
f.setMaxListeners(0);
}
{
var listen1 = function() {};
var listen2 = function() {};
var ee = new EventEmitter();
ee.once('newListener', function() {
var listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
ee.once('newListener', function() {
var listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
});
ee.on('hello', listen2);
});
ee.on('hello', listen1);
// The order of listeners on an event is not always the order in which the
// listeners were added.
var listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 2);
assert.strictEqual(listeners[0], listen2);
assert.strictEqual(listeners[1], listen1);
}
// Verify that the listener must be a function
assert.throws(function() {
var ee = new EventEmitter();
ee.on('foo', null);
}, /^TypeError: The "listener" argument must be of type Function. Received type object$/);

View File

@ -0,0 +1,101 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var events = require('../');
// Redirect warning output to tape.
var consoleWarn = console.warn;
console.warn = common.test.comment;
common.test.on('end', function () {
console.warn = consoleWarn;
});
// default
{
var e = new events.EventEmitter();
for (var i = 0; i < 10; i++) {
e.on('default', common.mustNotCall());
}
assert.ok(!e._events['default'].hasOwnProperty('warned'));
e.on('default', common.mustNotCall());
assert.ok(e._events['default'].warned);
// specific
e.setMaxListeners(5);
for (var i = 0; i < 5; i++) {
e.on('specific', common.mustNotCall());
}
assert.ok(!e._events['specific'].hasOwnProperty('warned'));
e.on('specific', common.mustNotCall());
assert.ok(e._events['specific'].warned);
// only one
e.setMaxListeners(1);
e.on('only one', common.mustNotCall());
assert.ok(!e._events['only one'].hasOwnProperty('warned'));
e.on('only one', common.mustNotCall());
assert.ok(e._events['only one'].hasOwnProperty('warned'));
// unlimited
e.setMaxListeners(0);
for (var i = 0; i < 1000; i++) {
e.on('unlimited', common.mustNotCall());
}
assert.ok(!e._events['unlimited'].hasOwnProperty('warned'));
}
// process-wide
{
events.EventEmitter.defaultMaxListeners = 42;
var e = new events.EventEmitter();
for (var i = 0; i < 42; ++i) {
e.on('fortytwo', common.mustNotCall());
}
assert.ok(!e._events['fortytwo'].hasOwnProperty('warned'));
e.on('fortytwo', common.mustNotCall());
assert.ok(e._events['fortytwo'].hasOwnProperty('warned'));
delete e._events['fortytwo'].warned;
events.EventEmitter.defaultMaxListeners = 44;
e.on('fortytwo', common.mustNotCall());
assert.ok(!e._events['fortytwo'].hasOwnProperty('warned'));
e.on('fortytwo', common.mustNotCall());
assert.ok(e._events['fortytwo'].hasOwnProperty('warned'));
}
// but _maxListeners still has precedence over defaultMaxListeners
{
events.EventEmitter.defaultMaxListeners = 42;
var e = new events.EventEmitter();
e.setMaxListeners(1);
e.on('uno', common.mustNotCall());
assert.ok(!e._events['uno'].hasOwnProperty('warned'));
e.on('uno', common.mustNotCall());
assert.ok(e._events['uno'].hasOwnProperty('warned'));
// chainable
assert.strictEqual(e, e.setMaxListeners(1));
}

View File

@ -0,0 +1,104 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var test = require('tape');
var assert = require('assert');
var noop = function() {};
var mustCallChecks = [];
function runCallChecks(exitCode) {
if (exitCode !== 0) return;
var failed = filter(mustCallChecks, function(context) {
if ('minimum' in context) {
context.messageSegment = 'at least ' + context.minimum;
return context.actual < context.minimum;
} else {
context.messageSegment = 'exactly ' + context.exact;
return context.actual !== context.exact;
}
});
for (var i = 0; i < failed.length; i++) {
var context = failed[i];
console.log('Mismatched %s function calls. Expected %s, actual %d.',
context.name,
context.messageSegment,
context.actual);
// IE8 has no .stack
if (context.stack) console.log(context.stack.split('\n').slice(2).join('\n'));
}
assert.strictEqual(failed.length, 0);
}
exports.mustCall = function(fn, exact) {
return _mustCallInner(fn, exact, 'exact');
};
function _mustCallInner(fn, criteria, field) {
if (typeof criteria == 'undefined') criteria = 1;
if (typeof fn === 'number') {
criteria = fn;
fn = noop;
} else if (fn === undefined) {
fn = noop;
}
if (typeof criteria !== 'number')
throw new TypeError('Invalid ' + field + ' value: ' + criteria);
var context = {
actual: 0,
stack: (new Error()).stack,
name: fn.name || '<anonymous>'
};
context[field] = criteria;
// add the exit listener only once to avoid listener leak warnings
if (mustCallChecks.length === 0) test.onFinish(function() { runCallChecks(0); });
mustCallChecks.push(context);
return function() {
context.actual++;
return fn.apply(this, arguments);
};
}
exports.mustNotCall = function(msg) {
return function mustNotCall() {
assert.fail(msg || 'function should not have been called');
};
};
function filter(arr, fn) {
if (arr.filter) return arr.filter(fn);
var filtered = [];
for (var i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) filtered.push(arr[i]);
}
return filtered
}

View File

@ -0,0 +1,13 @@
'use strict';
var assert = require('assert');
var EventEmitter = require('../');
var EE = new EventEmitter();
assert.throws(function () {
EE.emit('error', 'Accepts a string');
}, 'Error: Unhandled error. (Accepts a string)');
assert.throws(function () {
EE.emit('error', { message: 'Error!' });
}, 'Unhandled error. ([object Object])');

View File

@ -0,0 +1,28 @@
'use strict';
var EventEmitter = require('../');
var assert = require('assert');
var EE = new EventEmitter();
var m = function() {};
EE.on('foo', function() {});
assert.equal(1, EE.eventNames().length);
assert.equal('foo', EE.eventNames()[0]);
EE.on('bar', m);
assert.equal(2, EE.eventNames().length);
assert.equal('foo', EE.eventNames()[0]);
assert.equal('bar', EE.eventNames()[1]);
EE.removeListener('bar', m);
assert.equal(1, EE.eventNames().length);
assert.equal('foo', EE.eventNames()[0]);
if (typeof Symbol !== 'undefined') {
var s = Symbol('s');
EE.on(s, m);
assert.equal(2, EE.eventNames().length);
assert.equal('foo', EE.eventNames()[0]);
assert.equal(s, EE.eventNames()[1]);
EE.removeListener(s, m);
assert.equal(1, EE.eventNames().length);
assert.equal('foo', EE.eventNames()[0]);
}

View File

@ -0,0 +1,48 @@
var test = require('tape');
require('./legacy-compat');
var common = require('./common');
// we do this to easily wrap each file in a mocha test
// and also have browserify be able to statically analyze this file
var orig_require = require;
var require = function(file) {
test(file, function(t) {
// Store the tape object so tests can access it.
t.on('end', function () { delete common.test; });
common.test = t;
try { orig_require(file); } catch (err) { t.fail(err); }
t.end();
});
};
require('./add-listeners.js');
require('./check-listener-leaks.js');
require('./errors.js');
require('./events-list.js');
require('./listener-count.js');
require('./listeners-side-effects.js');
require('./listeners.js');
require('./max-listeners.js');
if ((function A () {}).name === 'A') {
require('./method-names.js');
} else {
// Function.name is not supported in IE
test('./method-names.js', { skip: true }, function () {});
}
require('./modify-in-emit.js');
require('./num-args.js');
require('./once.js');
require('./prepend.js');
require('./set-max-listeners-side-effects.js');
require('./special-event-names.js');
require('./subclass.js');
if (typeof Symbol === 'function') {
require('./symbols.js');
} else {
// Symbol is not available.
test('./symbols.js', { skip: true }, function () {});
}
require('./remove-all-listeners.js');
require('./remove-listeners.js');

View File

@ -0,0 +1,16 @@
// sigh... life is hard
if (!global.console) {
console = {}
}
var fns = ['log', 'error', 'trace'];
for (var i=0 ; i<fns.length ; ++i) {
var fn = fns[i];
if (!console[fn]) {
console[fn] = function() {};
}
}
if (!Array.isArray) {
Array.isArray = require('isarray');
}

View File

@ -0,0 +1,37 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var EventEmitter = require('../');
var emitter = new EventEmitter();
emitter.on('foo', function() {});
emitter.on('foo', function() {});
emitter.on('baz', function() {});
// Allow any type
emitter.on(123, function() {});
assert.strictEqual(EventEmitter.listenerCount(emitter, 'foo'), 2);
assert.strictEqual(emitter.listenerCount('foo'), 2);
assert.strictEqual(emitter.listenerCount('bar'), 0);
assert.strictEqual(emitter.listenerCount('baz'), 1);
assert.strictEqual(emitter.listenerCount(123), 1);

View File

@ -0,0 +1,56 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var EventEmitter = require('../').EventEmitter;
var e = new EventEmitter();
var fl; // foo listeners
fl = e.listeners('foo');
assert.ok(Array.isArray(fl));
assert.strictEqual(fl.length, 0);
if (Object.create) assert.ok(!(e._events instanceof Object));
assert.strictEqual(Object.keys(e._events).length, 0);
e.on('foo', assert.fail);
fl = e.listeners('foo');
assert.strictEqual(e._events.foo, assert.fail);
assert.ok(Array.isArray(fl));
assert.strictEqual(fl.length, 1);
assert.strictEqual(fl[0], assert.fail);
e.listeners('bar');
e.on('foo', assert.ok);
fl = e.listeners('foo');
assert.ok(Array.isArray(e._events.foo));
assert.strictEqual(e._events.foo.length, 2);
assert.strictEqual(e._events.foo[0], assert.fail);
assert.strictEqual(e._events.foo[1], assert.ok);
assert.ok(Array.isArray(fl));
assert.strictEqual(fl.length, 2);
assert.strictEqual(fl[0], assert.fail);
assert.strictEqual(fl[1], assert.ok);

View File

@ -0,0 +1,149 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var events = require('../');
var util = require('util');
var listener = function listener() {};
var listener2 = function listener2() {};
function TestStream() {}
util.inherits(TestStream, events.EventEmitter);
{
var ee = new events.EventEmitter();
ee.on('foo', listener);
var fooListeners = ee.listeners('foo');
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener);
ee.removeAllListeners('foo');
listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
assert.ok(Array.isArray(fooListeners));
assert.strictEqual(fooListeners.length, 1);
assert.strictEqual(fooListeners[0], listener);
}
{
var ee = new events.EventEmitter();
ee.on('foo', listener);
var eeListenersCopy = ee.listeners('foo');
assert.ok(Array.isArray(eeListenersCopy));
assert.strictEqual(eeListenersCopy.length, 1);
assert.strictEqual(eeListenersCopy[0], listener);
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener);
eeListenersCopy.push(listener2);
listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener);
assert.strictEqual(eeListenersCopy.length, 2);
assert.strictEqual(eeListenersCopy[0], listener);
assert.strictEqual(eeListenersCopy[1], listener2);
}
{
var ee = new events.EventEmitter();
ee.on('foo', listener);
var eeListenersCopy = ee.listeners('foo');
ee.on('foo', listener2);
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 2);
assert.strictEqual(listeners[0], listener);
assert.strictEqual(listeners[1], listener2);
assert.ok(Array.isArray(eeListenersCopy));
assert.strictEqual(eeListenersCopy.length, 1);
assert.strictEqual(eeListenersCopy[0], listener);
}
{
var ee = new events.EventEmitter();
ee.once('foo', listener);
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener);
}
{
var ee = new events.EventEmitter();
ee.on('foo', listener);
ee.once('foo', listener2);
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 2);
assert.strictEqual(listeners[0], listener);
assert.strictEqual(listeners[1], listener2);
}
{
var ee = new events.EventEmitter();
ee._events = undefined;
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var s = new TestStream();
var listeners = s.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var ee = new events.EventEmitter();
ee.on('foo', listener);
var wrappedListener = ee.rawListeners('foo');
assert.strictEqual(wrappedListener.length, 1);
assert.strictEqual(wrappedListener[0], listener);
assert.notStrictEqual(wrappedListener, ee.rawListeners('foo'));
ee.once('foo', listener);
var wrappedListeners = ee.rawListeners('foo');
assert.strictEqual(wrappedListeners.length, 2);
assert.strictEqual(wrappedListeners[0], listener);
assert.notStrictEqual(wrappedListeners[1], listener);
assert.strictEqual(wrappedListeners[1].listener, listener);
assert.notStrictEqual(wrappedListeners, ee.rawListeners('foo'));
ee.emit('foo');
assert.strictEqual(wrappedListeners.length, 2);
assert.strictEqual(wrappedListeners[1].listener, listener);
}

View File

@ -0,0 +1,47 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var events = require('../');
var e = new events.EventEmitter();
var hasDefineProperty = !!Object.defineProperty;
try { Object.defineProperty({}, 'x', { value: 0 }); } catch (err) { hasDefineProperty = false }
e.on('maxListeners', common.mustCall());
// Should not corrupt the 'maxListeners' queue.
e.setMaxListeners(42);
var throwsObjs = [NaN, -1, 'and even this'];
var maxError = /^RangeError: The value of "n" is out of range\. It must be a non-negative number\./;
var defError = /^RangeError: The value of "defaultMaxListeners" is out of range\. It must be a non-negative number\./;
for (var i = 0; i < throwsObjs.length; i++) {
var obj = throwsObjs[i];
assert.throws(function() { e.setMaxListeners(obj); }, maxError);
if (hasDefineProperty) {
assert.throws(function() { events.defaultMaxListeners = obj; }, defError);
}
}
e.emit('maxListeners');

View File

@ -0,0 +1,35 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
require('./common');
var assert = require('assert');
var events = require('../');
var E = events.EventEmitter.prototype;
assert.strictEqual(E.constructor.name, 'EventEmitter');
assert.strictEqual(E.on, E.addListener); // Same method.
assert.strictEqual(E.off, E.removeListener); // Same method.
Object.getOwnPropertyNames(E).forEach(function(name) {
if (name === 'constructor' || name === 'on' || name === 'off') return;
if (typeof E[name] !== 'function') return;
assert.strictEqual(E[name].name, name);
});

View File

@ -0,0 +1,90 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var events = require('../');
var callbacks_called = [];
var e = new events.EventEmitter();
function callback1() {
callbacks_called.push('callback1');
e.on('foo', callback2);
e.on('foo', callback3);
e.removeListener('foo', callback1);
}
function callback2() {
callbacks_called.push('callback2');
e.removeListener('foo', callback2);
}
function callback3() {
callbacks_called.push('callback3');
e.removeListener('foo', callback3);
}
e.on('foo', callback1);
assert.strictEqual(e.listeners('foo').length, 1);
e.emit('foo');
assert.strictEqual(e.listeners('foo').length, 2);
assert.ok(Array.isArray(callbacks_called));
assert.strictEqual(callbacks_called.length, 1);
assert.strictEqual(callbacks_called[0], 'callback1');
e.emit('foo');
assert.strictEqual(e.listeners('foo').length, 0);
assert.ok(Array.isArray(callbacks_called));
assert.strictEqual(callbacks_called.length, 3);
assert.strictEqual(callbacks_called[0], 'callback1');
assert.strictEqual(callbacks_called[1], 'callback2');
assert.strictEqual(callbacks_called[2], 'callback3');
e.emit('foo');
assert.strictEqual(e.listeners('foo').length, 0);
assert.ok(Array.isArray(callbacks_called));
assert.strictEqual(callbacks_called.length, 3);
assert.strictEqual(callbacks_called[0], 'callback1');
assert.strictEqual(callbacks_called[1], 'callback2');
assert.strictEqual(callbacks_called[2], 'callback3');
e.on('foo', callback1);
e.on('foo', callback2);
assert.strictEqual(e.listeners('foo').length, 2);
e.removeAllListeners('foo');
assert.strictEqual(e.listeners('foo').length, 0);
// Verify that removing callbacks while in emit allows emits to propagate to
// all listeners
callbacks_called = [];
e.on('foo', callback2);
e.on('foo', callback3);
assert.strictEqual(2, e.listeners('foo').length);
e.emit('foo');
assert.ok(Array.isArray(callbacks_called));
assert.strictEqual(callbacks_called.length, 2);
assert.strictEqual(callbacks_called[0], 'callback2');
assert.strictEqual(callbacks_called[1], 'callback3');
assert.strictEqual(0, e.listeners('foo').length);

View File

@ -0,0 +1,60 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var events = require('../');
var e = new events.EventEmitter();
var num_args_emitted = [];
e.on('numArgs', function() {
var numArgs = arguments.length;
num_args_emitted.push(numArgs);
});
e.on('foo', function() {
num_args_emitted.push(arguments.length);
});
e.on('foo', function() {
num_args_emitted.push(arguments.length);
});
e.emit('numArgs');
e.emit('numArgs', null);
e.emit('numArgs', null, null);
e.emit('numArgs', null, null, null);
e.emit('numArgs', null, null, null, null);
e.emit('numArgs', null, null, null, null, null);
e.emit('foo', null, null, null, null);
assert.ok(Array.isArray(num_args_emitted));
assert.strictEqual(num_args_emitted.length, 8);
assert.strictEqual(num_args_emitted[0], 0);
assert.strictEqual(num_args_emitted[1], 1);
assert.strictEqual(num_args_emitted[2], 2);
assert.strictEqual(num_args_emitted[3], 3);
assert.strictEqual(num_args_emitted[4], 4);
assert.strictEqual(num_args_emitted[5], 5);
assert.strictEqual(num_args_emitted[6], 4);
assert.strictEqual(num_args_emitted[6], 4);

View File

@ -0,0 +1,83 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var EventEmitter = require('../');
var e = new EventEmitter();
e.once('hello', common.mustCall());
e.emit('hello', 'a', 'b');
e.emit('hello', 'a', 'b');
e.emit('hello', 'a', 'b');
e.emit('hello', 'a', 'b');
function remove() {
assert.fail('once->foo should not be emitted');
}
e.once('foo', remove);
e.removeListener('foo', remove);
e.emit('foo');
e.once('e', common.mustCall(function() {
e.emit('e');
}));
e.once('e', common.mustCall());
e.emit('e');
// Verify that the listener must be a function
assert.throws(function() {
var ee = new EventEmitter();
ee.once('foo', null);
}, /^TypeError: The "listener" argument must be of type Function. Received type object$/);
{
// once() has different code paths based on the number of arguments being
// emitted. Verify that all of the cases are covered.
var maxArgs = 4;
for (var i = 0; i <= maxArgs; ++i) {
var ee = new EventEmitter();
var args = ['foo'];
for (var j = 0; j < i; ++j)
args.push(j);
ee.once('foo', common.mustCall(function() {
var params = Array.prototype.slice.call(arguments);
var restArgs = args.slice(1);
assert.ok(Array.isArray(params));
assert.strictEqual(params.length, restArgs.length);
for (var index = 0; index < params.length; index++) {
var param = params[index];
assert.strictEqual(param, restArgs[index]);
}
}));
EventEmitter.prototype.emit.apply(ee, args);
}
}

View File

@ -0,0 +1,31 @@
'use strict';
var common = require('./common');
var EventEmitter = require('../');
var assert = require('assert');
var myEE = new EventEmitter();
var m = 0;
// This one comes last.
myEE.on('foo', common.mustCall(function () {
assert.strictEqual(m, 2);
}));
// This one comes second.
myEE.prependListener('foo', common.mustCall(function () {
assert.strictEqual(m++, 1);
}));
// This one comes first.
myEE.prependOnceListener('foo',
common.mustCall(function () {
assert.strictEqual(m++, 0);
}));
myEE.emit('foo');
// Verify that the listener must be a function
assert.throws(function () {
var ee = new EventEmitter();
ee.prependOnceListener('foo', null);
}, 'TypeError: The "listener" argument must be of type Function. Received type object');

View File

@ -0,0 +1,133 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var events = require('../');
var test = require('tape');
function expect(expected) {
var actual = [];
test.onFinish(function() {
var sortedActual = actual.sort();
var sortedExpected = expected.sort();
assert.strictEqual(sortedActual.length, sortedExpected.length);
for (var index = 0; index < sortedActual.length; index++) {
var value = sortedActual[index];
assert.strictEqual(value, sortedExpected[index]);
}
});
function listener(name) {
actual.push(name);
}
return common.mustCall(listener, expected.length);
}
{
var ee = new events.EventEmitter();
var noop = common.mustNotCall();
ee.on('foo', noop);
ee.on('bar', noop);
ee.on('baz', noop);
ee.on('baz', noop);
var fooListeners = ee.listeners('foo');
var barListeners = ee.listeners('bar');
var bazListeners = ee.listeners('baz');
ee.on('removeListener', expect(['bar', 'baz', 'baz']));
ee.removeAllListeners('bar');
ee.removeAllListeners('baz');
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], noop);
listeners = ee.listeners('bar');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
listeners = ee.listeners('baz');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
// After calling removeAllListeners(),
// the old listeners array should stay unchanged.
assert.strictEqual(fooListeners.length, 1);
assert.strictEqual(fooListeners[0], noop);
assert.strictEqual(barListeners.length, 1);
assert.strictEqual(barListeners[0], noop);
assert.strictEqual(bazListeners.length, 2);
assert.strictEqual(bazListeners[0], noop);
assert.strictEqual(bazListeners[1], noop);
// After calling removeAllListeners(),
// new listeners arrays is different from the old.
assert.notStrictEqual(ee.listeners('bar'), barListeners);
assert.notStrictEqual(ee.listeners('baz'), bazListeners);
}
{
var ee = new events.EventEmitter();
ee.on('foo', common.mustNotCall());
ee.on('bar', common.mustNotCall());
// Expect LIFO order
ee.on('removeListener', expect(['foo', 'bar', 'removeListener']));
ee.on('removeListener', expect(['foo', 'bar']));
ee.removeAllListeners();
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
listeners = ee.listeners('bar');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var ee = new events.EventEmitter();
ee.on('removeListener', common.mustNotCall());
// Check for regression where removeAllListeners() throws when
// there exists a 'removeListener' listener, but there exists
// no listeners for the provided event type.
assert.doesNotThrow(function () { ee.removeAllListeners(ee, 'foo') });
}
{
var ee = new events.EventEmitter();
var expectLength = 2;
ee.on('removeListener', function() {
assert.strictEqual(expectLength--, this.listeners('baz').length);
});
ee.on('baz', common.mustNotCall());
ee.on('baz', common.mustNotCall());
ee.on('baz', common.mustNotCall());
assert.strictEqual(ee.listeners('baz').length, expectLength + 1);
ee.removeAllListeners('baz');
assert.strictEqual(ee.listeners('baz').length, 0);
}
{
var ee = new events.EventEmitter();
assert.strictEqual(ee, ee.removeAllListeners());
}
{
var ee = new events.EventEmitter();
ee._events = undefined;
assert.strictEqual(ee, ee.removeAllListeners());
}

View File

@ -0,0 +1,212 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var assert = require('assert');
var EventEmitter = require('../');
var listener1 = function listener1() {};
var listener2 = function listener2() {};
{
var ee = new EventEmitter();
ee.on('hello', listener1);
ee.on('removeListener', common.mustCall(function(name, cb) {
assert.strictEqual(name, 'hello');
assert.strictEqual(cb, listener1);
}));
ee.removeListener('hello', listener1);
var listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var ee = new EventEmitter();
ee.on('hello', listener1);
ee.on('removeListener', common.mustNotCall());
ee.removeListener('hello', listener2);
var listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener1);
}
{
var ee = new EventEmitter();
ee.on('hello', listener1);
ee.on('hello', listener2);
var listeners;
ee.once('removeListener', common.mustCall(function(name, cb) {
assert.strictEqual(name, 'hello');
assert.strictEqual(cb, listener1);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener2);
}));
ee.removeListener('hello', listener1);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener2);
ee.once('removeListener', common.mustCall(function(name, cb) {
assert.strictEqual(name, 'hello');
assert.strictEqual(cb, listener2);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}));
ee.removeListener('hello', listener2);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var ee = new EventEmitter();
function remove1() {
assert.fail('remove1 should not have been called');
}
function remove2() {
assert.fail('remove2 should not have been called');
}
ee.on('removeListener', common.mustCall(function(name, cb) {
if (cb !== remove1) return;
this.removeListener('quux', remove2);
this.emit('quux');
}, 2));
ee.on('quux', remove1);
ee.on('quux', remove2);
ee.removeListener('quux', remove1);
}
{
var ee = new EventEmitter();
ee.on('hello', listener1);
ee.on('hello', listener2);
var listeners;
ee.once('removeListener', common.mustCall(function(name, cb) {
assert.strictEqual(name, 'hello');
assert.strictEqual(cb, listener1);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 1);
assert.strictEqual(listeners[0], listener2);
ee.once('removeListener', common.mustCall(function(name, cb) {
assert.strictEqual(name, 'hello');
assert.strictEqual(cb, listener2);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}));
ee.removeListener('hello', listener2);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}));
ee.removeListener('hello', listener1);
listeners = ee.listeners('hello');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 0);
}
{
var ee = new EventEmitter();
var listener3 = common.mustCall(function() {
ee.removeListener('hello', listener4);
}, 2);
var listener4 = common.mustCall();
ee.on('hello', listener3);
ee.on('hello', listener4);
// listener4 will still be called although it is removed by listener 3.
ee.emit('hello');
// This is so because the interal listener array at time of emit
// was [listener3,listener4]
// Interal listener array [listener3]
ee.emit('hello');
}
{
var ee = new EventEmitter();
ee.once('hello', listener1);
ee.on('removeListener', common.mustCall(function(eventName, listener) {
assert.strictEqual(eventName, 'hello');
assert.strictEqual(listener, listener1);
}));
ee.emit('hello');
}
{
var ee = new EventEmitter();
assert.strictEqual(ee, ee.removeListener('foo', function() {}));
}
// Verify that the removed listener must be a function
assert.throws(function() {
var ee = new EventEmitter();
ee.removeListener('foo', null);
}, /^TypeError: The "listener" argument must be of type Function\. Received type object$/);
{
var ee = new EventEmitter();
var listener = function() {};
ee._events = undefined;
var e = ee.removeListener('foo', listener);
assert.strictEqual(e, ee);
}
{
var ee = new EventEmitter();
ee.on('foo', listener1);
ee.on('foo', listener2);
var listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 2);
assert.strictEqual(listeners[0], listener1);
assert.strictEqual(listeners[1], listener2);
ee.removeListener('foo', listener1);
assert.strictEqual(ee._events.foo, listener2);
ee.on('foo', listener1);
listeners = ee.listeners('foo');
assert.ok(Array.isArray(listeners));
assert.strictEqual(listeners.length, 2);
assert.strictEqual(listeners[0], listener2);
assert.strictEqual(listeners[1], listener1);
ee.removeListener('foo', listener1);
assert.strictEqual(ee._events.foo, listener2);
}

View File

@ -0,0 +1,31 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
require('./common');
var assert = require('assert');
var events = require('../');
var e = new events.EventEmitter();
if (Object.create) assert.ok(!(e._events instanceof Object));
assert.strictEqual(Object.keys(e._events).length, 0);
e.setMaxListeners(5);
assert.strictEqual(Object.keys(e._events).length, 0);

View File

@ -0,0 +1,45 @@
'use strict';
var common = require('./common');
var EventEmitter = require('../');
var assert = require('assert');
var ee = new EventEmitter();
var handler = function() {};
assert.strictEqual(ee.eventNames().length, 0);
assert.strictEqual(ee._events.hasOwnProperty, undefined);
assert.strictEqual(ee._events.toString, undefined);
ee.on('__defineGetter__', handler);
ee.on('toString', handler);
ee.on('__proto__', handler);
assert.strictEqual(ee.eventNames()[0], '__defineGetter__');
assert.strictEqual(ee.eventNames()[1], 'toString');
assert.strictEqual(ee.listeners('__defineGetter__').length, 1);
assert.strictEqual(ee.listeners('__defineGetter__')[0], handler);
assert.strictEqual(ee.listeners('toString').length, 1);
assert.strictEqual(ee.listeners('toString')[0], handler);
// Only run __proto__ tests if that property can actually be set
if ({ __proto__: 'ok' }.__proto__ === 'ok') {
assert.strictEqual(ee.eventNames().length, 3);
assert.strictEqual(ee.eventNames()[2], '__proto__');
assert.strictEqual(ee.listeners('__proto__').length, 1);
assert.strictEqual(ee.listeners('__proto__')[0], handler);
ee.on('__proto__', common.mustCall(function(val) {
assert.strictEqual(val, 1);
}));
ee.emit('__proto__', 1);
process.on('__proto__', common.mustCall(function(val) {
assert.strictEqual(val, 1);
}));
process.emit('__proto__', 1);
} else {
console.log('# skipped __proto__')
}

View File

@ -0,0 +1,66 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('./common');
var test = require('tape');
var assert = require('assert');
var EventEmitter = require('../').EventEmitter;
var util = require('util');
util.inherits(MyEE, EventEmitter);
function MyEE(cb) {
this.once(1, cb);
this.emit(1);
this.removeAllListeners();
EventEmitter.call(this);
}
var myee = new MyEE(common.mustCall());
util.inherits(ErrorEE, EventEmitter);
function ErrorEE() {
this.emit('error', new Error('blerg'));
}
assert.throws(function() {
new ErrorEE();
}, /blerg/);
test.onFinish(function() {
assert.ok(!(myee._events instanceof Object));
assert.strictEqual(Object.keys(myee._events).length, 0);
});
function MyEE2() {
EventEmitter.call(this);
}
MyEE2.prototype = new EventEmitter();
var ee1 = new MyEE2();
var ee2 = new MyEE2();
ee1.on('x', function() {});
assert.strictEqual(ee2.listenerCount('x'), 0);

View File

@ -0,0 +1,25 @@
'use strict';
var common = require('./common');
var EventEmitter = require('../');
var assert = require('assert');
var ee = new EventEmitter();
var foo = Symbol('foo');
var listener = common.mustCall();
ee.on(foo, listener);
assert.strictEqual(ee.listeners(foo).length, 1);
assert.strictEqual(ee.listeners(foo)[0], listener);
ee.emit(foo);
ee.removeAllListeners();
assert.strictEqual(ee.listeners(foo).length, 0);
ee.on(foo, listener);
assert.strictEqual(ee.listeners(foo).length, 1);
assert.strictEqual(ee.listeners(foo)[0], listener);
ee.removeListener(foo, listener);
assert.strictEqual(ee.listeners(foo).length, 0);

View File

@ -0,0 +1,63 @@
# mini-html-parser2
## 安装
```
$ npm install mini-html-parser2 --save
```
## 使用
```js
// page.js
const html = `<div>
<span>test</span>
<div>
<span>table test</span>
<table>
<thead>
<tr>
<th>title</th>
<th>title</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2">yy</td>
<td>xx</td>
<td>xx</td>
<td>xx</td>
</tr>
</tbody>
</table>
</div>
</div>`
import parse from 'mini-html-parser2';
Page({
data: {
nodes: [],
},
onLoad() {
parse(html, (err, nodes) => {
if (!err) {
this.setData({
nodes,
});
}
})
},
})
```
```html
<!-- page.axml -->
<rich-text nodes="{{nodes}}" />
```
## 运行测试
```
$ npm run build
$ npm test
```

View File

@ -0,0 +1,2 @@
declare function Parser(cbs: any, options: any): void;
export default Parser;

View File

@ -0,0 +1,292 @@
var Tokenizer = require("./Tokenizer.js");
/*
Options:
xmlMode: Disables the special behavior for script/style tags (false by default)
lowerCaseAttributeNames: call .toLowerCase for each attribute name (true if xmlMode is `false`)
lowerCaseTags: call .toLowerCase for each tag name (true if xmlMode is `false`)
*/
/*
Callbacks:
oncdataend,
oncdatastart,
onclosetag,
oncomment,
oncommentend,
onerror,
onopentag,
onprocessinginstruction,
onreset,
ontext
*/
var formTags = {
input: true,
option: true,
optgroup: true,
select: true,
button: true,
datalist: true,
textarea: true
};
var openImpliesClose = {
tr: { tr: true, th: true, td: true },
th: { th: true },
td: { thead: true, th: true, td: true },
body: { head: true, link: true, script: true },
li: { li: true },
p: { p: true },
h1: { p: true },
h2: { p: true },
h3: { p: true },
h4: { p: true },
h5: { p: true },
h6: { p: true },
select: formTags,
input: formTags,
output: formTags,
button: formTags,
datalist: formTags,
textarea: formTags,
option: { option: true },
optgroup: { optgroup: true }
};
var voidElements = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
command: true,
embed: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
var foreignContextElements = {
__proto__: null,
math: true,
svg: true
};
var htmlIntegrationElements = {
__proto__: null,
mi: true,
mo: true,
mn: true,
ms: true,
mtext: true,
"annotation-xml": true,
foreignObject: true,
desc: true,
title: true
};
var re_nameEnd = /\s|\//;
function Parser(cbs, options) {
this._options = options || {};
this._cbs = cbs || {};
this._tagname = "";
this._attribname = "";
this._attribvalue = "";
this._attribs = null;
this._stack = [];
this._foreignContext = [];
this.startIndex = 0;
this.endIndex = null;
this._lowerCaseTagNames = "lowerCaseTags" in this._options ? !!this._options.lowerCaseTags : !this._options.xmlMode;
this._lowerCaseAttributeNames = "lowerCaseAttributeNames" in this._options ? !!this._options.lowerCaseAttributeNames : !this._options.xmlMode;
if (this._options.Tokenizer) {
Tokenizer = this._options.Tokenizer;
}
this._tokenizer = new Tokenizer(this._options, this);
if (this._cbs.onparserinit) this._cbs.onparserinit(this);
}
require("./inherits")(Parser, require("events").EventEmitter);
Parser.prototype._updatePosition = function (initialOffset) {
if (this.endIndex === null) {
if (this._tokenizer._sectionStart <= initialOffset) {
this.startIndex = 0;
} else {
this.startIndex = this._tokenizer._sectionStart - initialOffset;
}
} else this.startIndex = this.endIndex + 1;
this.endIndex = this._tokenizer.getAbsoluteIndex();
};
//Tokenizer event handlers
Parser.prototype.ontext = function (data) {
this._updatePosition(1);
this.endIndex--;
if (this._cbs.ontext) this._cbs.ontext(data);
};
Parser.prototype.onopentagname = function (name) {
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
this._tagname = name;
if (!this._options.xmlMode && name in openImpliesClose) {
for (var el; (el = this._stack[this._stack.length - 1]) in openImpliesClose[name]; this.onclosetag(el)) {}
}
if (this._options.xmlMode || !(name in voidElements)) {
this._stack.push(name);
if (name in foreignContextElements) this._foreignContext.push(true);else if (name in htmlIntegrationElements) this._foreignContext.push(false);
}
if (this._cbs.onopentagname) this._cbs.onopentagname(name);
if (this._cbs.onopentag) this._attribs = {};
};
Parser.prototype.onopentagend = function () {
this._updatePosition(1);
if (this._attribs) {
if (this._cbs.onopentag) this._cbs.onopentag(this._tagname, this._attribs);
this._attribs = null;
}
if (!this._options.xmlMode && this._cbs.onclosetag && this._tagname in voidElements) {
this._cbs.onclosetag(this._tagname);
}
this._tagname = "";
};
Parser.prototype.onclosetag = function (name) {
this._updatePosition(1);
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
if (name in foreignContextElements || name in htmlIntegrationElements) {
this._foreignContext.pop();
}
if (this._stack.length && (!(name in voidElements) || this._options.xmlMode)) {
var pos = this._stack.lastIndexOf(name);
if (pos !== -1) {
if (this._cbs.onclosetag) {
pos = this._stack.length - pos;
while (pos--) {
this._cbs.onclosetag(this._stack.pop());
}
} else this._stack.length = pos;
} else if (name === "p" && !this._options.xmlMode) {
this.onopentagname(name);
this._closeCurrentTag();
}
} else if (!this._options.xmlMode && (name === "br" || name === "p")) {
this.onopentagname(name);
this._closeCurrentTag();
}
};
Parser.prototype.onselfclosingtag = function () {
if (this._options.xmlMode || this._options.recognizeSelfClosing || this._foreignContext[this._foreignContext.length - 1]) {
this._closeCurrentTag();
} else {
this.onopentagend();
}
};
Parser.prototype._closeCurrentTag = function () {
var name = this._tagname;
this.onopentagend();
//self-closing tags will be on the top of the stack
//(cheaper check than in onclosetag)
if (this._stack[this._stack.length - 1] === name) {
if (this._cbs.onclosetag) {
this._cbs.onclosetag(name);
}
this._stack.pop();
}
};
Parser.prototype.onattribname = function (name) {
if (this._lowerCaseAttributeNames) {
name = name.toLowerCase();
}
this._attribname = name;
};
Parser.prototype.onattribdata = function (value) {
this._attribvalue += value;
};
Parser.prototype.onattribend = function () {
if (this._cbs.onattribute) this._cbs.onattribute(this._attribname, this._attribvalue);
if (this._attribs && !Object.prototype.hasOwnProperty.call(this._attribs, this._attribname)) {
this._attribs[this._attribname] = this._attribvalue;
}
this._attribname = "";
this._attribvalue = "";
};
Parser.prototype._getInstructionName = function (value) {
var idx = value.search(re_nameEnd),
name = idx < 0 ? value : value.substr(0, idx);
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
return name;
};
Parser.prototype.ondeclaration = function (value) {
if (this._cbs.onprocessinginstruction) {
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("!" + name, "!" + value);
}
};
Parser.prototype.onprocessinginstruction = function (value) {
if (this._cbs.onprocessinginstruction) {
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("?" + name, "?" + value);
}
};
Parser.prototype.oncomment = function (value) {
this._updatePosition(4);
if (this._cbs.oncomment) this._cbs.oncomment(value);
if (this._cbs.oncommentend) this._cbs.oncommentend();
};
Parser.prototype.oncdata = function (value) {
this._updatePosition(1);
if (this._options.xmlMode || this._options.recognizeCDATA) {
if (this._cbs.oncdatastart) this._cbs.oncdatastart();
if (this._cbs.ontext) this._cbs.ontext(value);
if (this._cbs.oncdataend) this._cbs.oncdataend();
} else {
this.oncomment("[CDATA[" + value + "]]");
}
};
Parser.prototype.onerror = function (err) {
if (this._cbs.onerror) this._cbs.onerror(err);
};
Parser.prototype.onend = function () {
if (this._cbs.onclosetag) {
for (var i = this._stack.length; i > 0; this._cbs.onclosetag(this._stack[--i])) {}
}
if (this._cbs.onend) this._cbs.onend();
};
//Resets the parser to a blank state, ready to parse a new HTML document
Parser.prototype.reset = function () {
if (this._cbs.onreset) this._cbs.onreset();
this._tokenizer.reset();
this._tagname = "";
this._attribname = "";
this._attribs = null;
this._stack = [];
if (this._cbs.onparserinit) this._cbs.onparserinit(this);
};
//Parses a complete HTML document and pushes it to the handler
Parser.prototype.parseComplete = function (data) {
this.reset();
this.end(data);
};
Parser.prototype.write = function (chunk) {
this._tokenizer.write(chunk);
};
Parser.prototype.end = function (chunk) {
this._tokenizer.end(chunk);
};
Parser.prototype.pause = function () {
this._tokenizer.pause();
};
Parser.prototype.resume = function () {
this._tokenizer.resume();
};
//alias for backwards compat
Parser.prototype.parseChunk = Parser.prototype.write;
Parser.prototype.done = Parser.prototype.end;
export default Parser;

View File

@ -0,0 +1,68 @@
declare var decodeCodePoint: any;
declare var entityMap: {};
declare var legacyMap: any;
declare var xmlMap: any;
declare var i: number;
declare var TEXT: number;
declare var BEFORE_TAG_NAME: number;
declare var IN_TAG_NAME: number;
declare var IN_SELF_CLOSING_TAG: number;
declare var BEFORE_CLOSING_TAG_NAME: number;
declare var IN_CLOSING_TAG_NAME: number;
declare var AFTER_CLOSING_TAG_NAME: number;
declare var BEFORE_ATTRIBUTE_NAME: number;
declare var IN_ATTRIBUTE_NAME: number;
declare var AFTER_ATTRIBUTE_NAME: number;
declare var BEFORE_ATTRIBUTE_VALUE: number;
declare var IN_ATTRIBUTE_VALUE_DQ: number;
declare var IN_ATTRIBUTE_VALUE_SQ: number;
declare var IN_ATTRIBUTE_VALUE_NQ: number;
declare var BEFORE_DECLARATION: number;
declare var IN_DECLARATION: number;
declare var IN_PROCESSING_INSTRUCTION: number;
declare var BEFORE_COMMENT: number;
declare var IN_COMMENT: number;
declare var AFTER_COMMENT_1: number;
declare var AFTER_COMMENT_2: number;
declare var BEFORE_CDATA_1: number;
declare var BEFORE_CDATA_2: number;
declare var BEFORE_CDATA_3: number;
declare var BEFORE_CDATA_4: number;
declare var BEFORE_CDATA_5: number;
declare var BEFORE_CDATA_6: number;
declare var IN_CDATA: number;
declare var AFTER_CDATA_1: number;
declare var AFTER_CDATA_2: number;
declare var BEFORE_SPECIAL: number;
declare var BEFORE_SPECIAL_END: number;
declare var BEFORE_SCRIPT_1: number;
declare var BEFORE_SCRIPT_2: number;
declare var BEFORE_SCRIPT_3: number;
declare var BEFORE_SCRIPT_4: number;
declare var BEFORE_SCRIPT_5: number;
declare var AFTER_SCRIPT_1: number;
declare var AFTER_SCRIPT_2: number;
declare var AFTER_SCRIPT_3: number;
declare var AFTER_SCRIPT_4: number;
declare var AFTER_SCRIPT_5: number;
declare var BEFORE_STYLE_1: number;
declare var BEFORE_STYLE_2: number;
declare var BEFORE_STYLE_3: number;
declare var BEFORE_STYLE_4: number;
declare var AFTER_STYLE_1: number;
declare var AFTER_STYLE_2: number;
declare var AFTER_STYLE_3: number;
declare var AFTER_STYLE_4: number;
declare var BEFORE_ENTITY: number;
declare var BEFORE_NUMERIC_ENTITY: number;
declare var IN_NAMED_ENTITY: number;
declare var IN_NUMERIC_ENTITY: number;
declare var IN_HEX_ENTITY: number;
declare var j: number;
declare var SPECIAL_NONE: number;
declare var SPECIAL_SCRIPT: number;
declare var SPECIAL_STYLE: number;
declare function whitespace(c: any): boolean;
declare function ifElseState(upper: any, SUCCESS: any, FAILURE: any): (c: any) => void;
declare function consumeSpecialNameChar(upper: any, NEXT_STATE: any): (c: any) => void;
declare function Tokenizer(options: any, cbs: any): void;

View File

@ -0,0 +1,767 @@
var decodeCodePoint = require("entities/lib/decode_codepoint.js");
var entityMap = {};
var legacyMap = require("entities/maps/legacy.json");
var xmlMap = require("entities/maps/xml.json");
var i = 0;
var TEXT = i++;
var BEFORE_TAG_NAME = i++; //after <
var IN_TAG_NAME = i++;
var IN_SELF_CLOSING_TAG = i++;
var BEFORE_CLOSING_TAG_NAME = i++;
var IN_CLOSING_TAG_NAME = i++;
var AFTER_CLOSING_TAG_NAME = i++;
//attributes
var BEFORE_ATTRIBUTE_NAME = i++;
var IN_ATTRIBUTE_NAME = i++;
var AFTER_ATTRIBUTE_NAME = i++;
var BEFORE_ATTRIBUTE_VALUE = i++;
var IN_ATTRIBUTE_VALUE_DQ = i++; // "
var IN_ATTRIBUTE_VALUE_SQ = i++; // '
var IN_ATTRIBUTE_VALUE_NQ = i++;
//declarations
var BEFORE_DECLARATION = i++; // !
var IN_DECLARATION = i++;
//processing instructions
var IN_PROCESSING_INSTRUCTION = i++; // ?
//comments
var BEFORE_COMMENT = i++;
var IN_COMMENT = i++;
var AFTER_COMMENT_1 = i++;
var AFTER_COMMENT_2 = i++;
//cdata
var BEFORE_CDATA_1 = i++; // [
var BEFORE_CDATA_2 = i++; // C
var BEFORE_CDATA_3 = i++; // D
var BEFORE_CDATA_4 = i++; // A
var BEFORE_CDATA_5 = i++; // T
var BEFORE_CDATA_6 = i++; // A
var IN_CDATA = i++; // [
var AFTER_CDATA_1 = i++; // ]
var AFTER_CDATA_2 = i++; // ]
//special tags
var BEFORE_SPECIAL = i++; //S
var BEFORE_SPECIAL_END = i++; //S
var BEFORE_SCRIPT_1 = i++; //C
var BEFORE_SCRIPT_2 = i++; //R
var BEFORE_SCRIPT_3 = i++; //I
var BEFORE_SCRIPT_4 = i++; //P
var BEFORE_SCRIPT_5 = i++; //T
var AFTER_SCRIPT_1 = i++; //C
var AFTER_SCRIPT_2 = i++; //R
var AFTER_SCRIPT_3 = i++; //I
var AFTER_SCRIPT_4 = i++; //P
var AFTER_SCRIPT_5 = i++; //T
var BEFORE_STYLE_1 = i++; //T
var BEFORE_STYLE_2 = i++; //Y
var BEFORE_STYLE_3 = i++; //L
var BEFORE_STYLE_4 = i++; //E
var AFTER_STYLE_1 = i++; //T
var AFTER_STYLE_2 = i++; //Y
var AFTER_STYLE_3 = i++; //L
var AFTER_STYLE_4 = i++; //E
var BEFORE_ENTITY = i++; //&
var BEFORE_NUMERIC_ENTITY = i++; //#
var IN_NAMED_ENTITY = i++;
var IN_NUMERIC_ENTITY = i++;
var IN_HEX_ENTITY = i++; //X
var j = 0;
var SPECIAL_NONE = j++;
var SPECIAL_SCRIPT = j++;
var SPECIAL_STYLE = j++;
function whitespace(c) {
return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r";
}
function ifElseState(upper, SUCCESS, FAILURE) {
var lower = upper.toLowerCase();
if (upper === lower) {
return function (c) {
if (c === lower) {
this._state = SUCCESS;
} else {
this._state = FAILURE;
this._index--;
}
};
} else {
return function (c) {
if (c === lower || c === upper) {
this._state = SUCCESS;
} else {
this._state = FAILURE;
this._index--;
}
};
}
}
function consumeSpecialNameChar(upper, NEXT_STATE) {
var lower = upper.toLowerCase();
return function (c) {
if (c === lower || c === upper) {
this._state = NEXT_STATE;
} else {
this._state = IN_TAG_NAME;
this._index--; //consume the token again
}
};
}
function Tokenizer(options, cbs) {
this._state = TEXT;
this._buffer = "";
this._sectionStart = 0;
this._index = 0;
this._bufferOffset = 0; //chars removed from _buffer
this._baseState = TEXT;
this._special = SPECIAL_NONE;
this._cbs = cbs;
this._running = true;
this._ended = false;
this._xmlMode = !!(options && options.xmlMode);
this._decodeEntities = !!(options && options.decodeEntities);
}
Tokenizer.prototype._stateText = function (c) {
if (c === "<") {
if (this._index > this._sectionStart) {
this._cbs.ontext(this._getSection());
}
this._state = BEFORE_TAG_NAME;
this._sectionStart = this._index;
} else if (this._decodeEntities && this._special === SPECIAL_NONE && c === "&") {
if (this._index > this._sectionStart) {
this._cbs.ontext(this._getSection());
}
this._baseState = TEXT;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeTagName = function (c) {
if (c === "/") {
this._state = BEFORE_CLOSING_TAG_NAME;
} else if (c === "<") {
this._cbs.ontext(this._getSection());
this._sectionStart = this._index;
} else if (c === ">" || this._special !== SPECIAL_NONE || whitespace(c)) {
this._state = TEXT;
} else if (c === "!") {
this._state = BEFORE_DECLARATION;
this._sectionStart = this._index + 1;
} else if (c === "?") {
this._state = IN_PROCESSING_INSTRUCTION;
this._sectionStart = this._index + 1;
} else {
this._state = !this._xmlMode && (c === "s" || c === "S") ? BEFORE_SPECIAL : IN_TAG_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInTagName = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._emitToken("onopentagname");
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateBeforeCloseingTagName = function (c) {
if (whitespace(c)) {} else if (c === ">") {
this._state = TEXT;
} else if (this._special !== SPECIAL_NONE) {
if (c === "s" || c === "S") {
this._state = BEFORE_SPECIAL_END;
} else {
this._state = TEXT;
this._index--;
}
} else {
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInCloseingTagName = function (c) {
if (c === ">" || whitespace(c)) {
this._emitToken("onclosetag");
this._state = AFTER_CLOSING_TAG_NAME;
this._index--;
}
};
Tokenizer.prototype._stateAfterCloseingTagName = function (c) {
//skip everything until ">"
if (c === ">") {
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateBeforeAttributeName = function (c) {
if (c === ">") {
this._cbs.onopentagend();
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c === "/") {
this._state = IN_SELF_CLOSING_TAG;
} else if (!whitespace(c)) {
this._state = IN_ATTRIBUTE_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInSelfClosingTag = function (c) {
if (c === ">") {
this._cbs.onselfclosingtag();
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (!whitespace(c)) {
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateInAttributeName = function (c) {
if (c === "=" || c === "/" || c === ">" || whitespace(c)) {
this._cbs.onattribname(this._getSection());
this._sectionStart = -1;
this._state = AFTER_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateAfterAttributeName = function (c) {
if (c === "=") {
this._state = BEFORE_ATTRIBUTE_VALUE;
} else if (c === "/" || c === ">") {
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
} else if (!whitespace(c)) {
this._cbs.onattribend();
this._state = IN_ATTRIBUTE_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeAttributeValue = function (c) {
if (c === '"') {
this._state = IN_ATTRIBUTE_VALUE_DQ;
this._sectionStart = this._index + 1;
} else if (c === "'") {
this._state = IN_ATTRIBUTE_VALUE_SQ;
this._sectionStart = this._index + 1;
} else if (!whitespace(c)) {
this._state = IN_ATTRIBUTE_VALUE_NQ;
this._sectionStart = this._index;
this._index--; //reconsume token
}
};
Tokenizer.prototype._stateInAttributeValueDoubleQuotes = function (c) {
if (c === '"') {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInAttributeValueSingleQuotes = function (c) {
if (c === "'") {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInAttributeValueNoQuotes = function (c) {
if (whitespace(c) || c === ">") {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeDeclaration = function (c) {
this._state = c === "[" ? BEFORE_CDATA_1 : c === "-" ? BEFORE_COMMENT : IN_DECLARATION;
};
Tokenizer.prototype._stateInDeclaration = function (c) {
if (c === ">") {
this._cbs.ondeclaration(this._getSection());
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateInProcessingInstruction = function (c) {
if (c === ">") {
this._cbs.onprocessinginstruction(this._getSection());
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateBeforeComment = function (c) {
if (c === "-") {
this._state = IN_COMMENT;
this._sectionStart = this._index + 1;
} else {
this._state = IN_DECLARATION;
}
};
Tokenizer.prototype._stateInComment = function (c) {
if (c === "-") this._state = AFTER_COMMENT_1;
};
Tokenizer.prototype._stateAfterComment1 = function (c) {
if (c === "-") {
this._state = AFTER_COMMENT_2;
} else {
this._state = IN_COMMENT;
}
};
Tokenizer.prototype._stateAfterComment2 = function (c) {
if (c === ">") {
//remove 2 trailing chars
this._cbs.oncomment(this._buffer.substring(this._sectionStart, this._index - 2));
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c !== "-") {
this._state = IN_COMMENT;
}
// else: stay in AFTER_COMMENT_2 (`--->`)
};
Tokenizer.prototype._stateBeforeCdata1 = ifElseState("C", BEFORE_CDATA_2, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata2 = ifElseState("D", BEFORE_CDATA_3, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata3 = ifElseState("A", BEFORE_CDATA_4, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata4 = ifElseState("T", BEFORE_CDATA_5, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata5 = ifElseState("A", BEFORE_CDATA_6, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata6 = function (c) {
if (c === "[") {
this._state = IN_CDATA;
this._sectionStart = this._index + 1;
} else {
this._state = IN_DECLARATION;
this._index--;
}
};
Tokenizer.prototype._stateInCdata = function (c) {
if (c === "]") this._state = AFTER_CDATA_1;
};
Tokenizer.prototype._stateAfterCdata1 = function (c) {
if (c === "]") this._state = AFTER_CDATA_2;else this._state = IN_CDATA;
};
Tokenizer.prototype._stateAfterCdata2 = function (c) {
if (c === ">") {
//remove 2 trailing chars
this._cbs.oncdata(this._buffer.substring(this._sectionStart, this._index - 2));
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c !== "]") {
this._state = IN_CDATA;
}
//else: stay in AFTER_CDATA_2 (`]]]>`)
};
Tokenizer.prototype._stateBeforeSpecial = function (c) {
if (c === "c" || c === "C") {
this._state = BEFORE_SCRIPT_1;
} else if (c === "t" || c === "T") {
this._state = BEFORE_STYLE_1;
} else {
this._state = IN_TAG_NAME;
this._index--; //consume the token again
}
};
Tokenizer.prototype._stateBeforeSpecialEnd = function (c) {
if (this._special === SPECIAL_SCRIPT && (c === "c" || c === "C")) {
this._state = AFTER_SCRIPT_1;
} else if (this._special === SPECIAL_STYLE && (c === "t" || c === "T")) {
this._state = AFTER_STYLE_1;
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeScript1 = consumeSpecialNameChar("R", BEFORE_SCRIPT_2);
Tokenizer.prototype._stateBeforeScript2 = consumeSpecialNameChar("I", BEFORE_SCRIPT_3);
Tokenizer.prototype._stateBeforeScript3 = consumeSpecialNameChar("P", BEFORE_SCRIPT_4);
Tokenizer.prototype._stateBeforeScript4 = consumeSpecialNameChar("T", BEFORE_SCRIPT_5);
Tokenizer.prototype._stateBeforeScript5 = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._special = SPECIAL_SCRIPT;
}
this._state = IN_TAG_NAME;
this._index--; //consume the token again
};
Tokenizer.prototype._stateAfterScript1 = ifElseState("R", AFTER_SCRIPT_2, TEXT);
Tokenizer.prototype._stateAfterScript2 = ifElseState("I", AFTER_SCRIPT_3, TEXT);
Tokenizer.prototype._stateAfterScript3 = ifElseState("P", AFTER_SCRIPT_4, TEXT);
Tokenizer.prototype._stateAfterScript4 = ifElseState("T", AFTER_SCRIPT_5, TEXT);
Tokenizer.prototype._stateAfterScript5 = function (c) {
if (c === ">" || whitespace(c)) {
this._special = SPECIAL_NONE;
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index - 6;
this._index--; //reconsume the token
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeStyle1 = consumeSpecialNameChar("Y", BEFORE_STYLE_2);
Tokenizer.prototype._stateBeforeStyle2 = consumeSpecialNameChar("L", BEFORE_STYLE_3);
Tokenizer.prototype._stateBeforeStyle3 = consumeSpecialNameChar("E", BEFORE_STYLE_4);
Tokenizer.prototype._stateBeforeStyle4 = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._special = SPECIAL_STYLE;
}
this._state = IN_TAG_NAME;
this._index--; //consume the token again
};
Tokenizer.prototype._stateAfterStyle1 = ifElseState("Y", AFTER_STYLE_2, TEXT);
Tokenizer.prototype._stateAfterStyle2 = ifElseState("L", AFTER_STYLE_3, TEXT);
Tokenizer.prototype._stateAfterStyle3 = ifElseState("E", AFTER_STYLE_4, TEXT);
Tokenizer.prototype._stateAfterStyle4 = function (c) {
if (c === ">" || whitespace(c)) {
this._special = SPECIAL_NONE;
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index - 5;
this._index--; //reconsume the token
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeEntity = ifElseState("#", BEFORE_NUMERIC_ENTITY, IN_NAMED_ENTITY);
Tokenizer.prototype._stateBeforeNumericEntity = ifElseState("X", IN_HEX_ENTITY, IN_NUMERIC_ENTITY);
//for entities terminated with a semicolon
Tokenizer.prototype._parseNamedEntityStrict = function () {
//offset = 1
if (this._sectionStart + 1 < this._index) {
var entity = this._buffer.substring(this._sectionStart + 1, this._index),
map = this._xmlMode ? xmlMap : entityMap;
if (map.hasOwnProperty(entity)) {
this._emitPartial(map[entity]);
this._sectionStart = this._index + 1;
}
}
};
//parses legacy entities (without trailing semicolon)
Tokenizer.prototype._parseLegacyEntity = function () {
var start = this._sectionStart + 1,
limit = this._index - start;
if (limit > 6) limit = 6; //the max length of legacy entities is 6
while (limit >= 2) {
//the min length of legacy entities is 2
var entity = this._buffer.substr(start, limit);
if (legacyMap.hasOwnProperty(entity)) {
this._emitPartial(legacyMap[entity]);
this._sectionStart += limit + 1;
return;
} else {
limit--;
}
}
};
Tokenizer.prototype._stateInNamedEntity = function (c) {
if (c === ";") {
this._parseNamedEntityStrict();
if (this._sectionStart + 1 < this._index && !this._xmlMode) {
this._parseLegacyEntity();
}
this._state = this._baseState;
} else if ((c < "a" || c > "z") && (c < "A" || c > "Z") && (c < "0" || c > "9")) {
if (this._xmlMode) {} else if (this._sectionStart + 1 === this._index) {} else if (this._baseState !== TEXT) {
if (c !== "=") {
this._parseNamedEntityStrict();
}
} else {
this._parseLegacyEntity();
}
this._state = this._baseState;
this._index--;
}
};
Tokenizer.prototype._decodeNumericEntity = function (offset, base) {
var sectionStart = this._sectionStart + offset;
if (sectionStart !== this._index) {
//parse entity
var entity = this._buffer.substring(sectionStart, this._index);
var parsed = parseInt(entity, base);
this._emitPartial(decodeCodePoint(parsed));
this._sectionStart = this._index;
} else {
this._sectionStart--;
}
this._state = this._baseState;
};
Tokenizer.prototype._stateInNumericEntity = function (c) {
if (c === ";") {
this._decodeNumericEntity(2, 10);
this._sectionStart++;
} else if (c < "0" || c > "9") {
if (!this._xmlMode) {
this._decodeNumericEntity(2, 10);
} else {
this._state = this._baseState;
}
this._index--;
}
};
Tokenizer.prototype._stateInHexEntity = function (c) {
if (c === ";") {
this._decodeNumericEntity(3, 16);
this._sectionStart++;
} else if ((c < "a" || c > "f") && (c < "A" || c > "F") && (c < "0" || c > "9")) {
if (!this._xmlMode) {
this._decodeNumericEntity(3, 16);
} else {
this._state = this._baseState;
}
this._index--;
}
};
Tokenizer.prototype._cleanup = function () {
if (this._sectionStart < 0) {
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else if (this._running) {
if (this._state === TEXT) {
if (this._sectionStart !== this._index) {
this._cbs.ontext(this._buffer.substr(this._sectionStart));
}
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else if (this._sectionStart === this._index) {
//the section just started
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else {
//remove everything unnecessary
this._buffer = this._buffer.substr(this._sectionStart);
this._index -= this._sectionStart;
this._bufferOffset += this._sectionStart;
}
this._sectionStart = 0;
}
};
//TODO make events conditional
Tokenizer.prototype.write = function (chunk) {
if (this._ended) this._cbs.onerror(Error(".write() after done!"));
this._buffer += chunk;
this._parse();
};
Tokenizer.prototype._parse = function () {
while (this._index < this._buffer.length && this._running) {
var c = this._buffer.charAt(this._index);
if (this._state === TEXT) {
this._stateText(c);
} else if (this._state === BEFORE_TAG_NAME) {
this._stateBeforeTagName(c);
} else if (this._state === IN_TAG_NAME) {
this._stateInTagName(c);
} else if (this._state === BEFORE_CLOSING_TAG_NAME) {
this._stateBeforeCloseingTagName(c);
} else if (this._state === IN_CLOSING_TAG_NAME) {
this._stateInCloseingTagName(c);
} else if (this._state === AFTER_CLOSING_TAG_NAME) {
this._stateAfterCloseingTagName(c);
} else if (this._state === IN_SELF_CLOSING_TAG) {
this._stateInSelfClosingTag(c);
} else if (this._state === BEFORE_ATTRIBUTE_NAME) {
/*
* attributes
*/
this._stateBeforeAttributeName(c);
} else if (this._state === IN_ATTRIBUTE_NAME) {
this._stateInAttributeName(c);
} else if (this._state === AFTER_ATTRIBUTE_NAME) {
this._stateAfterAttributeName(c);
} else if (this._state === BEFORE_ATTRIBUTE_VALUE) {
this._stateBeforeAttributeValue(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_DQ) {
this._stateInAttributeValueDoubleQuotes(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_SQ) {
this._stateInAttributeValueSingleQuotes(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_NQ) {
this._stateInAttributeValueNoQuotes(c);
} else if (this._state === BEFORE_DECLARATION) {
/*
* declarations
*/
this._stateBeforeDeclaration(c);
} else if (this._state === IN_DECLARATION) {
this._stateInDeclaration(c);
} else if (this._state === IN_PROCESSING_INSTRUCTION) {
/*
* processing instructions
*/
this._stateInProcessingInstruction(c);
} else if (this._state === BEFORE_COMMENT) {
/*
* comments
*/
this._stateBeforeComment(c);
} else if (this._state === IN_COMMENT) {
this._stateInComment(c);
} else if (this._state === AFTER_COMMENT_1) {
this._stateAfterComment1(c);
} else if (this._state === AFTER_COMMENT_2) {
this._stateAfterComment2(c);
} else if (this._state === BEFORE_CDATA_1) {
/*
* cdata
*/
this._stateBeforeCdata1(c);
} else if (this._state === BEFORE_CDATA_2) {
this._stateBeforeCdata2(c);
} else if (this._state === BEFORE_CDATA_3) {
this._stateBeforeCdata3(c);
} else if (this._state === BEFORE_CDATA_4) {
this._stateBeforeCdata4(c);
} else if (this._state === BEFORE_CDATA_5) {
this._stateBeforeCdata5(c);
} else if (this._state === BEFORE_CDATA_6) {
this._stateBeforeCdata6(c);
} else if (this._state === IN_CDATA) {
this._stateInCdata(c);
} else if (this._state === AFTER_CDATA_1) {
this._stateAfterCdata1(c);
} else if (this._state === AFTER_CDATA_2) {
this._stateAfterCdata2(c);
} else if (this._state === BEFORE_SPECIAL) {
/*
* special tags
*/
this._stateBeforeSpecial(c);
} else if (this._state === BEFORE_SPECIAL_END) {
this._stateBeforeSpecialEnd(c);
} else if (this._state === BEFORE_SCRIPT_1) {
/*
* script
*/
this._stateBeforeScript1(c);
} else if (this._state === BEFORE_SCRIPT_2) {
this._stateBeforeScript2(c);
} else if (this._state === BEFORE_SCRIPT_3) {
this._stateBeforeScript3(c);
} else if (this._state === BEFORE_SCRIPT_4) {
this._stateBeforeScript4(c);
} else if (this._state === BEFORE_SCRIPT_5) {
this._stateBeforeScript5(c);
} else if (this._state === AFTER_SCRIPT_1) {
this._stateAfterScript1(c);
} else if (this._state === AFTER_SCRIPT_2) {
this._stateAfterScript2(c);
} else if (this._state === AFTER_SCRIPT_3) {
this._stateAfterScript3(c);
} else if (this._state === AFTER_SCRIPT_4) {
this._stateAfterScript4(c);
} else if (this._state === AFTER_SCRIPT_5) {
this._stateAfterScript5(c);
} else if (this._state === BEFORE_STYLE_1) {
/*
* style
*/
this._stateBeforeStyle1(c);
} else if (this._state === BEFORE_STYLE_2) {
this._stateBeforeStyle2(c);
} else if (this._state === BEFORE_STYLE_3) {
this._stateBeforeStyle3(c);
} else if (this._state === BEFORE_STYLE_4) {
this._stateBeforeStyle4(c);
} else if (this._state === AFTER_STYLE_1) {
this._stateAfterStyle1(c);
} else if (this._state === AFTER_STYLE_2) {
this._stateAfterStyle2(c);
} else if (this._state === AFTER_STYLE_3) {
this._stateAfterStyle3(c);
} else if (this._state === AFTER_STYLE_4) {
this._stateAfterStyle4(c);
} else if (this._state === BEFORE_ENTITY) {
/*
* entities
*/
this._stateBeforeEntity(c);
} else if (this._state === BEFORE_NUMERIC_ENTITY) {
this._stateBeforeNumericEntity(c);
} else if (this._state === IN_NAMED_ENTITY) {
this._stateInNamedEntity(c);
} else if (this._state === IN_NUMERIC_ENTITY) {
this._stateInNumericEntity(c);
} else if (this._state === IN_HEX_ENTITY) {
this._stateInHexEntity(c);
} else {
this._cbs.onerror(Error("unknown _state"), this._state);
}
this._index++;
}
this._cleanup();
};
Tokenizer.prototype.pause = function () {
this._running = false;
};
Tokenizer.prototype.resume = function () {
this._running = true;
if (this._index < this._buffer.length) {
this._parse();
}
if (this._ended) {
this._finish();
}
};
Tokenizer.prototype.end = function (chunk) {
if (this._ended) this._cbs.onerror(Error(".end() after done!"));
if (chunk) this.write(chunk);
this._ended = true;
if (this._running) this._finish();
};
Tokenizer.prototype._finish = function () {
//if there is remaining data, emit it in a reasonable way
if (this._sectionStart < this._index) {
this._handleTrailingData();
}
this._cbs.onend();
};
Tokenizer.prototype._handleTrailingData = function () {
var data = this._buffer.substr(this._sectionStart);
if (this._state === IN_CDATA || this._state === AFTER_CDATA_1 || this._state === AFTER_CDATA_2) {
this._cbs.oncdata(data);
} else if (this._state === IN_COMMENT || this._state === AFTER_COMMENT_1 || this._state === AFTER_COMMENT_2) {
this._cbs.oncomment(data);
} else if (this._state === IN_NAMED_ENTITY && !this._xmlMode) {
this._parseLegacyEntity();
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state === IN_NUMERIC_ENTITY && !this._xmlMode) {
this._decodeNumericEntity(2, 10);
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state === IN_HEX_ENTITY && !this._xmlMode) {
this._decodeNumericEntity(3, 16);
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state !== IN_TAG_NAME && this._state !== BEFORE_ATTRIBUTE_NAME && this._state !== BEFORE_ATTRIBUTE_VALUE && this._state !== AFTER_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_VALUE_SQ && this._state !== IN_ATTRIBUTE_VALUE_DQ && this._state !== IN_ATTRIBUTE_VALUE_NQ && this._state !== IN_CLOSING_TAG_NAME) {
this._cbs.ontext(data);
}
//else, ignore remaining data
//TODO add a way to remove current tag
};
Tokenizer.prototype.reset = function () {
Tokenizer.call(this, { xmlMode: this._xmlMode, decodeEntities: this._decodeEntities }, this._cbs);
};
Tokenizer.prototype.getAbsoluteIndex = function () {
return this._bufferOffset + this._index;
};
Tokenizer.prototype._getSection = function () {
return this._buffer.substring(this._sectionStart, this._index);
};
Tokenizer.prototype._emitToken = function (name) {
this._cbs[name](this._getSection());
this._sectionStart = -1;
};
Tokenizer.prototype._emitPartial = function (value) {
if (this._baseState !== TEXT) {
this._cbs.onattribdata(value); //TODO implement the new event
} else {
this._cbs.ontext(value);
}
};
module.exports = Tokenizer;

View File

@ -0,0 +1 @@
export default function parse(html: any, done: any): void;

View File

@ -0,0 +1,38 @@
import Handler from 'domhandler';
import Parser from './Parser';
function transformNode(node) {
if (['tag', 'text'].indexOf(node.type) === -1) {
throw new Error('not supported name ' + node.name + ' of type ' + node.type);
}
if (node.type === 'text') {
return {
type: node.type,
text: node.data
};
}
return {
name: node.name,
children: transform(node.children),
attrs: node.attribs
};
}
function transform(nodes) {
return nodes.map(transformNode);
}
export default function parse(html, done) {
var handler = new Handler(function (err, children) {
if (err) {
console.error(err);
done(err);
}
try {
done(null, transform(children));
} catch (e) {
console.error(e);
done(e);
}
}, {});
var parser = new Parser(handler, { xmlMode: true });
parser.write(html);
parser.done();
}

View File

@ -0,0 +1,23 @@
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
var TempCtor = function TempCtor() {};
TempCtor.prototype = superCtor.prototype;
ctor.prototype = new TempCtor();
ctor.prototype.constructor = ctor;
};
}

View File

@ -0,0 +1,2 @@
declare function Parser(cbs: any, options: any): void;
export default Parser;

View File

@ -0,0 +1,298 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var Tokenizer = require("./Tokenizer.js");
/*
Options:
xmlMode: Disables the special behavior for script/style tags (false by default)
lowerCaseAttributeNames: call .toLowerCase for each attribute name (true if xmlMode is `false`)
lowerCaseTags: call .toLowerCase for each tag name (true if xmlMode is `false`)
*/
/*
Callbacks:
oncdataend,
oncdatastart,
onclosetag,
oncomment,
oncommentend,
onerror,
onopentag,
onprocessinginstruction,
onreset,
ontext
*/
var formTags = {
input: true,
option: true,
optgroup: true,
select: true,
button: true,
datalist: true,
textarea: true
};
var openImpliesClose = {
tr: { tr: true, th: true, td: true },
th: { th: true },
td: { thead: true, th: true, td: true },
body: { head: true, link: true, script: true },
li: { li: true },
p: { p: true },
h1: { p: true },
h2: { p: true },
h3: { p: true },
h4: { p: true },
h5: { p: true },
h6: { p: true },
select: formTags,
input: formTags,
output: formTags,
button: formTags,
datalist: formTags,
textarea: formTags,
option: { option: true },
optgroup: { optgroup: true }
};
var voidElements = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
command: true,
embed: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
};
var foreignContextElements = {
__proto__: null,
math: true,
svg: true
};
var htmlIntegrationElements = {
__proto__: null,
mi: true,
mo: true,
mn: true,
ms: true,
mtext: true,
"annotation-xml": true,
foreignObject: true,
desc: true,
title: true
};
var re_nameEnd = /\s|\//;
function Parser(cbs, options) {
this._options = options || {};
this._cbs = cbs || {};
this._tagname = "";
this._attribname = "";
this._attribvalue = "";
this._attribs = null;
this._stack = [];
this._foreignContext = [];
this.startIndex = 0;
this.endIndex = null;
this._lowerCaseTagNames = "lowerCaseTags" in this._options ? !!this._options.lowerCaseTags : !this._options.xmlMode;
this._lowerCaseAttributeNames = "lowerCaseAttributeNames" in this._options ? !!this._options.lowerCaseAttributeNames : !this._options.xmlMode;
if (this._options.Tokenizer) {
Tokenizer = this._options.Tokenizer;
}
this._tokenizer = new Tokenizer(this._options, this);
if (this._cbs.onparserinit) this._cbs.onparserinit(this);
}
require("./inherits")(Parser, require("events").EventEmitter);
Parser.prototype._updatePosition = function (initialOffset) {
if (this.endIndex === null) {
if (this._tokenizer._sectionStart <= initialOffset) {
this.startIndex = 0;
} else {
this.startIndex = this._tokenizer._sectionStart - initialOffset;
}
} else this.startIndex = this.endIndex + 1;
this.endIndex = this._tokenizer.getAbsoluteIndex();
};
//Tokenizer event handlers
Parser.prototype.ontext = function (data) {
this._updatePosition(1);
this.endIndex--;
if (this._cbs.ontext) this._cbs.ontext(data);
};
Parser.prototype.onopentagname = function (name) {
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
this._tagname = name;
if (!this._options.xmlMode && name in openImpliesClose) {
for (var el; (el = this._stack[this._stack.length - 1]) in openImpliesClose[name]; this.onclosetag(el)) {}
}
if (this._options.xmlMode || !(name in voidElements)) {
this._stack.push(name);
if (name in foreignContextElements) this._foreignContext.push(true);else if (name in htmlIntegrationElements) this._foreignContext.push(false);
}
if (this._cbs.onopentagname) this._cbs.onopentagname(name);
if (this._cbs.onopentag) this._attribs = {};
};
Parser.prototype.onopentagend = function () {
this._updatePosition(1);
if (this._attribs) {
if (this._cbs.onopentag) this._cbs.onopentag(this._tagname, this._attribs);
this._attribs = null;
}
if (!this._options.xmlMode && this._cbs.onclosetag && this._tagname in voidElements) {
this._cbs.onclosetag(this._tagname);
}
this._tagname = "";
};
Parser.prototype.onclosetag = function (name) {
this._updatePosition(1);
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
if (name in foreignContextElements || name in htmlIntegrationElements) {
this._foreignContext.pop();
}
if (this._stack.length && (!(name in voidElements) || this._options.xmlMode)) {
var pos = this._stack.lastIndexOf(name);
if (pos !== -1) {
if (this._cbs.onclosetag) {
pos = this._stack.length - pos;
while (pos--) {
this._cbs.onclosetag(this._stack.pop());
}
} else this._stack.length = pos;
} else if (name === "p" && !this._options.xmlMode) {
this.onopentagname(name);
this._closeCurrentTag();
}
} else if (!this._options.xmlMode && (name === "br" || name === "p")) {
this.onopentagname(name);
this._closeCurrentTag();
}
};
Parser.prototype.onselfclosingtag = function () {
if (this._options.xmlMode || this._options.recognizeSelfClosing || this._foreignContext[this._foreignContext.length - 1]) {
this._closeCurrentTag();
} else {
this.onopentagend();
}
};
Parser.prototype._closeCurrentTag = function () {
var name = this._tagname;
this.onopentagend();
//self-closing tags will be on the top of the stack
//(cheaper check than in onclosetag)
if (this._stack[this._stack.length - 1] === name) {
if (this._cbs.onclosetag) {
this._cbs.onclosetag(name);
}
this._stack.pop();
}
};
Parser.prototype.onattribname = function (name) {
if (this._lowerCaseAttributeNames) {
name = name.toLowerCase();
}
this._attribname = name;
};
Parser.prototype.onattribdata = function (value) {
this._attribvalue += value;
};
Parser.prototype.onattribend = function () {
if (this._cbs.onattribute) this._cbs.onattribute(this._attribname, this._attribvalue);
if (this._attribs && !Object.prototype.hasOwnProperty.call(this._attribs, this._attribname)) {
this._attribs[this._attribname] = this._attribvalue;
}
this._attribname = "";
this._attribvalue = "";
};
Parser.prototype._getInstructionName = function (value) {
var idx = value.search(re_nameEnd),
name = idx < 0 ? value : value.substr(0, idx);
if (this._lowerCaseTagNames) {
name = name.toLowerCase();
}
return name;
};
Parser.prototype.ondeclaration = function (value) {
if (this._cbs.onprocessinginstruction) {
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("!" + name, "!" + value);
}
};
Parser.prototype.onprocessinginstruction = function (value) {
if (this._cbs.onprocessinginstruction) {
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("?" + name, "?" + value);
}
};
Parser.prototype.oncomment = function (value) {
this._updatePosition(4);
if (this._cbs.oncomment) this._cbs.oncomment(value);
if (this._cbs.oncommentend) this._cbs.oncommentend();
};
Parser.prototype.oncdata = function (value) {
this._updatePosition(1);
if (this._options.xmlMode || this._options.recognizeCDATA) {
if (this._cbs.oncdatastart) this._cbs.oncdatastart();
if (this._cbs.ontext) this._cbs.ontext(value);
if (this._cbs.oncdataend) this._cbs.oncdataend();
} else {
this.oncomment("[CDATA[" + value + "]]");
}
};
Parser.prototype.onerror = function (err) {
if (this._cbs.onerror) this._cbs.onerror(err);
};
Parser.prototype.onend = function () {
if (this._cbs.onclosetag) {
for (var i = this._stack.length; i > 0; this._cbs.onclosetag(this._stack[--i])) {}
}
if (this._cbs.onend) this._cbs.onend();
};
//Resets the parser to a blank state, ready to parse a new HTML document
Parser.prototype.reset = function () {
if (this._cbs.onreset) this._cbs.onreset();
this._tokenizer.reset();
this._tagname = "";
this._attribname = "";
this._attribs = null;
this._stack = [];
if (this._cbs.onparserinit) this._cbs.onparserinit(this);
};
//Parses a complete HTML document and pushes it to the handler
Parser.prototype.parseComplete = function (data) {
this.reset();
this.end(data);
};
Parser.prototype.write = function (chunk) {
this._tokenizer.write(chunk);
};
Parser.prototype.end = function (chunk) {
this._tokenizer.end(chunk);
};
Parser.prototype.pause = function () {
this._tokenizer.pause();
};
Parser.prototype.resume = function () {
this._tokenizer.resume();
};
//alias for backwards compat
Parser.prototype.parseChunk = Parser.prototype.write;
Parser.prototype.done = Parser.prototype.end;
exports["default"] = Parser;
module.exports = exports['default'];

View File

@ -0,0 +1,68 @@
declare var decodeCodePoint: any;
declare var entityMap: {};
declare var legacyMap: any;
declare var xmlMap: any;
declare var i: number;
declare var TEXT: number;
declare var BEFORE_TAG_NAME: number;
declare var IN_TAG_NAME: number;
declare var IN_SELF_CLOSING_TAG: number;
declare var BEFORE_CLOSING_TAG_NAME: number;
declare var IN_CLOSING_TAG_NAME: number;
declare var AFTER_CLOSING_TAG_NAME: number;
declare var BEFORE_ATTRIBUTE_NAME: number;
declare var IN_ATTRIBUTE_NAME: number;
declare var AFTER_ATTRIBUTE_NAME: number;
declare var BEFORE_ATTRIBUTE_VALUE: number;
declare var IN_ATTRIBUTE_VALUE_DQ: number;
declare var IN_ATTRIBUTE_VALUE_SQ: number;
declare var IN_ATTRIBUTE_VALUE_NQ: number;
declare var BEFORE_DECLARATION: number;
declare var IN_DECLARATION: number;
declare var IN_PROCESSING_INSTRUCTION: number;
declare var BEFORE_COMMENT: number;
declare var IN_COMMENT: number;
declare var AFTER_COMMENT_1: number;
declare var AFTER_COMMENT_2: number;
declare var BEFORE_CDATA_1: number;
declare var BEFORE_CDATA_2: number;
declare var BEFORE_CDATA_3: number;
declare var BEFORE_CDATA_4: number;
declare var BEFORE_CDATA_5: number;
declare var BEFORE_CDATA_6: number;
declare var IN_CDATA: number;
declare var AFTER_CDATA_1: number;
declare var AFTER_CDATA_2: number;
declare var BEFORE_SPECIAL: number;
declare var BEFORE_SPECIAL_END: number;
declare var BEFORE_SCRIPT_1: number;
declare var BEFORE_SCRIPT_2: number;
declare var BEFORE_SCRIPT_3: number;
declare var BEFORE_SCRIPT_4: number;
declare var BEFORE_SCRIPT_5: number;
declare var AFTER_SCRIPT_1: number;
declare var AFTER_SCRIPT_2: number;
declare var AFTER_SCRIPT_3: number;
declare var AFTER_SCRIPT_4: number;
declare var AFTER_SCRIPT_5: number;
declare var BEFORE_STYLE_1: number;
declare var BEFORE_STYLE_2: number;
declare var BEFORE_STYLE_3: number;
declare var BEFORE_STYLE_4: number;
declare var AFTER_STYLE_1: number;
declare var AFTER_STYLE_2: number;
declare var AFTER_STYLE_3: number;
declare var AFTER_STYLE_4: number;
declare var BEFORE_ENTITY: number;
declare var BEFORE_NUMERIC_ENTITY: number;
declare var IN_NAMED_ENTITY: number;
declare var IN_NUMERIC_ENTITY: number;
declare var IN_HEX_ENTITY: number;
declare var j: number;
declare var SPECIAL_NONE: number;
declare var SPECIAL_SCRIPT: number;
declare var SPECIAL_STYLE: number;
declare function whitespace(c: any): boolean;
declare function ifElseState(upper: any, SUCCESS: any, FAILURE: any): (c: any) => void;
declare function consumeSpecialNameChar(upper: any, NEXT_STATE: any): (c: any) => void;
declare function Tokenizer(options: any, cbs: any): void;

View File

@ -0,0 +1,769 @@
"use strict";
var decodeCodePoint = require("entities/lib/decode_codepoint.js");
var entityMap = {};
var legacyMap = require("entities/maps/legacy.json");
var xmlMap = require("entities/maps/xml.json");
var i = 0;
var TEXT = i++;
var BEFORE_TAG_NAME = i++; //after <
var IN_TAG_NAME = i++;
var IN_SELF_CLOSING_TAG = i++;
var BEFORE_CLOSING_TAG_NAME = i++;
var IN_CLOSING_TAG_NAME = i++;
var AFTER_CLOSING_TAG_NAME = i++;
//attributes
var BEFORE_ATTRIBUTE_NAME = i++;
var IN_ATTRIBUTE_NAME = i++;
var AFTER_ATTRIBUTE_NAME = i++;
var BEFORE_ATTRIBUTE_VALUE = i++;
var IN_ATTRIBUTE_VALUE_DQ = i++; // "
var IN_ATTRIBUTE_VALUE_SQ = i++; // '
var IN_ATTRIBUTE_VALUE_NQ = i++;
//declarations
var BEFORE_DECLARATION = i++; // !
var IN_DECLARATION = i++;
//processing instructions
var IN_PROCESSING_INSTRUCTION = i++; // ?
//comments
var BEFORE_COMMENT = i++;
var IN_COMMENT = i++;
var AFTER_COMMENT_1 = i++;
var AFTER_COMMENT_2 = i++;
//cdata
var BEFORE_CDATA_1 = i++; // [
var BEFORE_CDATA_2 = i++; // C
var BEFORE_CDATA_3 = i++; // D
var BEFORE_CDATA_4 = i++; // A
var BEFORE_CDATA_5 = i++; // T
var BEFORE_CDATA_6 = i++; // A
var IN_CDATA = i++; // [
var AFTER_CDATA_1 = i++; // ]
var AFTER_CDATA_2 = i++; // ]
//special tags
var BEFORE_SPECIAL = i++; //S
var BEFORE_SPECIAL_END = i++; //S
var BEFORE_SCRIPT_1 = i++; //C
var BEFORE_SCRIPT_2 = i++; //R
var BEFORE_SCRIPT_3 = i++; //I
var BEFORE_SCRIPT_4 = i++; //P
var BEFORE_SCRIPT_5 = i++; //T
var AFTER_SCRIPT_1 = i++; //C
var AFTER_SCRIPT_2 = i++; //R
var AFTER_SCRIPT_3 = i++; //I
var AFTER_SCRIPT_4 = i++; //P
var AFTER_SCRIPT_5 = i++; //T
var BEFORE_STYLE_1 = i++; //T
var BEFORE_STYLE_2 = i++; //Y
var BEFORE_STYLE_3 = i++; //L
var BEFORE_STYLE_4 = i++; //E
var AFTER_STYLE_1 = i++; //T
var AFTER_STYLE_2 = i++; //Y
var AFTER_STYLE_3 = i++; //L
var AFTER_STYLE_4 = i++; //E
var BEFORE_ENTITY = i++; //&
var BEFORE_NUMERIC_ENTITY = i++; //#
var IN_NAMED_ENTITY = i++;
var IN_NUMERIC_ENTITY = i++;
var IN_HEX_ENTITY = i++; //X
var j = 0;
var SPECIAL_NONE = j++;
var SPECIAL_SCRIPT = j++;
var SPECIAL_STYLE = j++;
function whitespace(c) {
return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r";
}
function ifElseState(upper, SUCCESS, FAILURE) {
var lower = upper.toLowerCase();
if (upper === lower) {
return function (c) {
if (c === lower) {
this._state = SUCCESS;
} else {
this._state = FAILURE;
this._index--;
}
};
} else {
return function (c) {
if (c === lower || c === upper) {
this._state = SUCCESS;
} else {
this._state = FAILURE;
this._index--;
}
};
}
}
function consumeSpecialNameChar(upper, NEXT_STATE) {
var lower = upper.toLowerCase();
return function (c) {
if (c === lower || c === upper) {
this._state = NEXT_STATE;
} else {
this._state = IN_TAG_NAME;
this._index--; //consume the token again
}
};
}
function Tokenizer(options, cbs) {
this._state = TEXT;
this._buffer = "";
this._sectionStart = 0;
this._index = 0;
this._bufferOffset = 0; //chars removed from _buffer
this._baseState = TEXT;
this._special = SPECIAL_NONE;
this._cbs = cbs;
this._running = true;
this._ended = false;
this._xmlMode = !!(options && options.xmlMode);
this._decodeEntities = !!(options && options.decodeEntities);
}
Tokenizer.prototype._stateText = function (c) {
if (c === "<") {
if (this._index > this._sectionStart) {
this._cbs.ontext(this._getSection());
}
this._state = BEFORE_TAG_NAME;
this._sectionStart = this._index;
} else if (this._decodeEntities && this._special === SPECIAL_NONE && c === "&") {
if (this._index > this._sectionStart) {
this._cbs.ontext(this._getSection());
}
this._baseState = TEXT;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeTagName = function (c) {
if (c === "/") {
this._state = BEFORE_CLOSING_TAG_NAME;
} else if (c === "<") {
this._cbs.ontext(this._getSection());
this._sectionStart = this._index;
} else if (c === ">" || this._special !== SPECIAL_NONE || whitespace(c)) {
this._state = TEXT;
} else if (c === "!") {
this._state = BEFORE_DECLARATION;
this._sectionStart = this._index + 1;
} else if (c === "?") {
this._state = IN_PROCESSING_INSTRUCTION;
this._sectionStart = this._index + 1;
} else {
this._state = !this._xmlMode && (c === "s" || c === "S") ? BEFORE_SPECIAL : IN_TAG_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInTagName = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._emitToken("onopentagname");
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateBeforeCloseingTagName = function (c) {
if (whitespace(c)) {} else if (c === ">") {
this._state = TEXT;
} else if (this._special !== SPECIAL_NONE) {
if (c === "s" || c === "S") {
this._state = BEFORE_SPECIAL_END;
} else {
this._state = TEXT;
this._index--;
}
} else {
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInCloseingTagName = function (c) {
if (c === ">" || whitespace(c)) {
this._emitToken("onclosetag");
this._state = AFTER_CLOSING_TAG_NAME;
this._index--;
}
};
Tokenizer.prototype._stateAfterCloseingTagName = function (c) {
//skip everything until ">"
if (c === ">") {
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateBeforeAttributeName = function (c) {
if (c === ">") {
this._cbs.onopentagend();
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c === "/") {
this._state = IN_SELF_CLOSING_TAG;
} else if (!whitespace(c)) {
this._state = IN_ATTRIBUTE_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInSelfClosingTag = function (c) {
if (c === ">") {
this._cbs.onselfclosingtag();
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (!whitespace(c)) {
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateInAttributeName = function (c) {
if (c === "=" || c === "/" || c === ">" || whitespace(c)) {
this._cbs.onattribname(this._getSection());
this._sectionStart = -1;
this._state = AFTER_ATTRIBUTE_NAME;
this._index--;
}
};
Tokenizer.prototype._stateAfterAttributeName = function (c) {
if (c === "=") {
this._state = BEFORE_ATTRIBUTE_VALUE;
} else if (c === "/" || c === ">") {
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
} else if (!whitespace(c)) {
this._cbs.onattribend();
this._state = IN_ATTRIBUTE_NAME;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeAttributeValue = function (c) {
if (c === '"') {
this._state = IN_ATTRIBUTE_VALUE_DQ;
this._sectionStart = this._index + 1;
} else if (c === "'") {
this._state = IN_ATTRIBUTE_VALUE_SQ;
this._sectionStart = this._index + 1;
} else if (!whitespace(c)) {
this._state = IN_ATTRIBUTE_VALUE_NQ;
this._sectionStart = this._index;
this._index--; //reconsume token
}
};
Tokenizer.prototype._stateInAttributeValueDoubleQuotes = function (c) {
if (c === '"') {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInAttributeValueSingleQuotes = function (c) {
if (c === "'") {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateInAttributeValueNoQuotes = function (c) {
if (whitespace(c) || c === ">") {
this._emitToken("onattribdata");
this._cbs.onattribend();
this._state = BEFORE_ATTRIBUTE_NAME;
this._index--;
} else if (this._decodeEntities && c === "&") {
this._emitToken("onattribdata");
this._baseState = this._state;
this._state = BEFORE_ENTITY;
this._sectionStart = this._index;
}
};
Tokenizer.prototype._stateBeforeDeclaration = function (c) {
this._state = c === "[" ? BEFORE_CDATA_1 : c === "-" ? BEFORE_COMMENT : IN_DECLARATION;
};
Tokenizer.prototype._stateInDeclaration = function (c) {
if (c === ">") {
this._cbs.ondeclaration(this._getSection());
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateInProcessingInstruction = function (c) {
if (c === ">") {
this._cbs.onprocessinginstruction(this._getSection());
this._state = TEXT;
this._sectionStart = this._index + 1;
}
};
Tokenizer.prototype._stateBeforeComment = function (c) {
if (c === "-") {
this._state = IN_COMMENT;
this._sectionStart = this._index + 1;
} else {
this._state = IN_DECLARATION;
}
};
Tokenizer.prototype._stateInComment = function (c) {
if (c === "-") this._state = AFTER_COMMENT_1;
};
Tokenizer.prototype._stateAfterComment1 = function (c) {
if (c === "-") {
this._state = AFTER_COMMENT_2;
} else {
this._state = IN_COMMENT;
}
};
Tokenizer.prototype._stateAfterComment2 = function (c) {
if (c === ">") {
//remove 2 trailing chars
this._cbs.oncomment(this._buffer.substring(this._sectionStart, this._index - 2));
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c !== "-") {
this._state = IN_COMMENT;
}
// else: stay in AFTER_COMMENT_2 (`--->`)
};
Tokenizer.prototype._stateBeforeCdata1 = ifElseState("C", BEFORE_CDATA_2, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata2 = ifElseState("D", BEFORE_CDATA_3, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata3 = ifElseState("A", BEFORE_CDATA_4, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata4 = ifElseState("T", BEFORE_CDATA_5, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata5 = ifElseState("A", BEFORE_CDATA_6, IN_DECLARATION);
Tokenizer.prototype._stateBeforeCdata6 = function (c) {
if (c === "[") {
this._state = IN_CDATA;
this._sectionStart = this._index + 1;
} else {
this._state = IN_DECLARATION;
this._index--;
}
};
Tokenizer.prototype._stateInCdata = function (c) {
if (c === "]") this._state = AFTER_CDATA_1;
};
Tokenizer.prototype._stateAfterCdata1 = function (c) {
if (c === "]") this._state = AFTER_CDATA_2;else this._state = IN_CDATA;
};
Tokenizer.prototype._stateAfterCdata2 = function (c) {
if (c === ">") {
//remove 2 trailing chars
this._cbs.oncdata(this._buffer.substring(this._sectionStart, this._index - 2));
this._state = TEXT;
this._sectionStart = this._index + 1;
} else if (c !== "]") {
this._state = IN_CDATA;
}
//else: stay in AFTER_CDATA_2 (`]]]>`)
};
Tokenizer.prototype._stateBeforeSpecial = function (c) {
if (c === "c" || c === "C") {
this._state = BEFORE_SCRIPT_1;
} else if (c === "t" || c === "T") {
this._state = BEFORE_STYLE_1;
} else {
this._state = IN_TAG_NAME;
this._index--; //consume the token again
}
};
Tokenizer.prototype._stateBeforeSpecialEnd = function (c) {
if (this._special === SPECIAL_SCRIPT && (c === "c" || c === "C")) {
this._state = AFTER_SCRIPT_1;
} else if (this._special === SPECIAL_STYLE && (c === "t" || c === "T")) {
this._state = AFTER_STYLE_1;
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeScript1 = consumeSpecialNameChar("R", BEFORE_SCRIPT_2);
Tokenizer.prototype._stateBeforeScript2 = consumeSpecialNameChar("I", BEFORE_SCRIPT_3);
Tokenizer.prototype._stateBeforeScript3 = consumeSpecialNameChar("P", BEFORE_SCRIPT_4);
Tokenizer.prototype._stateBeforeScript4 = consumeSpecialNameChar("T", BEFORE_SCRIPT_5);
Tokenizer.prototype._stateBeforeScript5 = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._special = SPECIAL_SCRIPT;
}
this._state = IN_TAG_NAME;
this._index--; //consume the token again
};
Tokenizer.prototype._stateAfterScript1 = ifElseState("R", AFTER_SCRIPT_2, TEXT);
Tokenizer.prototype._stateAfterScript2 = ifElseState("I", AFTER_SCRIPT_3, TEXT);
Tokenizer.prototype._stateAfterScript3 = ifElseState("P", AFTER_SCRIPT_4, TEXT);
Tokenizer.prototype._stateAfterScript4 = ifElseState("T", AFTER_SCRIPT_5, TEXT);
Tokenizer.prototype._stateAfterScript5 = function (c) {
if (c === ">" || whitespace(c)) {
this._special = SPECIAL_NONE;
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index - 6;
this._index--; //reconsume the token
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeStyle1 = consumeSpecialNameChar("Y", BEFORE_STYLE_2);
Tokenizer.prototype._stateBeforeStyle2 = consumeSpecialNameChar("L", BEFORE_STYLE_3);
Tokenizer.prototype._stateBeforeStyle3 = consumeSpecialNameChar("E", BEFORE_STYLE_4);
Tokenizer.prototype._stateBeforeStyle4 = function (c) {
if (c === "/" || c === ">" || whitespace(c)) {
this._special = SPECIAL_STYLE;
}
this._state = IN_TAG_NAME;
this._index--; //consume the token again
};
Tokenizer.prototype._stateAfterStyle1 = ifElseState("Y", AFTER_STYLE_2, TEXT);
Tokenizer.prototype._stateAfterStyle2 = ifElseState("L", AFTER_STYLE_3, TEXT);
Tokenizer.prototype._stateAfterStyle3 = ifElseState("E", AFTER_STYLE_4, TEXT);
Tokenizer.prototype._stateAfterStyle4 = function (c) {
if (c === ">" || whitespace(c)) {
this._special = SPECIAL_NONE;
this._state = IN_CLOSING_TAG_NAME;
this._sectionStart = this._index - 5;
this._index--; //reconsume the token
} else this._state = TEXT;
};
Tokenizer.prototype._stateBeforeEntity = ifElseState("#", BEFORE_NUMERIC_ENTITY, IN_NAMED_ENTITY);
Tokenizer.prototype._stateBeforeNumericEntity = ifElseState("X", IN_HEX_ENTITY, IN_NUMERIC_ENTITY);
//for entities terminated with a semicolon
Tokenizer.prototype._parseNamedEntityStrict = function () {
//offset = 1
if (this._sectionStart + 1 < this._index) {
var entity = this._buffer.substring(this._sectionStart + 1, this._index),
map = this._xmlMode ? xmlMap : entityMap;
if (map.hasOwnProperty(entity)) {
this._emitPartial(map[entity]);
this._sectionStart = this._index + 1;
}
}
};
//parses legacy entities (without trailing semicolon)
Tokenizer.prototype._parseLegacyEntity = function () {
var start = this._sectionStart + 1,
limit = this._index - start;
if (limit > 6) limit = 6; //the max length of legacy entities is 6
while (limit >= 2) {
//the min length of legacy entities is 2
var entity = this._buffer.substr(start, limit);
if (legacyMap.hasOwnProperty(entity)) {
this._emitPartial(legacyMap[entity]);
this._sectionStart += limit + 1;
return;
} else {
limit--;
}
}
};
Tokenizer.prototype._stateInNamedEntity = function (c) {
if (c === ";") {
this._parseNamedEntityStrict();
if (this._sectionStart + 1 < this._index && !this._xmlMode) {
this._parseLegacyEntity();
}
this._state = this._baseState;
} else if ((c < "a" || c > "z") && (c < "A" || c > "Z") && (c < "0" || c > "9")) {
if (this._xmlMode) {} else if (this._sectionStart + 1 === this._index) {} else if (this._baseState !== TEXT) {
if (c !== "=") {
this._parseNamedEntityStrict();
}
} else {
this._parseLegacyEntity();
}
this._state = this._baseState;
this._index--;
}
};
Tokenizer.prototype._decodeNumericEntity = function (offset, base) {
var sectionStart = this._sectionStart + offset;
if (sectionStart !== this._index) {
//parse entity
var entity = this._buffer.substring(sectionStart, this._index);
var parsed = parseInt(entity, base);
this._emitPartial(decodeCodePoint(parsed));
this._sectionStart = this._index;
} else {
this._sectionStart--;
}
this._state = this._baseState;
};
Tokenizer.prototype._stateInNumericEntity = function (c) {
if (c === ";") {
this._decodeNumericEntity(2, 10);
this._sectionStart++;
} else if (c < "0" || c > "9") {
if (!this._xmlMode) {
this._decodeNumericEntity(2, 10);
} else {
this._state = this._baseState;
}
this._index--;
}
};
Tokenizer.prototype._stateInHexEntity = function (c) {
if (c === ";") {
this._decodeNumericEntity(3, 16);
this._sectionStart++;
} else if ((c < "a" || c > "f") && (c < "A" || c > "F") && (c < "0" || c > "9")) {
if (!this._xmlMode) {
this._decodeNumericEntity(3, 16);
} else {
this._state = this._baseState;
}
this._index--;
}
};
Tokenizer.prototype._cleanup = function () {
if (this._sectionStart < 0) {
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else if (this._running) {
if (this._state === TEXT) {
if (this._sectionStart !== this._index) {
this._cbs.ontext(this._buffer.substr(this._sectionStart));
}
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else if (this._sectionStart === this._index) {
//the section just started
this._buffer = "";
this._bufferOffset += this._index;
this._index = 0;
} else {
//remove everything unnecessary
this._buffer = this._buffer.substr(this._sectionStart);
this._index -= this._sectionStart;
this._bufferOffset += this._sectionStart;
}
this._sectionStart = 0;
}
};
//TODO make events conditional
Tokenizer.prototype.write = function (chunk) {
if (this._ended) this._cbs.onerror(Error(".write() after done!"));
this._buffer += chunk;
this._parse();
};
Tokenizer.prototype._parse = function () {
while (this._index < this._buffer.length && this._running) {
var c = this._buffer.charAt(this._index);
if (this._state === TEXT) {
this._stateText(c);
} else if (this._state === BEFORE_TAG_NAME) {
this._stateBeforeTagName(c);
} else if (this._state === IN_TAG_NAME) {
this._stateInTagName(c);
} else if (this._state === BEFORE_CLOSING_TAG_NAME) {
this._stateBeforeCloseingTagName(c);
} else if (this._state === IN_CLOSING_TAG_NAME) {
this._stateInCloseingTagName(c);
} else if (this._state === AFTER_CLOSING_TAG_NAME) {
this._stateAfterCloseingTagName(c);
} else if (this._state === IN_SELF_CLOSING_TAG) {
this._stateInSelfClosingTag(c);
} else if (this._state === BEFORE_ATTRIBUTE_NAME) {
/*
* attributes
*/
this._stateBeforeAttributeName(c);
} else if (this._state === IN_ATTRIBUTE_NAME) {
this._stateInAttributeName(c);
} else if (this._state === AFTER_ATTRIBUTE_NAME) {
this._stateAfterAttributeName(c);
} else if (this._state === BEFORE_ATTRIBUTE_VALUE) {
this._stateBeforeAttributeValue(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_DQ) {
this._stateInAttributeValueDoubleQuotes(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_SQ) {
this._stateInAttributeValueSingleQuotes(c);
} else if (this._state === IN_ATTRIBUTE_VALUE_NQ) {
this._stateInAttributeValueNoQuotes(c);
} else if (this._state === BEFORE_DECLARATION) {
/*
* declarations
*/
this._stateBeforeDeclaration(c);
} else if (this._state === IN_DECLARATION) {
this._stateInDeclaration(c);
} else if (this._state === IN_PROCESSING_INSTRUCTION) {
/*
* processing instructions
*/
this._stateInProcessingInstruction(c);
} else if (this._state === BEFORE_COMMENT) {
/*
* comments
*/
this._stateBeforeComment(c);
} else if (this._state === IN_COMMENT) {
this._stateInComment(c);
} else if (this._state === AFTER_COMMENT_1) {
this._stateAfterComment1(c);
} else if (this._state === AFTER_COMMENT_2) {
this._stateAfterComment2(c);
} else if (this._state === BEFORE_CDATA_1) {
/*
* cdata
*/
this._stateBeforeCdata1(c);
} else if (this._state === BEFORE_CDATA_2) {
this._stateBeforeCdata2(c);
} else if (this._state === BEFORE_CDATA_3) {
this._stateBeforeCdata3(c);
} else if (this._state === BEFORE_CDATA_4) {
this._stateBeforeCdata4(c);
} else if (this._state === BEFORE_CDATA_5) {
this._stateBeforeCdata5(c);
} else if (this._state === BEFORE_CDATA_6) {
this._stateBeforeCdata6(c);
} else if (this._state === IN_CDATA) {
this._stateInCdata(c);
} else if (this._state === AFTER_CDATA_1) {
this._stateAfterCdata1(c);
} else if (this._state === AFTER_CDATA_2) {
this._stateAfterCdata2(c);
} else if (this._state === BEFORE_SPECIAL) {
/*
* special tags
*/
this._stateBeforeSpecial(c);
} else if (this._state === BEFORE_SPECIAL_END) {
this._stateBeforeSpecialEnd(c);
} else if (this._state === BEFORE_SCRIPT_1) {
/*
* script
*/
this._stateBeforeScript1(c);
} else if (this._state === BEFORE_SCRIPT_2) {
this._stateBeforeScript2(c);
} else if (this._state === BEFORE_SCRIPT_3) {
this._stateBeforeScript3(c);
} else if (this._state === BEFORE_SCRIPT_4) {
this._stateBeforeScript4(c);
} else if (this._state === BEFORE_SCRIPT_5) {
this._stateBeforeScript5(c);
} else if (this._state === AFTER_SCRIPT_1) {
this._stateAfterScript1(c);
} else if (this._state === AFTER_SCRIPT_2) {
this._stateAfterScript2(c);
} else if (this._state === AFTER_SCRIPT_3) {
this._stateAfterScript3(c);
} else if (this._state === AFTER_SCRIPT_4) {
this._stateAfterScript4(c);
} else if (this._state === AFTER_SCRIPT_5) {
this._stateAfterScript5(c);
} else if (this._state === BEFORE_STYLE_1) {
/*
* style
*/
this._stateBeforeStyle1(c);
} else if (this._state === BEFORE_STYLE_2) {
this._stateBeforeStyle2(c);
} else if (this._state === BEFORE_STYLE_3) {
this._stateBeforeStyle3(c);
} else if (this._state === BEFORE_STYLE_4) {
this._stateBeforeStyle4(c);
} else if (this._state === AFTER_STYLE_1) {
this._stateAfterStyle1(c);
} else if (this._state === AFTER_STYLE_2) {
this._stateAfterStyle2(c);
} else if (this._state === AFTER_STYLE_3) {
this._stateAfterStyle3(c);
} else if (this._state === AFTER_STYLE_4) {
this._stateAfterStyle4(c);
} else if (this._state === BEFORE_ENTITY) {
/*
* entities
*/
this._stateBeforeEntity(c);
} else if (this._state === BEFORE_NUMERIC_ENTITY) {
this._stateBeforeNumericEntity(c);
} else if (this._state === IN_NAMED_ENTITY) {
this._stateInNamedEntity(c);
} else if (this._state === IN_NUMERIC_ENTITY) {
this._stateInNumericEntity(c);
} else if (this._state === IN_HEX_ENTITY) {
this._stateInHexEntity(c);
} else {
this._cbs.onerror(Error("unknown _state"), this._state);
}
this._index++;
}
this._cleanup();
};
Tokenizer.prototype.pause = function () {
this._running = false;
};
Tokenizer.prototype.resume = function () {
this._running = true;
if (this._index < this._buffer.length) {
this._parse();
}
if (this._ended) {
this._finish();
}
};
Tokenizer.prototype.end = function (chunk) {
if (this._ended) this._cbs.onerror(Error(".end() after done!"));
if (chunk) this.write(chunk);
this._ended = true;
if (this._running) this._finish();
};
Tokenizer.prototype._finish = function () {
//if there is remaining data, emit it in a reasonable way
if (this._sectionStart < this._index) {
this._handleTrailingData();
}
this._cbs.onend();
};
Tokenizer.prototype._handleTrailingData = function () {
var data = this._buffer.substr(this._sectionStart);
if (this._state === IN_CDATA || this._state === AFTER_CDATA_1 || this._state === AFTER_CDATA_2) {
this._cbs.oncdata(data);
} else if (this._state === IN_COMMENT || this._state === AFTER_COMMENT_1 || this._state === AFTER_COMMENT_2) {
this._cbs.oncomment(data);
} else if (this._state === IN_NAMED_ENTITY && !this._xmlMode) {
this._parseLegacyEntity();
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state === IN_NUMERIC_ENTITY && !this._xmlMode) {
this._decodeNumericEntity(2, 10);
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state === IN_HEX_ENTITY && !this._xmlMode) {
this._decodeNumericEntity(3, 16);
if (this._sectionStart < this._index) {
this._state = this._baseState;
this._handleTrailingData();
}
} else if (this._state !== IN_TAG_NAME && this._state !== BEFORE_ATTRIBUTE_NAME && this._state !== BEFORE_ATTRIBUTE_VALUE && this._state !== AFTER_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_NAME && this._state !== IN_ATTRIBUTE_VALUE_SQ && this._state !== IN_ATTRIBUTE_VALUE_DQ && this._state !== IN_ATTRIBUTE_VALUE_NQ && this._state !== IN_CLOSING_TAG_NAME) {
this._cbs.ontext(data);
}
//else, ignore remaining data
//TODO add a way to remove current tag
};
Tokenizer.prototype.reset = function () {
Tokenizer.call(this, { xmlMode: this._xmlMode, decodeEntities: this._decodeEntities }, this._cbs);
};
Tokenizer.prototype.getAbsoluteIndex = function () {
return this._bufferOffset + this._index;
};
Tokenizer.prototype._getSection = function () {
return this._buffer.substring(this._sectionStart, this._index);
};
Tokenizer.prototype._emitToken = function (name) {
this._cbs[name](this._getSection());
this._sectionStart = -1;
};
Tokenizer.prototype._emitPartial = function (value) {
if (this._baseState !== TEXT) {
this._cbs.onattribdata(value); //TODO implement the new event
} else {
this._cbs.ontext(value);
}
};
module.exports = Tokenizer;

View File

@ -0,0 +1 @@
export default function parse(html: any, done: any): void;

View File

@ -0,0 +1,54 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = parse;
var _domhandler = require('domhandler');
var _domhandler2 = _interopRequireDefault(_domhandler);
var _Parser = require('./Parser');
var _Parser2 = _interopRequireDefault(_Parser);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function transformNode(node) {
if (['tag', 'text'].indexOf(node.type) === -1) {
throw new Error('not supported name ' + node.name + ' of type ' + node.type);
}
if (node.type === 'text') {
return {
type: node.type,
text: node.data
};
}
return {
name: node.name,
children: transform(node.children),
attrs: node.attribs
};
}
function transform(nodes) {
return nodes.map(transformNode);
}
function parse(html, done) {
var handler = new _domhandler2['default'](function (err, children) {
if (err) {
console.error(err);
done(err);
}
try {
done(null, transform(children));
} catch (e) {
console.error(e);
done(e);
}
}, {});
var parser = new _Parser2['default'](handler, { xmlMode: true });
parser.write(html);
parser.done();
}
module.exports = exports['default'];

View File

@ -0,0 +1,25 @@
'use strict';
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
var TempCtor = function TempCtor() {};
TempCtor.prototype = superCtor.prototype;
ctor.prototype = new TempCtor();
ctor.prototype.constructor = ctor;
};
}

View File

@ -0,0 +1,104 @@
{
"_args": [
[
{
"raw": "mini-html-parser2",
"scope": null,
"escapedName": "mini-html-parser2",
"name": "mini-html-parser2",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"/data/www/project/shopxo/public/appmini/old/alipay"
]
],
"_from": "mini-html-parser2@latest",
"_hasShrinkwrap": false,
"_id": "mini-html-parser2@0.1.4",
"_inCache": true,
"_location": "/mini-html-parser2",
"_nodeVersion": "8.9.4",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/mini-html-parser2_0.1.4_1555291892292_0.4695965720440094"
},
"_npmUser": {
"name": "issac.lj",
"email": "issac.lj@alibaba-inc.com"
},
"_npmVersion": "5.6.0",
"_phantomChildren": {},
"_requested": {
"raw": "mini-html-parser2",
"scope": null,
"escapedName": "mini-html-parser2",
"name": "mini-html-parser2",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/mini-html-parser2/-/mini-html-parser2-0.1.4.tgz",
"_shasum": "fe972bd76c93237a14a9440573fbda97fd8c0e61",
"_shrinkwrap": null,
"_spec": "mini-html-parser2",
"_where": "/data/www/project/shopxo/public/appmini/old/alipay",
"author": {
"name": "issac.lj@alibaba-inc.com"
},
"bugs": {
"url": "https://github.com/ant-mini-program/mini-html-parser/issues"
},
"dependencies": {
"domhandler": "^2.4.2",
"entities": "^1.1.1",
"events": "^3.0.0"
},
"description": "小程序富文本",
"devDependencies": {
"@types/node": "^11.9.6",
"jest": "^23.6.0",
"rc-tools": "^8.1.5"
},
"directories": {},
"dist": {
"integrity": "sha512-Z0pSC6Idpx6hYDVRu0j8LYoXLkOCxq/mcltmTMunqpFCT8ujyzybMjAuGdmDAh//rvE9tu/e4qAbHOjAjzDNAg==",
"shasum": "fe972bd76c93237a14a9440573fbda97fd8c0e61",
"tarball": "https://registry.npmjs.org/mini-html-parser2/-/mini-html-parser2-0.1.4.tgz",
"fileCount": 18,
"unpackedSize": 86353,
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcs971CRA9TVsSAnZWagAAZgsP/2A3+ebGSyEExrIztYMi\nuWeK/79oOgRpBAbX116YYW5PcduutSTqmZFPeSd6JqkiuwztEZiy3JoVwNCV\nMuAzWm2FU+iVYY0f7QcepOjMgGm27qvvBn4Cdfp7gxEHJdVpPeP5FnShmyxB\nBywDahvW+W6OEnKvxd0kislXmqMN+RwNIR9OHvw51fP8Eu73hte1NpZmLRpM\nBMVxAMwsK30xt9FlGhFxhR2aNH/TH522tVPjEuEK9iAGhRJrHOR1q/JB/kpc\nWFT6SodkGB4NJErVee79Tl5OjIPXlYH1sHEEH1z/96nLU83jVHKGOAGrwqdT\nTytKnAkL6Ie1JaEBQ8plh30FJ/wHG1AmVzgJ/HsPcrFMSMCXVLM07ahBCObE\nthO17rU3QdI8sn+xoPSk8HjU3lD69nxvzFsLHWE3W2JsrSRVElRYl5XJ+D7s\n2HCd+YS7u6JcJbJd30m+R3yKRZq1HNkFw1jKEKRf/a0M2qvajuUxttoem0Ac\nRJ2mkXWQ6tOhokRAtSDmRC/xjn47muEllXn3T8Gc1ER6Fqhr7VxJie6WPoUj\nnzm+BGpeLINUz82EAUwiY32Ry2AT8Y9/+E33qgZ4g6/g14WaxDCIIWuK0PWJ\nBpy70DCxIyj6H/+NfeZXYIXnWNnXvN0weXJAMizGllgBGumkcf0Gn7DWfsSq\nskcD\r\n=h4j9\r\n-----END PGP SIGNATURE-----\r\n"
},
"gitHead": "a041e07dec98b5f76318b2a040f52df07f42e1f7",
"homepage": "https://github.com/ant-mini-program/mini-html-parser#readme",
"keywords": [
"rich-text",
"mini-program",
"html-parser"
],
"main": "lib/index.js",
"maintainers": [
{
"name": "issac.lj",
"email": "issac.lj@alibaba-inc.com"
}
],
"module": "es/index.js",
"name": "mini-html-parser2",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/ant-mini-program/mini-html-parser.git"
},
"scripts": {
"build": "rc-tools run compile",
"pub": "git push origin && npm run build && npm publish",
"test": "jest"
},
"version": "0.1.4"
}