Skip to content

Commit 5b0c72b

Browse files
committed
first commit
0 parents  commit 5b0c72b

File tree

6 files changed

+221
-0
lines changed

6 files changed

+221
-0
lines changed

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 Ryan Carniato
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
HTML parse and stringify utils

index.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
parse: require('./lib/parse'),
3+
stringify: require('./lib/stringify')
4+
}

lib/parse.js

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Based on package html-parse-stringify2
2+
// Expanded to handle webcomponents
3+
4+
var attrRE, lookup, parseTag, pushCommentNode, pushTextNode, tagRE;
5+
6+
tagRE = /(?:<!--[\S\s]*?-->|<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>)/g;
7+
8+
attrRE = /([^\t\n\f \/><"'=]+)|(['"])(.*?)\2/g;
9+
10+
lookup = {
11+
area: true,
12+
base: true,
13+
br: true,
14+
col: true,
15+
embed: true,
16+
hr: true,
17+
img: true,
18+
input: true,
19+
keygen: true,
20+
link: true,
21+
menuitem: true,
22+
meta: true,
23+
param: true,
24+
source: true,
25+
track: true,
26+
wbr: true
27+
};
28+
29+
parseTag = function (tag) {
30+
var i, key, res;
31+
i = 0;
32+
key = void 0;
33+
res = {
34+
type: 'tag',
35+
name: '',
36+
voidElement: false,
37+
attrs: {},
38+
children: []
39+
};
40+
tag.replace(attrRE, function (match) {
41+
if (i % 2) {
42+
key = match;
43+
} else {
44+
if (i === 0) {
45+
if (lookup[match] || tag.charAt(tag.length - 2) === '/') {
46+
res.voidElement = true;
47+
}
48+
res.name = match;
49+
} else {
50+
res.attrs[key] = match.replace(/^['"]|['"]$/g, '');
51+
}
52+
}
53+
i++;
54+
});
55+
return res;
56+
};
57+
58+
// common logic for pushing a child node onto a list
59+
pushTextNode = function (list, html, start) {
60+
var content, end;
61+
// calculate correct end of the content slice in case there's
62+
// no tag after the text node.
63+
end = html.indexOf('<', start);
64+
content = html.slice(start, end === -1 ? void 0 : end);
65+
if (!/^\s*$/.test(content)) {
66+
list.push({
67+
type: 'text',
68+
content: content
69+
});
70+
}
71+
};
72+
73+
pushCommentNode = function (list, tag) {
74+
var content;
75+
// calculate correct end of the content slice in case there's
76+
// no tag after the text node.
77+
content = tag.replace('<!--', '').replace('-->', '');
78+
if (!/^\s*$/.test(content)) {
79+
list.push({
80+
type: 'comment',
81+
content: content
82+
});
83+
}
84+
};
85+
86+
87+
module.exports = function (html) {
88+
var arr, byTag, current, level, result;
89+
result = [];
90+
current = void 0;
91+
level = -1;
92+
arr = [];
93+
byTag = {};
94+
html.replace(tagRE, function (tag, index) {
95+
var isComment, isOpen, nextChar, parent, start;
96+
isOpen = tag.charAt(1) !== '/';
97+
isComment = tag.indexOf('<!--') === 0;
98+
start = index + tag.length;
99+
nextChar = html.charAt(start);
100+
parent = void 0;
101+
if (isOpen && !isComment) {
102+
level++;
103+
current = parseTag(tag);
104+
if (!current.voidElement && nextChar && nextChar !== '<') {
105+
pushTextNode(current.children, html, start);
106+
}
107+
byTag[current.tagName] = current;
108+
// if we're at root, push new base node
109+
if (level === 0) {
110+
result.push(current);
111+
}
112+
parent = arr[level - 1];
113+
if (parent) {
114+
parent.children.push(current);
115+
}
116+
arr[level] = current;
117+
}
118+
if (isComment) {
119+
if (level < 0) {
120+
pushCommentNode(result, tag);
121+
} else {
122+
pushCommentNode(arr[level].children, tag);
123+
}
124+
}
125+
if (isComment || !isOpen || current.voidElement) {
126+
if (!isComment) {
127+
level--;
128+
}
129+
if (nextChar !== '<' && nextChar) {
130+
// trailing text node
131+
// if we're at the root, push a base text node. otherwise add as
132+
// a child to the current node.
133+
parent = level === -1 ? result : arr[level].children;
134+
pushTextNode(parent, html, start);
135+
}
136+
}
137+
});
138+
return result;
139+
};

lib/stringify.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Based on package html-parse-stringify2
2+
// Expanded to handle webcomponents
3+
4+
var attrString, stringify;
5+
6+
attrString = function (attrs) {
7+
var buff, key;
8+
buff = [];
9+
for (key in attrs) {
10+
buff.push(key + '="' + attrs[key] + '"');
11+
}
12+
if (!buff.length) {
13+
return '';
14+
}
15+
return ' ' + buff.join(' ');
16+
};
17+
18+
stringify = function (buff, doc) {
19+
switch (doc.type) {
20+
case 'text':
21+
return buff + doc.content;
22+
case 'tag':
23+
buff += '<' + doc.name + (doc.attrs ? attrString(doc.attrs) : '') + (doc.voidElement ? '/>' : '>');
24+
if (doc.voidElement) {
25+
return buff;
26+
}
27+
return buff + doc.children.reduce(stringify, '') + '</' + doc.name + '>';
28+
case 'comment':
29+
return buff += '<!--' + doc.content + '-->';
30+
}
31+
};
32+
33+
module.exports = function (doc) {
34+
return doc.reduce(function (token, rootEl) {
35+
return token + stringify('', rootEl);
36+
}, '');
37+
};

package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "html-string-parser",
3+
"version": "0.0.1",
4+
"description": "Utils for parsing and stringify html strings",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/ryansolid/html-string-parser.git"
12+
},
13+
"author": "Ryan Carniato <[email protected]>",
14+
"license": "MIT",
15+
"bugs": {
16+
"url": "https://github.com/ryansolid/html-string-parser/issues"
17+
},
18+
"homepage": "https://github.com/ryansolid/html-string-parser#readme"
19+
}

0 commit comments

Comments
 (0)