als-document 1.0.4-alpha → 1.0.5-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/document.js CHANGED
@@ -29,7 +29,7 @@ class SingleNode extends Node{
29
29
  constructor(tagName,attributes={},parent=null)
30
30
  function parseAttributes(str){
31
31
  const attrs={};
32
32
  let key="";
33
33
  let value="";
34
34
  let isKey=true;
35
35
  let quoteChar=null;
36
36
  for (let i=0; i< str.length; i++){
37
37
  const char=str[i];
38
38
  if (isKey && (char==='=' || char===' ')){
39
39
  if (char==='=') isKey=false;
40
40
  else if (key.trim()){
41
41
  attrs[key.trim()]=true;
42
42
  key="";
43
43
  }
44
44
  continue;
45
45
  }
46
46
  if (!quoteChar && (char==='"' || char==="'")){
47
47
  quoteChar=char;
48
48
  continue;
49
49
  } else if (quoteChar && char===quoteChar){
50
50
  quoteChar=null;
51
51
  attrs[key.trim()]=value.trim();
52
52
  key=""; value=""; isKey=true;
53
53
  continue;
54
54
  }
55
55
  if (isKey) key+=char;
56
56
  else value+=char;
57
57
  }
58
58
  if (key.trim() &&!value) attrs[key.trim()]=true;
59
59
  return attrs;
60
60
  }
61
61
  const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
62
- function parseHTML(html){
63
62
  const root=new Node("ROOT");
64
63
  const stack=[root];
65
64
  let currentText="",i=0;
66
65
  let max=0
67
66
  function parseScript(){
68
67
  if (!html.startsWith("<script",i)) return false;
69
68
  const openTagEnd=html.indexOf(">",i);
70
69
  if (openTagEnd===-1) return false;
71
70
  const attributesString=html.substring(i+7,openTagEnd).trim();
72
71
  const attributes=parseAttributes(attributesString);
73
72
  let closeTagStart=html.indexOf("</script>",openTagEnd);
74
73
  if (closeTagStart===-1) return false;
75
74
  const content=html.substring(openTagEnd+1,closeTagStart);
76
75
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
77
76
  if(content.length>0) scriptNode.childNodes.push(content);
78
77
  i=closeTagStart+9;
79
78
  return true;
80
79
  }
81
80
  function parseSpecial(startStr,endStr,n1,n2,tag){
82
81
  if (!html.startsWith(startStr,i)) return false
83
82
  const end=html.indexOf(endStr,i+n1);
84
83
  const strNode=new Node(tag,{},stack[stack.length-1]);
85
84
  strNode.childNodes.push(html.substring(i+n1,end));
86
85
  i=end+n2;
87
86
  return true
88
87
  }
89
88
  while (i< html.length){
90
89
  if(i>=max) max=i;
91
90
  else break;
92
91
  if (parseScript()) continue
93
92
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
94
93
  if (parseSpecial("<style","</style>",7,8,'style')) continue
95
94
  if (html.startsWith("<![CDATA[",i)){
96
95
  const end=html.indexOf("]]>",i+9);
97
96
  if (end===-1) break;
98
97
  const content=html.substring(i+9,end);
99
98
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
100
99
  cdataNode.nodeValue=content;
101
100
  i=end+3;
102
101
  continue;
103
102
  }
104
103
  if (html.startsWith("<",i)){
105
104
  if (currentText){
106
105
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
107
106
  currentText="";
108
107
  }
109
108
  let tagEnd=i+1;
110
109
  let insideQuotes=false;
111
110
  let quoteChar=null;
112
111
  while (tagEnd< html.length){
113
112
  const char=html[tagEnd];
114
113
  if (!insideQuotes && (char==='"' || char==="'")){
115
114
  insideQuotes=true;
116
115
  quoteChar=char;
117
116
  } else if (insideQuotes && char===quoteChar){
118
117
  insideQuotes=false;
119
118
  quoteChar=null;
120
119
  }
121
120
  if (!insideQuotes && char==='>') break;
122
121
  tagEnd++;
123
122
  }
124
123
  const tagContent=html.substring(i+1,tagEnd);
125
124
  if (tagContent.startsWith("/")) stack.pop();
126
125
  else{
127
126
  let isSelfClosing=tagContent.endsWith('/');
128
127
  const tagNameEnd=tagContent.search(/\s|>|\//);
129
128
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
130
129
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
131
130
  const attributes=parseAttributes(attributesString);
132
131
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
133
132
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
134
133
  }
135
134
  i=tagEnd+1;
136
135
  } else{
137
136
  currentText+=html[i];
138
137
  i++;
139
138
  }
140
139
  }
141
140
  if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText));
142
141
  return root;
142
+ function parseHTML(html){
143
143
  const root=new Node("ROOT");
144
144
  const stack=[root];
145
145
  let currentText="",i=0;
146
146
  let max=0
147
147
  function parseScript(){
148
148
  if (!html.startsWith("<script",i)) return false;
149
149
  const openTagEnd=html.indexOf(">",i);
150
150
  if (openTagEnd===-1) return false;
151
151
  const attributesString=html.substring(i+7,openTagEnd).trim();
152
152
  const attributes=parseAttributes(attributesString);
153
153
  let closeTagStart=html.indexOf("</script>",openTagEnd);
154
154
  if (closeTagStart===-1) return false;
155
155
  const content=html.substring(openTagEnd+1,closeTagStart);
156
156
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
157
157
  if(content.length>0) scriptNode.childNodes.push(content);
158
158
  i=closeTagStart+9;
159
159
  return true;
160
160
  }
161
161
  function parseSpecial(startStr,endStr,n1,n2,tag){
162
162
  if (!html.startsWith(startStr,i)) return false
163
163
  const end=html.indexOf(endStr,i+n1);
164
164
  const strNode=new Node(tag,{},stack[stack.length-1]);
165
165
  strNode.childNodes.push(html.substring(i+n1,end));
166
166
  i=end+n2;
167
167
  return true
168
168
  }
169
169
  while (i< html.length){
170
170
  if(i>=max) max=i;
171
171
  else break;
172
172
  if (parseScript()) continue
173
173
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
174
174
  if (parseSpecial("<style","</style>",7,8,'style')) continue
175
175
  if (html.startsWith("<![CDATA[",i)){
176
176
  const end=html.indexOf("]]>",i+9);
177
177
  if (end===-1) break;
178
178
  const content=html.substring(i+9,end);
179
179
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
180
180
  cdataNode.nodeValue=content;
181
181
  i=end+3;
182
182
  continue;
183
183
  }
184
184
  if (html.startsWith("<",i)){
185
185
  if (currentText && stack[stack.length-1]){
186
186
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
187
187
  currentText="";
188
188
  }
189
189
  let tagEnd=i+1;
190
190
  let insideQuotes=false;
191
191
  let quoteChar=null;
192
192
  while (tagEnd< html.length){
193
193
  const char=html[tagEnd];
194
194
  if (!insideQuotes && (char==='"' || char==="'")){
195
195
  insideQuotes=true;
196
196
  quoteChar=char;
197
197
  } else if (insideQuotes && char===quoteChar){
198
198
  insideQuotes=false;
199
199
  quoteChar=null;
200
200
  }
201
201
  if (!insideQuotes && char==='>') break;
202
202
  tagEnd++;
203
203
  }
204
204
  const tagContent=html.substring(i+1,tagEnd);
205
205
  if (tagContent.startsWith("/")) stack.pop();
206
206
  else{
207
207
  let isSelfClosing=tagContent.endsWith('/');
208
208
  const tagNameEnd=tagContent.search(/\s|>|\//);
209
209
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
210
210
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
211
211
  const attributes=parseAttributes(attributesString);
212
212
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
213
213
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
214
214
  }
215
215
  i=tagEnd+1;
216
216
  } else{
217
217
  currentText+=html[i];
218
218
  i++;
219
219
  }
220
220
  }
221
221
  if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
222
222
  return root;
223
223
  }
224
224
  return { parseHTML, Node, Query, TextNode, SingleNode }
225
225
  })()
package/index.js CHANGED
@@ -28,6 +28,6 @@ class SingleNode extends Node{
28
28
  constructor(tagName,attributes={},parent=null)
29
29
  function parseAttributes(str){
30
30
  const attrs={};
31
31
  let key="";
32
32
  let value="";
33
33
  let isKey=true;
34
34
  let quoteChar=null;
35
35
  for (let i=0; i< str.length; i++){
36
36
  const char=str[i];
37
37
  if (isKey && (char==='=' || char===' ')){
38
38
  if (char==='=') isKey=false;
39
39
  else if (key.trim()){
40
40
  attrs[key.trim()]=true;
41
41
  key="";
42
42
  }
43
43
  continue;
44
44
  }
45
45
  if (!quoteChar && (char==='"' || char==="'")){
46
46
  quoteChar=char;
47
47
  continue;
48
48
  } else if (quoteChar && char===quoteChar){
49
49
  quoteChar=null;
50
50
  attrs[key.trim()]=value.trim();
51
51
  key=""; value=""; isKey=true;
52
52
  continue;
53
53
  }
54
54
  if (isKey) key+=char;
55
55
  else value+=char;
56
56
  }
57
57
  if (key.trim() &&!value) attrs[key.trim()]=true;
58
58
  return attrs;
59
59
  }
60
60
  const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
61
- function parseHTML(html){
62
61
  const root=new Node("ROOT");
63
62
  const stack=[root];
64
63
  let currentText="",i=0;
65
64
  let max=0
66
65
  function parseScript(){
67
66
  if (!html.startsWith("<script",i)) return false;
68
67
  const openTagEnd=html.indexOf(">",i);
69
68
  if (openTagEnd===-1) return false;
70
69
  const attributesString=html.substring(i+7,openTagEnd).trim();
71
70
  const attributes=parseAttributes(attributesString);
72
71
  let closeTagStart=html.indexOf("</script>",openTagEnd);
73
72
  if (closeTagStart===-1) return false;
74
73
  const content=html.substring(openTagEnd+1,closeTagStart);
75
74
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
76
75
  if(content.length>0) scriptNode.childNodes.push(content);
77
76
  i=closeTagStart+9;
78
77
  return true;
79
78
  }
80
79
  function parseSpecial(startStr,endStr,n1,n2,tag){
81
80
  if (!html.startsWith(startStr,i)) return false
82
81
  const end=html.indexOf(endStr,i+n1);
83
82
  const strNode=new Node(tag,{},stack[stack.length-1]);
84
83
  strNode.childNodes.push(html.substring(i+n1,end));
85
84
  i=end+n2;
86
85
  return true
87
86
  }
88
87
  while (i< html.length){
89
88
  if(i>=max) max=i;
90
89
  else break;
91
90
  if (parseScript()) continue
92
91
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
93
92
  if (parseSpecial("<style","</style>",7,8,'style')) continue
94
93
  if (html.startsWith("<![CDATA[",i)){
95
94
  const end=html.indexOf("]]>",i+9);
96
95
  if (end===-1) break;
97
96
  const content=html.substring(i+9,end);
98
97
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
99
98
  cdataNode.nodeValue=content;
100
99
  i=end+3;
101
100
  continue;
102
101
  }
103
102
  if (html.startsWith("<",i)){
104
103
  if (currentText){
105
104
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
106
105
  currentText="";
107
106
  }
108
107
  let tagEnd=i+1;
109
108
  let insideQuotes=false;
110
109
  let quoteChar=null;
111
110
  while (tagEnd< html.length){
112
111
  const char=html[tagEnd];
113
112
  if (!insideQuotes && (char==='"' || char==="'")){
114
113
  insideQuotes=true;
115
114
  quoteChar=char;
116
115
  } else if (insideQuotes && char===quoteChar){
117
116
  insideQuotes=false;
118
117
  quoteChar=null;
119
118
  }
120
119
  if (!insideQuotes && char==='>') break;
121
120
  tagEnd++;
122
121
  }
123
122
  const tagContent=html.substring(i+1,tagEnd);
124
123
  if (tagContent.startsWith("/")) stack.pop();
125
124
  else{
126
125
  let isSelfClosing=tagContent.endsWith('/');
127
126
  const tagNameEnd=tagContent.search(/\s|>|\//);
128
127
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
129
128
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
130
129
  const attributes=parseAttributes(attributesString);
131
130
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
132
131
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
133
132
  }
134
133
  i=tagEnd+1;
135
134
  } else{
136
135
  currentText+=html[i];
137
136
  i++;
138
137
  }
139
138
  }
140
139
  if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText));
141
140
  return root;
141
+ function parseHTML(html){
142
142
  const root=new Node("ROOT");
143
143
  const stack=[root];
144
144
  let currentText="",i=0;
145
145
  let max=0
146
146
  function parseScript(){
147
147
  if (!html.startsWith("<script",i)) return false;
148
148
  const openTagEnd=html.indexOf(">",i);
149
149
  if (openTagEnd===-1) return false;
150
150
  const attributesString=html.substring(i+7,openTagEnd).trim();
151
151
  const attributes=parseAttributes(attributesString);
152
152
  let closeTagStart=html.indexOf("</script>",openTagEnd);
153
153
  if (closeTagStart===-1) return false;
154
154
  const content=html.substring(openTagEnd+1,closeTagStart);
155
155
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
156
156
  if(content.length>0) scriptNode.childNodes.push(content);
157
157
  i=closeTagStart+9;
158
158
  return true;
159
159
  }
160
160
  function parseSpecial(startStr,endStr,n1,n2,tag){
161
161
  if (!html.startsWith(startStr,i)) return false
162
162
  const end=html.indexOf(endStr,i+n1);
163
163
  const strNode=new Node(tag,{},stack[stack.length-1]);
164
164
  strNode.childNodes.push(html.substring(i+n1,end));
165
165
  i=end+n2;
166
166
  return true
167
167
  }
168
168
  while (i< html.length){
169
169
  if(i>=max) max=i;
170
170
  else break;
171
171
  if (parseScript()) continue
172
172
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
173
173
  if (parseSpecial("<style","</style>",7,8,'style')) continue
174
174
  if (html.startsWith("<![CDATA[",i)){
175
175
  const end=html.indexOf("]]>",i+9);
176
176
  if (end===-1) break;
177
177
  const content=html.substring(i+9,end);
178
178
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
179
179
  cdataNode.nodeValue=content;
180
180
  i=end+3;
181
181
  continue;
182
182
  }
183
183
  if (html.startsWith("<",i)){
184
184
  if (currentText && stack[stack.length-1]){
185
185
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
186
186
  currentText="";
187
187
  }
188
188
  let tagEnd=i+1;
189
189
  let insideQuotes=false;
190
190
  let quoteChar=null;
191
191
  while (tagEnd< html.length){
192
192
  const char=html[tagEnd];
193
193
  if (!insideQuotes && (char==='"' || char==="'")){
194
194
  insideQuotes=true;
195
195
  quoteChar=char;
196
196
  } else if (insideQuotes && char===quoteChar){
197
197
  insideQuotes=false;
198
198
  quoteChar=null;
199
199
  }
200
200
  if (!insideQuotes && char==='>') break;
201
201
  tagEnd++;
202
202
  }
203
203
  const tagContent=html.substring(i+1,tagEnd);
204
204
  if (tagContent.startsWith("/")) stack.pop();
205
205
  else{
206
206
  let isSelfClosing=tagContent.endsWith('/');
207
207
  const tagNameEnd=tagContent.search(/\s|>|\//);
208
208
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
209
209
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
210
210
  const attributes=parseAttributes(attributesString);
211
211
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
212
212
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
213
213
  }
214
214
  i=tagEnd+1;
215
215
  } else{
216
216
  currentText+=html[i];
217
217
  i++;
218
218
  }
219
219
  }
220
220
  if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
221
221
  return root;
222
222
  }
223
223
  module.exports = { parseHTML, Node, Query, TextNode, SingleNode }
package/index.mjs CHANGED
@@ -28,6 +28,6 @@ class SingleNode extends Node{
28
28
  constructor(tagName,attributes={},parent=null)
29
29
  function parseAttributes(str){
30
30
  const attrs={};
31
31
  let key="";
32
32
  let value="";
33
33
  let isKey=true;
34
34
  let quoteChar=null;
35
35
  for (let i=0; i< str.length; i++){
36
36
  const char=str[i];
37
37
  if (isKey && (char==='=' || char===' ')){
38
38
  if (char==='=') isKey=false;
39
39
  else if (key.trim()){
40
40
  attrs[key.trim()]=true;
41
41
  key="";
42
42
  }
43
43
  continue;
44
44
  }
45
45
  if (!quoteChar && (char==='"' || char==="'")){
46
46
  quoteChar=char;
47
47
  continue;
48
48
  } else if (quoteChar && char===quoteChar){
49
49
  quoteChar=null;
50
50
  attrs[key.trim()]=value.trim();
51
51
  key=""; value=""; isKey=true;
52
52
  continue;
53
53
  }
54
54
  if (isKey) key+=char;
55
55
  else value+=char;
56
56
  }
57
57
  if (key.trim() &&!value) attrs[key.trim()]=true;
58
58
  return attrs;
59
59
  }
60
60
  const VOID_TAGS=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr","!doctype",'?xml']);
61
- function parseHTML(html){
62
61
  const root=new Node("ROOT");
63
62
  const stack=[root];
64
63
  let currentText="",i=0;
65
64
  let max=0
66
65
  function parseScript(){
67
66
  if (!html.startsWith("<script",i)) return false;
68
67
  const openTagEnd=html.indexOf(">",i);
69
68
  if (openTagEnd===-1) return false;
70
69
  const attributesString=html.substring(i+7,openTagEnd).trim();
71
70
  const attributes=parseAttributes(attributesString);
72
71
  let closeTagStart=html.indexOf("</script>",openTagEnd);
73
72
  if (closeTagStart===-1) return false;
74
73
  const content=html.substring(openTagEnd+1,closeTagStart);
75
74
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
76
75
  if(content.length>0) scriptNode.childNodes.push(content);
77
76
  i=closeTagStart+9;
78
77
  return true;
79
78
  }
80
79
  function parseSpecial(startStr,endStr,n1,n2,tag){
81
80
  if (!html.startsWith(startStr,i)) return false
82
81
  const end=html.indexOf(endStr,i+n1);
83
82
  const strNode=new Node(tag,{},stack[stack.length-1]);
84
83
  strNode.childNodes.push(html.substring(i+n1,end));
85
84
  i=end+n2;
86
85
  return true
87
86
  }
88
87
  while (i< html.length){
89
88
  if(i>=max) max=i;
90
89
  else break;
91
90
  if (parseScript()) continue
92
91
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
93
92
  if (parseSpecial("<style","</style>",7,8,'style')) continue
94
93
  if (html.startsWith("<![CDATA[",i)){
95
94
  const end=html.indexOf("]]>",i+9);
96
95
  if (end===-1) break;
97
96
  const content=html.substring(i+9,end);
98
97
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
99
98
  cdataNode.nodeValue=content;
100
99
  i=end+3;
101
100
  continue;
102
101
  }
103
102
  if (html.startsWith("<",i)){
104
103
  if (currentText){
105
104
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
106
105
  currentText="";
107
106
  }
108
107
  let tagEnd=i+1;
109
108
  let insideQuotes=false;
110
109
  let quoteChar=null;
111
110
  while (tagEnd< html.length){
112
111
  const char=html[tagEnd];
113
112
  if (!insideQuotes && (char==='"' || char==="'")){
114
113
  insideQuotes=true;
115
114
  quoteChar=char;
116
115
  } else if (insideQuotes && char===quoteChar){
117
116
  insideQuotes=false;
118
117
  quoteChar=null;
119
118
  }
120
119
  if (!insideQuotes && char==='>') break;
121
120
  tagEnd++;
122
121
  }
123
122
  const tagContent=html.substring(i+1,tagEnd);
124
123
  if (tagContent.startsWith("/")) stack.pop();
125
124
  else{
126
125
  let isSelfClosing=tagContent.endsWith('/');
127
126
  const tagNameEnd=tagContent.search(/\s|>|\//);
128
127
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
129
128
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
130
129
  const attributes=parseAttributes(attributesString);
131
130
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
132
131
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
133
132
  }
134
133
  i=tagEnd+1;
135
134
  } else{
136
135
  currentText+=html[i];
137
136
  i++;
138
137
  }
139
138
  }
140
139
  if (currentText.trim()) stack[stack.length-1].childNodes.push(new TextNode(currentText));
141
140
  return root;
141
+ function parseHTML(html){
142
142
  const root=new Node("ROOT");
143
143
  const stack=[root];
144
144
  let currentText="",i=0;
145
145
  let max=0
146
146
  function parseScript(){
147
147
  if (!html.startsWith("<script",i)) return false;
148
148
  const openTagEnd=html.indexOf(">",i);
149
149
  if (openTagEnd===-1) return false;
150
150
  const attributesString=html.substring(i+7,openTagEnd).trim();
151
151
  const attributes=parseAttributes(attributesString);
152
152
  let closeTagStart=html.indexOf("</script>",openTagEnd);
153
153
  if (closeTagStart===-1) return false;
154
154
  const content=html.substring(openTagEnd+1,closeTagStart);
155
155
  const scriptNode=new Node('script',attributes,stack[stack.length-1]);
156
156
  if(content.length>0) scriptNode.childNodes.push(content);
157
157
  i=closeTagStart+9;
158
158
  return true;
159
159
  }
160
160
  function parseSpecial(startStr,endStr,n1,n2,tag){
161
161
  if (!html.startsWith(startStr,i)) return false
162
162
  const end=html.indexOf(endStr,i+n1);
163
163
  const strNode=new Node(tag,{},stack[stack.length-1]);
164
164
  strNode.childNodes.push(html.substring(i+n1,end));
165
165
  i=end+n2;
166
166
  return true
167
167
  }
168
168
  while (i< html.length){
169
169
  if(i>=max) max=i;
170
170
  else break;
171
171
  if (parseScript()) continue
172
172
  if (parseSpecial("<!--","-->",4,3,'#comment')) continue
173
173
  if (parseSpecial("<style","</style>",7,8,'style')) continue
174
174
  if (html.startsWith("<![CDATA[",i)){
175
175
  const end=html.indexOf("]]>",i+9);
176
176
  if (end===-1) break;
177
177
  const content=html.substring(i+9,end);
178
178
  const cdataNode=new SingleNode("#cdata-section",{},stack[stack.length-1]);
179
179
  cdataNode.nodeValue=content;
180
180
  i=end+3;
181
181
  continue;
182
182
  }
183
183
  if (html.startsWith("<",i)){
184
184
  if (currentText && stack[stack.length-1]){
185
185
  stack[stack.length-1].childNodes.push(new TextNode(currentText));
186
186
  currentText="";
187
187
  }
188
188
  let tagEnd=i+1;
189
189
  let insideQuotes=false;
190
190
  let quoteChar=null;
191
191
  while (tagEnd< html.length){
192
192
  const char=html[tagEnd];
193
193
  if (!insideQuotes && (char==='"' || char==="'")){
194
194
  insideQuotes=true;
195
195
  quoteChar=char;
196
196
  } else if (insideQuotes && char===quoteChar){
197
197
  insideQuotes=false;
198
198
  quoteChar=null;
199
199
  }
200
200
  if (!insideQuotes && char==='>') break;
201
201
  tagEnd++;
202
202
  }
203
203
  const tagContent=html.substring(i+1,tagEnd);
204
204
  if (tagContent.startsWith("/")) stack.pop();
205
205
  else{
206
206
  let isSelfClosing=tagContent.endsWith('/');
207
207
  const tagNameEnd=tagContent.search(/\s|>|\//);
208
208
  const tagName=tagContent.substring(0,tagNameEnd>0 ? tagNameEnd : tagEnd-i-1);
209
209
  const attributesString=tagContent.substring(tagName.length,isSelfClosing ? tagContent.length-1 : tagContent.length).trim();
210
210
  const attributes=parseAttributes(attributesString);
211
211
  if (VOID_TAGS.has(tagName.toLowerCase()) || isSelfClosing) new SingleNode(tagName,attributes,stack[stack.length-1])
212
212
  else stack.push(new Node(tagName,attributes,stack[stack.length-1]));
213
213
  }
214
214
  i=tagEnd+1;
215
215
  } else{
216
216
  currentText+=html[i];
217
217
  i++;
218
218
  }
219
219
  }
220
220
  if (currentText.trim() && stack[stack.length-1]) stack[stack.length-1].childNodes.push(new TextNode(currentText));
221
221
  return root;
222
222
  }
223
223
  export default { parseHTML, Node, Query, TextNode, SingleNode }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "als-document",
3
- "version": "1.0.4-alpha",
3
+ "version": "1.0.5-alpha",
4
4
  "description": "A powerful HTML parser & DOM manipulation library for both backend and frontend.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -51,7 +51,7 @@ function parseHTML(html) {
51
51
  }
52
52
 
53
53
  if (html.startsWith("<", i)) {
54
- if (currentText) {
54
+ if (currentText && stack[stack.length - 1]) {
55
55
  stack[stack.length - 1].childNodes.push(new TextNode(currentText));
56
56
  currentText = "";
57
57
  }
@@ -91,6 +91,6 @@ function parseHTML(html) {
91
91
  i++;
92
92
  }
93
93
  }
94
- if (currentText.trim()) stack[stack.length - 1].childNodes.push(new TextNode(currentText));
94
+ if (currentText.trim() && stack[stack.length - 1]) stack[stack.length - 1].childNodes.push(new TextNode(currentText));
95
95
  return root;
96
96
  }
package/tests/index.html CHANGED
@@ -14,8 +14,8 @@
14
14
  let {describe,it,beforeEach,runTests,expect,delay,assert,beforeAll} = SimpleTest
15
15
  SimpleTest.showFullError = true
16
16
  </script>
17
- <script src="./query.js"></script>
18
17
  <script src="utils.js"></script>
18
+ <script src="./query.js"></script>
19
19
  <script src="parser.js"></script>
20
20
  <script src="node.js"></script>
21
21
  </head>
package/tests/node.js CHANGED
@@ -130,7 +130,7 @@ describe('Content Manipulation', () => {
130
130
  expect(rootNode.childNodes[2].tagName).equalTo('a');
131
131
 
132
132
  childNode.insertAdjacentHTML('beforebegin', '<strong></strong>');
133
- expect(rootNode.childNodes[0].tagName).equalTo('strong');
133
+ expect(rootNode.childNodes[1].tagName).equalTo('strong');
134
134
 
135
135
  childNode.insertAdjacentText('afterend', 'Some text');
136
136
  expect(typeof rootNode.childNodes[3].nodeValue).equalTo('string');
package/tests/parser.js CHANGED
@@ -225,11 +225,11 @@ describe('signle tags, script and style', () => {
225
225
  <link rel="stylesheet" href="styles.css">
226
226
  `;
227
227
  const rootMetaLink = parseHTML(testMetaLink);
228
- assert(rootMetaLink.childNodes[0].tagName === "meta", "Test Meta/Link 1: Meta tag not created");
229
- assert(rootMetaLink.childNodes[0].getAttribute("charset") === "UTF-8", "Test Meta/Link 1: Meta content not correct");
230
- assert(rootMetaLink.childNodes[1].tagName === "link", "Test Meta/Link 2: Link tag not created");
231
- assert(rootMetaLink.childNodes[1].getAttribute("rel") === "stylesheet", "Test Meta/Link 2: Link rel attribute not correct");
232
- assert(rootMetaLink.childNodes[1].getAttribute("href") === "styles.css", "Test Meta/Link 2: Link href attribute not correct");
228
+ assert(rootMetaLink.children[0].tagName === "meta", "Test Meta/Link 1: Meta tag not created");
229
+ assert(rootMetaLink.children[0].getAttribute("charset") === "UTF-8", "Test Meta/Link 1: Meta content not correct");
230
+ assert(rootMetaLink.children[1].tagName === "link", "Test Meta/Link 2: Link tag not created");
231
+ assert(rootMetaLink.children[1].getAttribute("rel") === "stylesheet", "Test Meta/Link 2: Link rel attribute not correct");
232
+ assert(rootMetaLink.children[1].getAttribute("href") === "styles.css", "Test Meta/Link 2: Link href attribute not correct");
233
233
  })
234
234
 
235
235
  it('broken html structure', () => {