strip-json-comments.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const singleComment = Symbol('singleComment');
  2. const multiComment = Symbol('multiComment');
  3. const stripWithoutWhitespace = () => '';
  4. const stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/\S/g, ' ');
  5. const isEscaped = (jsonString, quotePosition) => {
  6. let index = quotePosition - 1;
  7. let backslashCount = 0;
  8. while (jsonString[index] === '\\') {
  9. index -= 1;
  10. backslashCount += 1;
  11. }
  12. return Boolean(backslashCount % 2);
  13. };
  14. export default function stripJsonComments(jsonString, { whitespace = true } = {}) {
  15. if (typeof jsonString !== 'string') {
  16. throw new TypeError(
  17. `Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``,
  18. );
  19. }
  20. const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
  21. let isInsideString = false;
  22. let isInsideComment = false;
  23. let offset = 0;
  24. let result = '';
  25. for (let index = 0; index < jsonString.length; index++) {
  26. const currentCharacter = jsonString[index];
  27. const nextCharacter = jsonString[index + 1];
  28. if (!isInsideComment && currentCharacter === '"') {
  29. const escaped = isEscaped(jsonString, index);
  30. if (!escaped) {
  31. isInsideString = !isInsideString;
  32. }
  33. }
  34. if (isInsideString) {
  35. continue;
  36. }
  37. if (!isInsideComment && currentCharacter + nextCharacter === '//') {
  38. result += jsonString.slice(offset, index);
  39. offset = index;
  40. isInsideComment = singleComment;
  41. index++;
  42. } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === '\r\n') {
  43. index++;
  44. isInsideComment = false;
  45. result += strip(jsonString, offset, index);
  46. offset = index;
  47. continue;
  48. } else if (isInsideComment === singleComment && currentCharacter === '\n') {
  49. isInsideComment = false;
  50. result += strip(jsonString, offset, index);
  51. offset = index;
  52. } else if (!isInsideComment && currentCharacter + nextCharacter === '/*') {
  53. result += jsonString.slice(offset, index);
  54. offset = index;
  55. isInsideComment = multiComment;
  56. index++;
  57. continue;
  58. } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === '*/') {
  59. index++;
  60. isInsideComment = false;
  61. result += strip(jsonString, offset, index + 1);
  62. offset = index + 1;
  63. continue;
  64. }
  65. }
  66. return result + (isInsideComment ? strip(jsonString.slice(offset)) : jsonString.slice(offset));
  67. }