tokenizer_mixin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. 'use strict';
  2. var Mixin = require('../../utils/mixin'),
  3. Tokenizer = require('../../tokenizer'),
  4. PositionTrackingPreprocessorMixin = require('../position_tracking/preprocessor_mixin'),
  5. inherits = require('util').inherits;
  6. var LocationInfoTokenizerMixin = module.exports = function (tokenizer) {
  7. Mixin.call(this, tokenizer);
  8. this.tokenizer = tokenizer;
  9. this.posTracker = new PositionTrackingPreprocessorMixin(tokenizer.preprocessor);
  10. this.currentAttrLocation = null;
  11. this.currentTokenLocation = null;
  12. };
  13. inherits(LocationInfoTokenizerMixin, Mixin);
  14. LocationInfoTokenizerMixin.prototype._getCurrentLocation = function () {
  15. return {
  16. line: this.posTracker.line,
  17. col: this.posTracker.col,
  18. startOffset: this.posTracker.offset,
  19. endOffset: -1
  20. };
  21. };
  22. LocationInfoTokenizerMixin.prototype._attachCurrentAttrLocationInfo = function () {
  23. this.currentAttrLocation.endOffset = this.posTracker.offset;
  24. var currentToken = this.tokenizer.currentToken,
  25. currentAttr = this.tokenizer.currentAttr;
  26. if (!currentToken.location.attrs)
  27. currentToken.location.attrs = Object.create(null);
  28. currentToken.location.attrs[currentAttr.name] = this.currentAttrLocation;
  29. };
  30. LocationInfoTokenizerMixin.prototype._getOverriddenMethods = function (mxn, orig) {
  31. var methods = {
  32. _createStartTagToken: function () {
  33. orig._createStartTagToken.call(this);
  34. this.currentToken.location = mxn.currentTokenLocation;
  35. },
  36. _createEndTagToken: function () {
  37. orig._createEndTagToken.call(this);
  38. this.currentToken.location = mxn.currentTokenLocation;
  39. },
  40. _createCommentToken: function () {
  41. orig._createCommentToken.call(this);
  42. this.currentToken.location = mxn.currentTokenLocation;
  43. },
  44. _createDoctypeToken: function (initialName) {
  45. orig._createDoctypeToken.call(this, initialName);
  46. this.currentToken.location = mxn.currentTokenLocation;
  47. },
  48. _createCharacterToken: function (type, ch) {
  49. orig._createCharacterToken.call(this, type, ch);
  50. this.currentCharacterToken.location = mxn.currentTokenLocation;
  51. },
  52. _createAttr: function (attrNameFirstCh) {
  53. orig._createAttr.call(this, attrNameFirstCh);
  54. mxn.currentAttrLocation = mxn._getCurrentLocation();
  55. },
  56. _leaveAttrName: function (toState) {
  57. orig._leaveAttrName.call(this, toState);
  58. mxn._attachCurrentAttrLocationInfo();
  59. },
  60. _leaveAttrValue: function (toState) {
  61. orig._leaveAttrValue.call(this, toState);
  62. mxn._attachCurrentAttrLocationInfo();
  63. },
  64. _emitCurrentToken: function () {
  65. //NOTE: if we have pending character token make it's end location equal to the
  66. //current token's start location.
  67. if (this.currentCharacterToken)
  68. this.currentCharacterToken.location.endOffset = this.currentToken.location.startOffset;
  69. this.currentToken.location.endOffset = mxn.posTracker.offset + 1;
  70. orig._emitCurrentToken.call(this);
  71. },
  72. _emitCurrentCharacterToken: function () {
  73. //NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
  74. //then set it's location at the current preprocessor position.
  75. //We don't need to increment preprocessor position, since character token
  76. //emission is always forced by the start of the next character token here.
  77. //So, we already have advanced position.
  78. if (this.currentCharacterToken && this.currentCharacterToken.location.endOffset === -1)
  79. this.currentCharacterToken.location.endOffset = mxn.posTracker.offset;
  80. orig._emitCurrentCharacterToken.call(this);
  81. }
  82. };
  83. //NOTE: patch initial states for each mode to obtain token start position
  84. Object.keys(Tokenizer.MODE).forEach(function (modeName) {
  85. var state = Tokenizer.MODE[modeName];
  86. methods[state] = function (cp) {
  87. mxn.currentTokenLocation = mxn._getCurrentLocation();
  88. orig[state].call(this, cp);
  89. };
  90. });
  91. return methods;
  92. };