type Source = unknown;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Replacer = ((this: any, key: string, value: any) => any) | (number | string)[];
type Space = string | number;
/**
* JSON.stringify wrapper. Some characters or substrings of stringify result are unicode-encoded to make result safe for
* embedding into HTML (including CDATA strings).
* In short, it should encode these:
* - " });`
*
* will result in
*
* `// {"comment":"xss, here i come\u003c/script>\u003cscript>alert(69)\u003c/script>"}`
* @returns {void|string} - A JSON string representing the given value or undefined if non-convertable value is passed.
*/
const stringify = (source: Source, replacer?: Replacer, space?: Space) => {
// @ts-expect-error TS isn't smart enough for this
const result = JSON.stringify(source, replacer, space);
if (typeof result !== "string") {
return result;
}
return result
.replace(/<(\/?)(script)/gi, "\\u003c$1$2") // $2 here is to preserve case of the tag name
.replace(/]]>/g, "]]\\u003e")
.replace(/\u2028/g, "\\u2028")
.replace(/\u2029/g, "\\u2029")
.replace(/-->/g, "--\\u003e");
};
export { stringify };
// eslint-disable-next-line import/no-default-export
export default stringify;