diff --git a/scripts/build/parsers.js b/scripts/build/parsers.js index 021cad06..ae86a2f8 100644 --- a/scripts/build/parsers.js +++ b/scripts/build/parsers.js @@ -3,6 +3,7 @@ module.exports = [ "language-js/parser-babylon", "language-js/parser-flow", + "language-js/parser-json-stringify", "language-js/parser-typescript", "language-graphql/parser-graphql", "language-handlebars/parser-glimmer", diff --git a/scripts/build/rollup.docs.config.js b/scripts/build/rollup.docs.config.js index 46ad2ac9..82bf0ffd 100644 --- a/scripts/build/rollup.docs.config.js +++ b/scripts/build/rollup.docs.config.js @@ -14,6 +14,8 @@ export default Object.assign(baseConfig, { format: "iife", plugins: [json(), resolve({ preferBuiltins: true }), commonjs(), globals()], useStrict: false, - moduleName: basename.replace(/.+-/, ""), + moduleName: basename + .replace(/^parser-/, "") + .replace(/-/g, "_") /* `json-stringify` is not a valid identifier */, external: ["assert", "fs", "module"] }); diff --git a/src/language-js/index.js b/src/language-js/index.js index 4752f575..d634afb0 100644 --- a/src/language-js/index.js +++ b/src/language-js/index.js @@ -1,6 +1,7 @@ "use strict"; -const printer = require("./printer-estree"); +const estreePrinter = require("./printer-estree"); +const estreeJsonPrinter = require("./printer-estree-json"); const hasPragma = require("./pragma").hasPragma; const options = require("./options"); const privateUtil = require("../common/util"); @@ -127,6 +128,20 @@ const languages = [ liguistLanguageId: 378, vscodeLanguageIds: ["typescript", "typescriptreact"] }, + { + name: "JSON.stringify", + since: "1.13.0", + parsers: ["json-stringify"], + group: "JavaScript", + tmScope: "source.json", + aceMode: "json", + codemirrorMode: "javascript", + codemirrorMimeType: "application/json", + extensions: [], // .json file defaults to json instead of json-stringify + filenames: ["package.json", "package-lock.json"], + linguistLanguageId: 174, + vscodeLanguageIds: ["json"] + }, { name: "JSON", since: "1.5.0", @@ -192,6 +207,14 @@ const parsers = { } }), json5: babylon, + "json-stringify": { + get parse() { + return eval("require")("./parser-json-stringify"); + }, + astFormat: "estree-json", + locStart, + locEnd + }, flow: { get parse() { return eval("require")("./parser-flow"); @@ -207,7 +230,8 @@ const parsers = { }; const printers = { - estree: printer + estree: estreePrinter, + "estree-json": estreeJsonPrinter }; module.exports = { diff --git a/src/language-js/parser-json-stringify.js b/src/language-js/parser-json-stringify.js new file mode 100644 index 00000000..564b2661 --- /dev/null +++ b/src/language-js/parser-json-stringify.js @@ -0,0 +1,77 @@ +"use strict"; + +const parserBabylon = eval("require")("./parser-babylon"); +const createError = require("../common/parser-create-error"); + +function parse(text, parsers, opts) { + const ast = parserBabylon( + text, + parsers, + Object.assign({}, opts, { parser: "json" }) + ); + + ast.comments.forEach(assertJsonNode); + assertJsonNode(ast); + + return ast; +} + +function assertJsonNode(node, parent) { + switch (node.type) { + case "ArrayExpression": + return node.elements.forEach(assertJsonChildNode); + case "ObjectExpression": + return node.properties.forEach(assertJsonChildNode); + case "ObjectProperty": + // istanbul ignore if + if (node.computed) { + throw createJsonError("computed"); + } + // istanbul ignore if + if (node.shorthand) { + throw createJsonError("shorthand"); + } + return [node.key, node.value].forEach(assertJsonChildNode); + case "UnaryExpression": + switch (node.operator) { + case "+": + case "-": + return assertJsonChildNode(node.argument); + // istanbul ignore next + default: + throw createJsonError("operator"); + } + case "Identifier": + if (parent && parent.type === "ObjectProperty" && parent.key === node) { + return; + } + throw createJsonError(); + case "NullLiteral": + case "BooleanLiteral": + case "NumericLiteral": + case "StringLiteral": + return; + // istanbul ignore next + default: + throw createJsonError(); + } + + function assertJsonChildNode(child) { + return assertJsonNode(child, node); + } + + // istanbul ignore next + function createJsonError(attribute) { + const name = !attribute + ? node.type + : `${node.type} with ${attribute}=${JSON.stringify(node[attribute])}`; + return createError(`${name} is not allowed in JSON.`, { + start: { + line: node.loc.start.line, + column: node.loc.start.column + 1 + } + }); + } +} + +module.exports = parse; diff --git a/src/language-js/printer-estree-json.js b/src/language-js/printer-estree-json.js new file mode 100644 index 00000000..ae399638 --- /dev/null +++ b/src/language-js/printer-estree-json.js @@ -0,0 +1,76 @@ +"use strict"; + +const docBuilders = require("../doc/doc-builders"); + +const concat = docBuilders.concat; +const hardline = docBuilders.hardline; +const indent = docBuilders.indent; +const join = docBuilders.join; + +function genericPrint(path, options, print) { + const node = path.getValue(); + switch (node.type) { + case "ArrayExpression": + return node.elements.length === 0 + ? "[]" + : concat([ + "[", + indent( + concat([ + hardline, + join(concat([",", hardline]), path.map(print, "elements")) + ]) + ), + hardline, + "]" + ]); + case "ObjectExpression": + return node.properties.length === 0 + ? "{}" + : concat([ + "{", + indent( + concat([ + hardline, + join(concat([",", hardline]), path.map(print, "properties")) + ]) + ), + hardline, + "}" + ]); + case "ObjectProperty": + return concat([path.call(print, "key"), ": ", path.call(print, "value")]); + case "UnaryExpression": + return concat([ + node.operator === "+" ? "" : node.operator, + path.call(print, "argument") + ]); + case "NullLiteral": + return "null"; + case "BooleanLiteral": + return node.value ? "true" : "false"; + case "StringLiteral": + case "NumericLiteral": + return JSON.stringify(node.value); + case "Identifier": + return JSON.stringify(node.name); + } +} + +function clean(node, newNode /*, parent*/) { + delete newNode.start; + delete newNode.end; + delete newNode.extra; + + if (node.type === "Identifier") { + return { type: "StringLiteral", value: node.name }; + } + if (node.type === "UnaryExpression" && node.operator === "+") { + return newNode.argument; + } +} + +module.exports = { + print: genericPrint, + massageAstNode: clean +}; diff --git a/src/main/ast-to-doc.js b/src/main/ast-to-doc.js index 8d5ad6ac..675ff7a5 100644 --- a/src/main/ast-to-doc.js +++ b/src/main/ast-to-doc.js @@ -59,7 +59,11 @@ function printAstToDoc(ast, options, addAlignmentSize) { } docUtils.propagateBreaks(doc); - if (options.parser === "json" || options.parser === "json5") { + if ( + options.parser === "json" || + options.parser === "json5" || + options.parser === "json-stringify" + ) { doc = concat([doc, hardline]); } diff --git a/src/main/core-options.js b/src/main/core-options.js index ba77619c..4715f2b1 100644 --- a/src/main/core-options.js +++ b/src/main/core-options.js @@ -105,6 +105,11 @@ const options = { { value: "scss", since: "1.7.1", description: "SCSS" }, { value: "json", since: "1.5.0", description: "JSON" }, { value: "json5", since: "1.13.0", description: "JSON5" }, + { + value: "json-stringify", + since: "1.13.0", + description: "JSON.stringify" + }, { value: "graphql", since: "1.5.0", description: "GraphQL" }, { value: "markdown", since: "1.8.0", description: "Markdown" }, { value: "vue", since: "1.10.0", description: "Vue" } diff --git a/tests/json/__snapshots__/jsfmt.spec.js.snap b/tests/json/__snapshots__/jsfmt.spec.js.snap index 0907ab83..2bfedb37 100644 --- a/tests/json/__snapshots__/jsfmt.spec.js.snap +++ b/tests/json/__snapshots__/jsfmt.spec.js.snap @@ -1,33 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`block-comment.json 1`] = ` -{/*comment*/"K":"V"} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ /*comment*/ "K": "V" } - -`; - -exports[`block-comment.json 2`] = ` -{/*comment*/"K":"V"} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ /*comment*/ "K": "V" } - -`; - -exports[`block-comment.json 3`] = ` -{/*comment*/"K":"V"} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ /*comment*/ K: "V" } - -`; - -exports[`block-comment.json 4`] = ` -{/*comment*/"K":"V"} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ /*comment*/ K: "V" } - -`; - exports[`boolean.json 1`] = ` true ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -56,55 +28,10 @@ true `; -exports[`line-comment.json 1`] = ` -{ - //comment - "K":"V" -} +exports[`boolean.json 5`] = ` +true ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ - //comment - "K": "V" -} - -`; - -exports[`line-comment.json 2`] = ` -{ - //comment - "K":"V" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ - //comment - "K": "V" -} - -`; - -exports[`line-comment.json 3`] = ` -{ - //comment - "K":"V" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ - //comment - K: "V" -} - -`; - -exports[`line-comment.json 4`] = ` -{ - //comment - "K":"V" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -{ - //comment - K: "V", -} +true `; @@ -160,6 +87,29 @@ exports[`multi-line.json 4`] = ` `; +exports[`multi-line.json 5`] = ` +{"key1":[true,false,null],"key2":{"key3":[1,2,"3", +1e10,1e-3]}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + "key1": [ + true, + false, + null + ], + "key2": { + "key3": [ + 1, + 2, + "3", + 10000000000, + 0.001 + ] + } +} + +`; + exports[`null.json 1`] = ` null ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -188,6 +138,13 @@ null `; +exports[`null.json 5`] = ` +null +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +null + +`; + exports[`number.json 1`] = ` 0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -216,6 +173,13 @@ exports[`number.json 4`] = ` `; +exports[`number.json 5`] = ` +0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +0 + +`; + exports[`pass1.json 1`] = ` [ "JSON Test Pattern pass1", @@ -692,6 +656,179 @@ exports[`pass1.json 4`] = ` `; +exports[`pass1.json 5`] = ` +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\\"", + "backslash": "\\\\", + "controls": "\\b\\f\\n\\r\\t", + "slash": "/ & \\/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "\`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\\"object with 1 member\\":[\\"array with 1 element\\"]}", + "quotes": "" \\u0022 %22 0x22 034 "", + "\\/\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t\`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +[ + "JSON Test Pattern pass1", + { + "object with 1 member": [ + "array with 1 element" + ] + }, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.54321, + "e": 1.23456789e-13, + "E": 1.23456789e+34, + "": 2.3456789012e+76, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\\"", + "backslash": "\\\\", + "controls": "\\b\\f\\n\\r\\t", + "slash": "/ & /", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "\`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "ģ䕧覫췯ꯍ", + "true": true, + "false": false, + "null": null, + "array": [], + "object": {}, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d ": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "compact": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "jsontext": "{\\"object with 1 member\\":[\\"array with 1 element\\"]}", + "quotes": "" \\" %22 0x22 034 "", + "/\\\\\\"쫾몾ꮘﳞ볚\\b\\f\\n\\r\\t\`1~!@#$%^&*()_+-=[]{}|;:',./<>?": "A key can be any string" + }, + 0.5, + 98.6, + 99.44, + 1066, + 10, + 1, + 0.1, + 1, + 2, + 2, + "rosebud" +] + +`; + +exports[`positive-number.json 1`] = ` ++123 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++123 + +`; + +exports[`positive-number.json 2`] = ` ++123 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++123 + +`; + +exports[`positive-number.json 3`] = ` ++123 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++123 + +`; + +exports[`positive-number.json 4`] = ` ++123 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++123 + +`; + +exports[`positive-number.json 5`] = ` ++123 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +123 + +`; + exports[`propertyKey.json 1`] = ` { a: 123 @@ -736,6 +873,17 @@ exports[`propertyKey.json 4`] = ` `; +exports[`propertyKey.json 5`] = ` +{ + a: 123 +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + "a": 123 +} + +`; + exports[`single-line.json 1`] = ` {"key1":[true,false,null],"key2":{"key3":[1,2,"3",1e10,1e-3]}} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -764,6 +912,63 @@ exports[`single-line.json 4`] = ` `; +exports[`single-line.json 5`] = ` +{"key1":[true,false,null],"key2":{"key3":[1,2,"3",1e10,1e-3]}} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + "key1": [ + true, + false, + null + ], + "key2": { + "key3": [ + 1, + 2, + "3", + 10000000000, + 0.001 + ] + } +} + +`; + +exports[`single-quote.json 1`] = ` +'hello' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"hello" + +`; + +exports[`single-quote.json 2`] = ` +'hello' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"hello" + +`; + +exports[`single-quote.json 3`] = ` +'hello' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"hello" + +`; + +exports[`single-quote.json 4`] = ` +'hello' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"hello" + +`; + +exports[`single-quote.json 5`] = ` +'hello' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"hello" + +`; + exports[`string.json 1`] = ` "string" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -792,107 +997,10 @@ exports[`string.json 4`] = ` `; -exports[`top-block-comment.json 1`] = ` -/* comment */{ - "foo": "bar" -} +exports[`string.json 5`] = ` +"string" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* comment */ { - "foo": "bar" -} - -`; - -exports[`top-block-comment.json 2`] = ` -/* comment */{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* comment */ { - "foo": "bar" -} - -`; - -exports[`top-block-comment.json 3`] = ` -/* comment */{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* comment */ { - foo: "bar" -} - -`; - -exports[`top-block-comment.json 4`] = ` -/* comment */{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/* comment */ { - foo: "bar", -} - -`; - -exports[`top-line-comment.json 1`] = ` -// comment 1 -// comment 2 -{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// comment 1 -// comment 2 -{ - "foo": "bar" -} - -`; - -exports[`top-line-comment.json 2`] = ` -// comment 1 -// comment 2 -{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// comment 1 -// comment 2 -{ - "foo": "bar" -} - -`; - -exports[`top-line-comment.json 3`] = ` -// comment 1 -// comment 2 -{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// comment 1 -// comment 2 -{ - foo: "bar" -} - -`; - -exports[`top-line-comment.json 4`] = ` -// comment 1 -// comment 2 -{ - "foo": "bar" -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// comment 1 -// comment 2 -{ - foo: "bar", -} +"string" `; @@ -955,3 +1063,18 @@ exports[`trailingComma.notjson 4`] = ` } `; + +exports[`trailingComma.notjson 5`] = ` +{ + "k1": "v1", + "k2": "v2", + "k3": "v3" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + "k1": "v1", + "k2": "v2", + "k3": "v3" +} + +`; diff --git a/tests/json/jsfmt.spec.js b/tests/json/jsfmt.spec.js index 2bd71ed8..1c74f7e8 100644 --- a/tests/json/jsfmt.spec.js +++ b/tests/json/jsfmt.spec.js @@ -2,3 +2,4 @@ run_spec(__dirname, ["json"]); run_spec(__dirname, ["json"], { trailingComma: "all" }); run_spec(__dirname, ["json5"]); run_spec(__dirname, ["json5"], { trailingComma: "all" }); +run_spec(__dirname, ["json-stringify"]); diff --git a/tests/json/positive-number.json b/tests/json/positive-number.json new file mode 100644 index 00000000..feeface9 --- /dev/null +++ b/tests/json/positive-number.json @@ -0,0 +1 @@ ++123 diff --git a/tests/json/single-quote.json b/tests/json/single-quote.json new file mode 100644 index 00000000..30f1577b --- /dev/null +++ b/tests/json/single-quote.json @@ -0,0 +1 @@ +'hello' diff --git a/tests/json/with-comment/__snapshots__/jsfmt.spec.js.snap b/tests/json/with-comment/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 00000000..26a4ea11 --- /dev/null +++ b/tests/json/with-comment/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,185 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`block-comment.json 1`] = ` +{/*comment*/"K":"V"} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ /*comment*/ "K": "V" } + +`; + +exports[`block-comment.json 2`] = ` +{/*comment*/"K":"V"} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ /*comment*/ "K": "V" } + +`; + +exports[`block-comment.json 3`] = ` +{/*comment*/"K":"V"} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ /*comment*/ K: "V" } + +`; + +exports[`block-comment.json 4`] = ` +{/*comment*/"K":"V"} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ /*comment*/ K: "V" } + +`; + +exports[`line-comment.json 1`] = ` +{ + //comment + "K":"V" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + //comment + "K": "V" +} + +`; + +exports[`line-comment.json 2`] = ` +{ + //comment + "K":"V" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + //comment + "K": "V" +} + +`; + +exports[`line-comment.json 3`] = ` +{ + //comment + "K":"V" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + //comment + K: "V" +} + +`; + +exports[`line-comment.json 4`] = ` +{ + //comment + "K":"V" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{ + //comment + K: "V", +} + +`; + +exports[`top-block-comment.json 1`] = ` +/* comment */{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* comment */ { + "foo": "bar" +} + +`; + +exports[`top-block-comment.json 2`] = ` +/* comment */{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* comment */ { + "foo": "bar" +} + +`; + +exports[`top-block-comment.json 3`] = ` +/* comment */{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* comment */ { + foo: "bar" +} + +`; + +exports[`top-block-comment.json 4`] = ` +/* comment */{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* comment */ { + foo: "bar", +} + +`; + +exports[`top-line-comment.json 1`] = ` +// comment 1 +// comment 2 +{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// comment 1 +// comment 2 +{ + "foo": "bar" +} + +`; + +exports[`top-line-comment.json 2`] = ` +// comment 1 +// comment 2 +{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// comment 1 +// comment 2 +{ + "foo": "bar" +} + +`; + +exports[`top-line-comment.json 3`] = ` +// comment 1 +// comment 2 +{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// comment 1 +// comment 2 +{ + foo: "bar" +} + +`; + +exports[`top-line-comment.json 4`] = ` +// comment 1 +// comment 2 +{ + "foo": "bar" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// comment 1 +// comment 2 +{ + foo: "bar", +} + +`; diff --git a/tests/json/block-comment.json b/tests/json/with-comment/block-comment.json similarity index 100% rename from tests/json/block-comment.json rename to tests/json/with-comment/block-comment.json diff --git a/tests/json/with-comment/jsfmt.spec.js b/tests/json/with-comment/jsfmt.spec.js new file mode 100644 index 00000000..2bd71ed8 --- /dev/null +++ b/tests/json/with-comment/jsfmt.spec.js @@ -0,0 +1,4 @@ +run_spec(__dirname, ["json"]); +run_spec(__dirname, ["json"], { trailingComma: "all" }); +run_spec(__dirname, ["json5"]); +run_spec(__dirname, ["json5"], { trailingComma: "all" }); diff --git a/tests/json/line-comment.json b/tests/json/with-comment/line-comment.json similarity index 100% rename from tests/json/line-comment.json rename to tests/json/with-comment/line-comment.json diff --git a/tests/json/top-block-comment.json b/tests/json/with-comment/top-block-comment.json similarity index 100% rename from tests/json/top-block-comment.json rename to tests/json/with-comment/top-block-comment.json diff --git a/tests/json/top-line-comment.json b/tests/json/with-comment/top-line-comment.json similarity index 100% rename from tests/json/top-line-comment.json rename to tests/json/with-comment/top-line-comment.json diff --git a/tests_integration/__tests__/__snapshots__/early-exit.js.snap b/tests_integration/__tests__/__snapshots__/early-exit.js.snap index 483d4880..20de82ea 100644 --- a/tests_integration/__tests__/__snapshots__/early-exit.js.snap +++ b/tests_integration/__tests__/__snapshots__/early-exit.js.snap @@ -278,23 +278,24 @@ exports[`show detailed usage with --help no-semi (write) 1`] = `Array []`; exports[`show detailed usage with --help parser (stderr) 1`] = `""`; exports[`show detailed usage with --help parser (stdout) 1`] = ` -"--parser +"--parser Which parser to use. Valid options: - flow Flow - babylon JavaScript - typescript TypeScript - css CSS - less Less - scss SCSS - json JSON - json5 JSON5 - graphql GraphQL - markdown Markdown - vue Vue + flow Flow + babylon JavaScript + typescript TypeScript + css CSS + less Less + scss SCSS + json JSON + json5 JSON5 + json-stringify JSON.stringify + graphql GraphQL + markdown Markdown + vue Vue Default: babylon " @@ -594,7 +595,7 @@ Format options: --no-bracket-spacing Do not print spaces between brackets. --jsx-bracket-same-line Put > on the last line instead of at a new line. Defaults to false. - --parser + --parser Which parser to use. Defaults to babylon. --print-width The line length where Prettier will try wrap. @@ -698,23 +699,24 @@ exports[`show warning with --help not-found (typo) (stderr) 1`] = ` `; exports[`show warning with --help not-found (typo) (stdout) 1`] = ` -"--parser +"--parser Which parser to use. Valid options: - flow Flow - babylon JavaScript - typescript TypeScript - css CSS - less Less - scss SCSS - json JSON - json5 JSON5 - graphql GraphQL - markdown Markdown - vue Vue + flow Flow + babylon JavaScript + typescript TypeScript + css CSS + less Less + scss SCSS + json JSON + json5 JSON5 + json-stringify JSON.stringify + graphql GraphQL + markdown Markdown + vue Vue Default: babylon " @@ -745,7 +747,7 @@ Format options: --no-bracket-spacing Do not print spaces between brackets. --jsx-bracket-same-line Put > on the last line instead of at a new line. Defaults to false. - --parser + --parser Which parser to use. Defaults to babylon. --print-width The line length where Prettier will try wrap. diff --git a/tests_integration/__tests__/__snapshots__/plugin-options.js.snap b/tests_integration/__tests__/__snapshots__/plugin-options.js.snap index 32f680c3..f9585886 100644 --- a/tests_integration/__tests__/__snapshots__/plugin-options.js.snap +++ b/tests_integration/__tests__/__snapshots__/plugin-options.js.snap @@ -15,7 +15,7 @@ exports[` 1`] = ` + Defaults to bar. --jsx-bracket-same-line Put > on the last line instead of at a new line. Defaults to false. - --parser + --parser Which parser to use. Defaults to babylon." `; diff --git a/tests_integration/__tests__/plugin-precedence.js b/tests_integration/__tests__/plugin-precedence.js new file mode 100644 index 00000000..6a2b9e9b --- /dev/null +++ b/tests_integration/__tests__/plugin-precedence.js @@ -0,0 +1,20 @@ +"use strict"; + +test("TODO: enable this test after releasing 1.13, you can manually set 1.13.0 in /package.json to test it for now", () => {}); + +/* +const runPrettier = require("../runPrettier"); + +describe("json-stringify takes precedence over json for package.json", () => { + runPrettier("plugins", ["--stdin", "--stdin-filepath=package.json"], { + input: + '{ "a": "longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong" }' + }).test({ + stdout: + '{\n "a": "longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"\n}\n', + stderr: "", + status: 0, + write: [] + }); +}); +*/ diff --git a/website/playground/codeSamples.js b/website/playground/codeSamples.js index 5283a085..37f26707 100644 --- a/website/playground/codeSamples.js +++ b/website/playground/codeSamples.js @@ -111,6 +111,7 @@ export default function(parser) { ].join("\n"); case "json": case "json5": + case "json-stringify": // Excerpted & adapted from Wikipedia, under the Creative Commons Attribution-ShareAlike License // https://en.wikipedia.org/wiki/JSON#Example return [ diff --git a/website/static/service-worker.js b/website/static/service-worker.js index 910b5ae4..bfebf132 100644 --- a/website/static/service-worker.js +++ b/website/static/service-worker.js @@ -12,6 +12,7 @@ toolbox.precache([ "lib/parser-typescript.js", "lib/parser-postcss.js", "lib/parser-flow.js", + "lib/parser-json-stringify.js", "lib/parser-glimmer.js", "lib/parser-graphql.js", "lib/parser-markdown.js", diff --git a/website/static/worker.js b/website/static/worker.js index 1c94124b..5cef5751 100644 --- a/website/static/worker.js +++ b/website/static/worker.js @@ -47,12 +47,14 @@ self.require = function require(path) { } if (~path.indexOf("parser-")) { - var parser = path.replace(/.+-/, ""); + var parser = path.replace(/^.*parser-/, ""); if (!parsersLoaded[parser]) { importScripts("lib/parser-" + parser + ".js"); parsersLoaded[parser] = true; } - return self[parser]; + return self[ + parser.replace(/-/g, "_") // `json-stringify` is not a valid identifier + ]; } return self[path];