| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 | 'use strict';const Mixin = require('../../utils/mixin');const Tokenizer = require('../../tokenizer');const PositionTrackingPreprocessorMixin = require('../position-tracking/preprocessor-mixin');class LocationInfoTokenizerMixin extends Mixin {    constructor(tokenizer) {        super(tokenizer);        this.tokenizer = tokenizer;        this.posTracker = Mixin.install(tokenizer.preprocessor, PositionTrackingPreprocessorMixin);        this.currentAttrLocation = null;        this.ctLoc = null;    }    _getCurrentLocation() {        return {            startLine: this.posTracker.line,            startCol: this.posTracker.col,            startOffset: this.posTracker.offset,            endLine: -1,            endCol: -1,            endOffset: -1        };    }    _attachCurrentAttrLocationInfo() {        this.currentAttrLocation.endLine = this.posTracker.line;        this.currentAttrLocation.endCol = this.posTracker.col;        this.currentAttrLocation.endOffset = this.posTracker.offset;        const currentToken = this.tokenizer.currentToken;        const currentAttr = this.tokenizer.currentAttr;        if (!currentToken.location.attrs) {            currentToken.location.attrs = Object.create(null);        }        currentToken.location.attrs[currentAttr.name] = this.currentAttrLocation;    }    _getOverriddenMethods(mxn, orig) {        const methods = {            _createStartTagToken() {                orig._createStartTagToken.call(this);                this.currentToken.location = mxn.ctLoc;            },            _createEndTagToken() {                orig._createEndTagToken.call(this);                this.currentToken.location = mxn.ctLoc;            },            _createCommentToken() {                orig._createCommentToken.call(this);                this.currentToken.location = mxn.ctLoc;            },            _createDoctypeToken(initialName) {                orig._createDoctypeToken.call(this, initialName);                this.currentToken.location = mxn.ctLoc;            },            _createCharacterToken(type, ch) {                orig._createCharacterToken.call(this, type, ch);                this.currentCharacterToken.location = mxn.ctLoc;            },            _createEOFToken() {                orig._createEOFToken.call(this);                this.currentToken.location = mxn._getCurrentLocation();            },            _createAttr(attrNameFirstCh) {                orig._createAttr.call(this, attrNameFirstCh);                mxn.currentAttrLocation = mxn._getCurrentLocation();            },            _leaveAttrName(toState) {                orig._leaveAttrName.call(this, toState);                mxn._attachCurrentAttrLocationInfo();            },            _leaveAttrValue(toState) {                orig._leaveAttrValue.call(this, toState);                mxn._attachCurrentAttrLocationInfo();            },            _emitCurrentToken() {                const ctLoc = this.currentToken.location;                //NOTE: if we have pending character token make it's end location equal to the                //current token's start location.                if (this.currentCharacterToken) {                    this.currentCharacterToken.location.endLine = ctLoc.startLine;                    this.currentCharacterToken.location.endCol = ctLoc.startCol;                    this.currentCharacterToken.location.endOffset = ctLoc.startOffset;                }                if (this.currentToken.type === Tokenizer.EOF_TOKEN) {                    ctLoc.endLine = ctLoc.startLine;                    ctLoc.endCol = ctLoc.startCol;                    ctLoc.endOffset = ctLoc.startOffset;                } else {                    ctLoc.endLine = mxn.posTracker.line;                    ctLoc.endCol = mxn.posTracker.col + 1;                    ctLoc.endOffset = mxn.posTracker.offset + 1;                }                orig._emitCurrentToken.call(this);            },            _emitCurrentCharacterToken() {                const ctLoc = this.currentCharacterToken && this.currentCharacterToken.location;                //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),                //then set it's location at the current preprocessor position.                //We don't need to increment preprocessor position, since character token                //emission is always forced by the start of the next character token here.                //So, we already have advanced position.                if (ctLoc && ctLoc.endOffset === -1) {                    ctLoc.endLine = mxn.posTracker.line;                    ctLoc.endCol = mxn.posTracker.col;                    ctLoc.endOffset = mxn.posTracker.offset;                }                orig._emitCurrentCharacterToken.call(this);            }        };        //NOTE: patch initial states for each mode to obtain token start position        Object.keys(Tokenizer.MODE).forEach(modeName => {            const state = Tokenizer.MODE[modeName];            methods[state] = function(cp) {                mxn.ctLoc = mxn._getCurrentLocation();                orig[state].call(this, cp);            };        });        return methods;    }}module.exports = LocationInfoTokenizerMixin;
 |