UNPKG

dynatrace-cordova-outsystems-plugin

Version:

This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con

223 lines (174 loc) 8.54 kB
'use strict'; const Mixin = require('../../utils/mixin'); const Tokenizer = require('../../tokenizer'); const LocationInfoTokenizerMixin = require('./tokenizer-mixin'); const LocationInfoOpenElementStackMixin = require('./open-element-stack-mixin'); const HTML = require('../../common/html'); //Aliases const $ = HTML.TAG_NAMES; class LocationInfoParserMixin extends Mixin { constructor(parser) { super(parser); this.parser = parser; this.treeAdapter = this.parser.treeAdapter; this.posTracker = null; this.lastStartTagToken = null; this.lastFosterParentingLocation = null; this.currentToken = null; } _setStartLocation(element) { let loc = null; if (this.lastStartTagToken) { loc = Object.assign({}, this.lastStartTagToken.location); loc.startTag = this.lastStartTagToken.location; } this.treeAdapter.setNodeSourceCodeLocation(element, loc); } _setEndLocation(element, closingToken) { const loc = this.treeAdapter.getNodeSourceCodeLocation(element); if (loc) { if (closingToken.location) { const ctLoc = closingToken.location; const tn = this.treeAdapter.getTagName(element); // NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing // tag and for cases like <td> <p> </td> - 'p' closes without a closing tag. const isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN && tn === closingToken.tagName; if (isClosingEndTag) { loc.endTag = Object.assign({}, ctLoc); loc.endLine = ctLoc.endLine; loc.endCol = ctLoc.endCol; loc.endOffset = ctLoc.endOffset; } else { loc.endLine = ctLoc.startLine; loc.endCol = ctLoc.startCol; loc.endOffset = ctLoc.startOffset; } } } } _getOverriddenMethods(mxn, orig) { return { _bootstrap(document, fragmentContext) { orig._bootstrap.call(this, document, fragmentContext); mxn.lastStartTagToken = null; mxn.lastFosterParentingLocation = null; mxn.currentToken = null; const tokenizerMixin = Mixin.install(this.tokenizer, LocationInfoTokenizerMixin); mxn.posTracker = tokenizerMixin.posTracker; Mixin.install(this.openElements, LocationInfoOpenElementStackMixin, { onItemPop: function(element) { mxn._setEndLocation(element, mxn.currentToken); } }); }, _runParsingLoop(scriptHandler) { orig._runParsingLoop.call(this, scriptHandler); // NOTE: generate location info for elements // that remains on open element stack for (let i = this.openElements.stackTop; i >= 0; i--) { mxn._setEndLocation(this.openElements.items[i], mxn.currentToken); } }, //Token processing _processTokenInForeignContent(token) { mxn.currentToken = token; orig._processTokenInForeignContent.call(this, token); }, _processToken(token) { mxn.currentToken = token; orig._processToken.call(this, token); //NOTE: <body> and <html> are never popped from the stack, so we need to updated //their end location explicitly. const requireExplicitUpdate = token.type === Tokenizer.END_TAG_TOKEN && (token.tagName === $.HTML || (token.tagName === $.BODY && this.openElements.hasInScope($.BODY))); if (requireExplicitUpdate) { for (let i = this.openElements.stackTop; i >= 0; i--) { const element = this.openElements.items[i]; if (this.treeAdapter.getTagName(element) === token.tagName) { mxn._setEndLocation(element, token); break; } } } }, //Doctype _setDocumentType(token) { orig._setDocumentType.call(this, token); const documentChildren = this.treeAdapter.getChildNodes(this.document); const cnLength = documentChildren.length; for (let i = 0; i < cnLength; i++) { const node = documentChildren[i]; if (this.treeAdapter.isDocumentTypeNode(node)) { this.treeAdapter.setNodeSourceCodeLocation(node, token.location); break; } } }, //Elements _attachElementToTree(element) { //NOTE: _attachElementToTree is called from _appendElement, _insertElement and _insertTemplate methods. //So we will use token location stored in this methods for the element. mxn._setStartLocation(element); mxn.lastStartTagToken = null; orig._attachElementToTree.call(this, element); }, _appendElement(token, namespaceURI) { mxn.lastStartTagToken = token; orig._appendElement.call(this, token, namespaceURI); }, _insertElement(token, namespaceURI) { mxn.lastStartTagToken = token; orig._insertElement.call(this, token, namespaceURI); }, _insertTemplate(token) { mxn.lastStartTagToken = token; orig._insertTemplate.call(this, token); const tmplContent = this.treeAdapter.getTemplateContent(this.openElements.current); this.treeAdapter.setNodeSourceCodeLocation(tmplContent, null); }, _insertFakeRootElement() { orig._insertFakeRootElement.call(this); this.treeAdapter.setNodeSourceCodeLocation(this.openElements.current, null); }, //Comments _appendCommentNode(token, parent) { orig._appendCommentNode.call(this, token, parent); const children = this.treeAdapter.getChildNodes(parent); const commentNode = children[children.length - 1]; this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location); }, //Text _findFosterParentingLocation() { //NOTE: store last foster parenting location, so we will be able to find inserted text //in case of foster parenting mxn.lastFosterParentingLocation = orig._findFosterParentingLocation.call(this); return mxn.lastFosterParentingLocation; }, _insertCharacters(token) { orig._insertCharacters.call(this, token); const hasFosterParent = this._shouldFosterParentOnInsertion(); const parent = (hasFosterParent && mxn.lastFosterParentingLocation.parent) || this.openElements.currentTmplContent || this.openElements.current; const siblings = this.treeAdapter.getChildNodes(parent); const textNodeIdx = hasFosterParent && mxn.lastFosterParentingLocation.beforeElement ? siblings.indexOf(mxn.lastFosterParentingLocation.beforeElement) - 1 : siblings.length - 1; const textNode = siblings[textNodeIdx]; //NOTE: if we have location assigned by another token, then just update end position const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode); if (tnLoc) { tnLoc.endLine = token.location.endLine; tnLoc.endCol = token.location.endCol; tnLoc.endOffset = token.location.endOffset; } else { this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location); } } }; } } module.exports = LocationInfoParserMixin;