| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Natsu @xiaoxiaojx
- This file contains code ported from strip-json-comments:
- https://github.com/sindresorhus/strip-json-comments
- Original license: MIT
- Original author: Sindre Sorhus
- */
- "use strict";
- /**
- * @typedef {object} StripJsonCommentsOptions
- * @property {boolean=} whitespace Replace comments with whitespace
- * @property {boolean=} trailingCommas Strip trailing commas
- */
- const singleComment = Symbol("singleComment");
- const multiComment = Symbol("multiComment");
- /**
- * Strip without whitespace (returns empty string)
- * @param {string} _string Unused
- * @param {number} _start Unused
- * @param {number} _end Unused
- * @returns {string} Empty string for all input
- */
- const stripWithoutWhitespace = (_string, _start, _end) => "";
- /**
- * Replace all characters except ASCII spaces, tabs and line endings with regular spaces to ensure valid JSON output.
- * @param {string} string String to process
- * @param {number} start Start index
- * @param {number} end End index
- * @returns {string} Processed string with comments replaced by whitespace
- */
- const stripWithWhitespace = (string, start, end) =>
- string.slice(start, end).replace(/[^ \t\r\n]/g, " ");
- /**
- * Check if a quote is escaped
- * @param {string} jsonString JSON string
- * @param {number} quotePosition Position of the quote
- * @returns {boolean} True if the quote at the given position is escaped
- */
- const isEscaped = (jsonString, quotePosition) => {
- let index = quotePosition - 1;
- let backslashCount = 0;
- while (jsonString[index] === "\\") {
- index -= 1;
- backslashCount += 1;
- }
- return Boolean(backslashCount % 2);
- };
- /**
- * Strip comments from JSON string
- * @param {string} jsonString JSON string with potential comments
- * @param {StripJsonCommentsOptions} options Options
- * @returns {string} JSON string without comments
- */
- function stripJsonComments(
- jsonString,
- { whitespace = true, trailingCommas = false } = {},
- ) {
- if (typeof jsonString !== "string") {
- throw new TypeError(
- `Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``,
- );
- }
- const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
- let isInsideString = false;
- /** @type {false | typeof singleComment | typeof multiComment} */
- let isInsideComment = false;
- let offset = 0;
- let buffer = "";
- let result = "";
- let commaIndex = -1;
- for (let index = 0; index < jsonString.length; index++) {
- const currentCharacter = jsonString[index];
- const nextCharacter = jsonString[index + 1];
- if (!isInsideComment && currentCharacter === '"') {
- // Enter or exit string
- const escaped = isEscaped(jsonString, index);
- if (!escaped) {
- isInsideString = !isInsideString;
- }
- }
- if (isInsideString) {
- continue;
- }
- if (!isInsideComment && currentCharacter + nextCharacter === "//") {
- // Enter single-line comment
- buffer += jsonString.slice(offset, index);
- offset = index;
- isInsideComment = singleComment;
- index++;
- } else if (
- isInsideComment === singleComment &&
- currentCharacter + nextCharacter === "\r\n"
- ) {
- // Exit single-line comment via \r\n
- index++;
- isInsideComment = false;
- buffer += strip(jsonString, offset, index);
- offset = index;
- continue;
- } else if (isInsideComment === singleComment && currentCharacter === "\n") {
- // Exit single-line comment via \n
- isInsideComment = false;
- buffer += strip(jsonString, offset, index);
- offset = index;
- } else if (!isInsideComment && currentCharacter + nextCharacter === "/*") {
- // Enter multiline comment
- buffer += jsonString.slice(offset, index);
- offset = index;
- isInsideComment = multiComment;
- index++;
- continue;
- } else if (
- isInsideComment === multiComment &&
- currentCharacter + nextCharacter === "*/"
- ) {
- // Exit multiline comment
- index++;
- isInsideComment = false;
- buffer += strip(jsonString, offset, index + 1);
- offset = index + 1;
- continue;
- } else if (trailingCommas && !isInsideComment) {
- if (commaIndex !== -1) {
- if (currentCharacter === "}" || currentCharacter === "]") {
- // Strip trailing comma
- buffer += jsonString.slice(offset, index);
- result += strip(buffer, 0, 1) + buffer.slice(1);
- buffer = "";
- offset = index;
- commaIndex = -1;
- } else if (
- currentCharacter !== " " &&
- currentCharacter !== "\t" &&
- currentCharacter !== "\r" &&
- currentCharacter !== "\n"
- ) {
- // Hit non-whitespace following a comma; comma is not trailing
- buffer += jsonString.slice(offset, index);
- offset = index;
- commaIndex = -1;
- }
- } else if (currentCharacter === ",") {
- // Flush buffer prior to this point, and save new comma index
- result += buffer + jsonString.slice(offset, index);
- buffer = "";
- offset = index;
- commaIndex = index;
- }
- }
- }
- const remaining =
- isInsideComment === singleComment
- ? strip(jsonString, offset, jsonString.length)
- : jsonString.slice(offset);
- return result + buffer + remaining;
- }
- module.exports = stripJsonComments;
|