parser.mjs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. const tokenize = (input) => {
  2. let current = 0;
  3. let tokens = [];
  4. while (current < input.length) {
  5. let char = input[current];
  6. if (char === '\\') {
  7. current++;
  8. continue;
  9. }
  10. if (char === '{') {
  11. tokens.push({
  12. type: 'brace',
  13. value: '{',
  14. });
  15. current++;
  16. continue;
  17. }
  18. if (char === '}') {
  19. tokens.push({
  20. type: 'brace',
  21. value: '}',
  22. });
  23. current++;
  24. continue;
  25. }
  26. if (char === '[') {
  27. tokens.push({
  28. type: 'paren',
  29. value: '[',
  30. });
  31. current++;
  32. continue;
  33. }
  34. if (char === ']') {
  35. tokens.push({
  36. type: 'paren',
  37. value: ']',
  38. });
  39. current++;
  40. continue;
  41. }
  42. if (char === ':') {
  43. tokens.push({
  44. type: 'separator',
  45. value: ':',
  46. });
  47. current++;
  48. continue;
  49. }
  50. if (char === ',') {
  51. tokens.push({
  52. type: 'delimiter',
  53. value: ',',
  54. });
  55. current++;
  56. continue;
  57. }
  58. if (char === '"') {
  59. let value = '';
  60. let danglingQuote = false;
  61. char = input[++current];
  62. while (char !== '"') {
  63. if (current === input.length) {
  64. danglingQuote = true;
  65. break;
  66. }
  67. if (char === '\\') {
  68. current++;
  69. if (current === input.length) {
  70. danglingQuote = true;
  71. break;
  72. }
  73. value += char + input[current];
  74. char = input[++current];
  75. }
  76. else {
  77. value += char;
  78. char = input[++current];
  79. }
  80. }
  81. char = input[++current];
  82. if (!danglingQuote) {
  83. tokens.push({
  84. type: 'string',
  85. value,
  86. });
  87. }
  88. continue;
  89. }
  90. let WHITESPACE = /\s/;
  91. if (char && WHITESPACE.test(char)) {
  92. current++;
  93. continue;
  94. }
  95. let NUMBERS = /[0-9]/;
  96. if ((char && NUMBERS.test(char)) || char === '-' || char === '.') {
  97. let value = '';
  98. if (char === '-') {
  99. value += char;
  100. char = input[++current];
  101. }
  102. while ((char && NUMBERS.test(char)) || char === '.') {
  103. value += char;
  104. char = input[++current];
  105. }
  106. tokens.push({
  107. type: 'number',
  108. value,
  109. });
  110. continue;
  111. }
  112. let LETTERS = /[a-z]/i;
  113. if (char && LETTERS.test(char)) {
  114. let value = '';
  115. while (char && LETTERS.test(char)) {
  116. if (current === input.length) {
  117. break;
  118. }
  119. value += char;
  120. char = input[++current];
  121. }
  122. if (value == 'true' || value == 'false' || value === 'null') {
  123. tokens.push({
  124. type: 'name',
  125. value,
  126. });
  127. }
  128. else {
  129. // unknown token, e.g. `nul` which isn't quite `null`
  130. current++;
  131. continue;
  132. }
  133. continue;
  134. }
  135. current++;
  136. }
  137. return tokens;
  138. }, strip = (tokens) => {
  139. if (tokens.length === 0) {
  140. return tokens;
  141. }
  142. let lastToken = tokens[tokens.length - 1];
  143. switch (lastToken.type) {
  144. case 'separator':
  145. tokens = tokens.slice(0, tokens.length - 1);
  146. return strip(tokens);
  147. break;
  148. case 'number':
  149. let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];
  150. if (lastCharacterOfLastToken === '.' || lastCharacterOfLastToken === '-') {
  151. tokens = tokens.slice(0, tokens.length - 1);
  152. return strip(tokens);
  153. }
  154. case 'string':
  155. let tokenBeforeTheLastToken = tokens[tokens.length - 2];
  156. if (tokenBeforeTheLastToken?.type === 'delimiter') {
  157. tokens = tokens.slice(0, tokens.length - 1);
  158. return strip(tokens);
  159. }
  160. else if (tokenBeforeTheLastToken?.type === 'brace' && tokenBeforeTheLastToken.value === '{') {
  161. tokens = tokens.slice(0, tokens.length - 1);
  162. return strip(tokens);
  163. }
  164. break;
  165. case 'delimiter':
  166. tokens = tokens.slice(0, tokens.length - 1);
  167. return strip(tokens);
  168. break;
  169. }
  170. return tokens;
  171. }, unstrip = (tokens) => {
  172. let tail = [];
  173. tokens.map((token) => {
  174. if (token.type === 'brace') {
  175. if (token.value === '{') {
  176. tail.push('}');
  177. }
  178. else {
  179. tail.splice(tail.lastIndexOf('}'), 1);
  180. }
  181. }
  182. if (token.type === 'paren') {
  183. if (token.value === '[') {
  184. tail.push(']');
  185. }
  186. else {
  187. tail.splice(tail.lastIndexOf(']'), 1);
  188. }
  189. }
  190. });
  191. if (tail.length > 0) {
  192. tail.reverse().map((item) => {
  193. if (item === '}') {
  194. tokens.push({
  195. type: 'brace',
  196. value: '}',
  197. });
  198. }
  199. else if (item === ']') {
  200. tokens.push({
  201. type: 'paren',
  202. value: ']',
  203. });
  204. }
  205. });
  206. }
  207. return tokens;
  208. }, generate = (tokens) => {
  209. let output = '';
  210. tokens.map((token) => {
  211. switch (token.type) {
  212. case 'string':
  213. output += '"' + token.value + '"';
  214. break;
  215. default:
  216. output += token.value;
  217. break;
  218. }
  219. });
  220. return output;
  221. }, partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));
  222. export { partialParse };
  223. //# sourceMappingURL=parser.mjs.map