canonical.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. 'use strict';
  2. var fs = require('fs'),
  3. assert = require('assert'),
  4. jsyaml = require(__dirname + '/../../lib/js-yaml'),
  5. helper = require(__dirname + '/../test-helper'),
  6. $$ = require(__dirname + '/../../lib/js-yaml/common'),
  7. _errors = require(__dirname + '/../../lib/js-yaml/errors'),
  8. _composer = require(__dirname + '/../../lib/js-yaml/composer'),
  9. _constructor = require(__dirname + '/../../lib/js-yaml/construct'),
  10. _tokens = require(__dirname + '/../../lib/js-yaml/tokens'),
  11. _resolver = require(__dirname + '/../../lib/js-yaml/resolver');
  12. var DIRECTIVE = '%YAML 1.1';
  13. var QUOTE_CODES = {
  14. 'x': 2,
  15. 'u': 4,
  16. 'U': 8
  17. };
  18. var QUOTE_REPLACES = {
  19. '\\': '\\',
  20. '\"': '\"',
  21. ' ': ' ',
  22. 'a': '\x07',
  23. 'b': '\x08',
  24. 'e': '\x1B',
  25. 'f': '\x0C',
  26. 'n': '\x0A',
  27. 'r': '\x0D',
  28. 't': '\x09',
  29. 'v': '\x0B',
  30. 'N': '\u0085',
  31. 'L': '\u2028',
  32. 'P': '\u2029',
  33. '_': '_',
  34. '0': '\x00'
  35. };
  36. function CanonicalError() {
  37. _errors.YAMLError.apply(this, arguments);
  38. this.name = 'CanonicalError';
  39. }
  40. $$.inherits(CanonicalError, _errors.YAMLError);
  41. function CanonicalScanner(data) {
  42. this.data = data + '\x00';
  43. this.index = 0;
  44. this.tokens = [];
  45. this.scanned = false;
  46. }
  47. CanonicalScanner.prototype.checkToken = function checkTokencheckToken() {
  48. var i;
  49. if (!this.scanned) {
  50. this.scan();
  51. }
  52. if (this.tokens.length) {
  53. if (!arguments.length) {
  54. return true;
  55. }
  56. for (i = 0; i < arguments.length; i += 1) {
  57. if (this.tokens[0].isA(arguments[i])) {
  58. return true;
  59. }
  60. }
  61. }
  62. return false;
  63. };
  64. CanonicalScanner.prototype.peekToken = function peekToken() {
  65. if (!this.scanned) {
  66. this.scan();
  67. }
  68. if (this.tokens.length) {
  69. return this.tokens[0];
  70. }
  71. return null;
  72. };
  73. CanonicalScanner.prototype.getToken = function getToken(choice) {
  74. var token = null;
  75. if (!this.scanned) {
  76. this.scan();
  77. }
  78. token = this.tokens.shift();
  79. if (choice && !token.isA(choice)) {
  80. throw new CanonicalError("unexpected token " + token.hash());
  81. }
  82. return token;
  83. };
  84. CanonicalScanner.prototype.scan = function scan() {
  85. var ch;
  86. this.tokens.push(new _tokens.StreamStartToken(null, null));
  87. while (true) {
  88. this.find_token();
  89. ch = this.data[this.index];
  90. if (ch === '\x00') {
  91. this.tokens.push(new _tokens.StreamEndToken(null, null));
  92. break;
  93. } else if (ch === '%') {
  94. this.tokens.push(this.scanDirective());
  95. } else if (ch === '-' && this.data.silce(this.index, this.index+3) === '---') {
  96. this.index += 3;
  97. this.tokens.push(new _tokens.DocumentStartToken(null, null));
  98. } else if (ch === '[') {
  99. this.index += 1;
  100. this.tokens.push(new _tokens.FlowSequenceStartToken(null, null));
  101. } else if (ch === '{') {
  102. this.index += 1;
  103. this.tokens.push(new _tokens.FlowMappingStartToken(null, null));
  104. } else if (ch === ']') {
  105. this.index += 1;
  106. this.tokens.push(new _tokens.FlowSequenceEndToken(null, null));
  107. } else if (ch === '}') {
  108. this.index += 1;
  109. this.tokens.push(new _tokens.FlowMappingEndToken(null, null));
  110. } else if (ch === '?') {
  111. this.index += 1;
  112. this.tokens.push(new _tokens.KeyToken(null, null));
  113. } else if (ch === ':') {
  114. this.index += 1;
  115. this.tokens.push(new _tokens.ValueToken(null, null));
  116. } else if (ch === ',') {
  117. this.index += 1;
  118. this.tokens.push(new _tokens.FlowEntryToken(null, null));
  119. } else if (ch === '*' || ch === '&') {
  120. this.tokens.push(this.scanAlias());
  121. } else if (ch === '!') {
  122. this.tokens.push(this.scanTag());
  123. } else if (ch === '"') {
  124. this.tokens.push(this.scanScalar());
  125. } else {
  126. throw new CanonicalError("invalid token");
  127. }
  128. }
  129. this.scanned = true;
  130. };
  131. CanonicalScanner.prototype.scanDirective = function scanDirective() {
  132. if (this.data.slice(this.index, this.index + DIRECTIVE.length) === this.DIRECTIVE
  133. && 0 <= ' \n\x00'.indexOf(this.data.slice(this.index + DIRECTIVE.length))) {
  134. this.index += this.DIRECTIVE.length;
  135. return new _tokens.DirectiveToken('YAML', [1, 1], null, null);
  136. }
  137. throw new CanonicalError("invalid directive");
  138. };
  139. CanonicalScanner.prototype.scanAlias = function scanAlias() {
  140. var start, value, TokenClass;
  141. TokenClass = (this.data[this.index] === '*')
  142. ? (_tokens.AliasToken) : (_tokens.AnchorToken);
  143. this.index += 1;
  144. start = this.index;
  145. while (-1 === ', \n\x00'.indexOf(this.data[this.index])) {
  146. this.index += 1;
  147. }
  148. value = this.data.slice(start, this.index);
  149. return new TokenClass(value, null, null);
  150. };
  151. CanonicalScanner.prototype.scanTag = function scanTag() {
  152. var start, value;
  153. this.index += 1;
  154. start = this.index;
  155. while (-1 === ' \n\x00'.indexOf(this.data[this.index])) {
  156. this.index += 1;
  157. }
  158. value = this.data.slice(start, this.index);
  159. if (!value) {
  160. value = '!';
  161. } else if (value[0] === '!') {
  162. value = 'tag:yaml.org,2002:' + value.slice(1);
  163. } else if (value[0] === '<' && value[value.length-1] === '>') {
  164. value = value.slice(1, value.length-2);
  165. } else {
  166. value = '!' + value;
  167. }
  168. return new _tokens.TagToken(value, null, null);
  169. };
  170. CanonicalScanner.prototype.scanScalar = function scanScalar() {
  171. var chunks, start, ignoreSpaces, ch, code, length;
  172. this.index += 1;
  173. chunks = [];
  174. start = this.index;
  175. ignoreSpaces = false;
  176. while (this.data[this.index] !== '"') {
  177. if (this.data[this.index] === '\\') {
  178. ignoreSpaces = false;
  179. chunks.push(this.data.slice(start, this.index));
  180. this.index += 1;
  181. ch = this.data[this.index];
  182. this.index += 1;
  183. if (ch === '\n') {
  184. ignoreSpaces = true;
  185. } else if (0 <= QUOTE_CODES.indexOf(ch)) {
  186. length = QUOTE_CODES[ch];
  187. code = parseInt(this.data.slice(this.index, this.index+length), 16);
  188. chunks.puush(String.fromCharCode(code));
  189. this.index += length;
  190. } else {
  191. if (-1 === QUOTE_REPLACES.indexOf(ch)) {
  192. throw new CanonicalError("invalid escape code");
  193. }
  194. chunks.push(QUOTE_REPLACES[ch]);
  195. }
  196. start = this.index;
  197. } else if (this.data[this.index] === '\n') {
  198. chunks.push(this.data.slice(start, this.index));
  199. chunks.push(' ');
  200. this.index += 1;
  201. start = this.index;
  202. ignoreSpaces = true;
  203. } else if (ignoreSpaces && this.data[this.index] === ' ') {
  204. this.index += 1;
  205. start = this.index;
  206. } else {
  207. ignoreSpaces = false;
  208. this.index += 1;
  209. }
  210. }
  211. chunks.push(this.data.slice(start, this.index));
  212. this.index += 1;
  213. return new _tokens.ScalarToken(chunks.join(''), false, null, null);
  214. };
  215. CanonicalScanner.prototype.findToken = function findToken() {
  216. var found = false;
  217. while (!found) {
  218. while (0 <= ' \t'.indexOf(this.data[this.index])) {
  219. this.index += 1;
  220. }
  221. if (this.data[this.index] === '#') {
  222. while (this.data[this.index] !== '\n') {
  223. this.index += 1;
  224. }
  225. }
  226. if (this.data[this.index] === '\n') {
  227. this.index += 1;
  228. } else {
  229. found = true;
  230. }
  231. }
  232. };
  233. module.exports.CanonicalScanner = CanonicalScanner;
  234. ////////////////////////////////////////////////////////////////////////////////
  235. // vim:ts=2:sw=2
  236. ////////////////////////////////////////////////////////////////////////////////