• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3exports.assign = function (tokenizer) {
4    //NOTE: obtain Tokenizer proto this way to avoid module circular references
5    var tokenizerProto = Object.getPrototypeOf(tokenizer);
6
7    tokenizer.tokenStartLoc = -1;
8
9    //NOTE: add location info builder method
10    tokenizer._attachLocationInfo = function (token) {
11        token.location = {
12            start: this.tokenStartLoc,
13            end: -1
14        };
15    };
16
17    //NOTE: patch token creation methods and attach location objects
18    tokenizer._createStartTagToken = function (tagNameFirstCh) {
19        tokenizerProto._createStartTagToken.call(this, tagNameFirstCh);
20        this._attachLocationInfo(this.currentToken);
21    };
22
23    tokenizer._createEndTagToken = function (tagNameFirstCh) {
24        tokenizerProto._createEndTagToken.call(this, tagNameFirstCh);
25        this._attachLocationInfo(this.currentToken);
26    };
27
28    tokenizer._createCommentToken = function () {
29        tokenizerProto._createCommentToken.call(this);
30        this._attachLocationInfo(this.currentToken);
31    };
32
33    tokenizer._createDoctypeToken = function (doctypeNameFirstCh) {
34        tokenizerProto._createDoctypeToken.call(this, doctypeNameFirstCh);
35        this._attachLocationInfo(this.currentToken);
36    };
37
38    tokenizer._createCharacterToken = function (type, ch) {
39        tokenizerProto._createCharacterToken.call(this, type, ch);
40        this._attachLocationInfo(this.currentCharacterToken);
41    };
42
43    //NOTE: patch token emission methods to determine end location
44    tokenizer._emitCurrentToken = function () {
45        //NOTE: if we have pending character token make it's end location equal to the
46        //current token's start location.
47        if (this.currentCharacterToken)
48            this.currentCharacterToken.location.end = this.currentToken.location.start;
49
50        this.currentToken.location.end = this.preprocessor.pos + 1;
51        tokenizerProto._emitCurrentToken.call(this);
52    };
53
54    tokenizer._emitCurrentCharacterToken = function () {
55        //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
56        //then set it's location at the current preprocessor position
57        if (this.currentCharacterToken && this.currentCharacterToken.location.end === -1) {
58            //NOTE: we don't need to increment preprocessor position, since character token
59            //emission is always forced by the start of the next character token here.
60            //So, we already have advanced position.
61            this.currentCharacterToken.location.end = this.preprocessor.pos;
62        }
63
64        tokenizerProto._emitCurrentCharacterToken.call(this);
65    };
66
67    //NOTE: patch initial states for each mode to obtain token start position
68    Object.keys(tokenizerProto.MODE)
69
70        .map(function (modeName) {
71            return tokenizerProto.MODE[modeName];
72        })
73
74        .forEach(function (state) {
75            tokenizer[state] = function (cp) {
76                this.tokenStartLoc = this.preprocessor.pos;
77                tokenizerProto[state].call(this, cp);
78            };
79        });
80};
81