Guest User

Untitled

a guest
May 21st, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.79 KB | None | 0 0
  1. import * as XRegExp from 'xregexp'
  2.  
  3. export const GSON = (() => {
  4. let _json;
  5. let _pos;
  6. let _len;
  7.  
  8. function peekRegex(regex) {
  9. return XRegExp.exec(_json, regex, _pos, true);
  10. }
  11.  
  12. function eatRegex(regex) {
  13. let match = peekRegex(regex);
  14.  
  15. if (!match) {
  16. return false;
  17. }
  18.  
  19. _pos += match[0].length;
  20.  
  21. return match[0];
  22. }
  23.  
  24. function peekChar() {
  25. return _json[_pos];
  26. }
  27.  
  28. function eatChar(c) {
  29. if (peekChar() !== c) {
  30. return false;
  31. }
  32. return !!(_pos++);
  33. }
  34.  
  35. function skipWhitespace() {
  36. while (true) {
  37. switch (peekChar()) {
  38. case ' ':
  39. case '\t':
  40. case '\r':
  41. case '\n':
  42. ++_pos;
  43. continue;
  44. }
  45. break;
  46. }
  47. }
  48.  
  49. let _strict;
  50. let _depth;
  51.  
  52. const _startObject = /{/;
  53. const _endObject = /}/;
  54.  
  55. const _startArray = /\[/;
  56. const _endArray = /]/;
  57.  
  58. const _colon = /:/;
  59. const _comma = /,/;
  60.  
  61. const _null = /null/;
  62. const _boolean = /true|false/;
  63. const _number = /-?(0|[1-9][0-9]*)(\.[0-9]+)?(e[+-]?[0-9]+)?([df])?/i;
  64.  
  65. const _stringBoundary = /"/;
  66. const _stringEscape = /\\/;
  67. const _controlCharacter = /["\\/bfnrtu]/;
  68. const _controlUnicode = /[0-9a-f]{4}/i;
  69.  
  70. const _lenientSemicolon = /;/;
  71. const _lenientNonExecutePrefix = /\)]}'\n/;
  72. const _lenientNaNOrInfinite = /NaN|-?Infinity/;
  73. const _lenientStringBoundary = /["']/;
  74. const _lenientControlCharacter = /['"\\/bfnrtu]/;
  75. const _lenientKeyValueSeparator = /(:)|(=>)|(=)/;
  76. const _lenientCommentsGlobal = /(?:(?:(?:\/\/)|#).*$)|(?:\/\*[\s\S]*?\*\/)/mg;
  77. const _lenientStringStart = /[a-z_$]/i;
  78.  
  79. function _error(str) {
  80. throw new Error('[index ' + _pos + '] ' + str);
  81. }
  82.  
  83. function _checkUndefined(char) {
  84. if (char == undefined) {
  85. return "nothing"
  86. }
  87. return char;
  88. }
  89.  
  90. function _parseString() {
  91. skipWhitespace();
  92.  
  93. let str = '';
  94. let boundary;
  95.  
  96. // "Strings that are unquoted or 'single quoted'."
  97. if (!_strict) {
  98. if ((boundary = eatRegex(_lenientStringBoundary)) === false) {
  99. boundary = null;
  100. }
  101. }
  102. else {
  103. if ((boundary = eatRegex(_stringBoundary)) === false) {
  104. _error('expected ", got ' + _checkUndefined(peekChar()));
  105. }
  106. }
  107.  
  108. let stringContainer;
  109.  
  110. if (boundary) {
  111. stringContainer = new RegExp('[^' + boundary + '\\\\]*');
  112. } else {
  113. stringContainer = new RegExp('\\w*');
  114. }
  115.  
  116. while (true) {
  117. let grp = eatRegex(stringContainer);
  118.  
  119. if (grp !== false) {
  120. str += grp;
  121. }
  122.  
  123. if (boundary === null || eatChar(boundary)) {
  124. break;
  125. } else if (eatRegex(_stringEscape)) {
  126. let ctrl = eatRegex(!_strict ? _lenientControlCharacter : _controlCharacter);
  127.  
  128. if (ctrl === false) {
  129. _error('expected valid control character, got ' + _checkUndefined(peekChar()));
  130. }
  131.  
  132. switch (ctrl) {
  133. case '\'': // not strict (accept single quotes)
  134.  
  135. case '"':
  136. case '\\':
  137. case '/':
  138. str += ctrl;
  139. break;
  140. case 'b':
  141. str += '\b';
  142. break;
  143. case 'f':
  144. str += '\f';
  145. break;
  146. case 'n':
  147. str += '\n';
  148. break;
  149. case 'r':
  150. str += '\r';
  151. break;
  152. case 't':
  153. str += '\t';
  154. break;
  155. case 'u':
  156. let hex = eatRegex(_controlUnicode);
  157.  
  158. if (hex === false) {
  159. _error('expected valid 4-character hex number, got ' + _checkUndefined(peekChar()));
  160. }
  161.  
  162. str += String.fromCharCode(parseInt(hex, 16));
  163. break;
  164. }
  165. }
  166. else {
  167. _error('expected " or \\, got ' + _checkUndefined(peekChar()));
  168. }
  169. }
  170. return str;
  171. }
  172.  
  173. function _parseObject() {
  174. skipWhitespace();
  175.  
  176. if (eatRegex(_startObject) === false) {
  177. _error('expected {, got ' + _checkUndefined(peekChar()));
  178. }
  179.  
  180. let obj = {};
  181.  
  182. while (true) {
  183. skipWhitespace();
  184.  
  185. if (eatRegex(_endObject)) {
  186. break;
  187. }
  188.  
  189. let key = _parseString();
  190.  
  191. skipWhitespace();
  192.  
  193. // "Names and values separated by = or => instead of :."
  194. if (!_strict) {
  195. if (eatRegex(_lenientKeyValueSeparator) === false) {
  196. _error('expected =, => or :, got ' + _checkUndefined(peekChar()));
  197. }
  198. }
  199. else if (eatRegex(_colon) === false) {
  200. _error('expected :, got ' + _checkUndefined(peekChar()));
  201. }
  202.  
  203. let value = _parseAny();
  204. obj[key] = value;
  205.  
  206. skipWhitespace();
  207.  
  208. if (eatRegex(_comma)) {
  209. continue;
  210. }// "Name/value pairs separated by ; instead of ,."
  211. else if (!_strict && eatRegex(_lenientSemicolon)) {
  212. continue;
  213. } else if (!eatRegex(_endObject)) {
  214. _error('expected }, got ' + _checkUndefined(peekChar()));
  215. }
  216.  
  217. break;
  218. }
  219. return obj;
  220. }
  221.  
  222. function _parseArray() {
  223. skipWhitespace();
  224.  
  225. if (eatRegex(_startArray) === false) {
  226. _error('expected [, got ' + _checkUndefined(peekChar()));
  227. }
  228.  
  229. let arr = [];
  230.  
  231. while (true) {
  232. // todo: "Unnecessary array separators. These are interpreted as if null was the omitted value."
  233. skipWhitespace();
  234.  
  235. if (eatRegex(_endArray)) {
  236. break;
  237. }
  238.  
  239. let value = _parseAny();
  240. arr.push(value);
  241.  
  242. skipWhitespace();
  243.  
  244. if (eatRegex(_comma)) {
  245. continue;
  246. }// "Array elements separated by ; instead of ,."
  247. else if (!_strict && eatRegex(_lenientSemicolon)) {
  248. continue;
  249. } else if (!eatRegex(_endArray)) {
  250. _error('expected ], got ' + _checkUndefined(peekChar()));
  251. }
  252.  
  253. break;
  254. }
  255. return arr;
  256. }
  257.  
  258. function _parseNumber() {
  259. let str;
  260.  
  261. if ((str = eatRegex(_number)) === false) {
  262. // "Numbers may be NaNs or infinities."
  263. if (!_strict) {
  264. if ((str = eatRegex(_lenientNaNOrInfinite)) !== false) {
  265. return Number(str);
  266. }
  267. }
  268.  
  269. _error('expected number, got ' + _checkUndefined(peekChar()));
  270. }
  271. return Number(str);
  272. }
  273.  
  274. function _parseBoolean() {
  275. let str;
  276.  
  277. if ((str = eatRegex(_boolean)) === false) {
  278. _error('expected boolean, got' + peekChar());
  279. }
  280. return str === "true";
  281. }
  282.  
  283. function _parseNull() {
  284. if (eatRegex(_null) === false) {
  285. _error('expected null, got ' + _checkUndefined(peekChar()));
  286. }
  287. return null;
  288. }
  289.  
  290. function _parseAny() {
  291. skipWhitespace();
  292.  
  293. if (peekRegex(_startObject)) {
  294. return _parseObject();
  295. } else if (peekRegex(_startArray)) {
  296. return _parseArray();
  297. } else if (peekRegex(_number) || (!_strict && peekRegex(_lenientNaNOrInfinite))) {
  298. return _parseNumber();
  299. } else if (peekRegex(_boolean)) {
  300. return _parseBoolean();
  301. } else if (peekRegex(_null)) {
  302. return _parseNull();
  303. } else if (peekRegex(_stringBoundary) || (!_strict && (peekRegex(_lenientStringBoundary) || peekRegex(_lenientStringStart)))) {
  304. return _parseString();
  305. }
  306.  
  307. _error('expected ANY, got ' + _checkUndefined(peekChar()));
  308. }
  309.  
  310. function _parseObjectOrArray() {
  311. skipWhitespace();
  312.  
  313. if (peekRegex(_startObject)) {
  314. return _parseObject();
  315. } else if (peekRegex(_startArray)) {
  316. return _parseArray();
  317. }
  318.  
  319. _error('expected object or array, got ' + _checkUndefined(peekChar()));
  320. }
  321.  
  322. function parse(json, strict = false) {
  323. if (strict === undefined) {
  324. strict = false;
  325. }
  326.  
  327. _strict = strict;
  328. _depth = 0;
  329.  
  330. if (!strict) {
  331. _json = json.replace(_lenientCommentsGlobal, '');
  332. }// Single-line comments (// or #) and block-comments (/* */)
  333. else {
  334. _json = json;
  335. }
  336. _pos = 0;
  337. _len = json.length;
  338.  
  339. // "Streams that start with the non-execute prefix, ")]}'\n"."
  340. if (!_strict) {
  341. eatRegex(_lenientNonExecutePrefix);
  342. }
  343.  
  344. // "Top-level values of any type. With strict parsing, the top-level value must be an object or an array."
  345. if (!_strict) {
  346. return _parseAny();
  347. }
  348.  
  349. // todo: "Streams that include multiple top-level values. With strict parsing, each stream must contain exactly one top-level value."
  350. return _parseObjectOrArray();
  351. }
  352.  
  353. // STRINGIFY CODE
  354. let _options;
  355. let _str;
  356.  
  357. function _opt(name, def) {
  358. if (!_options || _options[name] === undefined) {
  359. return def;
  360. }
  361. return _options[name];
  362. }
  363.  
  364. function _validKey(key) {
  365. try {
  366. eval("let " + key + ";");
  367. return true;
  368. }
  369. catch (e) {
  370. return false;
  371. }
  372. }
  373.  
  374. function _stringifyNull() {
  375. _str += 'null';
  376. }
  377.  
  378. function _stringifyObject(object) {
  379. // start object
  380. _str += '{';
  381.  
  382. // properties
  383. let props = Object.getOwnPropertyNames(object);
  384.  
  385. // options used
  386. let keyPairSeparator = _opt('keyPairSeparator', ':');
  387.  
  388. for (let i = 0; i < props.length; ++i) {
  389. if (i !== 0) {
  390. _str += ',';
  391. }
  392.  
  393. _stringifyString(props[i], true);
  394. _str += keyPairSeparator;
  395. _stringifyAny(object[props[i]]);
  396. }
  397.  
  398. // end object
  399. _str += '}';
  400. }
  401.  
  402. function _stringifyArray(array) {
  403. // start array
  404. _str += '[';
  405.  
  406. // options used
  407. let arraySeparator = _opt('arraySeparator', ',');
  408.  
  409. for (let i = 0; i < array.length; ++i) {
  410. if (i !== 0) {
  411. _str += arraySeparator;
  412. }
  413.  
  414. _stringifyAny(array[i]);
  415. }
  416.  
  417. // end array
  418. _str += ']';
  419. }
  420.  
  421. function _stringifyNumber(number) {
  422. // options used
  423. let allowNaNInfinite = _opt('allowNaNInfinite', false);
  424.  
  425. if (!allowNaNInfinite && (isNaN(number) || !isFinite(number))) {
  426. _stringifyNull();
  427. return;
  428. }
  429.  
  430. _str += number.toString();
  431. }
  432.  
  433. function _stringifyBoolean(bool) {
  434. _str += (bool) ? 'true' : 'false';
  435. }
  436.  
  437. function _fixString(str) {
  438. return str
  439. .replace('\\', '\\\\')
  440. .replace("\b", "\\b")
  441. .replace("\f", "\\f")
  442. .replace("\n", "\\n")
  443. .replace("\r", "\\r")
  444. .replace("\t", "\\t")
  445. .replace("\v", "\\v");
  446. }
  447.  
  448. function _stringifyString(input, isKey) {
  449. let unquotedKeys, preferSingleQuotedKeys;
  450.  
  451. if (isKey) {
  452. unquotedKeys = _opt('unquotedKeys', false);
  453. preferSingleQuotedKeys = _opt('preferSingleQuotedKeys', false);
  454. }
  455. else {
  456. unquotedKeys = _opt('unquotedStrings', false);
  457. preferSingleQuotedKeys = _opt('preferSingleQuotedStrings', false);
  458. }
  459.  
  460. let output = null;
  461.  
  462. if (unquotedKeys && _validKey(input))
  463. // see if the key is a valid identifier, if so use it raw.
  464. {
  465. output = input;
  466. } else if (preferSingleQuotedKeys) {
  467. // can use single-quoted keys, find the best candidate
  468. let dq = input.indexOf('"') !== -1;
  469. let sq = input.indexOf("'") !== -1;
  470.  
  471. // for having both or only double quotes, use single.
  472. if ((dq && sq) || dq) {
  473. output = "'" + _fixString(input).replace("'", "\\'") + "'";
  474. }
  475. }
  476.  
  477. if (output === null) {
  478. output = '"' + _fixString(input).replace('"', '\\"') + '"';
  479. }
  480.  
  481. _str += output;
  482. }
  483.  
  484. function _stringifyAny(object) {
  485. if (object === null) {
  486. _stringifyNull();
  487. return;
  488. }
  489.  
  490. switch (Object.prototype.toString.call(object)) {
  491. case '[object Object]':
  492. _stringifyObject(object);
  493. return;
  494. case '[object Array]':
  495. _stringifyArray(object);
  496. return;
  497. case '[object Number]':
  498. _stringifyNumber(object);
  499. return;
  500. case '[object Boolean]':
  501. _stringifyBoolean(object);
  502. return;
  503. case '[object String]':
  504. default:
  505. _stringifyString(object, false);
  506. return;
  507. }
  508. }
  509.  
  510. function stringify(object, options) {
  511. if (options === false)
  512. // if options is "false", act like parses' "strict"
  513. {
  514. options = {unquotedKeys: true, unquotedStrings: true, allowNaNInfinite: true};
  515. }
  516.  
  517. _str = '';
  518. _options = options;
  519.  
  520. _stringifyAny(object);
  521.  
  522. // copy so that global _str is cleared. ugly?
  523. let copy = _str;
  524. _str = null;
  525. return copy;
  526. }
  527.  
  528. return {
  529. parse: parse,
  530. stringify: stringify
  531. };
  532. })();
Add Comment
Please, Sign In to add comment