source: trip-planner-front/node_modules/parse5/lib/extensions/location-info/parser-mixin.js@ 571e0df

Last change on this file since 571e0df was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 8.5 KB
Line 
1'use strict';
2
3const Mixin = require('../../utils/mixin');
4const Tokenizer = require('../../tokenizer');
5const LocationInfoTokenizerMixin = require('./tokenizer-mixin');
6const LocationInfoOpenElementStackMixin = require('./open-element-stack-mixin');
7const HTML = require('../../common/html');
8
9//Aliases
10const $ = HTML.TAG_NAMES;
11
12class LocationInfoParserMixin extends Mixin {
13 constructor(parser) {
14 super(parser);
15
16 this.parser = parser;
17 this.treeAdapter = this.parser.treeAdapter;
18 this.posTracker = null;
19 this.lastStartTagToken = null;
20 this.lastFosterParentingLocation = null;
21 this.currentToken = null;
22 }
23
24 _setStartLocation(element) {
25 let loc = null;
26
27 if (this.lastStartTagToken) {
28 loc = Object.assign({}, this.lastStartTagToken.location);
29 loc.startTag = this.lastStartTagToken.location;
30 }
31
32 this.treeAdapter.setNodeSourceCodeLocation(element, loc);
33 }
34
35 _setEndLocation(element, closingToken) {
36 const loc = this.treeAdapter.getNodeSourceCodeLocation(element);
37
38 if (loc) {
39 if (closingToken.location) {
40 const ctLoc = closingToken.location;
41 const tn = this.treeAdapter.getTagName(element);
42
43 // NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
44 // tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
45 const isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN && tn === closingToken.tagName;
46 const endLoc = {};
47 if (isClosingEndTag) {
48 endLoc.endTag = Object.assign({}, ctLoc);
49 endLoc.endLine = ctLoc.endLine;
50 endLoc.endCol = ctLoc.endCol;
51 endLoc.endOffset = ctLoc.endOffset;
52 } else {
53 endLoc.endLine = ctLoc.startLine;
54 endLoc.endCol = ctLoc.startCol;
55 endLoc.endOffset = ctLoc.startOffset;
56 }
57
58 this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
59 }
60 }
61 }
62
63 _getOverriddenMethods(mxn, orig) {
64 return {
65 _bootstrap(document, fragmentContext) {
66 orig._bootstrap.call(this, document, fragmentContext);
67
68 mxn.lastStartTagToken = null;
69 mxn.lastFosterParentingLocation = null;
70 mxn.currentToken = null;
71
72 const tokenizerMixin = Mixin.install(this.tokenizer, LocationInfoTokenizerMixin);
73
74 mxn.posTracker = tokenizerMixin.posTracker;
75
76 Mixin.install(this.openElements, LocationInfoOpenElementStackMixin, {
77 onItemPop: function(element) {
78 mxn._setEndLocation(element, mxn.currentToken);
79 }
80 });
81 },
82
83 _runParsingLoop(scriptHandler) {
84 orig._runParsingLoop.call(this, scriptHandler);
85
86 // NOTE: generate location info for elements
87 // that remains on open element stack
88 for (let i = this.openElements.stackTop; i >= 0; i--) {
89 mxn._setEndLocation(this.openElements.items[i], mxn.currentToken);
90 }
91 },
92
93 //Token processing
94 _processTokenInForeignContent(token) {
95 mxn.currentToken = token;
96 orig._processTokenInForeignContent.call(this, token);
97 },
98
99 _processToken(token) {
100 mxn.currentToken = token;
101 orig._processToken.call(this, token);
102
103 //NOTE: <body> and <html> are never popped from the stack, so we need to updated
104 //their end location explicitly.
105 const requireExplicitUpdate =
106 token.type === Tokenizer.END_TAG_TOKEN &&
107 (token.tagName === $.HTML || (token.tagName === $.BODY && this.openElements.hasInScope($.BODY)));
108
109 if (requireExplicitUpdate) {
110 for (let i = this.openElements.stackTop; i >= 0; i--) {
111 const element = this.openElements.items[i];
112
113 if (this.treeAdapter.getTagName(element) === token.tagName) {
114 mxn._setEndLocation(element, token);
115 break;
116 }
117 }
118 }
119 },
120
121 //Doctype
122 _setDocumentType(token) {
123 orig._setDocumentType.call(this, token);
124
125 const documentChildren = this.treeAdapter.getChildNodes(this.document);
126 const cnLength = documentChildren.length;
127
128 for (let i = 0; i < cnLength; i++) {
129 const node = documentChildren[i];
130
131 if (this.treeAdapter.isDocumentTypeNode(node)) {
132 this.treeAdapter.setNodeSourceCodeLocation(node, token.location);
133 break;
134 }
135 }
136 },
137
138 //Elements
139 _attachElementToTree(element) {
140 //NOTE: _attachElementToTree is called from _appendElement, _insertElement and _insertTemplate methods.
141 //So we will use token location stored in this methods for the element.
142 mxn._setStartLocation(element);
143 mxn.lastStartTagToken = null;
144 orig._attachElementToTree.call(this, element);
145 },
146
147 _appendElement(token, namespaceURI) {
148 mxn.lastStartTagToken = token;
149 orig._appendElement.call(this, token, namespaceURI);
150 },
151
152 _insertElement(token, namespaceURI) {
153 mxn.lastStartTagToken = token;
154 orig._insertElement.call(this, token, namespaceURI);
155 },
156
157 _insertTemplate(token) {
158 mxn.lastStartTagToken = token;
159 orig._insertTemplate.call(this, token);
160
161 const tmplContent = this.treeAdapter.getTemplateContent(this.openElements.current);
162
163 this.treeAdapter.setNodeSourceCodeLocation(tmplContent, null);
164 },
165
166 _insertFakeRootElement() {
167 orig._insertFakeRootElement.call(this);
168 this.treeAdapter.setNodeSourceCodeLocation(this.openElements.current, null);
169 },
170
171 //Comments
172 _appendCommentNode(token, parent) {
173 orig._appendCommentNode.call(this, token, parent);
174
175 const children = this.treeAdapter.getChildNodes(parent);
176 const commentNode = children[children.length - 1];
177
178 this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location);
179 },
180
181 //Text
182 _findFosterParentingLocation() {
183 //NOTE: store last foster parenting location, so we will be able to find inserted text
184 //in case of foster parenting
185 mxn.lastFosterParentingLocation = orig._findFosterParentingLocation.call(this);
186
187 return mxn.lastFosterParentingLocation;
188 },
189
190 _insertCharacters(token) {
191 orig._insertCharacters.call(this, token);
192
193 const hasFosterParent = this._shouldFosterParentOnInsertion();
194
195 const parent =
196 (hasFosterParent && mxn.lastFosterParentingLocation.parent) ||
197 this.openElements.currentTmplContent ||
198 this.openElements.current;
199
200 const siblings = this.treeAdapter.getChildNodes(parent);
201
202 const textNodeIdx =
203 hasFosterParent && mxn.lastFosterParentingLocation.beforeElement
204 ? siblings.indexOf(mxn.lastFosterParentingLocation.beforeElement) - 1
205 : siblings.length - 1;
206
207 const textNode = siblings[textNodeIdx];
208
209 //NOTE: if we have location assigned by another token, then just update end position
210 const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode);
211
212 if (tnLoc) {
213 const { endLine, endCol, endOffset } = token.location;
214 this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset });
215 } else {
216 this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location);
217 }
218 }
219 };
220 }
221}
222
223module.exports = LocationInfoParserMixin;
Note: See TracBrowser for help on using the repository browser.