javascript-stringify
Advanced tools
| import { Next } from "./types"; | ||
| /** | ||
| * Stringify an array of values. | ||
| */ | ||
| export declare function arrayToString(array: any[], space: string, next: Next): string; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| /** | ||
| * Stringify an array of values. | ||
| */ | ||
| function arrayToString(array, space, next) { | ||
| // Map array values to their stringified values with correct indentation. | ||
| const values = array | ||
| .map(function (value, index) { | ||
| const result = next(value, index); | ||
| if (result === undefined) | ||
| return String(result); | ||
| return space + result.split("\n").join(`\n${space}`); | ||
| }) | ||
| .join(space ? ",\n" : ","); | ||
| // Wrap the array in newlines if we have indentation set. | ||
| if (space && values) { | ||
| return "[\n" + values + "\n]"; | ||
| } | ||
| return "[" + values + "]"; | ||
| } | ||
| exports.arrayToString = arrayToString; | ||
| //# sourceMappingURL=array.js.map |
| {"version":3,"file":"array.js","sourceRoot":"","sources":["../src/array.ts"],"names":[],"mappings":";;AAEA;;GAEG;AACH,SAAgB,aAAa,CAAC,KAAY,EAAE,KAAa,EAAE,IAAU;IACnE,yEAAyE;IACzE,MAAM,MAAM,GAAG,KAAK;SACjB,GAAG,CAAC,UAAS,KAAK,EAAE,KAAK;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAElC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhD,OAAO,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAE7B,yDAAyD;IACzD,IAAI,KAAK,IAAI,MAAM,EAAE;QACnB,OAAO,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;KAC/B;IAED,OAAO,GAAG,GAAG,MAAM,GAAG,GAAG,CAAC;AAC5B,CAAC;AAlBD,sCAkBC","sourcesContent":["import { Next } from \"./types\";\n\n/**\n * Stringify an array of values.\n */\nexport function arrayToString(array: any[], space: string, next: Next) {\n // Map array values to their stringified values with correct indentation.\n const values = array\n .map(function(value, index) {\n const result = next(value, index);\n\n if (result === undefined) return String(result);\n\n return space + result.split(\"\\n\").join(`\\n${space}`);\n })\n .join(space ? \",\\n\" : \",\");\n\n // Wrap the array in newlines if we have indentation set.\n if (space && values) {\n return \"[\\n\" + values + \"\\n]\";\n }\n\n return \"[\" + values + \"]\";\n}\n"]} |
| import { Next } from "./types"; | ||
| declare const FUNCTION_PREFIXES: { | ||
| Function: string; | ||
| GeneratorFunction: string; | ||
| AsyncFunction: string; | ||
| AsyncGeneratorFunction: string; | ||
| }; | ||
| /** | ||
| * Stringify a function. | ||
| */ | ||
| export declare function functionToString(fn: Function, space: string, next: Next): string; | ||
| /** | ||
| * Rewrite a stringified function to remove initial indentation. | ||
| */ | ||
| export declare function dedentFunction(fnString: string): string; | ||
| /** | ||
| * Function parser and stringify. | ||
| */ | ||
| export declare class FunctionParser { | ||
| fn: Function; | ||
| indent: string; | ||
| next: Next; | ||
| key?: string | number | symbol | undefined; | ||
| fnString: string; | ||
| fnType: keyof typeof FUNCTION_PREFIXES; | ||
| keyQuote: string | undefined; | ||
| keyPrefix: string; | ||
| isMethodCandidate: boolean; | ||
| pos: number; | ||
| hadKeyword: boolean; | ||
| constructor(fn: Function, indent: string, next: Next, key?: string | number | symbol | undefined); | ||
| stringify(): string; | ||
| getPrefix(): string; | ||
| tryParse(): string | undefined; | ||
| /** | ||
| * Attempt to parse the function from the current position by first stripping | ||
| * the function's name from the front. This is not a fool-proof method on all | ||
| * JavaScript engines, but yields good results on Node.js 4 (and slightly | ||
| * less good results on Node.js 6 and 8). | ||
| */ | ||
| tryStrippingName(): string | undefined; | ||
| /** | ||
| * Attempt to advance the parser past the keywords expected to be at the | ||
| * start of this function's definition. This method sets `this.hadKeyword` | ||
| * based on whether or not a `function` keyword is consumed. | ||
| * | ||
| * @return {boolean} | ||
| */ | ||
| tryParsePrefixTokens(): boolean; | ||
| /** | ||
| * Advance the parser past one element of JavaScript syntax. This could be a | ||
| * matched pair of delimiters, like braces or parentheses, or an atomic unit | ||
| * like a keyword, variable, or operator. Return a normalized string | ||
| * representation of the element parsed--for example, returns '{}' for a | ||
| * matched pair of braces. Comments and whitespace are skipped. | ||
| * | ||
| * (This isn't a full parser, so the token scanning logic used here is as | ||
| * simple as it can be. As a consequence, some things that are one token in | ||
| * JavaScript, like decimal number literals or most multicharacter operators | ||
| * like '&&', are split into more than one token here. However, awareness of | ||
| * some multicharacter sequences like '=>' is necessary, so we match the few | ||
| * of them that we care about.) | ||
| */ | ||
| consumeSyntax(wordLikeToken?: string): string | undefined; | ||
| consumeSyntaxUntil(startToken: string, endToken: string): string | undefined; | ||
| consumeMatch(re: RegExp): RegExpExecArray | null; | ||
| /** | ||
| * Advance the parser past an arbitrary regular expression. Return `token`, | ||
| * or the match object of the regexp. | ||
| */ | ||
| consumeRegExp(re: RegExp, token: string): string | undefined; | ||
| /** | ||
| * Advance the parser past a template string. | ||
| */ | ||
| consumeTemplate(): "`" | undefined; | ||
| /** | ||
| * Advance the parser past any whitespace or comments. | ||
| */ | ||
| consumeWhitespace(): void; | ||
| } | ||
| export {}; |
+296
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const quote_1 = require("./quote"); | ||
| /** | ||
| * Used in function stringification. | ||
| */ | ||
| /* istanbul ignore next */ | ||
| const METHOD_NAMES_ARE_QUOTED = { | ||
| " "() { | ||
| /* Empty. */ | ||
| } | ||
| }[" "] | ||
| .toString() | ||
| .charAt(0) === '"'; | ||
| const FUNCTION_PREFIXES = { | ||
| Function: "function ", | ||
| GeneratorFunction: "function* ", | ||
| AsyncFunction: "async function ", | ||
| AsyncGeneratorFunction: "async function* " | ||
| }; | ||
| const METHOD_PREFIXES = { | ||
| Function: "", | ||
| GeneratorFunction: "*", | ||
| AsyncFunction: "async ", | ||
| AsyncGeneratorFunction: "async *" | ||
| }; | ||
| const TOKENS_PRECEDING_REGEXPS = new Set(("case delete else in instanceof new return throw typeof void " + | ||
| ", ; : + - ! ~ & | ^ * / % < > ? =").split(" ")); | ||
| /** | ||
| * Stringify a function. | ||
| */ | ||
| function functionToString(fn, space, next) { | ||
| return new FunctionParser(fn, space, next).stringify(); | ||
| } | ||
| exports.functionToString = functionToString; | ||
| /** | ||
| * Rewrite a stringified function to remove initial indentation. | ||
| */ | ||
| function dedentFunction(fnString) { | ||
| let found; | ||
| for (const line of fnString.split("\n").slice(1)) { | ||
| const m = /^[\s\t]+/.exec(line); | ||
| if (!m) | ||
| return fnString; // Early exit without indent. | ||
| const [str] = m; | ||
| if (found === undefined) | ||
| found = str; | ||
| else if (str.length < found.length) | ||
| found = str; | ||
| } | ||
| return found ? fnString.split(`\n${found}`).join("\n") : fnString; | ||
| } | ||
| exports.dedentFunction = dedentFunction; | ||
| /** | ||
| * Function parser and stringify. | ||
| */ | ||
| class FunctionParser { | ||
| constructor(fn, indent, next, key) { | ||
| this.fn = fn; | ||
| this.indent = indent; | ||
| this.next = next; | ||
| this.key = key; | ||
| this.pos = 0; | ||
| this.hadKeyword = false; | ||
| this.fnString = Function.prototype.toString.call(fn); | ||
| this.fnType = fn.constructor.name; | ||
| this.keyQuote = key === undefined ? "" : quote_1.quoteKey(key, next); | ||
| this.keyPrefix = | ||
| key === undefined ? "" : `${this.keyQuote}:${indent ? " " : ""}`; | ||
| this.isMethodCandidate = | ||
| key === undefined ? false : this.fn.name === "" || this.fn.name === key; | ||
| } | ||
| stringify() { | ||
| const value = this.tryParse(); | ||
| // If we can't stringify this function, return a void expression; for | ||
| // bonus help with debugging, include the function as a string literal. | ||
| if (!value) { | ||
| return `${this.keyPrefix}void ${this.next(this.fnString)}`; | ||
| } | ||
| return dedentFunction(value); | ||
| } | ||
| getPrefix() { | ||
| if (this.isMethodCandidate && !this.hadKeyword) { | ||
| return METHOD_PREFIXES[this.fnType] + this.keyQuote; | ||
| } | ||
| return this.keyPrefix + FUNCTION_PREFIXES[this.fnType]; | ||
| } | ||
| tryParse() { | ||
| if (this.fnString[this.fnString.length - 1] !== "}") { | ||
| // Must be an arrow function. | ||
| return this.keyPrefix + this.fnString; | ||
| } | ||
| // Attempt to remove function prefix. | ||
| if (this.fn.name) { | ||
| const result = this.tryStrippingName(); | ||
| if (result) | ||
| return result; | ||
| } | ||
| // Support class expressions. | ||
| const prevPos = this.pos; | ||
| if (this.consumeSyntax() === "class") | ||
| return this.fnString; | ||
| this.pos = prevPos; | ||
| if (this.tryParsePrefixTokens()) { | ||
| const result = this.tryStrippingName(); | ||
| if (result) | ||
| return result; | ||
| let offset = this.pos; | ||
| switch (this.consumeSyntax("WORD_LIKE")) { | ||
| case "WORD_LIKE": | ||
| if (this.isMethodCandidate && !this.hadKeyword) { | ||
| offset = this.pos; | ||
| } | ||
| // tslint:disable-next-line no-switch-case-fall-through | ||
| case "()": | ||
| if (this.fnString.substr(this.pos, 2) === "=>") { | ||
| return this.keyPrefix + this.fnString; | ||
| } | ||
| this.pos = offset; | ||
| // tslint:disable-next-line no-switch-case-fall-through | ||
| case '"': | ||
| case "'": | ||
| case "[]": | ||
| return this.getPrefix() + this.fnString.substr(this.pos); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Attempt to parse the function from the current position by first stripping | ||
| * the function's name from the front. This is not a fool-proof method on all | ||
| * JavaScript engines, but yields good results on Node.js 4 (and slightly | ||
| * less good results on Node.js 6 and 8). | ||
| */ | ||
| tryStrippingName() { | ||
| if (METHOD_NAMES_ARE_QUOTED) { | ||
| // ... then this approach is unnecessary and yields false positives. | ||
| return; | ||
| } | ||
| let start = this.pos; | ||
| const prefix = this.fnString.substr(this.pos, this.fn.name.length); | ||
| if (prefix === this.fn.name) { | ||
| this.pos += prefix.length; | ||
| if (this.consumeSyntax() === "()" && | ||
| this.consumeSyntax() === "{}" && | ||
| this.pos === this.fnString.length) { | ||
| // Don't include the function's name if it will be included in the | ||
| // prefix, or if it's invalid as a name in a function expression. | ||
| if (this.isMethodCandidate || !quote_1.isValidVariableName(prefix)) { | ||
| start += prefix.length; | ||
| } | ||
| return this.getPrefix() + this.fnString.substr(start); | ||
| } | ||
| } | ||
| this.pos = start; | ||
| } | ||
| /** | ||
| * Attempt to advance the parser past the keywords expected to be at the | ||
| * start of this function's definition. This method sets `this.hadKeyword` | ||
| * based on whether or not a `function` keyword is consumed. | ||
| * | ||
| * @return {boolean} | ||
| */ | ||
| tryParsePrefixTokens() { | ||
| let posPrev = this.pos; | ||
| this.hadKeyword = false; | ||
| switch (this.fnType) { | ||
| case "AsyncFunction": | ||
| if (this.consumeSyntax() !== "async") | ||
| return false; | ||
| posPrev = this.pos; | ||
| // tslint:disable-next-line no-switch-case-fall-through | ||
| case "Function": | ||
| if (this.consumeSyntax() === "function") { | ||
| this.hadKeyword = true; | ||
| } | ||
| else { | ||
| this.pos = posPrev; | ||
| } | ||
| return true; | ||
| case "AsyncGeneratorFunction": | ||
| if (this.consumeSyntax() !== "async") | ||
| return false; | ||
| // tslint:disable-next-line no-switch-case-fall-through | ||
| case "GeneratorFunction": | ||
| let token = this.consumeSyntax(); | ||
| if (token === "function") { | ||
| token = this.consumeSyntax(); | ||
| this.hadKeyword = true; | ||
| } | ||
| return token === "*"; | ||
| } | ||
| } | ||
| /** | ||
| * Advance the parser past one element of JavaScript syntax. This could be a | ||
| * matched pair of delimiters, like braces or parentheses, or an atomic unit | ||
| * like a keyword, variable, or operator. Return a normalized string | ||
| * representation of the element parsed--for example, returns '{}' for a | ||
| * matched pair of braces. Comments and whitespace are skipped. | ||
| * | ||
| * (This isn't a full parser, so the token scanning logic used here is as | ||
| * simple as it can be. As a consequence, some things that are one token in | ||
| * JavaScript, like decimal number literals or most multicharacter operators | ||
| * like '&&', are split into more than one token here. However, awareness of | ||
| * some multicharacter sequences like '=>' is necessary, so we match the few | ||
| * of them that we care about.) | ||
| */ | ||
| consumeSyntax(wordLikeToken) { | ||
| const m = this.consumeMatch(/^(?:([A-Za-z_0-9$\xA0-\uFFFF]+)|=>|\+\+|\-\-|.)/); | ||
| if (!m) | ||
| return; | ||
| const [token, match] = m; | ||
| this.consumeWhitespace(); | ||
| if (match) | ||
| return wordLikeToken || match; | ||
| switch (token) { | ||
| case "(": | ||
| return this.consumeSyntaxUntil("(", ")"); | ||
| case "[": | ||
| return this.consumeSyntaxUntil("[", "]"); | ||
| case "{": | ||
| return this.consumeSyntaxUntil("{", "}"); | ||
| case "`": | ||
| return this.consumeTemplate(); | ||
| case '"': | ||
| return this.consumeRegExp(/^(?:[^\\"]|\\.)*"/, '"'); | ||
| case "'": | ||
| return this.consumeRegExp(/^(?:[^\\']|\\.)*'/, "'"); | ||
| } | ||
| return token; | ||
| } | ||
| consumeSyntaxUntil(startToken, endToken) { | ||
| let isRegExpAllowed = true; | ||
| for (;;) { | ||
| const token = this.consumeSyntax(); | ||
| if (token === endToken) | ||
| return startToken + endToken; | ||
| if (!token || token === ")" || token === "]" || token === "}") | ||
| return; | ||
| if (token === "/" && | ||
| isRegExpAllowed && | ||
| this.consumeMatch(/^(?:\\.|[^\\\/\n[]|\[(?:\\.|[^\]])*\])+\/[a-z]*/)) { | ||
| isRegExpAllowed = false; | ||
| this.consumeWhitespace(); | ||
| } | ||
| else { | ||
| isRegExpAllowed = TOKENS_PRECEDING_REGEXPS.has(token); | ||
| } | ||
| } | ||
| } | ||
| consumeMatch(re) { | ||
| const m = re.exec(this.fnString.substr(this.pos)); | ||
| if (m) | ||
| this.pos += m[0].length; | ||
| return m; | ||
| } | ||
| /** | ||
| * Advance the parser past an arbitrary regular expression. Return `token`, | ||
| * or the match object of the regexp. | ||
| */ | ||
| consumeRegExp(re, token) { | ||
| const m = re.exec(this.fnString.substr(this.pos)); | ||
| if (!m) | ||
| return; | ||
| this.pos += m[0].length; | ||
| this.consumeWhitespace(); | ||
| return token; | ||
| } | ||
| /** | ||
| * Advance the parser past a template string. | ||
| */ | ||
| consumeTemplate() { | ||
| for (;;) { | ||
| this.consumeMatch(/^(?:[^`$\\]|\\.|\$(?!{))*/); | ||
| if (this.fnString[this.pos] === "`") { | ||
| this.pos++; | ||
| this.consumeWhitespace(); | ||
| return "`"; | ||
| } | ||
| if (this.fnString.substr(this.pos, 2) === "${") { | ||
| this.pos += 2; | ||
| this.consumeWhitespace(); | ||
| if (this.consumeSyntaxUntil("{", "}")) | ||
| continue; | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| /** | ||
| * Advance the parser past any whitespace or comments. | ||
| */ | ||
| consumeWhitespace() { | ||
| this.consumeMatch(/^(?:\s|\/\/.*|\/\*[^]*?\*\/)*/); | ||
| } | ||
| } | ||
| exports.FunctionParser = FunctionParser; | ||
| //# sourceMappingURL=function.js.map |
| {"version":3,"file":"function.js","sourceRoot":"","sources":["../src/function.ts"],"names":[],"mappings":"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","sourcesContent":["import { Next } from \"./types\";\nimport { quoteKey, isValidVariableName } from \"./quote\";\n\n/**\n * Used in function stringification.\n */\n/* istanbul ignore next */\nconst METHOD_NAMES_ARE_QUOTED =\n {\n \" \"() {\n /* Empty. */\n }\n }[\" \"]\n .toString()\n .charAt(0) === '\"';\n\nconst FUNCTION_PREFIXES = {\n Function: \"function \",\n GeneratorFunction: \"function* \",\n AsyncFunction: \"async function \",\n AsyncGeneratorFunction: \"async function* \"\n};\n\nconst METHOD_PREFIXES = {\n Function: \"\",\n GeneratorFunction: \"*\",\n AsyncFunction: \"async \",\n AsyncGeneratorFunction: \"async *\"\n};\n\nconst TOKENS_PRECEDING_REGEXPS = new Set(\n (\n \"case delete else in instanceof new return throw typeof void \" +\n \", ; : + - ! ~ & | ^ * / % < > ? =\"\n ).split(\" \")\n);\n\n/**\n * Stringify a function.\n */\nexport function functionToString(fn: Function, space: string, next: Next) {\n return new FunctionParser(fn, space, next).stringify();\n}\n\n/**\n * Rewrite a stringified function to remove initial indentation.\n */\nexport function dedentFunction(fnString: string) {\n let found: string | undefined;\n\n for (const line of fnString.split(\"\\n\").slice(1)) {\n const m = /^[\\s\\t]+/.exec(line);\n if (!m) return fnString; // Early exit without indent.\n\n const [str] = m;\n\n if (found === undefined) found = str;\n else if (str.length < found.length) found = str;\n }\n\n return found ? fnString.split(`\\n${found}`).join(\"\\n\") : fnString;\n}\n\n/**\n * Function parser and stringify.\n */\nexport class FunctionParser {\n fnString: string;\n fnType: keyof typeof FUNCTION_PREFIXES;\n keyQuote: string | undefined;\n keyPrefix: string;\n isMethodCandidate: boolean;\n\n pos = 0;\n hadKeyword = false;\n\n constructor(\n public fn: Function,\n public indent: string,\n public next: Next,\n public key?: PropertyKey\n ) {\n this.fnString = Function.prototype.toString.call(fn);\n this.fnType = fn.constructor.name as keyof typeof FUNCTION_PREFIXES;\n this.keyQuote = key === undefined ? \"\" : quoteKey(key, next);\n this.keyPrefix =\n key === undefined ? \"\" : `${this.keyQuote}:${indent ? \" \" : \"\"}`;\n this.isMethodCandidate =\n key === undefined ? false : this.fn.name === \"\" || this.fn.name === key;\n }\n\n stringify() {\n const value = this.tryParse();\n\n // If we can't stringify this function, return a void expression; for\n // bonus help with debugging, include the function as a string literal.\n if (!value) {\n return `${this.keyPrefix}void ${this.next(this.fnString)}`;\n }\n\n return dedentFunction(value);\n }\n\n getPrefix() {\n if (this.isMethodCandidate && !this.hadKeyword) {\n return METHOD_PREFIXES[this.fnType] + this.keyQuote;\n }\n\n return this.keyPrefix + FUNCTION_PREFIXES[this.fnType];\n }\n\n tryParse() {\n if (this.fnString[this.fnString.length - 1] !== \"}\") {\n // Must be an arrow function.\n return this.keyPrefix + this.fnString;\n }\n\n // Attempt to remove function prefix.\n if (this.fn.name) {\n const result = this.tryStrippingName();\n if (result) return result;\n }\n\n // Support class expressions.\n const prevPos = this.pos;\n if (this.consumeSyntax() === \"class\") return this.fnString;\n this.pos = prevPos;\n\n if (this.tryParsePrefixTokens()) {\n const result = this.tryStrippingName();\n if (result) return result;\n\n let offset = this.pos;\n\n switch (this.consumeSyntax(\"WORD_LIKE\")) {\n case \"WORD_LIKE\":\n if (this.isMethodCandidate && !this.hadKeyword) {\n offset = this.pos;\n }\n // tslint:disable-next-line no-switch-case-fall-through\n case \"()\":\n if (this.fnString.substr(this.pos, 2) === \"=>\") {\n return this.keyPrefix + this.fnString;\n }\n\n this.pos = offset;\n // tslint:disable-next-line no-switch-case-fall-through\n case '\"':\n case \"'\":\n case \"[]\":\n return this.getPrefix() + this.fnString.substr(this.pos);\n }\n }\n }\n\n /**\n * Attempt to parse the function from the current position by first stripping\n * the function's name from the front. This is not a fool-proof method on all\n * JavaScript engines, but yields good results on Node.js 4 (and slightly\n * less good results on Node.js 6 and 8).\n */\n tryStrippingName() {\n if (METHOD_NAMES_ARE_QUOTED) {\n // ... then this approach is unnecessary and yields false positives.\n return;\n }\n\n let start = this.pos;\n const prefix = this.fnString.substr(this.pos, this.fn.name.length);\n\n if (prefix === this.fn.name) {\n this.pos += prefix.length;\n\n if (\n this.consumeSyntax() === \"()\" &&\n this.consumeSyntax() === \"{}\" &&\n this.pos === this.fnString.length\n ) {\n // Don't include the function's name if it will be included in the\n // prefix, or if it's invalid as a name in a function expression.\n if (this.isMethodCandidate || !isValidVariableName(prefix)) {\n start += prefix.length;\n }\n\n return this.getPrefix() + this.fnString.substr(start);\n }\n }\n\n this.pos = start;\n }\n\n /**\n * Attempt to advance the parser past the keywords expected to be at the\n * start of this function's definition. This method sets `this.hadKeyword`\n * based on whether or not a `function` keyword is consumed.\n *\n * @return {boolean}\n */\n tryParsePrefixTokens() {\n let posPrev = this.pos;\n\n this.hadKeyword = false;\n\n switch (this.fnType) {\n case \"AsyncFunction\":\n if (this.consumeSyntax() !== \"async\") return false;\n\n posPrev = this.pos;\n // tslint:disable-next-line no-switch-case-fall-through\n case \"Function\":\n if (this.consumeSyntax() === \"function\") {\n this.hadKeyword = true;\n } else {\n this.pos = posPrev;\n }\n return true;\n case \"AsyncGeneratorFunction\":\n if (this.consumeSyntax() !== \"async\") return false;\n // tslint:disable-next-line no-switch-case-fall-through\n case \"GeneratorFunction\":\n let token = this.consumeSyntax();\n\n if (token === \"function\") {\n token = this.consumeSyntax();\n this.hadKeyword = true;\n }\n\n return token === \"*\";\n }\n }\n\n /**\n * Advance the parser past one element of JavaScript syntax. This could be a\n * matched pair of delimiters, like braces or parentheses, or an atomic unit\n * like a keyword, variable, or operator. Return a normalized string\n * representation of the element parsed--for example, returns '{}' for a\n * matched pair of braces. Comments and whitespace are skipped.\n *\n * (This isn't a full parser, so the token scanning logic used here is as\n * simple as it can be. As a consequence, some things that are one token in\n * JavaScript, like decimal number literals or most multicharacter operators\n * like '&&', are split into more than one token here. However, awareness of\n * some multicharacter sequences like '=>' is necessary, so we match the few\n * of them that we care about.)\n */\n consumeSyntax(wordLikeToken?: string) {\n const m = this.consumeMatch(\n /^(?:([A-Za-z_0-9$\\xA0-\\uFFFF]+)|=>|\\+\\+|\\-\\-|.)/\n );\n\n if (!m) return;\n\n const [token, match] = m;\n this.consumeWhitespace();\n\n if (match) return wordLikeToken || match;\n\n switch (token) {\n case \"(\":\n return this.consumeSyntaxUntil(\"(\", \")\");\n case \"[\":\n return this.consumeSyntaxUntil(\"[\", \"]\");\n case \"{\":\n return this.consumeSyntaxUntil(\"{\", \"}\");\n case \"`\":\n return this.consumeTemplate();\n case '\"':\n return this.consumeRegExp(/^(?:[^\\\\\"]|\\\\.)*\"/, '\"');\n case \"'\":\n return this.consumeRegExp(/^(?:[^\\\\']|\\\\.)*'/, \"'\");\n }\n\n return token;\n }\n\n consumeSyntaxUntil(startToken: string, endToken: string): string | undefined {\n let isRegExpAllowed = true;\n\n for (;;) {\n const token = this.consumeSyntax();\n if (token === endToken) return startToken + endToken;\n if (!token || token === \")\" || token === \"]\" || token === \"}\") return;\n\n if (\n token === \"/\" &&\n isRegExpAllowed &&\n this.consumeMatch(/^(?:\\\\.|[^\\\\\\/\\n[]|\\[(?:\\\\.|[^\\]])*\\])+\\/[a-z]*/)\n ) {\n isRegExpAllowed = false;\n this.consumeWhitespace();\n } else {\n isRegExpAllowed = TOKENS_PRECEDING_REGEXPS.has(token);\n }\n }\n }\n\n consumeMatch(re: RegExp) {\n const m = re.exec(this.fnString.substr(this.pos));\n if (m) this.pos += m[0].length;\n return m;\n }\n\n /**\n * Advance the parser past an arbitrary regular expression. Return `token`,\n * or the match object of the regexp.\n */\n consumeRegExp(re: RegExp, token: string): string | undefined {\n const m = re.exec(this.fnString.substr(this.pos));\n if (!m) return;\n this.pos += m[0].length;\n this.consumeWhitespace();\n return token;\n }\n\n /**\n * Advance the parser past a template string.\n */\n consumeTemplate() {\n for (;;) {\n this.consumeMatch(/^(?:[^`$\\\\]|\\\\.|\\$(?!{))*/);\n\n if (this.fnString[this.pos] === \"`\") {\n this.pos++;\n this.consumeWhitespace();\n return \"`\";\n }\n\n if (this.fnString.substr(this.pos, 2) === \"${\") {\n this.pos += 2;\n this.consumeWhitespace();\n\n if (this.consumeSyntaxUntil(\"{\", \"}\")) continue;\n }\n\n return;\n }\n }\n\n /**\n * Advance the parser past any whitespace or comments.\n */\n consumeWhitespace() {\n this.consumeMatch(/^(?:\\s|\\/\\/.*|\\/\\*[^]*?\\*\\/)*/);\n }\n}\n"]} |
| import { ToString } from "./types"; | ||
| export interface Options { | ||
| maxDepth?: number; | ||
| maxValues?: number; | ||
| references?: boolean; | ||
| skipUndefinedProperties?: boolean; | ||
| } | ||
| /** | ||
| * Stringify any JavaScript value. | ||
| */ | ||
| export declare function stringify(value: any, replacer?: ToString | null, indent?: string | number | null, options?: Options): string | undefined; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const stringify_1 = require("./stringify"); | ||
| const quote_1 = require("./quote"); | ||
| /** | ||
| * Root path node. | ||
| */ | ||
| const ROOT_SENTINEL = Symbol("root"); | ||
| /** | ||
| * Stringify any JavaScript value. | ||
| */ | ||
| function stringify(value, replacer, indent, options = {}) { | ||
| const space = typeof indent === "string" ? indent : " ".repeat(indent || 0); | ||
| const path = []; | ||
| const stack = new Set(); | ||
| const tracking = new Map(); | ||
| const unpack = new Map(); | ||
| let valueCount = 0; | ||
| const { maxDepth = 100, references = false, skipUndefinedProperties = false, maxValues = 100000 } = options; | ||
| // Wrap replacer function to support falling back on supported stringify. | ||
| const valueToString = replacerToString(replacer); | ||
| // Every time you call `next(value)` execute this function. | ||
| const onNext = (value, key) => { | ||
| if (++valueCount > maxValues) | ||
| return; | ||
| if (skipUndefinedProperties && value === undefined) | ||
| return; | ||
| if (path.length > maxDepth) | ||
| return; | ||
| // An undefined key is treated as an out-of-band "value". | ||
| if (key === undefined) | ||
| return valueToString(value, space, onNext); | ||
| path.push(key); | ||
| const result = builder(value); | ||
| path.pop(); | ||
| return result; | ||
| }; | ||
| const builder = references | ||
| ? (value) => { | ||
| if (value !== null && | ||
| (typeof value === "object" || | ||
| typeof value === "function" || | ||
| typeof value === "symbol")) { | ||
| // Track nodes to restore later. | ||
| if (tracking.has(value)) { | ||
| unpack.set(path.slice(1), tracking.get(value)); | ||
| return; // Avoid serializing referenced nodes on an expression. | ||
| } | ||
| // Track encountered nodes. | ||
| tracking.set(value, path.slice(1)); | ||
| } | ||
| return valueToString(value, space, onNext); | ||
| } | ||
| : (value) => { | ||
| // Stop on recursion. | ||
| if (stack.has(value)) | ||
| return; | ||
| stack.add(value); | ||
| const result = valueToString(value, space, onNext); | ||
| stack.delete(value); | ||
| return result; | ||
| }; | ||
| const result = onNext(value, ROOT_SENTINEL); | ||
| // Attempt to restore circular references. | ||
| if (unpack.size) { | ||
| const sp = space ? " " : ""; | ||
| const eol = space ? "\n" : ""; | ||
| let wrapper = `var x${sp}=${sp}${result};${eol}`; | ||
| for (const [key, value] of unpack.entries()) { | ||
| const keyPath = quote_1.stringifyPath(key, onNext); | ||
| const valuePath = quote_1.stringifyPath(value, onNext); | ||
| wrapper += `x${keyPath}${sp}=${sp}x${valuePath};${eol}`; | ||
| } | ||
| return `(function${sp}()${sp}{${eol}${wrapper}return x;${eol}}())`; | ||
| } | ||
| return result; | ||
| } | ||
| exports.stringify = stringify; | ||
| /** | ||
| * Create `toString()` function from replacer. | ||
| */ | ||
| function replacerToString(replacer) { | ||
| if (!replacer) | ||
| return stringify_1.toString; | ||
| return (value, space, next) => { | ||
| return replacer(value, space, (value) => stringify_1.toString(value, space, next)); | ||
| }; | ||
| } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { toString } from \"./stringify\";\nimport { stringifyPath } from \"./quote\";\nimport { Next, ToString } from \"./types\";\n\nexport interface Options {\n maxDepth?: number;\n maxValues?: number;\n references?: boolean;\n skipUndefinedProperties?: boolean;\n}\n\n/**\n * Root path node.\n */\nconst ROOT_SENTINEL = Symbol(\"root\");\n\n/**\n * Stringify any JavaScript value.\n */\nexport function stringify(\n value: any,\n replacer?: ToString | null,\n indent?: string | number | null,\n options: Options = {}\n) {\n const space = typeof indent === \"string\" ? indent : \" \".repeat(indent || 0);\n const path: PropertyKey[] = [];\n const stack = new Set();\n const tracking = new Map<any, PropertyKey[]>();\n const unpack = new Map<PropertyKey[], PropertyKey[]>();\n let valueCount = 0;\n\n const {\n maxDepth = 100,\n references = false,\n skipUndefinedProperties = false,\n maxValues = 100000\n } = options;\n\n // Wrap replacer function to support falling back on supported stringify.\n const valueToString = replacerToString(replacer);\n\n // Every time you call `next(value)` execute this function.\n const onNext: Next = (value, key) => {\n if (++valueCount > maxValues) return;\n if (skipUndefinedProperties && value === undefined) return;\n if (path.length > maxDepth) return;\n\n // An undefined key is treated as an out-of-band \"value\".\n if (key === undefined) return valueToString(value, space, onNext);\n\n path.push(key);\n const result = builder(value);\n path.pop();\n return result;\n };\n\n const builder = references\n ? (value: any): string | undefined => {\n if (\n value !== null &&\n (typeof value === \"object\" ||\n typeof value === \"function\" ||\n typeof value === \"symbol\")\n ) {\n // Track nodes to restore later.\n if (tracking.has(value)) {\n unpack.set(path.slice(1), tracking.get(value)!);\n return; // Avoid serializing referenced nodes on an expression.\n }\n\n // Track encountered nodes.\n tracking.set(value, path.slice(1));\n }\n\n return valueToString(value, space, onNext);\n }\n : (value: any): string | undefined => {\n // Stop on recursion.\n if (stack.has(value)) return;\n\n stack.add(value);\n const result = valueToString(value, space, onNext);\n stack.delete(value);\n return result;\n };\n\n const result = onNext(value, ROOT_SENTINEL);\n\n // Attempt to restore circular references.\n if (unpack.size) {\n const sp = space ? \" \" : \"\";\n const eol = space ? \"\\n\" : \"\";\n let wrapper = `var x${sp}=${sp}${result};${eol}`;\n\n for (const [key, value] of unpack.entries()) {\n const keyPath = stringifyPath(key, onNext);\n const valuePath = stringifyPath(value, onNext);\n\n wrapper += `x${keyPath}${sp}=${sp}x${valuePath};${eol}`;\n }\n\n return `(function${sp}()${sp}{${eol}${wrapper}return x;${eol}}())`;\n }\n\n return result;\n}\n\n/**\n * Create `toString()` function from replacer.\n */\nfunction replacerToString(replacer?: ToString | null) {\n if (!replacer) return toString;\n\n return (value: any, space: string, next: Next) => {\n return replacer(value, space, (value: any) => toString(value, space, next));\n };\n}\n"]} |
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const fc = require("fast-check"); | ||
| const semver_1 = require("semver"); | ||
| const index_1 = require("./index"); | ||
| // Evaluate a string into JavaScript | ||
| const evalValue = (str) => { | ||
| // tslint:disable-next-line no-eval | ||
| return eval(`(${str})`); | ||
| }; | ||
| /** | ||
| * Create a quick test function wrapper. | ||
| */ | ||
| function test(value, result, indent, options) { | ||
| return () => { | ||
| expect(index_1.stringify(value, null, indent, options)).toEqual(result); | ||
| }; | ||
| } | ||
| /** | ||
| * Create a wrapper for round-trip eval tests. | ||
| */ | ||
| function testRoundTrip(expression, indent, options) { | ||
| return () => test(evalValue(expression), expression, indent, options)(); | ||
| } | ||
| /** | ||
| * Check if syntax is supported. | ||
| */ | ||
| function isSupported(expr) { | ||
| try { | ||
| // tslint:disable-next-line no-eval | ||
| eval(expr); | ||
| return true; | ||
| } | ||
| catch (err) { | ||
| if (err.name === "SyntaxError") | ||
| return false; | ||
| throw err; | ||
| } | ||
| } | ||
| /** | ||
| * Generate a list of test cases to run. | ||
| */ | ||
| function cases(cases) { | ||
| return () => { | ||
| for (const value of cases) { | ||
| if (value) | ||
| it(value, testRoundTrip(value)); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Conditionally execute test cases. | ||
| */ | ||
| function describeIf(description, condition, fn) { | ||
| return condition ? describe(description, fn) : describe.skip(description, fn); | ||
| } | ||
| describe("javascript-stringify", () => { | ||
| describe("types", () => { | ||
| describe("booleans", () => { | ||
| it("should be stringified", test(true, "true")); | ||
| }); | ||
| describe("strings", () => { | ||
| it("should wrap in single quotes", test("string", "'string'")); | ||
| it("should escape quote characters", test("'test'", "'\\'test\\''")); | ||
| it("should escape control characters", test("multi\nline", "'multi\\nline'")); | ||
| it("should escape back slashes", test("back\\slash", "'back\\\\slash'")); | ||
| it("should escape certain unicode sequences", test("\u0602", "'\\u0602'")); | ||
| }); | ||
| describe("numbers", () => { | ||
| it("should stringify integers", test(10, "10")); | ||
| it("should stringify floats", test(10.5, "10.5")); | ||
| it('should stringify "NaN"', test(10.5, "10.5")); | ||
| it('should stringify "Infinity"', test(Infinity, "Infinity")); | ||
| it('should stringify "-Infinity"', test(-Infinity, "-Infinity")); | ||
| it('should stringify "-0"', test(-0, "-0")); | ||
| }); | ||
| describe("arrays", () => { | ||
| it("should stringify as array shorthand", test([1, 2, 3], "[1,2,3]")); | ||
| it("should indent elements", test([{ x: 10 }], "[\n\t{\n\t\tx: 10\n\t}\n]", "\t")); | ||
| }); | ||
| describe("objects", () => { | ||
| it("should stringify as object shorthand", test({ key: "value", "-": 10 }, "{key:'value','-':10}")); | ||
| it("should stringify undefined keys", test({ a: true, b: undefined }, "{a:true,b:undefined}")); | ||
| it("should stringify omit undefined keys", test({ a: true, b: undefined }, "{a:true}", null, { | ||
| skipUndefinedProperties: true | ||
| })); | ||
| it("should quote reserved word keys", test({ if: true, else: false }, "{'if':true,'else':false}")); | ||
| it("should not quote Object.prototype keys", test({ constructor: 1, toString: 2 }, "{constructor:1,toString:2}")); | ||
| }); | ||
| describe("functions", () => { | ||
| it("should reindent function bodies", test(evalValue(`function() { | ||
| if (true) { | ||
| return "hello"; | ||
| } | ||
| }`), 'function () {\n if (true) {\n return "hello";\n }\n}', 2)); | ||
| it("should reindent function bodies in objects", test(evalValue(` | ||
| { | ||
| fn: function() { | ||
| if (true) { | ||
| return "hello"; | ||
| } | ||
| } | ||
| } | ||
| `), '{\n fn: function () {\n if (true) {\n return "hello";\n }\n }\n}', 2)); | ||
| it("should reindent function bodies in arrays", test(evalValue(`[ | ||
| function() { | ||
| if (true) { | ||
| return "hello"; | ||
| } | ||
| } | ||
| ]`), '[\n function () {\n if (true) {\n return "hello";\n }\n }\n]', 2)); | ||
| it("should not need to reindent one-liners", testRoundTrip("{\n fn: function () { return; }\n}", 2)); | ||
| it("should gracefully handle unexpected Function.toString formats", () => { | ||
| const origToString = Function.prototype.toString; | ||
| Function.prototype.toString = () => "{nope}"; | ||
| try { | ||
| expect(index_1.stringify(function () { | ||
| /* Empty */ | ||
| })).toEqual("void '{nope}'"); | ||
| } | ||
| finally { | ||
| Function.prototype.toString = origToString; | ||
| } | ||
| }); | ||
| describe("should not take the names of their keys", cases(["{name:function () {}}", "{'tricky name':function () {}}"])); | ||
| }); | ||
| describe("native instances", () => { | ||
| describe("Date", () => { | ||
| const date = new Date(); | ||
| it("should stringify", test(date, "new Date(" + date.getTime() + ")")); | ||
| }); | ||
| describe("RegExp", () => { | ||
| it("should stringify as shorthand", test(/[abc]/gi, "/[abc]/gi")); | ||
| }); | ||
| describe("Number", () => { | ||
| it("should stringify", test(new Number(10), "new Number(10)")); | ||
| }); | ||
| describe("String", () => { | ||
| it("should stringify", test(new String("abc"), "new String('abc')")); | ||
| }); | ||
| describe("Boolean", () => { | ||
| it("should stringify", test(new Boolean(true), "new Boolean(true)")); | ||
| }); | ||
| describeIf("Buffer", typeof Buffer === "function", () => { | ||
| it("should stringify", test(Buffer.from("test"), "new Buffer('test')")); | ||
| }); | ||
| describe("Error", () => { | ||
| it("should stringify", test(new Error("test"), "new Error('test')")); | ||
| }); | ||
| describe("unknown native type", () => { | ||
| it("should be omitted", test({ | ||
| k: typeof process === "undefined" | ||
| ? window.navigator | ||
| : process | ||
| }, "{}")); | ||
| }); | ||
| }); | ||
| describeIf("ES6", typeof Array.from === "function", () => { | ||
| describeIf("Map", typeof Map === "function", () => { | ||
| it("should stringify", test(new Map([["key", "value"]]), "new Map([['key','value']])")); | ||
| }); | ||
| describeIf("Set", typeof Set === "function", () => { | ||
| it("should stringify", test(new Set(["key", "value"]), "new Set(['key','value'])")); | ||
| }); | ||
| describe("arrow functions", () => { | ||
| describe("should stringify", cases([ | ||
| "(a, b) => a + b", | ||
| "o => { return o.a + o.b; }", | ||
| "(a, b) => { if (a) { return b; } }", | ||
| "(a, b) => ({ [a]: b })", | ||
| "a => b => () => a + b" | ||
| ])); | ||
| it("should reindent function bodies", test(evalValue(" () => {\n" + | ||
| " if (true) {\n" + | ||
| ' return "hello";\n' + | ||
| " }\n" + | ||
| " }"), '() => {\n if (true) {\n return "hello";\n }\n}', 2)); | ||
| describeIf("arrows with patterns", isSupported("({x}) => x"), () => { | ||
| describe("should stringify", cases([ | ||
| "({ x, y }) => x + y", | ||
| "({ x, y }) => { if (x === '}') { return y; } }", | ||
| "({ x, y = /[/})]/.test(x) }) => { return y ? x : 0; }" | ||
| ])); | ||
| }); | ||
| }); | ||
| describe("generators", () => { | ||
| it("should stringify", testRoundTrip("function* (x) { yield x; }")); | ||
| }); | ||
| describe("class notation", () => { | ||
| it("should stringify classes", testRoundTrip("class {}")); | ||
| it("should stringify class and method", testRoundTrip("class { method() {} }")); | ||
| it("should stringify with newline", testRoundTrip("class\n{ method() {} }")); | ||
| it("should stringify with comment", testRoundTrip("class/*test*/\n{ method() {} }")); | ||
| }); | ||
| describe("method notation", () => { | ||
| it("should stringify", testRoundTrip("{a(b, c) { return b + c; }}")); | ||
| it("should stringify generator methods", testRoundTrip("{*a(b) { yield b; }}")); | ||
| describe("should not be fooled by tricky names", cases([ | ||
| "{'function a'(b, c) { return b + c; }}", | ||
| "{'a(a'(b, c) { return b + c; }}", | ||
| "{'() => function '() {}}", | ||
| "{'['() { return x[y]()\n{ return true; }}}", | ||
| "{'() { return false;//'() { return true;\n}}" | ||
| ])); | ||
| it("should not be fooled by tricky generator names", testRoundTrip("{*'function a'(b, c) { return b + c; }}")); | ||
| it("should not be fooled by empty names", testRoundTrip("{''(b, c) { return b + c; }}")); | ||
| it("should not be fooled by keys that look like functions", () => { | ||
| const fn = evalValue('{ "() => ": () => () => 42 }')["() => "]; | ||
| expect(index_1.stringify(fn)).toEqual("() => () => 42"); | ||
| }); | ||
| describe("should not be fooled by arrow functions", cases([ | ||
| "{a:(b, c) => b + c}", | ||
| "{a:a => a + 1}", | ||
| "{'() => ':() => () => 42}", | ||
| '{\'() => "\':() => "() {//"}', | ||
| '{\'() => "\':() => "() {`//"}', | ||
| '{\'() => "\':() => "() {`${//"}', | ||
| '{\'() => "\':() => "() {/*//"}', | ||
| semver_1.satisfies(process.versions.node, "<=4 || >=10") | ||
| ? "{'a => function ':a => function () { return a + 1; }}" | ||
| : undefined | ||
| ])); | ||
| describe("should not be fooled by regexp literals", cases([ | ||
| "{' '(s) { return /}/.test(s); }}", | ||
| "{' '(s) { return /abc/ .test(s); }}", | ||
| "{' '() { return x / y; // /}\n}}", | ||
| "{' '() { return / y; }//* } */}}", | ||
| "{' '() { return delete / y; }/.x}}", | ||
| "{' '() { switch (x) { case / y; }}/: }}}", | ||
| "{' '() { if (x) return; else / y;}/; }}", | ||
| "{' '() { return x in / y;}/; }}", | ||
| "{' '() { return x instanceof / y;}/; }}", | ||
| "{' '() { return new / y;}/.x; }}", | ||
| "{' '() { throw / y;}/.x; }}", | ||
| "{' '() { return typeof / y;}/; }}", | ||
| "{' '() { void / y;}/; }}", | ||
| "{' '() { return x, / y;}/; }}", | ||
| "{' '() { return x; / y;}/; }}", | ||
| "{' '() { return { x: / y;}/ }; }}", | ||
| "{' '() { return x + / y;}/.x; }}", | ||
| "{' '() { return x - / y;}/.x; }}", | ||
| "{' '() { return !/ y;}/; }}", | ||
| "{' '() { return ~/ y;}/.x; }}", | ||
| "{' '() { return x && / y;}/; }}", | ||
| "{' '() { return x || / y;}/; }}", | ||
| "{' '() { return x ^ / y;}/.x; }}", | ||
| "{' '() { return x * / y;}/.x; }}", | ||
| "{' '() { return x / / y;}/.x; }}", | ||
| "{' '() { return x % / y;}/.x; }}", | ||
| "{' '() { return x < / y;}/.x; }}", | ||
| "{' '() { return x > / y;}/.x; }}", | ||
| "{' '() { return x <= / y;}/.x; }}", | ||
| "{' '() { return x /= / y;}/.x; }}", | ||
| "{' '() { return x ? / y;}/ : false; }}" | ||
| ])); | ||
| describe("should not be fooled by computed names", () => { | ||
| it("1", test(evalValue('{ ["foobar".slice(3)](x) { return x + 1; } }'), "{bar(x) { return x + 1; }}")); | ||
| it("2", test(evalValue('{[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\",\\"+s(b)+b)(JSON.stringify,",")]() {}")]() {}}'), '{\'[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\\\",\\\\"+s(b)+b)(JSON.stringify,",")]() {}")]() {}\'() {}}')); | ||
| it("3", test(evalValue('{[`over${`6${"0".repeat(3)}`.replace("6", "9")}`]() { this.activateHair(); }}'), "{over9000() { this.activateHair(); }}")); | ||
| it("4", test(evalValue("{[\"() {'\"]() {''}}"), "{'() {\\''() {''}}")); | ||
| it("5", test(evalValue('{["() {`"]() {``}}'), "{'() {`'() {``}}")); | ||
| it("6", test(evalValue('{["() {/*"]() {/*`${()=>{/*}*/}}'), "{'() {/*'() {/*`${()=>{/*}*/}}")); | ||
| }); | ||
| // These two cases demonstrate that branching on | ||
| // METHOD_NAMES_ARE_QUOTED is unavoidable--you can't write code | ||
| // without it that will pass both of these cases on both node.js 4 | ||
| // and node.js 10. (If you think you can, consider that the name and | ||
| // toString of the first case when executed on node.js 10 are | ||
| // identical to the name and toString of the second case when | ||
| // executed on node.js 4, so good luck telling them apart without | ||
| // knowing which node you're on.) | ||
| describe("should handle different versions of node correctly", () => { | ||
| it("1", test(evalValue('{[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\",\\"+s(b)+b)(JSON.stringify,",")]() { return 0; /*")]() { return 0; /*() {/* */ return 1;}}'), '{\'[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\\\",\\\\"+s(b)+b)(JSON.stringify,",")]() { return 0; /*")]() { return 0; /*\'() { return 0; /*() {/* */ return 1;}}')); | ||
| it("2", test(evalValue('{\'[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\\\",\\\\"+s(b)+b)(JSON.stringify,",")]() { return 0; /*")]() { return 0; /*\'() {/* */ return 1;}}'), '{\'[((s,a,b)=>a+s(a)+","+s(b)+b)(JSON.stringify,"[((s,a,b)=>a+s(a)+\\\\",\\\\"+s(b)+b)(JSON.stringify,",")]() { return 0; /*")]() { return 0; /*\'() {/* */ return 1;}}')); | ||
| }); | ||
| it("should not be fooled by comments", test(evalValue("{'method' /* a comment! */ () /* another comment! */ {}}"), "{method() /* another comment! */ {}}")); | ||
| it("should stringify extracted methods", () => { | ||
| const fn = evalValue("{ foo(x) { return x + 1; } }").foo; | ||
| expect(index_1.stringify(fn)).toEqual("function foo(x) { return x + 1; }"); | ||
| }); | ||
| it("should stringify extracted generators", () => { | ||
| const fn = evalValue("{ *foo(x) { yield x; } }").foo; | ||
| expect(index_1.stringify(fn)).toEqual("function* foo(x) { yield x; }"); | ||
| }); | ||
| it("should stringify extracted methods with tricky names", () => { | ||
| const fn = evalValue('{ "a(a"(x) { return x + 1; } }')["a(a"]; | ||
| expect(index_1.stringify(fn)).toEqual("function (x) { return x + 1; }"); | ||
| }); | ||
| it("should stringify extracted methods with arrow-like tricky names", () => { | ||
| const fn = evalValue('{ "() => function "(x) { return x + 1; } }')["() => function "]; | ||
| expect(index_1.stringify(fn)).toEqual("function (x) { return x + 1; }"); | ||
| }); | ||
| it("should stringify extracted methods with empty names", () => { | ||
| const fn = evalValue('{ ""(x) { return x + 1; } }')[""]; | ||
| expect(index_1.stringify(fn)).toEqual("function (x) { return x + 1; }"); | ||
| }); | ||
| it("should handle transplanted names", () => { | ||
| const fn = evalValue("{ foo(x) { return x + 1; } }").foo; | ||
| expect(index_1.stringify({ bar: fn })).toEqual("{bar:function foo(x) { return x + 1; }}"); | ||
| }); | ||
| it("should handle transplanted names with generators", () => { | ||
| const fn = evalValue("{ *foo(x) { yield x; } }").foo; | ||
| expect(index_1.stringify({ bar: fn })).toEqual("{bar:function* foo(x) { yield x; }}"); | ||
| }); | ||
| it("should reindent methods", test(evalValue(" {\n" + | ||
| " fn() {\n" + | ||
| " if (true) {\n" + | ||
| ' return "hello";\n' + | ||
| " }\n" + | ||
| " }\n" + | ||
| " }"), '{\n fn() {\n if (true) {\n return "hello";\n }\n }\n}', 2)); | ||
| }); | ||
| }); | ||
| describe("ES2017", () => { | ||
| describeIf("async functions", isSupported("(async function () {})"), () => { | ||
| it("should stringify", testRoundTrip("async function (x) { await x; }")); | ||
| it("should gracefully handle unexpected Function.toString formats", () => { | ||
| const origToString = Function.prototype.toString; | ||
| Function.prototype.toString = () => "{nope}"; | ||
| try { | ||
| expect(index_1.stringify(evalValue("async function () {}"))).toEqual("void '{nope}'"); | ||
| } | ||
| finally { | ||
| Function.prototype.toString = origToString; | ||
| } | ||
| }); | ||
| }); | ||
| describeIf("async arrows", isSupported("async () => {}"), () => { | ||
| describe("should stringify", cases([ | ||
| "async (x) => x + 1", | ||
| "async x => x + 1", | ||
| "async x => { await x.then(y => y + 1); }" | ||
| ])); | ||
| describe("should stringify as object properties", cases([ | ||
| "{f:async a => a + 1}", | ||
| semver_1.satisfies(process.versions.node, "<=4 || >=10") | ||
| ? "{'async a => function ':async a => function () { return a + 1; }}" | ||
| : undefined | ||
| ])); | ||
| }); | ||
| }); | ||
| describe("ES2018", () => { | ||
| describeIf("async generators", isSupported("(async function* () {})"), () => { | ||
| it("should stringify", testRoundTrip("async function* (x) { yield x; }")); | ||
| it("should gracefully handle unexpected Function.toString formats", () => { | ||
| const origToString = Function.prototype.toString; | ||
| Function.prototype.toString = () => "{nope}"; | ||
| try { | ||
| expect(index_1.stringify(evalValue("async function* () {}"))).toEqual("void '{nope}'"); | ||
| } | ||
| finally { | ||
| Function.prototype.toString = origToString; | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| describe("global", () => { | ||
| it("should access the global in the current environment", testRoundTrip("Function('return this')()")); | ||
| }); | ||
| }); | ||
| describe("circular references", () => { | ||
| it("should omit circular references", () => { | ||
| const obj = { key: "value" }; | ||
| obj.obj = obj; | ||
| const result = index_1.stringify(obj); | ||
| expect(result).toEqual("{key:'value'}"); | ||
| }); | ||
| it("should restore value", () => { | ||
| const obj = { key: "value" }; | ||
| obj.obj = obj; | ||
| const result = index_1.stringify(obj, null, null, { references: true }); | ||
| expect(result).toEqual("(function(){var x={key:'value'};x.obj=x;return x;}())"); | ||
| }); | ||
| it("should omit recursive array value", () => { | ||
| const obj = [1, 2, 3]; | ||
| obj.push(obj); | ||
| const result = index_1.stringify(obj); | ||
| expect(result).toEqual("[1,2,3,undefined]"); | ||
| }); | ||
| it("should restore array value", () => { | ||
| const obj = [1, 2, 3]; | ||
| obj.push(obj); | ||
| const result = index_1.stringify(obj, null, null, { references: true }); | ||
| expect(result).toEqual("(function(){var x=[1,2,3,undefined];x[3]=x;return x;}())"); | ||
| }); | ||
| it("should print repeated values when no references enabled", () => { | ||
| const obj = {}; | ||
| const child = {}; | ||
| obj.a = child; | ||
| obj.b = child; | ||
| const result = index_1.stringify(obj); | ||
| expect(result).toEqual("{a:{},b:{}}"); | ||
| }); | ||
| it("should restore repeated values", () => { | ||
| const obj = {}; | ||
| const child = {}; | ||
| obj.a = child; | ||
| obj.b = child; | ||
| const result = index_1.stringify(obj, null, null, { references: true }); | ||
| expect(result).toEqual("(function(){var x={a:{}};x.b=x.a;return x;}())"); | ||
| }); | ||
| it("should restore repeated values with indentation", function () { | ||
| const obj = {}; | ||
| const child = {}; | ||
| obj.a = child; | ||
| obj.b = child; | ||
| const result = index_1.stringify(obj, null, 2, { references: true }); | ||
| expect(result).toEqual("(function () {\nvar x = {\n a: {}\n};\nx.b = x.a;\nreturn x;\n}())"); | ||
| }); | ||
| }); | ||
| describe("custom indent", () => { | ||
| it("string", () => { | ||
| const result = index_1.stringify({ | ||
| test: [1, 2, 3], | ||
| nested: { | ||
| key: "value" | ||
| } | ||
| }, null, "\t"); | ||
| expect(result).toEqual("{\n" + | ||
| "\ttest: [\n\t\t1,\n\t\t2,\n\t\t3\n\t],\n" + | ||
| "\tnested: {\n\t\tkey: 'value'\n\t}\n" + | ||
| "}"); | ||
| }); | ||
| it("integer", () => { | ||
| const result = index_1.stringify({ | ||
| test: [1, 2, 3], | ||
| nested: { | ||
| key: "value" | ||
| } | ||
| }, null, 2); | ||
| expect(result).toEqual("{\n" + | ||
| " test: [\n 1,\n 2,\n 3\n ],\n" + | ||
| " nested: {\n key: 'value'\n }\n" + | ||
| "}"); | ||
| }); | ||
| it("float", () => { | ||
| const result = index_1.stringify({ | ||
| test: [1, 2, 3], | ||
| nested: { | ||
| key: "value" | ||
| } | ||
| }, null, 2.6); | ||
| expect(result).toEqual("{\n" + | ||
| " test: [\n 1,\n 2,\n 3\n ],\n" + | ||
| " nested: {\n key: 'value'\n }\n" + | ||
| "}"); | ||
| }); | ||
| }); | ||
| describe("replacer function", () => { | ||
| it("should allow custom replacements", () => { | ||
| let callCount = 0; | ||
| const result = index_1.stringify({ | ||
| test: "value" | ||
| }, function (value, indent, next) { | ||
| callCount++; | ||
| if (typeof value === "string") { | ||
| return '"hello"'; | ||
| } | ||
| return next(value); | ||
| }); | ||
| expect(callCount).toEqual(2); | ||
| expect(result).toEqual('{test:"hello"}'); | ||
| }); | ||
| it("change primitive to object", () => { | ||
| const result = index_1.stringify({ | ||
| test: 10 | ||
| }, function (value, indent, next) { | ||
| if (typeof value === "number") { | ||
| return next({ obj: "value" }); | ||
| } | ||
| return next(value); | ||
| }); | ||
| expect(result).toEqual("{test:{obj:'value'}}"); | ||
| }); | ||
| it("change object to primitive", () => { | ||
| const result = index_1.stringify({ | ||
| test: 10 | ||
| }, value => Object.prototype.toString.call(value)); | ||
| expect(result).toEqual("[object Object]"); | ||
| }); | ||
| }); | ||
| describe("max depth", () => { | ||
| const obj = { a: { b: { c: 1 } } }; | ||
| it("should get all object", test(obj, "{a:{b:{c:1}}}")); | ||
| it("should get part of the object", test(obj, "{a:{b:{}}}", null, { maxDepth: 2 })); | ||
| it("should get part of the object when tracking references", test(obj, "{a:{b:{}}}", null, { maxDepth: 2, references: true })); | ||
| }); | ||
| describe("property based", () => { | ||
| it("should produce string evaluating to the original value", () => { | ||
| fc.assert(fc.property(fc.anything(), value => { | ||
| expect(evalValue(index_1.stringify(value))).toEqual(value); | ||
| })); | ||
| }); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=index.spec.js.map |
| {"version":3,"file":"index.spec.js","sourceRoot":"","sources":["../src/index.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fc from \"fast-check\";\nimport { satisfies } from \"semver\";\nimport { stringify, Options } from \"./index\";\n\n// Declare global window type.\ndeclare const window: any;\n\n// Evaluate a string into JavaScript\nconst evalValue = (str: string | undefined) => {\n // tslint:disable-next-line no-eval\n return eval(`(${str})`);\n};\n\n/**\n * Create a quick test function wrapper.\n */\nfunction test(\n value: any,\n result: string,\n indent?: string | number | null,\n options?: Options\n) {\n return () => {\n expect(stringify(value, null, indent, options)).toEqual(result);\n };\n}\n\n/**\n * Create a wrapper for round-trip eval tests.\n */\nfunction testRoundTrip(\n expression: string,\n indent?: string | number,\n options?: Options\n) {\n return () => test(evalValue(expression), expression, indent, options)();\n}\n\n/**\n * Check if syntax is supported.\n */\nfunction isSupported(expr: string) {\n try {\n // tslint:disable-next-line no-eval\n eval(expr);\n return true;\n } catch (err) {\n if (err.name === \"SyntaxError\") return false;\n throw err;\n }\n}\n\n/**\n * Generate a list of test cases to run.\n */\nfunction cases(cases: (string | undefined)[]) {\n return () => {\n for (const value of cases) {\n if (value) it(value, testRoundTrip(value));\n }\n };\n}\n\n/**\n * Conditionally execute test cases.\n */\nfunction describeIf(\n description: string,\n condition: boolean,\n fn: jest.EmptyFunction\n) {\n return condition ? describe(description, fn) : describe.skip(description, fn);\n}\n\ndescribe(\"javascript-stringify\", () => {\n describe(\"types\", () => {\n describe(\"booleans\", () => {\n it(\"should be stringified\", test(true, \"true\"));\n });\n\n describe(\"strings\", () => {\n it(\"should wrap in single quotes\", test(\"string\", \"'string'\"));\n\n it(\"should escape quote characters\", test(\"'test'\", \"'\\\\'test\\\\''\"));\n\n it(\n \"should escape control characters\",\n test(\"multi\\nline\", \"'multi\\\\nline'\")\n );\n\n it(\"should escape back slashes\", test(\"back\\\\slash\", \"'back\\\\\\\\slash'\"));\n\n it(\n \"should escape certain unicode sequences\",\n test(\"\\u0602\", \"'\\\\u0602'\")\n );\n });\n\n describe(\"numbers\", () => {\n it(\"should stringify integers\", test(10, \"10\"));\n\n it(\"should stringify floats\", test(10.5, \"10.5\"));\n\n it('should stringify \"NaN\"', test(10.5, \"10.5\"));\n\n it('should stringify \"Infinity\"', test(Infinity, \"Infinity\"));\n\n it('should stringify \"-Infinity\"', test(-Infinity, \"-Infinity\"));\n\n it('should stringify \"-0\"', test(-0, \"-0\"));\n });\n\n describe(\"arrays\", () => {\n it(\"should stringify as array shorthand\", test([1, 2, 3], \"[1,2,3]\"));\n\n it(\n \"should indent elements\",\n test([{ x: 10 }], \"[\\n\\t{\\n\\t\\tx: 10\\n\\t}\\n]\", \"\\t\")\n );\n });\n\n describe(\"objects\", () => {\n it(\n \"should stringify as object shorthand\",\n test({ key: \"value\", \"-\": 10 }, \"{key:'value','-':10}\")\n );\n\n it(\n \"should stringify undefined keys\",\n test({ a: true, b: undefined }, \"{a:true,b:undefined}\")\n );\n\n it(\n \"should stringify omit undefined keys\",\n test({ a: true, b: undefined }, \"{a:true}\", null, {\n skipUndefinedProperties: true\n })\n );\n\n it(\n \"should quote reserved word keys\",\n test({ if: true, else: false }, \"{'if':true,'else':false}\")\n );\n\n it(\n \"should not quote Object.prototype keys\",\n test({ constructor: 1, toString: 2 }, \"{constructor:1,toString:2}\")\n );\n });\n\n describe(\"functions\", () => {\n it(\n \"should reindent function bodies\",\n test(\n evalValue(\n `function() {\n if (true) {\n return \"hello\";\n }\n }`\n ),\n 'function () {\\n if (true) {\\n return \"hello\";\\n }\\n}',\n 2\n )\n );\n\n it(\n \"should reindent function bodies in objects\",\n test(\n evalValue(`\n {\n fn: function() {\n if (true) {\n return \"hello\";\n }\n }\n }\n `),\n '{\\n fn: function () {\\n if (true) {\\n return \"hello\";\\n }\\n }\\n}',\n 2\n )\n );\n\n it(\n \"should reindent function bodies in arrays\",\n test(\n evalValue(`[\n function() {\n if (true) {\n return \"hello\";\n }\n }\n ]`),\n '[\\n function () {\\n if (true) {\\n return \"hello\";\\n }\\n }\\n]',\n 2\n )\n );\n\n it(\n \"should not need to reindent one-liners\",\n testRoundTrip(\"{\\n fn: function () { return; }\\n}\", 2)\n );\n\n it(\"should gracefully handle unexpected Function.toString formats\", () => {\n const origToString = Function.prototype.toString;\n\n Function.prototype.toString = () => \"{nope}\";\n\n try {\n expect(\n stringify(function() {\n /* Empty */\n })\n ).toEqual(\"void '{nope}'\");\n } finally {\n Function.prototype.toString = origToString;\n }\n });\n\n describe(\n \"should not take the names of their keys\",\n cases([\"{name:function () {}}\", \"{'tricky name':function () {}}\"])\n );\n });\n\n describe(\"native instances\", () => {\n describe(\"Date\", () => {\n const date = new Date();\n\n it(\"should stringify\", test(date, \"new Date(\" + date.getTime() + \")\"));\n });\n\n describe(\"RegExp\", () => {\n it(\"should stringify as shorthand\", test(/[abc]/gi, \"/[abc]/gi\"));\n });\n\n describe(\"Number\", () => {\n it(\"should stringify\", test(new Number(10), \"new Number(10)\"));\n });\n\n describe(\"String\", () => {\n it(\"should stringify\", test(new String(\"abc\"), \"new String('abc')\"));\n });\n\n describe(\"Boolean\", () => {\n it(\"should stringify\", test(new Boolean(true), \"new Boolean(true)\"));\n });\n\n describeIf(\"Buffer\", typeof (Buffer as any) === \"function\", () => {\n it(\"should stringify\", test(Buffer.from(\"test\"), \"new Buffer('test')\"));\n });\n\n describe(\"Error\", () => {\n it(\"should stringify\", test(new Error(\"test\"), \"new Error('test')\"));\n });\n\n describe(\"unknown native type\", () => {\n it(\n \"should be omitted\",\n test(\n {\n k:\n typeof (process as any) === \"undefined\"\n ? window.navigator\n : process\n },\n \"{}\"\n )\n );\n });\n });\n\n describeIf(\"ES6\", typeof (Array as any).from === \"function\", () => {\n describeIf(\"Map\", typeof (Map as any) === \"function\", () => {\n it(\n \"should stringify\",\n test(new Map([[\"key\", \"value\"]]), \"new Map([['key','value']])\")\n );\n });\n\n describeIf(\"Set\", typeof (Set as any) === \"function\", () => {\n it(\n \"should stringify\",\n test(new Set([\"key\", \"value\"]), \"new Set(['key','value'])\")\n );\n });\n\n describe(\"arrow functions\", () => {\n describe(\n \"should stringify\",\n cases([\n \"(a, b) => a + b\",\n \"o => { return o.a + o.b; }\",\n \"(a, b) => { if (a) { return b; } }\",\n \"(a, b) => ({ [a]: b })\",\n \"a => b => () => a + b\"\n ])\n );\n\n it(\n \"should reindent function bodies\",\n test(\n evalValue(\n \" () => {\\n\" +\n \" if (true) {\\n\" +\n ' return \"hello\";\\n' +\n \" }\\n\" +\n \" }\"\n ),\n '() => {\\n if (true) {\\n return \"hello\";\\n }\\n}',\n 2\n )\n );\n\n describeIf(\"arrows with patterns\", isSupported(\"({x}) => x\"), () => {\n describe(\n \"should stringify\",\n cases([\n \"({ x, y }) => x + y\",\n \"({ x, y }) => { if (x === '}') { return y; } }\",\n \"({ x, y = /[/})]/.test(x) }) => { return y ? x : 0; }\"\n ])\n );\n });\n });\n\n describe(\"generators\", () => {\n it(\"should stringify\", testRoundTrip(\"function* (x) { yield x; }\"));\n });\n\n describe(\"class notation\", () => {\n it(\"should stringify classes\", testRoundTrip(\"class {}\"));\n it(\n \"should stringify class and method\",\n testRoundTrip(\"class { method() {} }\")\n );\n it(\n \"should stringify with newline\",\n testRoundTrip(\"class\\n{ method() {} }\")\n );\n it(\n \"should stringify with comment\",\n testRoundTrip(\"class/*test*/\\n{ method() {} }\")\n );\n });\n\n describe(\"method notation\", () => {\n it(\"should stringify\", testRoundTrip(\"{a(b, c) { return b + c; }}\"));\n\n it(\n \"should stringify generator methods\",\n testRoundTrip(\"{*a(b) { yield b; }}\")\n );\n\n describe(\n \"should not be fooled by tricky names\",\n cases([\n \"{'function a'(b, c) { return b + c; }}\",\n \"{'a(a'(b, c) { return b + c; }}\",\n \"{'() => function '() {}}\",\n \"{'['() { return x[y]()\\n{ return true; }}}\",\n \"{'() { return false;//'() { return true;\\n}}\"\n ])\n );\n\n it(\n \"should not be fooled by tricky generator names\",\n testRoundTrip(\"{*'function a'(b, c) { return b + c; }}\")\n );\n\n it(\n \"should not be fooled by empty names\",\n testRoundTrip(\"{''(b, c) { return b + c; }}\")\n );\n\n it(\"should not be fooled by keys that look like functions\", () => {\n const fn = evalValue('{ \"() => \": () => () => 42 }')[\"() => \"];\n expect(stringify(fn)).toEqual(\"() => () => 42\");\n });\n\n describe(\n \"should not be fooled by arrow functions\",\n cases([\n \"{a:(b, c) => b + c}\",\n \"{a:a => a + 1}\",\n \"{'() => ':() => () => 42}\",\n '{\\'() => \"\\':() => \"() {//\"}',\n '{\\'() => \"\\':() => \"() {`//\"}',\n '{\\'() => \"\\':() => \"() {`${//\"}',\n '{\\'() => \"\\':() => \"() {/*//\"}',\n satisfies(process.versions.node, \"<=4 || >=10\")\n ? \"{'a => function ':a => function () { return a + 1; }}\"\n : undefined\n ])\n );\n\n describe(\n \"should not be fooled by regexp literals\",\n cases([\n \"{' '(s) { return /}/.test(s); }}\",\n \"{' '(s) { return /abc/ .test(s); }}\",\n \"{' '() { return x / y; // /}\\n}}\",\n \"{' '() { return / y; }//* } */}}\",\n \"{' '() { return delete / y; }/.x}}\",\n \"{' '() { switch (x) { case / y; }}/: }}}\",\n \"{' '() { if (x) return; else / y;}/; }}\",\n \"{' '() { return x in / y;}/; }}\",\n \"{' '() { return x instanceof / y;}/; }}\",\n \"{' '() { return new / y;}/.x; }}\",\n \"{' '() { throw / y;}/.x; }}\",\n \"{' '() { return typeof / y;}/; }}\",\n \"{' '() { void / y;}/; }}\",\n \"{' '() { return x, / y;}/; }}\",\n \"{' '() { return x; / y;}/; }}\",\n \"{' '() { return { x: / y;}/ }; }}\",\n \"{' '() { return x + / y;}/.x; }}\",\n \"{' '() { return x - / y;}/.x; }}\",\n \"{' '() { return !/ y;}/; }}\",\n \"{' '() { return ~/ y;}/.x; }}\",\n \"{' '() { return x && / y;}/; }}\",\n \"{' '() { return x || / y;}/; }}\",\n \"{' '() { return x ^ / y;}/.x; }}\",\n \"{' '() { return x * / y;}/.x; }}\",\n \"{' '() { return x / / y;}/.x; }}\",\n \"{' '() { return x % / y;}/.x; }}\",\n \"{' '() { return x < / y;}/.x; }}\",\n \"{' '() { return x > / y;}/.x; }}\",\n \"{' '() { return x <= / y;}/.x; }}\",\n \"{' '() { return x /= / y;}/.x; }}\",\n \"{' '() { return x ? / y;}/ : false; }}\"\n ])\n );\n\n describe(\"should not be fooled by computed names\", () => {\n it(\n \"1\",\n test(\n evalValue('{ [\"foobar\".slice(3)](x) { return x + 1; } }'),\n \"{bar(x) { return x + 1; }}\"\n )\n );\n\n it(\n \"2\",\n test(\n evalValue(\n '{[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\",\\\\\"+s(b)+b)(JSON.stringify,\",\")]() {}\")]() {}}'\n ),\n '{\\'[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\\\\\",\\\\\\\\\"+s(b)+b)(JSON.stringify,\",\")]() {}\")]() {}\\'() {}}'\n )\n );\n\n it(\n \"3\",\n test(\n evalValue(\n '{[`over${`6${\"0\".repeat(3)}`.replace(\"6\", \"9\")}`]() { this.activateHair(); }}'\n ),\n \"{over9000() { this.activateHair(); }}\"\n )\n );\n\n it(\n \"4\",\n test(evalValue(\"{[\\\"() {'\\\"]() {''}}\"), \"{'() {\\\\''() {''}}\")\n );\n\n it(\"5\", test(evalValue('{[\"() {`\"]() {``}}'), \"{'() {`'() {``}}\"));\n\n it(\n \"6\",\n test(\n evalValue('{[\"() {/*\"]() {/*`${()=>{/*}*/}}'),\n \"{'() {/*'() {/*`${()=>{/*}*/}}\"\n )\n );\n });\n\n // These two cases demonstrate that branching on\n // METHOD_NAMES_ARE_QUOTED is unavoidable--you can't write code\n // without it that will pass both of these cases on both node.js 4\n // and node.js 10. (If you think you can, consider that the name and\n // toString of the first case when executed on node.js 10 are\n // identical to the name and toString of the second case when\n // executed on node.js 4, so good luck telling them apart without\n // knowing which node you're on.)\n describe(\"should handle different versions of node correctly\", () => {\n it(\n \"1\",\n test(\n evalValue(\n '{[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\",\\\\\"+s(b)+b)(JSON.stringify,\",\")]() { return 0; /*\")]() { return 0; /*() {/* */ return 1;}}'\n ),\n '{\\'[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\\\\\",\\\\\\\\\"+s(b)+b)(JSON.stringify,\",\")]() { return 0; /*\")]() { return 0; /*\\'() { return 0; /*() {/* */ return 1;}}'\n )\n );\n\n it(\n \"2\",\n test(\n evalValue(\n '{\\'[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\\\\\",\\\\\\\\\"+s(b)+b)(JSON.stringify,\",\")]() { return 0; /*\")]() { return 0; /*\\'() {/* */ return 1;}}'\n ),\n '{\\'[((s,a,b)=>a+s(a)+\",\"+s(b)+b)(JSON.stringify,\"[((s,a,b)=>a+s(a)+\\\\\\\\\",\\\\\\\\\"+s(b)+b)(JSON.stringify,\",\")]() { return 0; /*\")]() { return 0; /*\\'() {/* */ return 1;}}'\n )\n );\n });\n\n it(\n \"should not be fooled by comments\",\n test(\n evalValue(\n \"{'method' /* a comment! */ () /* another comment! */ {}}\"\n ),\n \"{method() /* another comment! */ {}}\"\n )\n );\n\n it(\"should stringify extracted methods\", () => {\n const fn = evalValue(\"{ foo(x) { return x + 1; } }\").foo;\n expect(stringify(fn)).toEqual(\"function foo(x) { return x + 1; }\");\n });\n\n it(\"should stringify extracted generators\", () => {\n const fn = evalValue(\"{ *foo(x) { yield x; } }\").foo;\n expect(stringify(fn)).toEqual(\"function* foo(x) { yield x; }\");\n });\n\n it(\"should stringify extracted methods with tricky names\", () => {\n const fn = evalValue('{ \"a(a\"(x) { return x + 1; } }')[\"a(a\"];\n expect(stringify(fn)).toEqual(\"function (x) { return x + 1; }\");\n });\n\n it(\"should stringify extracted methods with arrow-like tricky names\", () => {\n const fn = evalValue('{ \"() => function \"(x) { return x + 1; } }')[\n \"() => function \"\n ];\n expect(stringify(fn)).toEqual(\"function (x) { return x + 1; }\");\n });\n\n it(\"should stringify extracted methods with empty names\", () => {\n const fn = evalValue('{ \"\"(x) { return x + 1; } }')[\"\"];\n expect(stringify(fn)).toEqual(\"function (x) { return x + 1; }\");\n });\n\n it(\"should handle transplanted names\", () => {\n const fn = evalValue(\"{ foo(x) { return x + 1; } }\").foo;\n\n expect(stringify({ bar: fn })).toEqual(\n \"{bar:function foo(x) { return x + 1; }}\"\n );\n });\n\n it(\"should handle transplanted names with generators\", () => {\n const fn = evalValue(\"{ *foo(x) { yield x; } }\").foo;\n\n expect(stringify({ bar: fn })).toEqual(\n \"{bar:function* foo(x) { yield x; }}\"\n );\n });\n\n it(\n \"should reindent methods\",\n test(\n evalValue(\n \" {\\n\" +\n \" fn() {\\n\" +\n \" if (true) {\\n\" +\n ' return \"hello\";\\n' +\n \" }\\n\" +\n \" }\\n\" +\n \" }\"\n ),\n '{\\n fn() {\\n if (true) {\\n return \"hello\";\\n }\\n }\\n}',\n 2\n )\n );\n });\n });\n\n describe(\"ES2017\", () => {\n describeIf(\n \"async functions\",\n isSupported(\"(async function () {})\"),\n () => {\n it(\n \"should stringify\",\n testRoundTrip(\"async function (x) { await x; }\")\n );\n\n it(\"should gracefully handle unexpected Function.toString formats\", () => {\n const origToString = Function.prototype.toString;\n\n Function.prototype.toString = () => \"{nope}\";\n\n try {\n expect(stringify(evalValue(\"async function () {}\"))).toEqual(\n \"void '{nope}'\"\n );\n } finally {\n Function.prototype.toString = origToString;\n }\n });\n }\n );\n\n describeIf(\"async arrows\", isSupported(\"async () => {}\"), () => {\n describe(\n \"should stringify\",\n cases([\n \"async (x) => x + 1\",\n \"async x => x + 1\",\n \"async x => { await x.then(y => y + 1); }\"\n ])\n );\n\n describe(\n \"should stringify as object properties\",\n cases([\n \"{f:async a => a + 1}\",\n satisfies(process.versions.node, \"<=4 || >=10\")\n ? \"{'async a => function ':async a => function () { return a + 1; }}\"\n : undefined\n ])\n );\n });\n });\n\n describe(\"ES2018\", () => {\n describeIf(\n \"async generators\",\n isSupported(\"(async function* () {})\"),\n () => {\n it(\n \"should stringify\",\n testRoundTrip(\"async function* (x) { yield x; }\")\n );\n\n it(\"should gracefully handle unexpected Function.toString formats\", () => {\n const origToString = Function.prototype.toString;\n\n Function.prototype.toString = () => \"{nope}\";\n\n try {\n expect(stringify(evalValue(\"async function* () {}\"))).toEqual(\n \"void '{nope}'\"\n );\n } finally {\n Function.prototype.toString = origToString;\n }\n });\n }\n );\n });\n\n describe(\"global\", () => {\n it(\n \"should access the global in the current environment\",\n testRoundTrip(\"Function('return this')()\")\n );\n });\n });\n\n describe(\"circular references\", () => {\n it(\"should omit circular references\", () => {\n const obj: any = { key: \"value\" };\n obj.obj = obj;\n\n const result = stringify(obj);\n\n expect(result).toEqual(\"{key:'value'}\");\n });\n\n it(\"should restore value\", () => {\n const obj: any = { key: \"value\" };\n obj.obj = obj;\n\n const result = stringify(obj, null, null, { references: true });\n\n expect(result).toEqual(\n \"(function(){var x={key:'value'};x.obj=x;return x;}())\"\n );\n });\n\n it(\"should omit recursive array value\", () => {\n const obj: any = [1, 2, 3];\n obj.push(obj);\n\n const result = stringify(obj);\n\n expect(result).toEqual(\"[1,2,3,undefined]\");\n });\n\n it(\"should restore array value\", () => {\n const obj: any = [1, 2, 3];\n obj.push(obj);\n\n const result = stringify(obj, null, null, { references: true });\n\n expect(result).toEqual(\n \"(function(){var x=[1,2,3,undefined];x[3]=x;return x;}())\"\n );\n });\n\n it(\"should print repeated values when no references enabled\", () => {\n const obj: any = {};\n const child = {};\n\n obj.a = child;\n obj.b = child;\n\n const result = stringify(obj);\n\n expect(result).toEqual(\"{a:{},b:{}}\");\n });\n\n it(\"should restore repeated values\", () => {\n const obj: any = {};\n const child = {};\n\n obj.a = child;\n obj.b = child;\n\n const result = stringify(obj, null, null, { references: true });\n\n expect(result).toEqual(\"(function(){var x={a:{}};x.b=x.a;return x;}())\");\n });\n\n it(\"should restore repeated values with indentation\", function() {\n const obj: any = {};\n const child = {};\n\n obj.a = child;\n obj.b = child;\n\n const result = stringify(obj, null, 2, { references: true });\n\n expect(result).toEqual(\n \"(function () {\\nvar x = {\\n a: {}\\n};\\nx.b = x.a;\\nreturn x;\\n}())\"\n );\n });\n });\n\n describe(\"custom indent\", () => {\n it(\"string\", () => {\n const result = stringify(\n {\n test: [1, 2, 3],\n nested: {\n key: \"value\"\n }\n },\n null,\n \"\\t\"\n );\n\n expect(result).toEqual(\n \"{\\n\" +\n \"\\ttest: [\\n\\t\\t1,\\n\\t\\t2,\\n\\t\\t3\\n\\t],\\n\" +\n \"\\tnested: {\\n\\t\\tkey: 'value'\\n\\t}\\n\" +\n \"}\"\n );\n });\n\n it(\"integer\", () => {\n const result = stringify(\n {\n test: [1, 2, 3],\n nested: {\n key: \"value\"\n }\n },\n null,\n 2\n );\n\n expect(result).toEqual(\n \"{\\n\" +\n \" test: [\\n 1,\\n 2,\\n 3\\n ],\\n\" +\n \" nested: {\\n key: 'value'\\n }\\n\" +\n \"}\"\n );\n });\n\n it(\"float\", () => {\n const result = stringify(\n {\n test: [1, 2, 3],\n nested: {\n key: \"value\"\n }\n },\n null,\n 2.6\n );\n\n expect(result).toEqual(\n \"{\\n\" +\n \" test: [\\n 1,\\n 2,\\n 3\\n ],\\n\" +\n \" nested: {\\n key: 'value'\\n }\\n\" +\n \"}\"\n );\n });\n });\n\n describe(\"replacer function\", () => {\n it(\"should allow custom replacements\", () => {\n let callCount = 0;\n\n const result = stringify(\n {\n test: \"value\"\n },\n function(value, indent, next) {\n callCount++;\n\n if (typeof value === \"string\") {\n return '\"hello\"';\n }\n\n return next(value);\n }\n );\n\n expect(callCount).toEqual(2);\n expect(result).toEqual('{test:\"hello\"}');\n });\n\n it(\"change primitive to object\", () => {\n const result = stringify(\n {\n test: 10\n },\n function(value, indent, next) {\n if (typeof value === \"number\") {\n return next({ obj: \"value\" });\n }\n\n return next(value);\n }\n );\n\n expect(result).toEqual(\"{test:{obj:'value'}}\");\n });\n\n it(\"change object to primitive\", () => {\n const result = stringify(\n {\n test: 10\n },\n value => Object.prototype.toString.call(value)\n );\n\n expect(result).toEqual(\"[object Object]\");\n });\n });\n\n describe(\"max depth\", () => {\n const obj = { a: { b: { c: 1 } } };\n\n it(\"should get all object\", test(obj, \"{a:{b:{c:1}}}\"));\n\n it(\n \"should get part of the object\",\n test(obj, \"{a:{b:{}}}\", null, { maxDepth: 2 })\n );\n\n it(\n \"should get part of the object when tracking references\",\n test(obj, \"{a:{b:{}}}\", null, { maxDepth: 2, references: true })\n );\n });\n\n describe(\"property based\", () => {\n it(\"should produce string evaluating to the original value\", () => {\n fc.assert(\n fc.property(fc.anything(), value => {\n expect(evalValue(stringify(value))).toEqual(value);\n })\n );\n });\n });\n});\n"]} |
| import { Next } from "./types"; | ||
| /** | ||
| * Stringify an object of keys and values. | ||
| */ | ||
| export declare function objectToString(obj: any, indent: string, next: Next): string; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const quote_1 = require("./quote"); | ||
| const function_1 = require("./function"); | ||
| /** | ||
| * Stringify an object of keys and values. | ||
| */ | ||
| function objectToString(obj, indent, next) { | ||
| const eol = indent ? "\n" : ""; | ||
| // Iterate over object keys and concat string together. | ||
| const values = Object.keys(obj) | ||
| .reduce(function (values, key) { | ||
| if (typeof obj[key] === "function") { | ||
| const parser = new function_1.FunctionParser(obj[key], indent, next, key); | ||
| const result = parser.stringify(); | ||
| values.push(indent + result.split("\n").join(`\n${indent}`)); | ||
| return values; | ||
| } | ||
| const result = next(obj[key], key); | ||
| // Omit `undefined` object entries. | ||
| if (result === undefined) | ||
| return values; | ||
| // String format the value data. | ||
| const value = result.split("\n").join(`\n${indent}`); | ||
| values.push(`${indent}${quote_1.quoteKey(key, next)}:${indent ? " " : ""}${value}`); | ||
| return values; | ||
| }, []) | ||
| .join(`,${eol}`); | ||
| // Avoid new lines in an empty object. | ||
| if (values === "") | ||
| return "{}"; | ||
| return `{${eol}${values}${eol}}`; | ||
| } | ||
| exports.objectToString = objectToString; | ||
| //# sourceMappingURL=object.js.map |
| {"version":3,"file":"object.js","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":";;AACA,mCAAmC;AACnC,yCAA4C;AAE5C;;GAEG;AACH,SAAgB,cAAc,CAAC,GAAQ,EAAE,MAAc,EAAE,IAAU;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/B,uDAAuD;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SAC5B,MAAM,CACL,UAAS,MAAM,EAAE,GAAG;QAClB,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,UAAU,EAAE;YAClC,MAAM,MAAM,GAAG,IAAI,yBAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,MAAM,CAAC;SACf;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QAEnC,mCAAmC;QACnC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QAExC,gCAAgC;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;QAErD,MAAM,CAAC,IAAI,CACT,GAAG,MAAM,GAAG,gBAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAC/D,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC,EACD,EAAc,CACf;SACA,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAEnB,sCAAsC;IACtC,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAE/B,OAAO,IAAI,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,CAAC;AACnC,CAAC;AApCD,wCAoCC","sourcesContent":["import { Next } from \"./types\";\nimport { quoteKey } from \"./quote\";\nimport { FunctionParser } from \"./function\";\n\n/**\n * Stringify an object of keys and values.\n */\nexport function objectToString(obj: any, indent: string, next: Next) {\n const eol = indent ? \"\\n\" : \"\";\n\n // Iterate over object keys and concat string together.\n const values = Object.keys(obj)\n .reduce(\n function(values, key) {\n if (typeof obj[key] === \"function\") {\n const parser = new FunctionParser(obj[key], indent, next, key);\n const result = parser.stringify();\n values.push(indent + result.split(\"\\n\").join(`\\n${indent}`));\n return values;\n }\n\n const result = next(obj[key], key);\n\n // Omit `undefined` object entries.\n if (result === undefined) return values;\n\n // String format the value data.\n const value = result.split(\"\\n\").join(`\\n${indent}`);\n\n values.push(\n `${indent}${quoteKey(key, next)}:${indent ? \" \" : \"\"}${value}`\n );\n\n return values;\n },\n [] as string[]\n )\n .join(`,${eol}`);\n\n // Avoid new lines in an empty object.\n if (values === \"\") return \"{}\";\n\n return `{${eol}${values}${eol}}`;\n}\n"]} |
| import { Next } from "./types"; | ||
| /** | ||
| * Quote a string. | ||
| */ | ||
| export declare function quoteString(str: string): string; | ||
| /** | ||
| * Test for valid JavaScript identifier. | ||
| */ | ||
| export declare const IS_VALID_IDENTIFIER: RegExp; | ||
| /** | ||
| * Check if a variable name is valid. | ||
| */ | ||
| export declare function isValidVariableName(name: PropertyKey): name is string; | ||
| /** | ||
| * Quote JavaScript key access. | ||
| */ | ||
| export declare function quoteKey(key: PropertyKey, next: Next): string | undefined; | ||
| /** | ||
| * Serialize the path to a string. | ||
| */ | ||
| export declare function stringifyPath(path: PropertyKey[], next: Next): string; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| /** | ||
| * Match all characters that need to be escaped in a string. Modified from | ||
| * source to match single quotes instead of double. | ||
| * | ||
| * Source: https://github.com/douglascrockford/JSON-js/blob/master/json2.js | ||
| */ | ||
| const ESCAPABLE = /[\\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | ||
| /** | ||
| * Map of characters to escape characters. | ||
| */ | ||
| const META_CHARS = new Map([ | ||
| ["\b", "\\b"], | ||
| ["\t", "\\t"], | ||
| ["\n", "\\n"], | ||
| ["\f", "\\f"], | ||
| ["\r", "\\r"], | ||
| ["'", "\\'"], | ||
| ['"', '\\"'], | ||
| ["\\", "\\\\"] | ||
| ]); | ||
| /** | ||
| * Escape any character into its literal JavaScript string. | ||
| * | ||
| * @param {string} char | ||
| * @return {string} | ||
| */ | ||
| function escapeChar(char) { | ||
| return (META_CHARS.get(char) || | ||
| `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`); | ||
| } | ||
| /** | ||
| * Quote a string. | ||
| */ | ||
| function quoteString(str) { | ||
| return `'${str.replace(ESCAPABLE, escapeChar)}'`; | ||
| } | ||
| exports.quoteString = quoteString; | ||
| /** | ||
| * JavaScript reserved keywords. | ||
| */ | ||
| const RESERVED_WORDS = new Set(("break else new var case finally return void catch for switch while " + | ||
| "continue function this with default if throw delete in try " + | ||
| "do instanceof typeof abstract enum int short boolean export " + | ||
| "interface static byte extends long super char final native synchronized " + | ||
| "class float package throws const goto private transient debugger " + | ||
| "implements protected volatile double import public let yield").split(" ")); | ||
| /** | ||
| * Test for valid JavaScript identifier. | ||
| */ | ||
| exports.IS_VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/; | ||
| /** | ||
| * Check if a variable name is valid. | ||
| */ | ||
| function isValidVariableName(name) { | ||
| return (typeof name === "string" && | ||
| !RESERVED_WORDS.has(name) && | ||
| exports.IS_VALID_IDENTIFIER.test(name)); | ||
| } | ||
| exports.isValidVariableName = isValidVariableName; | ||
| /** | ||
| * Quote JavaScript key access. | ||
| */ | ||
| function quoteKey(key, next) { | ||
| return isValidVariableName(key) ? key : next(key); | ||
| } | ||
| exports.quoteKey = quoteKey; | ||
| /** | ||
| * Serialize the path to a string. | ||
| */ | ||
| function stringifyPath(path, next) { | ||
| let result = ""; | ||
| for (const key of path) { | ||
| if (isValidVariableName(key)) { | ||
| result += `.${key}`; | ||
| } | ||
| else { | ||
| result += `[${next(key)}]`; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| exports.stringifyPath = stringifyPath; | ||
| //# sourceMappingURL=quote.js.map |
| {"version":3,"file":"quote.js","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":";;AAEA;;;;;GAKG;AACH,MAAM,SAAS,GAAG,0HAA0H,CAAC;AAE7I;;GAEG;AACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAiB;IACzC,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,IAAI,EAAE,KAAK,CAAC;IACb,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,GAAG,EAAE,KAAK,CAAC;IACZ,CAAC,IAAI,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH;;;;;GAKG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,CACL,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QACpB,MAAM,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAC3D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,GAAW;IACrC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC;AACnD,CAAC;AAFD,kCAEC;AAED;;GAEG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,CACE,qEAAqE;IACrE,6DAA6D;IAC7D,8DAA8D;IAC9D,0EAA0E;IAC1E,mEAAmE;IACnE,8DAA8D,CAC/D,CAAC,KAAK,CAAC,GAAG,CAAC,CACb,CAAC;AAEF;;GAEG;AACU,QAAA,mBAAmB,GAAG,4BAA4B,CAAC;AAEhE;;GAEG;AACH,SAAgB,mBAAmB,CAAC,IAAiB;IACnD,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB,2BAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAC/B,CAAC;AACJ,CAAC;AAND,kDAMC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,GAAgB,EAAE,IAAU;IACnD,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAFD,4BAEC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,IAAmB,EAAE,IAAU;IAC3D,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;QACtB,IAAI,mBAAmB,CAAC,GAAG,CAAC,EAAE;YAC5B,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;SACrB;aAAM;YACL,MAAM,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;SAC5B;KACF;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAZD,sCAYC","sourcesContent":["import { Next } from \"./types\";\n\n/**\n * Match all characters that need to be escaped in a string. Modified from\n * source to match single quotes instead of double.\n *\n * Source: https://github.com/douglascrockford/JSON-js/blob/master/json2.js\n */\nconst ESCAPABLE = /[\\\\\\'\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g;\n\n/**\n * Map of characters to escape characters.\n */\nconst META_CHARS = new Map<string, string>([\n [\"\\b\", \"\\\\b\"],\n [\"\\t\", \"\\\\t\"],\n [\"\\n\", \"\\\\n\"],\n [\"\\f\", \"\\\\f\"],\n [\"\\r\", \"\\\\r\"],\n [\"'\", \"\\\\'\"],\n ['\"', '\\\\\"'],\n [\"\\\\\", \"\\\\\\\\\"]\n]);\n\n/**\n * Escape any character into its literal JavaScript string.\n *\n * @param {string} char\n * @return {string}\n */\nfunction escapeChar(char: string) {\n return (\n META_CHARS.get(char) ||\n `\\\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`\n );\n}\n\n/**\n * Quote a string.\n */\nexport function quoteString(str: string) {\n return `'${str.replace(ESCAPABLE, escapeChar)}'`;\n}\n\n/**\n * JavaScript reserved keywords.\n */\nconst RESERVED_WORDS = new Set(\n (\n \"break else new var case finally return void catch for switch while \" +\n \"continue function this with default if throw delete in try \" +\n \"do instanceof typeof abstract enum int short boolean export \" +\n \"interface static byte extends long super char final native synchronized \" +\n \"class float package throws const goto private transient debugger \" +\n \"implements protected volatile double import public let yield\"\n ).split(\" \")\n);\n\n/**\n * Test for valid JavaScript identifier.\n */\nexport const IS_VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * Check if a variable name is valid.\n */\nexport function isValidVariableName(name: PropertyKey): name is string {\n return (\n typeof name === \"string\" &&\n !RESERVED_WORDS.has(name) &&\n IS_VALID_IDENTIFIER.test(name)\n );\n}\n\n/**\n * Quote JavaScript key access.\n */\nexport function quoteKey(key: PropertyKey, next: Next) {\n return isValidVariableName(key) ? key : next(key);\n}\n\n/**\n * Serialize the path to a string.\n */\nexport function stringifyPath(path: PropertyKey[], next: Next) {\n let result = \"\";\n\n for (const key of path) {\n if (isValidVariableName(key)) {\n result += `.${key}`;\n } else {\n result += `[${next(key)}]`;\n }\n }\n\n return result;\n}\n"]} |
| import { Next } from "./types"; | ||
| /** | ||
| * Stringify a value recursively. | ||
| */ | ||
| export declare function toString(value: any, space: string, next: Next): string | undefined; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const quote_1 = require("./quote"); | ||
| const array_1 = require("./array"); | ||
| const object_1 = require("./object"); | ||
| const function_1 = require("./function"); | ||
| /** | ||
| * Stringify primitive values. | ||
| */ | ||
| const PRIMITIVE_TYPES = { | ||
| string: quote_1.quoteString, | ||
| number: (value) => (Object.is(value, -0) ? "-0" : String(value)), | ||
| boolean: String, | ||
| symbol: (value, space, next) => { | ||
| const key = Symbol.keyFor(value); | ||
| if (key !== undefined) | ||
| return `Symbol.for(${next(key)})`; | ||
| // ES2018 `Symbol.description`. | ||
| return `Symbol(${next(value.description)})`; | ||
| }, | ||
| undefined: String | ||
| }; | ||
| /** | ||
| * Stringify global variable access. | ||
| */ | ||
| function globalToString(value, space, next) { | ||
| return `Function(${next("return this")})()`; | ||
| } | ||
| /** | ||
| * Convert JavaScript objects into strings. | ||
| */ | ||
| const OBJECT_TYPES = { | ||
| "[object Array]": array_1.arrayToString, | ||
| "[object Object]": object_1.objectToString, | ||
| "[object Error]": function (error, space, next) { | ||
| return `new Error(${next(error.message)})`; | ||
| }, | ||
| "[object Date]": function (date) { | ||
| return `new Date(${date.getTime()})`; | ||
| }, | ||
| "[object String]": function (str, space, next) { | ||
| return `new String(${next(str.toString())})`; | ||
| }, | ||
| "[object Number]": function (num) { | ||
| return `new Number(${num})`; | ||
| }, | ||
| "[object Boolean]": function (bool) { | ||
| return `new Boolean(${bool})`; | ||
| }, | ||
| "[object Set]": function (set, space, next) { | ||
| return `new Set(${next(Array.from(set))})`; | ||
| }, | ||
| "[object Map]": function (map, space, next) { | ||
| return `new Map(${next(Array.from(map))})`; | ||
| }, | ||
| "[object RegExp]": String, | ||
| "[object Function]": function_1.functionToString, | ||
| "[object GeneratorFunction]": function_1.functionToString, | ||
| "[object AsyncFunction]": function_1.functionToString, | ||
| "[object AsyncGeneratorFunction]": function_1.functionToString, | ||
| "[object global]": globalToString, | ||
| "[object Window]": globalToString | ||
| }; | ||
| /** | ||
| * Stringify a value recursively. | ||
| */ | ||
| function toString(value, space, next) { | ||
| if (value === null) | ||
| return "null"; | ||
| const typeOf = typeof value; | ||
| if (PRIMITIVE_TYPES.hasOwnProperty(typeOf)) { | ||
| return PRIMITIVE_TYPES[typeOf](value, space, next); | ||
| } | ||
| // Handle buffer objects before object types (node < 6 was an object, node >= 6 is a `Uint8Array`). | ||
| if (typeof Buffer === "function" && Buffer.isBuffer(value)) { | ||
| return `new Buffer(${next(value.toString())})`; | ||
| } | ||
| // Use the internal object string to select stringify method. | ||
| const toString = Object.prototype.toString.call(value); | ||
| // Convert objects into strings. | ||
| if (OBJECT_TYPES.hasOwnProperty(toString)) { | ||
| return OBJECT_TYPES[toString](value, space, next); | ||
| } | ||
| } | ||
| exports.toString = toString; | ||
| //# sourceMappingURL=stringify.js.map |
| {"version":3,"file":"stringify.js","sourceRoot":"","sources":["../src/stringify.ts"],"names":[],"mappings":"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","sourcesContent":["import { quoteString } from \"./quote\";\nimport { Next } from \"./types\";\nimport { arrayToString } from \"./array\";\nimport { objectToString } from \"./object\";\nimport { functionToString } from \"./function\";\n\n/**\n * Stringify primitive values.\n */\nconst PRIMITIVE_TYPES = {\n string: quoteString,\n number: (value: number) => (Object.is(value, -0) ? \"-0\" : String(value)),\n boolean: String,\n symbol: (value: symbol, space: string, next: Next) => {\n const key = Symbol.keyFor(value);\n\n if (key !== undefined) return `Symbol.for(${next(key)})`;\n\n // ES2018 `Symbol.description`.\n return `Symbol(${next((value as any).description)})`;\n },\n undefined: String\n};\n\n/**\n * Stringify global variable access.\n */\nfunction globalToString(value: any, space: string, next: Next) {\n return `Function(${next(\"return this\")})()`;\n}\n\n/**\n * Convert JavaScript objects into strings.\n */\nconst OBJECT_TYPES = {\n \"[object Array]\": arrayToString,\n \"[object Object]\": objectToString,\n \"[object Error]\": function(error: Error, space: string, next: Next) {\n return `new Error(${next(error.message)})`;\n },\n \"[object Date]\": function(date: Date) {\n return `new Date(${date.getTime()})`;\n },\n \"[object String]\": function(str: String, space: string, next: Next) {\n return `new String(${next(str.toString())})`;\n },\n \"[object Number]\": function(num: number) {\n return `new Number(${num})`;\n },\n \"[object Boolean]\": function(bool: boolean) {\n return `new Boolean(${bool})`;\n },\n \"[object Set]\": function(set: Set<any>, space: string, next: Next) {\n return `new Set(${next(Array.from(set))})`;\n },\n \"[object Map]\": function(map: Map<any, any>, space: string, next: Next) {\n return `new Map(${next(Array.from(map))})`;\n },\n \"[object RegExp]\": String,\n \"[object Function]\": functionToString,\n \"[object GeneratorFunction]\": functionToString,\n \"[object AsyncFunction]\": functionToString,\n \"[object AsyncGeneratorFunction]\": functionToString,\n \"[object global]\": globalToString,\n \"[object Window]\": globalToString\n};\n\n/**\n * Stringify a value recursively.\n */\nexport function toString(value: any, space: string, next: Next) {\n if (value === null) return \"null\";\n\n const typeOf = typeof value;\n\n if (PRIMITIVE_TYPES.hasOwnProperty(typeOf)) {\n return PRIMITIVE_TYPES[typeOf as keyof typeof PRIMITIVE_TYPES](\n value,\n space,\n next\n );\n }\n\n // Handle buffer objects before object types (node < 6 was an object, node >= 6 is a `Uint8Array`).\n if (typeof (Buffer as unknown) === \"function\" && Buffer.isBuffer(value)) {\n return `new Buffer(${next(value.toString())})`;\n }\n\n // Use the internal object string to select stringify method.\n const toString = Object.prototype.toString.call(value);\n\n // Convert objects into strings.\n if (OBJECT_TYPES.hasOwnProperty(toString)) {\n return OBJECT_TYPES[toString as keyof typeof OBJECT_TYPES](\n value,\n space,\n next\n );\n }\n}\n"]} |
| /** | ||
| * Call `next()` every time you want to stringify a new value. | ||
| */ | ||
| export declare type Next = (value: any, key?: PropertyKey) => string | undefined; | ||
| /** | ||
| * Stringify a value. | ||
| */ | ||
| export declare type ToString = (value: any, space: string, next: Next) => string | undefined; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| //# sourceMappingURL=types.js.map |
| {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Call `next()` every time you want to stringify a new value.\n */\nexport type Next = (value: any, key?: PropertyKey) => string | undefined;\n\n/**\n * Stringify a value.\n */\nexport type ToString = (\n value: any,\n space: string,\n next: Next\n) => string | undefined;\n"]} |
+55
-11
| { | ||
| "name": "javascript-stringify", | ||
| "version": "1.6.0", | ||
| "version": "2.0.0", | ||
| "description": "Stringify is to `eval` as `JSON.stringify` is to `JSON.parse`", | ||
| "main": "javascript-stringify.js", | ||
| "typings": "javascript-stringify.d.ts", | ||
| "main": "dist/index.js", | ||
| "types": "dist/index.d.ts", | ||
| "files": [ | ||
| "javascript-stringify.js", | ||
| "javascript-stringify.d.ts" | ||
| "dist/" | ||
| ], | ||
| "scripts": { | ||
| "test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec" | ||
| "prettier": "prettier --write", | ||
| "format": "npm run prettier -- \"{.,src/**}/*.{js,ts,json,md,yml,css}\"", | ||
| "lint": "tslint \"src/**/*.ts\" --project tsconfig.json", | ||
| "build": "rimraf dist/ && tsc", | ||
| "specs": "jest --coverage", | ||
| "test": "npm run lint && npm run build && npm run specs", | ||
| "prepare": "npm run build" | ||
| }, | ||
@@ -19,3 +24,5 @@ "repository": "https://github.com/blakeembrey/javascript-stringify.git", | ||
| "object", | ||
| "string" | ||
| "eval", | ||
| "string", | ||
| "code" | ||
| ], | ||
@@ -28,8 +35,45 @@ "author": { | ||
| "license": "MIT", | ||
| "readmeFilename": "README.md", | ||
| "bugs": { | ||
| "url": "https://github.com/blakeembrey/javascript-stringify/issues" | ||
| }, | ||
| "homepage": "https://github.com/blakeembrey/javascript-stringify", | ||
| "jest": { | ||
| "roots": [ | ||
| "<rootDir>/src/" | ||
| ], | ||
| "transform": { | ||
| "\\.tsx?$": "ts-jest" | ||
| } | ||
| }, | ||
| "husky": { | ||
| "hooks": { | ||
| "pre-commit": "lint-staged" | ||
| } | ||
| }, | ||
| "lint-staged": { | ||
| "*.{js,ts,json,md,yml,css}": [ | ||
| "npm run prettier", | ||
| "git add" | ||
| ] | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "devDependencies": { | ||
| "chai": "^1.9.1", | ||
| "istanbul": "^0.3.0", | ||
| "mocha": "^1.21.3" | ||
| "@types/jest": "^24.0.9", | ||
| "@types/node": "^11.10.4", | ||
| "@types/semver": "^5.5.0", | ||
| "fast-check": "^1.12.0", | ||
| "husky": "^1.3.1", | ||
| "jest": "^24.0.0", | ||
| "lint-staged": "^8.1.1", | ||
| "prettier": "^1.16.1", | ||
| "rimraf": "^2.5.4", | ||
| "semver": "^5.6.0", | ||
| "ts-jest": "^24.0.0", | ||
| "tslint": "^5.0.0", | ||
| "tslint-config-prettier": "^1.17.0", | ||
| "tslint-config-standard": "^8.0.0", | ||
| "typescript": "^3.3.1" | ||
| } | ||
| } |
+27
-42
@@ -12,53 +12,38 @@ # JavaScript Stringify | ||
| ```javascript | ||
| ``` | ||
| npm install javascript-stringify --save | ||
| bower install javascript-stringify --save | ||
| ``` | ||
| ### Node | ||
| --- | ||
| ```javascript | ||
| var javascriptStringify = require('javascript-stringify'); | ||
| ``` | ||
| <a href="https://www.buymeacoffee.com/blakeembrey" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" ></a> | ||
| ### AMD | ||
| ```javascript | ||
| define(function (require, exports, module) { | ||
| var javascriptStringify = require('javascript-stringify'); | ||
| }); | ||
| ``` | ||
| ### `<script>` tag | ||
| ```html | ||
| <script src="javascript-stringify.js"></script> | ||
| ``` | ||
| ## Usage | ||
| ```javascript | ||
| javascriptStringify(value[, replacer [, space [, options]]]) | ||
| import { stringify } from "javascript-stringify"; | ||
| ``` | ||
| The API is similar to `JSON.stringify`. However, any value returned by the replacer will be used literally. For this reason, the replacer is passed three arguments - `value`, `indentation` and `stringify`. If you need to continue the stringification process inside your replacer, you can call `stringify(value)` with the new value. | ||
| The API is similar `JSON.stringify`: | ||
| The `options` object allows some additional configuration: | ||
| - `value` The value to convert to a string | ||
| - `replacer` A function that alters the behavior of the stringification process | ||
| - `space` A string or number that's used to insert white space into the output for readability purposes | ||
| - `options` | ||
| - **maxDepth** _(number, default: 100)_ The maximum depth of values to stringify | ||
| - **maxValues** _(number, default: 100000)_ The maximum number of values to stringify | ||
| - **references** _(boolean, default: false)_ Restore circular/repeated references in the object (uses IIFE) | ||
| - **skipUndefinedProperties** _(boolean, default: false)_ Omits `undefined` properties instead of restoring as `undefined` | ||
| * **maxDepth** _(number, default: 100)_ The maximum depth of values to stringify | ||
| * **maxValues** _(number, default: 100000)_ The maximum number of values to stringify | ||
| * **references** _(boolean, default: false)_ Restore circular/repeated references in the object (uses IIFE) | ||
| * **skipUndefinedProperties** _(boolean, default: false)_ Omits `undefined` properties instead of restoring as `undefined` | ||
| ### Examples | ||
| ```javascript | ||
| javascriptStringify({}); // "{}" | ||
| javascriptStringify(true); // "true" | ||
| javascriptStringify('foo'); // "'foo'" | ||
| stringify({}); // "{}" | ||
| stringify(true); // "true" | ||
| stringify("foo"); // "'foo'" | ||
| javascriptStringify({ x: 5, y: 6}); // "{x:5,y:6}" | ||
| javascriptStringify([1, 2, 3, 'string']); // "[1,2,3,'string']" | ||
| stringify({ x: 5, y: 6 }); // "{x:5,y:6}" | ||
| stringify([1, 2, 3, "string"]); // "[1,2,3,'string']" | ||
| javascriptStringify({ a: { b: { c: 1 } } }, null, null, { maxDepth: 2 }); // "{a:{b:{}}}" | ||
| stringify({ a: { b: { c: 1 } } }, null, null, { maxDepth: 2 }); // "{a:{b:{}}}" | ||
@@ -69,3 +54,3 @@ /** | ||
| javascriptStringify({ 'some-key': 10 }); // "{'some-key':10}" | ||
| stringify({ "some-key": 10 }); // "{'some-key':10}" | ||
@@ -76,3 +61,3 @@ /** | ||
| javascriptStringify([/.+/ig, new Number(10), new Date()]); // "[/.+/gi,new Number(10),new Date(1406623295732)]" | ||
| stringify([/.+/gi, new Number(10), new Date()]); // "[/.+/gi,new Number(10),new Date(1406623295732)]" | ||
@@ -86,4 +71,4 @@ /** | ||
| javascriptStringify(obj); // "{x:10}" | ||
| javascriptStringify(obj, null, null, { references: true }); // "(function(){var x={x:10};x.circular=x;return x;}())" | ||
| stringify(obj); // "{x:10}" | ||
| stringify(obj, null, null, { references: true }); // "(function(){var x={x:10};x.circular=x;return x;}())" | ||
@@ -94,4 +79,4 @@ /** | ||
| javascriptStringify({ a: 2 }, null, ' '); // "{\n a: 2\n}" | ||
| javascriptStringify({ uno: 1, dos : 2 }, null, '\t'); // "{\n\tuno: 1,\n\tdos: 2\n}" | ||
| stringify({ a: 2 }, null, " "); // "{\n a: 2\n}" | ||
| stringify({ uno: 1, dos: 2 }, null, "\t"); // "{\n\tuno: 1,\n\tdos: 2\n}" | ||
@@ -102,4 +87,4 @@ /** | ||
| javascriptStringify(['test', 'string'], function (value, indent, stringify) { | ||
| if (typeof value === 'string') { | ||
| stringify(["test", "string"], function(value, indent, stringify) { | ||
| if (typeof value === "string") { | ||
| return '"' + value.replace(/"/g, '\\"') + '"'; | ||
@@ -106,0 +91,0 @@ } |
| declare function stringify (value: any, replacer?: Function, space?: string | number, options?: javascriptStringify.Options): string; | ||
| declare namespace javascriptStringify { | ||
| export interface Options { | ||
| maxDepth?: number; | ||
| references?: boolean; | ||
| } | ||
| } | ||
| export = stringify; |
| (function (root, stringify) { | ||
| /* istanbul ignore else */ | ||
| if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { | ||
| // Node. | ||
| module.exports = stringify(); | ||
| } else if (typeof define === 'function' && define.amd) { | ||
| // AMD, registers as an anonymous module. | ||
| define(function () { | ||
| return stringify(); | ||
| }); | ||
| } else { | ||
| // Browser global. | ||
| root.javascriptStringify = stringify(); | ||
| } | ||
| })(this, function () { | ||
| /** | ||
| * Match all characters that need to be escaped in a string. Modified from | ||
| * source to match single quotes instead of double. | ||
| * | ||
| * Source: https://github.com/douglascrockford/JSON-js/blob/master/json2.js | ||
| */ | ||
| var ESCAPABLE = /[\\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | ||
| /** | ||
| * Map of characters to escape characters. | ||
| */ | ||
| var META_CHARS = { | ||
| '\b': '\\b', | ||
| '\t': '\\t', | ||
| '\n': '\\n', | ||
| '\f': '\\f', | ||
| '\r': '\\r', | ||
| "'": "\\'", | ||
| '"': '\\"', | ||
| '\\': '\\\\' | ||
| }; | ||
| /** | ||
| * Escape any character into its literal JavaScript string. | ||
| * | ||
| * @param {string} char | ||
| * @return {string} | ||
| */ | ||
| function escapeChar (char) { | ||
| var meta = META_CHARS[char]; | ||
| return meta || '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4); | ||
| }; | ||
| /** | ||
| * JavaScript reserved word list. | ||
| */ | ||
| var RESERVED_WORDS = {}; | ||
| /** | ||
| * Map reserved words to the object. | ||
| */ | ||
| ( | ||
| 'break else new var case finally return void catch for switch while ' + | ||
| 'continue function this with default if throw delete in try ' + | ||
| 'do instanceof typeof abstract enum int short boolean export ' + | ||
| 'interface static byte extends long super char final native synchronized ' + | ||
| 'class float package throws const goto private transient debugger ' + | ||
| 'implements protected volatile double import public let yield' | ||
| ).split(' ').map(function (key) { | ||
| RESERVED_WORDS[key] = true; | ||
| }); | ||
| /** | ||
| * Test for valid JavaScript identifier. | ||
| */ | ||
| var IS_VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/; | ||
| /** | ||
| * Check if a variable name is valid. | ||
| * | ||
| * @param {string} name | ||
| * @return {boolean} | ||
| */ | ||
| function isValidVariableName (name) { | ||
| return !RESERVED_WORDS[name] && IS_VALID_IDENTIFIER.test(name); | ||
| } | ||
| /** | ||
| * Return the global variable name. | ||
| * | ||
| * @return {string} | ||
| */ | ||
| function toGlobalVariable (value) { | ||
| return 'Function(' + stringify('return this;') + ')()'; | ||
| } | ||
| /** | ||
| * Serialize the path to a string. | ||
| * | ||
| * @param {Array} path | ||
| * @return {string} | ||
| */ | ||
| function toPath (path) { | ||
| var result = ''; | ||
| for (var i = 0; i < path.length; i++) { | ||
| if (isValidVariableName(path[i])) { | ||
| result += '.' + path[i]; | ||
| } else { | ||
| result += '[' + stringify(path[i]) + ']'; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Stringify an array of values. | ||
| * | ||
| * @param {Array} array | ||
| * @param {string} indent | ||
| * @param {Function} next | ||
| * @return {string} | ||
| */ | ||
| function stringifyArray (array, indent, next) { | ||
| // Map array values to their stringified values with correct indentation. | ||
| var values = array.map(function (value, index) { | ||
| var str = next(value, index); | ||
| if (str === undefined) { | ||
| return String(str); | ||
| } | ||
| return indent + str.split('\n').join('\n' + indent); | ||
| }).join(indent ? ',\n' : ','); | ||
| // Wrap the array in newlines if we have indentation set. | ||
| if (indent && values) { | ||
| return '[\n' + values + '\n]'; | ||
| } | ||
| return '[' + values + ']'; | ||
| } | ||
| /** | ||
| * Stringify a map of values. | ||
| * | ||
| * @param {Object} object | ||
| * @param {string} indent | ||
| * @param {Function} next | ||
| * @return {string} | ||
| */ | ||
| function stringifyObject (object, indent, next) { | ||
| // Iterate over object keys and concat string together. | ||
| var values = Object.keys(object).reduce(function (values, key) { | ||
| var value = next(object[key], key); | ||
| // Omit `undefined` object values. | ||
| if (value === undefined) { | ||
| return values; | ||
| } | ||
| // String format the key and value data. | ||
| key = isValidVariableName(key) ? key : stringify(key); | ||
| value = String(value).split('\n').join('\n' + indent); | ||
| // Push the current object key and value into the values array. | ||
| values.push(indent + key + ':' + (indent ? ' ' : '') + value); | ||
| return values; | ||
| }, []).join(indent ? ',\n' : ','); | ||
| // Wrap the object in newlines if we have indentation set. | ||
| if (indent && values) { | ||
| return '{\n' + values + '\n}'; | ||
| } | ||
| return '{' + values + '}'; | ||
| } | ||
| /** | ||
| * Convert JavaScript objects into strings. | ||
| */ | ||
| var OBJECT_TYPES = { | ||
| '[object Array]': stringifyArray, | ||
| '[object Object]': stringifyObject, | ||
| '[object Error]': function (error) { | ||
| return 'new Error(' + stringify(error.message) + ')'; | ||
| }, | ||
| '[object Date]': function (date) { | ||
| return 'new Date(' + date.getTime() + ')'; | ||
| }, | ||
| '[object String]': function (string) { | ||
| return 'new String(' + stringify(string.toString()) + ')'; | ||
| }, | ||
| '[object Number]': function (number) { | ||
| return 'new Number(' + number + ')'; | ||
| }, | ||
| '[object Boolean]': function (boolean) { | ||
| return 'new Boolean(' + boolean + ')'; | ||
| }, | ||
| '[object Uint8Array]': function (array, indent) { | ||
| return 'new Uint8Array(' + stringifyArray(array) + ')'; | ||
| }, | ||
| '[object Set]': function (array, indent, next) { | ||
| if (typeof Array.from === 'function') { | ||
| return 'new Set(' + stringify(Array.from(array), indent, next) + ')'; | ||
| } else return undefined; | ||
| }, | ||
| '[object Map]': function (array, indent, next) { | ||
| if (typeof Array.from === 'function') { | ||
| return 'new Map(' + stringify(Array.from(array), indent, next) + ')'; | ||
| } else return undefined; | ||
| }, | ||
| '[object RegExp]': String, | ||
| '[object Function]': String, | ||
| '[object global]': toGlobalVariable, | ||
| '[object Window]': toGlobalVariable | ||
| }; | ||
| /** | ||
| * Convert JavaScript primitives into strings. | ||
| */ | ||
| var PRIMITIVE_TYPES = { | ||
| 'string': function (string) { | ||
| return "'" + string.replace(ESCAPABLE, escapeChar) + "'"; | ||
| }, | ||
| 'number': String, | ||
| 'object': String, | ||
| 'boolean': String, | ||
| 'symbol': String, | ||
| 'undefined': String | ||
| }; | ||
| /** | ||
| * Convert any value to a string. | ||
| * | ||
| * @param {*} value | ||
| * @param {string} indent | ||
| * @param {Function} next | ||
| * @return {string} | ||
| */ | ||
| function stringify (value, indent, next) { | ||
| // Convert primitives into strings. | ||
| if (Object(value) !== value) { | ||
| return PRIMITIVE_TYPES[typeof value](value, indent, next); | ||
| } | ||
| // Handle buffer objects before recursing (node < 6 was an object, node >= 6 is a `Uint8Array`). | ||
| if (typeof Buffer === 'function' && Buffer.isBuffer(value)) { | ||
| return 'new Buffer(' + next(value.toString()) + ')'; | ||
| } | ||
| // Use the internal object string to select stringification method. | ||
| var toString = OBJECT_TYPES[Object.prototype.toString.call(value)]; | ||
| // Convert objects into strings. | ||
| return toString ? toString(value, indent, next) : undefined; | ||
| } | ||
| /** | ||
| * Stringify an object into the literal string. | ||
| * | ||
| * @param {*} value | ||
| * @param {Function} [replacer] | ||
| * @param {(number|string)} [space] | ||
| * @param {Object} [options] | ||
| * @return {string} | ||
| */ | ||
| return function (value, replacer, space, options) { | ||
| options = options || {} | ||
| // Convert the spaces into a string. | ||
| if (typeof space !== 'string') { | ||
| space = new Array(Math.max(0, space|0) + 1).join(' '); | ||
| } | ||
| var maxDepth = Number(options.maxDepth) || 100; | ||
| var references = !!options.references; | ||
| var skipUndefinedProperties = !!options.skipUndefinedProperties; | ||
| var valueCount = Number(options.maxValues) || 100000; | ||
| var path = []; | ||
| var stack = []; | ||
| var encountered = []; | ||
| var paths = []; | ||
| var restore = []; | ||
| /** | ||
| * Stringify the next value in the stack. | ||
| * | ||
| * @param {*} value | ||
| * @param {string} key | ||
| * @return {string} | ||
| */ | ||
| function next (value, key) { | ||
| if (skipUndefinedProperties && value === undefined) { | ||
| return undefined; | ||
| } | ||
| path.push(key); | ||
| var result = recurse(value, stringify); | ||
| path.pop(); | ||
| return result; | ||
| } | ||
| /** | ||
| * Handle recursion by checking if we've visited this node every iteration. | ||
| * | ||
| * @param {*} value | ||
| * @param {Function} stringify | ||
| * @return {string} | ||
| */ | ||
| var recurse = references ? | ||
| function (value, stringify) { | ||
| if (value && (typeof value === 'object' || typeof value === 'function')) { | ||
| var seen = encountered.indexOf(value); | ||
| // Track nodes to restore later. | ||
| if (seen > -1) { | ||
| restore.push(path.slice(), paths[seen]); | ||
| return; | ||
| } | ||
| // Track encountered nodes. | ||
| encountered.push(value); | ||
| paths.push(path.slice()); | ||
| } | ||
| // Stop when we hit the max depth. | ||
| if (path.length > maxDepth || valueCount-- <= 0) { | ||
| return; | ||
| } | ||
| // Stringify the value and fallback to | ||
| return stringify(value, space, next); | ||
| } : | ||
| function (value, stringify) { | ||
| var seen = stack.indexOf(value); | ||
| if (seen > -1 || path.length > maxDepth || valueCount-- <= 0) { | ||
| return; | ||
| } | ||
| stack.push(value); | ||
| var value = stringify(value, space, next); | ||
| stack.pop(); | ||
| return value; | ||
| }; | ||
| // If the user defined a replacer function, make the recursion function | ||
| // a double step process - `recurse -> replacer -> stringify`. | ||
| if (typeof replacer === 'function') { | ||
| var before = recurse | ||
| // Intertwine the replacer function with the regular recursion. | ||
| recurse = function (value, stringify) { | ||
| return before(value, function (value, space, next) { | ||
| return replacer(value, space, function (value) { | ||
| return stringify(value, space, next); | ||
| }); | ||
| }); | ||
| }; | ||
| } | ||
| var result = recurse(value, stringify); | ||
| // Attempt to restore circular references. | ||
| if (restore.length) { | ||
| var sep = space ? '\n' : ''; | ||
| var assignment = space ? ' = ' : '='; | ||
| var eol = ';' + sep; | ||
| var before = space ? '(function () {' : '(function(){' | ||
| var after = '}())' | ||
| var results = ['var x' + assignment + result]; | ||
| for (var i = 0; i < restore.length; i += 2) { | ||
| results.push('x' + toPath(restore[i]) + assignment + 'x' + toPath(restore[i + 1])); | ||
| } | ||
| results.push('return x'); | ||
| return before + sep + results.join(eol) + eol + after | ||
| } | ||
| return result; | ||
| }; | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
140199
743.61%27
440%1245
264.04%0
-100%0
-100%15
400%104
-12.61%4
300%5
400%