Verifier.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. 'use strict';
  2. const {Writable} = require('stream');
  3. const {StringDecoder} = require('string_decoder');
  4. const patterns = {
  5. value1: /^(?:[\"\{\[\]\-\d]|true\b|false\b|null\b|\s{1,256})/,
  6. string: /^(?:[^\x00-\x1f\"\\]{1,256}|\\[bfnrt\"\\\/]|\\u[\da-fA-F]{4}|\")/,
  7. key1: /^(?:[\"\}]|\s{1,256})/,
  8. colon: /^(?:\:|\s{1,256})/,
  9. comma: /^(?:[\,\]\}]|\s{1,256})/,
  10. ws: /^\s{1,256}/,
  11. numberStart: /^\d/,
  12. numberDigit: /^\d{0,256}/,
  13. numberFraction: /^[\.eE]/,
  14. numberExponent: /^[eE]/,
  15. numberExpSign: /^[-+]/
  16. };
  17. const MAX_PATTERN_SIZE = 16;
  18. let noSticky = true;
  19. try {
  20. new RegExp('.', 'y');
  21. noSticky = false;
  22. } catch (e) {
  23. // suppress
  24. }
  25. !noSticky &&
  26. Object.keys(patterns).forEach(key => {
  27. let src = patterns[key].source.slice(1); // lop off ^
  28. if (src.slice(0, 3) === '(?:' && src.slice(-1) === ')') {
  29. src = src.slice(3, -1);
  30. }
  31. patterns[key] = new RegExp(src, 'y');
  32. });
  33. patterns.numberFracStart = patterns.numberExpStart = patterns.numberStart;
  34. patterns.numberFracDigit = patterns.numberExpDigit = patterns.numberDigit;
  35. const eol = /[\u000A\u2028\u2029]|\u000D\u000A|\u000D/g;
  36. const expected = {object: 'objectStop', array: 'arrayStop', '': 'done'};
  37. class Verifier extends Writable {
  38. static make(options) {
  39. return new Verifier(options);
  40. }
  41. constructor(options) {
  42. super(Object.assign({}, options, {objectMode: false}));
  43. if (options) {
  44. this._jsonStreaming = options.jsonStreaming;
  45. }
  46. this._buffer = '';
  47. this._done = false;
  48. this._expect = this._jsonStreaming ? 'done' : 'value';
  49. this._stack = [];
  50. this._parent = '';
  51. this._line = this._pos = 1;
  52. this._offset = 0;
  53. }
  54. _write(chunk, encoding, callback) {
  55. if (typeof chunk == 'string') {
  56. this._write = this._writeString;
  57. } else {
  58. this._stringDecoder = new StringDecoder();
  59. this._write = this._writeBuffer;
  60. }
  61. this._write(chunk, encoding, callback);
  62. }
  63. _writeBuffer(chunk, _, callback) {
  64. this._buffer += this._stringDecoder.write(chunk);
  65. this._processBuffer(callback);
  66. }
  67. _writeString(chunk, _, callback) {
  68. this._buffer += chunk.toString();
  69. this._processBuffer(callback);
  70. }
  71. _final(callback) {
  72. if (this._stringDecoder) {
  73. this._buffer += this._stringDecoder.end();
  74. }
  75. this._done = true;
  76. this._processBuffer(callback);
  77. }
  78. _makeError(msg) {
  79. const error = new Error('ERROR at ' + this._offset + ' (' + this._line + ', ' + this._pos + '): ' + msg);
  80. error.line = this._line;
  81. error.pos = this._pos;
  82. error.offset = this._offset;
  83. return error;
  84. }
  85. _updatePos(value) {
  86. let len = value.length;
  87. this._offset += len;
  88. value.replace(eol, (match, offset) => {
  89. len = value.length - match.length - offset;
  90. ++this._line;
  91. this._pos = 1;
  92. return '';
  93. });
  94. this._pos += len;
  95. }
  96. _processBuffer(callback) {
  97. let match,
  98. value,
  99. index = 0;
  100. main: for (;;) {
  101. switch (this._expect) {
  102. case 'value1':
  103. case 'value':
  104. patterns.value1.lastIndex = index;
  105. match = patterns.value1.exec(this._buffer);
  106. if (!match) {
  107. if (this._done || index + MAX_PATTERN_SIZE < this._buffer.length) {
  108. if (index < this._buffer.length) return callback(this._makeError('Verifier cannot parse input: expected a value'));
  109. return callback(this._makeError('Verifier has expected a value'));
  110. }
  111. break main; // wait for more input
  112. }
  113. value = match[0];
  114. switch (value) {
  115. case '"':
  116. this._expect = 'string';
  117. break;
  118. case '{':
  119. this._stack.push(this._parent);
  120. this._parent = 'object';
  121. this._expect = 'key1';
  122. break;
  123. case '[':
  124. this._stack.push(this._parent);
  125. this._parent = 'array';
  126. this._expect = 'value1';
  127. break;
  128. case ']':
  129. if (this._expect !== 'value1') return callback(this._makeError("Verifier cannot parse input: unexpected token ']'"));
  130. this._parent = this._stack.pop();
  131. this._expect = expected[this._parent];
  132. break;
  133. case '-':
  134. this._expect = 'numberStart';
  135. break;
  136. case '0':
  137. this._expect = 'numberFraction';
  138. break;
  139. case '1':
  140. case '2':
  141. case '3':
  142. case '4':
  143. case '5':
  144. case '6':
  145. case '7':
  146. case '8':
  147. case '9':
  148. this._expect = 'numberDigit';
  149. break;
  150. case 'true':
  151. case 'false':
  152. case 'null':
  153. if (this._buffer.length - index === value.length && !this._done) break main; // wait for more input
  154. this._expect = expected[this._parent];
  155. break;
  156. // default: // ws
  157. }
  158. this._updatePos(value);
  159. if (noSticky) {
  160. this._buffer = this._buffer.slice(value.length);
  161. } else {
  162. index += value.length;
  163. }
  164. break;
  165. case 'keyVal':
  166. case 'string':
  167. patterns.string.lastIndex = index;
  168. match = patterns.string.exec(this._buffer);
  169. if (!match) {
  170. if (index < this._buffer.length && (this._done || this._buffer.length - index >= 6))
  171. return callback(this._makeError('Verifier cannot parse input: escaped characters'));
  172. if (this._done) return callback(this._makeError('Verifier has expected a string value'));
  173. break main; // wait for more input
  174. }
  175. value = match[0];
  176. if (value === '"') {
  177. if (this._expect === 'keyVal') {
  178. this._expect = 'colon';
  179. } else {
  180. this._expect = expected[this._parent];
  181. }
  182. }
  183. this._updatePos(value);
  184. if (noSticky) {
  185. this._buffer = this._buffer.slice(value.length);
  186. } else {
  187. index += value.length;
  188. }
  189. break;
  190. case 'key1':
  191. case 'key':
  192. patterns.key1.lastIndex = index;
  193. match = patterns.key1.exec(this._buffer);
  194. if (!match) {
  195. if (index < this._buffer.length || this._done) return callback(this._makeError('Verifier cannot parse input: expected an object key'));
  196. break main; // wait for more input
  197. }
  198. value = match[0];
  199. if (value === '"') {
  200. this._expect = 'keyVal';
  201. } else if (value === '}') {
  202. if (this._expect !== 'key1') return callback(this._makeError("Verifier cannot parse input: unexpected token '}'"));
  203. this._parent = this._stack.pop();
  204. this._expect = expected[this._parent];
  205. }
  206. this._updatePos(value);
  207. if (noSticky) {
  208. this._buffer = this._buffer.slice(value.length);
  209. } else {
  210. index += value.length;
  211. }
  212. break;
  213. case 'colon':
  214. patterns.colon.lastIndex = index;
  215. match = patterns.colon.exec(this._buffer);
  216. if (!match) {
  217. if (index < this._buffer.length || this._done) return callback(this._makeError("Verifier cannot parse input: expected ':'"));
  218. break main; // wait for more input
  219. }
  220. value = match[0];
  221. value === ':' && (this._expect = 'value');
  222. this._updatePos(value);
  223. if (noSticky) {
  224. this._buffer = this._buffer.slice(value.length);
  225. } else {
  226. index += value.length;
  227. }
  228. break;
  229. case 'arrayStop':
  230. case 'objectStop':
  231. patterns.comma.lastIndex = index;
  232. match = patterns.comma.exec(this._buffer);
  233. if (!match) {
  234. if (index < this._buffer.length || this._done) return callback(this._makeError("Verifier cannot parse input: expected ','"));
  235. break main; // wait for more input
  236. }
  237. value = match[0];
  238. if (value === ',') {
  239. this._expect = this._expect === 'arrayStop' ? 'value' : 'key';
  240. } else if (value === '}' || value === ']') {
  241. if (value === '}' ? this._expect === 'arrayStop' : this._expect !== 'arrayStop') {
  242. return callback(this._makeError("Verifier cannot parse input: expected '" + (this._expect === 'arrayStop' ? ']' : '}') + "'"));
  243. }
  244. this._parent = this._stack.pop();
  245. this._expect = expected[this._parent];
  246. }
  247. this._updatePos(value);
  248. if (noSticky) {
  249. this._buffer = this._buffer.slice(value.length);
  250. } else {
  251. index += value.length;
  252. }
  253. break;
  254. // number chunks
  255. case 'numberStart': // [0-9]
  256. patterns.numberStart.lastIndex = index;
  257. match = patterns.numberStart.exec(this._buffer);
  258. if (!match) {
  259. if (index < this._buffer.length || this._done) return callback(this._makeError('Verifier cannot parse input: expected a starting digit'));
  260. break main; // wait for more input
  261. }
  262. value = match[0];
  263. this._expect = value === '0' ? 'numberFraction' : 'numberDigit';
  264. this._updatePos(value);
  265. if (noSticky) {
  266. this._buffer = this._buffer.slice(value.length);
  267. } else {
  268. index += value.length;
  269. }
  270. break;
  271. case 'numberDigit': // [0-9]*
  272. patterns.numberDigit.lastIndex = index;
  273. match = patterns.numberDigit.exec(this._buffer);
  274. if (!match) {
  275. if (index < this._buffer.length || this._done) return callback(this._makeError('Verifier cannot parse input: expected a digit'));
  276. break main; // wait for more input
  277. }
  278. value = match[0];
  279. if (value) {
  280. this._updatePos(value);
  281. if (noSticky) {
  282. this._buffer = this._buffer.slice(value.length);
  283. } else {
  284. index += value.length;
  285. }
  286. } else {
  287. if (index < this._buffer.length) {
  288. this._expect = 'numberFraction';
  289. break;
  290. }
  291. if (this._done) {
  292. this._expect = expected[this._parent];
  293. break;
  294. }
  295. break main; // wait for more input
  296. }
  297. break;
  298. case 'numberFraction': // [\.eE]?
  299. patterns.numberFraction.lastIndex = index;
  300. match = patterns.numberFraction.exec(this._buffer);
  301. if (!match) {
  302. if (index < this._buffer.length || this._done) {
  303. this._expect = expected[this._parent];
  304. break;
  305. }
  306. break main; // wait for more input
  307. }
  308. value = match[0];
  309. this._expect = value === '.' ? 'numberFracStart' : 'numberExpSign';
  310. this._updatePos(value);
  311. if (noSticky) {
  312. this._buffer = this._buffer.slice(value.length);
  313. } else {
  314. index += value.length;
  315. }
  316. break;
  317. case 'numberFracStart': // [0-9]
  318. patterns.numberFracStart.lastIndex = index;
  319. match = patterns.numberFracStart.exec(this._buffer);
  320. if (!match) {
  321. if (index < this._buffer.length || this._done)
  322. return callback(this._makeError('Verifier cannot parse input: expected a fractional part of a number'));
  323. break main; // wait for more input
  324. }
  325. value = match[0];
  326. this._expect = 'numberFracDigit';
  327. this._updatePos(value);
  328. if (noSticky) {
  329. this._buffer = this._buffer.slice(value.length);
  330. } else {
  331. index += value.length;
  332. }
  333. break;
  334. case 'numberFracDigit': // [0-9]*
  335. patterns.numberFracDigit.lastIndex = index;
  336. match = patterns.numberFracDigit.exec(this._buffer);
  337. value = match[0];
  338. if (value) {
  339. this._updatePos(value);
  340. if (noSticky) {
  341. this._buffer = this._buffer.slice(value.length);
  342. } else {
  343. index += value.length;
  344. }
  345. } else {
  346. if (index < this._buffer.length) {
  347. this._expect = 'numberExponent';
  348. break;
  349. }
  350. if (this._done) {
  351. this._expect = expected[this._parent];
  352. break;
  353. }
  354. break main; // wait for more input
  355. }
  356. break;
  357. case 'numberExponent': // [eE]?
  358. patterns.numberExponent.lastIndex = index;
  359. match = patterns.numberExponent.exec(this._buffer);
  360. if (!match) {
  361. if (index < this._buffer.length) {
  362. this._expect = expected[this._parent];
  363. break;
  364. }
  365. if (this._done) {
  366. this._expect = 'done';
  367. break;
  368. }
  369. break main; // wait for more input
  370. }
  371. value = match[0];
  372. this._expect = 'numberExpSign';
  373. this._updatePos(value);
  374. if (noSticky) {
  375. this._buffer = this._buffer.slice(value.length);
  376. } else {
  377. index += value.length;
  378. }
  379. break;
  380. case 'numberExpSign': // [-+]?
  381. patterns.numberExpSign.lastIndex = index;
  382. match = patterns.numberExpSign.exec(this._buffer);
  383. if (!match) {
  384. if (index < this._buffer.length) {
  385. this._expect = 'numberExpStart';
  386. break;
  387. }
  388. if (this._done) return callback(this._makeError('Verifier has expected an exponent value of a number'));
  389. break main; // wait for more input
  390. }
  391. value = match[0];
  392. this._expect = 'numberExpStart';
  393. this._updatePos(value);
  394. if (noSticky) {
  395. this._buffer = this._buffer.slice(value.length);
  396. } else {
  397. index += value.length;
  398. }
  399. break;
  400. case 'numberExpStart': // [0-9]
  401. patterns.numberExpStart.lastIndex = index;
  402. match = patterns.numberExpStart.exec(this._buffer);
  403. if (!match) {
  404. if (index < this._buffer.length || this._done)
  405. return callback(this._makeError('Verifier cannot parse input: expected an exponent part of a number'));
  406. break main; // wait for more input
  407. }
  408. value = match[0];
  409. this._expect = 'numberExpDigit';
  410. this._updatePos(value);
  411. if (noSticky) {
  412. this._buffer = this._buffer.slice(value.length);
  413. } else {
  414. index += value.length;
  415. }
  416. break;
  417. case 'numberExpDigit': // [0-9]*
  418. patterns.numberExpDigit.lastIndex = index;
  419. match = patterns.numberExpDigit.exec(this._buffer);
  420. value = match[0];
  421. if (value) {
  422. this._updatePos(value);
  423. if (noSticky) {
  424. this._buffer = this._buffer.slice(value.length);
  425. } else {
  426. index += value.length;
  427. }
  428. } else {
  429. if (index < this._buffer.length || this._done) {
  430. this._expect = expected[this._parent];
  431. break;
  432. }
  433. break main; // wait for more input
  434. }
  435. break;
  436. case 'done':
  437. patterns.ws.lastIndex = index;
  438. match = patterns.ws.exec(this._buffer);
  439. if (!match) {
  440. if (index < this._buffer.length) {
  441. if (this._jsonStreaming) {
  442. this._expect = 'value';
  443. break;
  444. }
  445. return callback(this._makeError('Verifier cannot parse input: unexpected characters'));
  446. }
  447. break main; // wait for more input
  448. }
  449. value = match[0];
  450. this._updatePos(value);
  451. if (noSticky) {
  452. this._buffer = this._buffer.slice(value.length);
  453. } else {
  454. index += value.length;
  455. }
  456. break;
  457. }
  458. }
  459. !noSticky && (this._buffer = this._buffer.slice(index));
  460. callback(null);
  461. }
  462. }
  463. Verifier.verifier = Verifier.make;
  464. Verifier.make.Constructor = Verifier;
  465. module.exports = Verifier;