diff --git a/changelog_unreleased/javascript/14082.md b/changelog_unreleased/javascript/14082.md new file mode 100644 index 000000000..e56693154 --- /dev/null +++ b/changelog_unreleased/javascript/14082.md @@ -0,0 +1,17 @@ +#### Fix formatting for comments inside JSX attribute (#14082 with by @fisker) + + +```jsx +// Input +function MyFunctionComponent() { + +} + +// Prettier stable +Error: Comment "old" was not printed. Please report this error! + +// Prettier main +function MyFunctionComponent() { + ; +} +``` diff --git a/changelog_unreleased/json/14083.md b/changelog_unreleased/json/14083.md new file mode 100644 index 000000000..0ab6322f8 --- /dev/null +++ b/changelog_unreleased/json/14083.md @@ -0,0 +1,17 @@ +#### Quote numeric keys for json-stringify parser (#14083 by @fisker) + + +```jsx +// Input +{0: 'value'} + +// Prettier stable +{ + 0: "value" +} + +// Prettier main +{ + "0": "value" +} +``` diff --git a/changelog_unreleased/less/14007.md b/changelog_unreleased/less/14007.md new file mode 100644 index 000000000..eed8b756d --- /dev/null +++ b/changelog_unreleased/less/14007.md @@ -0,0 +1,19 @@ +#### Fix semicolon duplicated at the end of LESS file (#14007 by @mvorisek) + + +```less +// Input +@variable: { + field: something; +}; + +// Prettier stable +@variable: { + field: something; +}; ; + +// Prettier main +@variable: { + field: something; +}; +``` diff --git a/changelog_unreleased/less/14034.md b/changelog_unreleased/less/14034.md new file mode 100644 index 000000000..02d0d2d5f --- /dev/null +++ b/changelog_unreleased/less/14034.md @@ -0,0 +1,19 @@ +#### Do not change case of property name if inside a variable declaration in LESS (#14034 by @mvorisek) + + +```less +// Input +@var: { + preserveCase: 0; +}; + +// Prettier stable +@var: { + preservecase: 0; +}; + +// Prettier main +@var: { + preserveCase: 0; +}; +``` diff --git a/changelog_unreleased/typescript/14042.md b/changelog_unreleased/typescript/14042.md new file mode 100644 index 000000000..9b37741bb --- /dev/null +++ b/changelog_unreleased/typescript/14042.md @@ -0,0 +1,19 @@ +#### Add parentheses for TSTypeQuery to improve readability (#14042 by @onishi-kohei) + + +```tsx +// Input +a as (typeof node.children)[number] +a as (typeof node.children)[] +a as ((typeof node.children)[number])[] + +// Prettier stable +a as typeof node.children[number]; +a as typeof node.children[]; +a as typeof node.children[number][]; + +// Prettier main +a as (typeof node.children)[number]; +a as (typeof node.children)[]; +a as (typeof node.children)[number][]; +``` diff --git a/src/language-css/parser-postcss.js b/src/language-css/parser-postcss.js index 88c9eb583..fb3055c50 100644 --- a/src/language-css/parser-postcss.js +++ b/src/language-css/parser-postcss.js @@ -544,13 +544,21 @@ async function parseNestedCSS(node, options) { node.params?.[0] === ":" ) { node.variable = true; - node.value = await parseValue(node.params.slice(1), options); + const text = node.params.slice(1); + if (text) { + node.value = await parseValue(text, options); + } node.raws.afterName += ":"; } // Less variable if (node.variable) { delete node.params; + + if (!node.value) { + delete node.value; + } + return node; } } diff --git a/src/language-css/printer-postcss.js b/src/language-css/printer-postcss.js index cf3dccc28..f06e33f0b 100644 --- a/src/language-css/printer-postcss.js +++ b/src/language-css/printer-postcss.js @@ -87,7 +87,10 @@ function genericPrint(path, options, print) { return [node.raw, hardline]; case "css-root": { const nodes = printNodeSequence(path, options, print); - const after = node.raws.after.trim(); + let after = node.raws.after.trim(); + if (after.startsWith(";")) { + after = after.slice(1).trim(); + } return [ node.frontMatter ? [print("frontMatter"), hardline] : "", @@ -144,7 +147,11 @@ function genericPrint(path, options, print) { return [ node.raws.before.replaceAll(/[\s;]/g, ""), - insideICSSRuleNode(path) ? node.prop : maybeToLowerCase(node.prop), + // Less variable + (parentNode.type === "css-atrule" && parentNode.variable) || + insideICSSRuleNode(path) + ? node.prop + : maybeToLowerCase(node.prop), trimmedBetween.startsWith("//") ? " " : "", trimmedBetween, node.extend || isValueAllSpace ? "" : " ", diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index a7aa5e267..7401a5ee2 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -488,7 +488,11 @@ function needsParens(path, options) { (parent.type === "TSTypeAnnotation" && path.grandparent.type.startsWith("TSJSDoc")) ); - + case "TSTypeQuery": + return ( + (key === "objectType" && parent.type === "TSIndexedAccessType") || + (key === "elementType" && parent.type === "TSArrayType") + ); case "ArrayTypeAnnotation": return parent.type === "NullableTypeAnnotation"; diff --git a/src/language-js/print/jsx.js b/src/language-js/print/jsx.js index ab6f2d7d2..4a5e2e592 100644 --- a/src/language-js/print/jsx.js +++ b/src/language-js/print/jsx.js @@ -1,4 +1,8 @@ -import { printComments, printDanglingComments } from "../../main/comments.js"; +import { + printComments, + printDanglingComments, + printCommentsSeparately, +} from "../../main/comments.js"; import { line, hardline, @@ -471,7 +475,11 @@ function printJsxAttribute(path, options, print) { options.jsxSingleQuote ? "'" : '"' ); final = final.replace(regex, escaped); - res = [quote, final, quote]; + const { leading, trailing } = path.call( + () => printCommentsSeparately(path, options), + "value" + ); + res = [leading, quote, final, quote, trailing]; } else { res = print("value"); } @@ -743,7 +751,7 @@ function printJsx(path, options, print) { return printJsxEmptyExpression(path, options /*, print*/); case "JSXText": /* c8 ignore next */ - throw new Error("JSXTest should be handled by JSXElement"); + throw new Error("JSXText should be handled by JSXElement"); default: /* c8 ignore next */ throw new UnexpectedNodeError(node, "JSX"); diff --git a/src/language-json/printer-estree-json.js b/src/language-json/printer-estree-json.js index 2525958dc..ca27f6c6d 100644 --- a/src/language-json/printer-estree-json.js +++ b/src/language-json/printer-estree-json.js @@ -46,15 +46,13 @@ function genericPrint(path, options, print) { case "BooleanLiteral": return node.value ? "true" : "false"; case "StringLiteral": - case "NumericLiteral": return JSON.stringify(node.value); - case "Identifier": { - const { parent, key } = path; - if (parent.type === "ObjectProperty" && key === "key") { - return JSON.stringify(node.name); - } - return node.name; - } + case "NumericLiteral": + return isObjectKey(path) + ? JSON.stringify(String(node.value)) + : JSON.stringify(node.value); + case "Identifier": + return isObjectKey(path) ? JSON.stringify(node.name) : node.name; case "TemplateLiteral": // There is only one `TemplateElement` return print(["quasis", 0]); @@ -66,6 +64,10 @@ function genericPrint(path, options, print) { } } +function isObjectKey(path) { + return path.key === "key" && path.parent.type === "ObjectProperty"; +} + const ignoredProperties = new Set([ "start", "end", @@ -83,8 +85,13 @@ const ignoredProperties = new Set([ function clean(node, newNode /*, parent*/) { const { type } = node; // We print quoted key - if (type === "ObjectProperty" && node.key.type === "Identifier") { - newNode.key = { type: "StringLiteral", value: node.key.name }; + if (type === "ObjectProperty") { + const { key } = node; + if (key.type === "Identifier") { + newNode.key = { type: "StringLiteral", value: key.name }; + } else if (key.type === "NumericLiteral") { + newNode.key = { type: "StringLiteral", value: String(key.value) }; + } return; } if (type === "UnaryExpression" && node.operator === "+") { diff --git a/tests/config/format-test.js b/tests/config/format-test.js index 6ad54dc97..aa927bf23 100644 --- a/tests/config/format-test.js +++ b/tests/config/format-test.js @@ -40,6 +40,7 @@ const unstableTests = new Map( "js/sequence-expression/parenthesized.js", "typescript/satisfies-operators/comments-unstable.ts", ["js/identifier/parentheses/let.js", (options) => options.semi === false], + "jsx/comments/in-attributes.js", ].map((fixture) => { const [file, isUnstable = () => true] = Array.isArray(fixture) ? fixture diff --git a/tests/format/json/json/__snapshots__/jsfmt.spec.js.snap b/tests/format/json/json/__snapshots__/jsfmt.spec.js.snap index 1b81c48da..7dbe02e29 100644 --- a/tests/format/json/json/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/json/json/__snapshots__/jsfmt.spec.js.snap @@ -2195,12 +2195,54 @@ trailingComma: "all" | printWidth =====================================input====================================== { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } =====================================output===================================== { - "a": 123 + "a": "", + "null": "", + "true": "", + "string": "", + "0": "", + 1e2: "", + 1.0e2: "", + 0.1e2: "", + 1e-2: "", + 0.1e-2: "", + 0.1e2: "", + 1.0: "", + 1.0: "", + "0.1": "", + "0.1": "", + "0.1": "", + "0.1": "", + 999999999999999999999999999999: "", + 0.000000000000000000000000000001: "", + 0.000000000000000000000000000001: "", + 1e999999999999999999999999999999: "", + 1_2_3: "" } ================================================================================ @@ -2214,12 +2256,54 @@ trailingComma: "all" | printWidth =====================================input====================================== { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } =====================================output===================================== { - a: 123, + a: "", + null: "", + true: "", + string: "", + 0: "", + 1e2: "", + 1.0e2: "", + 0.1e2: "", + 1e-2: "", + 0.1e-2: "", + 0.1e2: "", + 1.0: "", + 1.0: "", + 0.1: "", + 0.1: "", + 0.1: "", + 0.1: "", + 999999999999999999999999999999: "", + 0.000000000000000000000000000001: "", + 0.000000000000000000000000000001: "", + 1e999999999999999999999999999999: "", + 1_2_3: "", } ================================================================================ @@ -2233,12 +2317,54 @@ trailingComma: "es5" | printWidth =====================================input====================================== { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } =====================================output===================================== { - "a": 123 + "a": "", + "null": "", + "true": "", + "string": "", + "0": "", + 1e2: "", + 1.0e2: "", + 0.1e2: "", + 1e-2: "", + 0.1e-2: "", + 0.1e2: "", + 1.0: "", + 1.0: "", + "0.1": "", + "0.1": "", + "0.1": "", + "0.1": "", + 999999999999999999999999999999: "", + 0.000000000000000000000000000001: "", + 0.000000000000000000000000000001: "", + 1e999999999999999999999999999999: "", + 1_2_3: "" } ================================================================================ @@ -2252,12 +2378,54 @@ trailingComma: "es5" | printWidth =====================================input====================================== { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } =====================================output===================================== { - a: 123, + a: "", + null: "", + true: "", + string: "", + 0: "", + 1e2: "", + 1.0e2: "", + 0.1e2: "", + 1e-2: "", + 0.1e-2: "", + 0.1e2: "", + 1.0: "", + 1.0: "", + 0.1: "", + 0.1: "", + 0.1: "", + 0.1: "", + 999999999999999999999999999999: "", + 0.000000000000000000000000000001: "", + 0.000000000000000000000000000001: "", + 1e999999999999999999999999999999: "", + 1_2_3: "", } ================================================================================ @@ -2270,12 +2438,54 @@ printWidth: 80 | printWidth =====================================input====================================== { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } =====================================output===================================== { - "a": 123 + "a": "", + "null": "", + "true": "", + "string": "", + "0": "", + "100": "", + "100": "", + "10": "", + "0.01": "", + "0.001": "", + "10": "", + "1": "", + "1": "", + "0.1": "", + "0.1": "", + "0.1": "", + "0.1": "", + "1e+30": "", + "1e-30": "", + "1e-30": "", + "Infinity": "", + "123": "" } ================================================================================ diff --git a/tests/format/json/json/propertyKey.json b/tests/format/json/json/propertyKey.json index 399e7b9a6..12d3f130e 100644 --- a/tests/format/json/json/propertyKey.json +++ b/tests/format/json/json/propertyKey.json @@ -1,3 +1,24 @@ { - a: 123 + a: '', + null: '', + true: '', + "string": "", + 0: '', + 1e2: '', + 1.0e+2: '', + .10e+2: '', + 1e-2: '', + .1e-2: '', + 0.1e+2: '', + 1.0: '', + 1.00000: '', + .1: '', + .100000: '', + 0.1: '', + 0.100000: '', + 999999999999999999999999999999: '', + .000000000000000000000000000001: '', + 0.000000000000000000000000000001: '', + 1e999999999999999999999999999999: '', + 1_2_3: '', } diff --git a/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap b/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap index 498158e46..6a7ba0281 100644 --- a/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/jsx/comments/__snapshots__/jsfmt.spec.js.snap @@ -27,6 +27,62 @@ const render = (items) => ( ================================================================================ `; +exports[`in-attributes.js - {"bracketSameLine":true} format 1`] = ` +====================================options===================================== +bracketSameLine: true +parsers: ["flow", "babel", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +
; + +; + +; + +; + +; + +; + +=====================================output===================================== +; + +; + +; + +; + +; + +; // comment + +================================================================================ +`; + exports[`in-end-tag.js - {"bracketSameLine":true} [typescript] format 1`] = ` "Identifier expected. (2:6) 1 | /* =========== before slash =========== */ diff --git a/tests/format/jsx/comments/in-attributes.js b/tests/format/jsx/comments/in-attributes.js new file mode 100644 index 000000000..4b3565c38 --- /dev/null +++ b/tests/format/jsx/comments/in-attributes.js @@ -0,0 +1,30 @@ +; + +; + +; + +; + +; + +; diff --git a/tests/format/less/case/__snapshots__/jsfmt.spec.js.snap b/tests/format/less/case/__snapshots__/jsfmt.spec.js.snap index 9bc7e9003..9abe3bd1d 100644 --- a/tests/format/less/case/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/less/case/__snapshots__/jsfmt.spec.js.snap @@ -204,7 +204,7 @@ svg[viewBox] linearGradient, } @KeepDetachedRuleset: /*:*/ { - background: RED; + BACKGROUND: RED; }; %KeepScssPlaceholderSelector { @@ -321,3 +321,145 @@ TABLE { ================================================================================ `; + +exports[`variable.less format 1`] = ` +====================================options===================================== +parsers: ["less"] +printWidth: 80 + | printWidth +=====================================input====================================== +// Do not change case of property name if inside a variable declaration + +@var: { + notVar: 0; + @notVarNested: { + notVar: 1; + notVar2: 2; + }; +}; + +@var : { + preserveCase: 5; +}; + +@var: { + preserveCase: 5; +}; + +@var :{ + preserveCase: 5; +}; + +@var /* comment */ : /* comment */ { + preserveCase: 5; +}; + +@var: /* comment */ { + preserveCase: 5; +}; + +@var /* comment */ :{ + preserveCase: 5; +}; + +@var // comment +: // comment +{ + /* FIXME: should not change case */ + preserveCase: 5; +}; + +@var: // comment +{ + preserveCase: 5; +}; + +@var // comment +:{ + /* FIXME: should not change case */ + preserveCase: 5; +}; + +// Known css properties +@var: { + COLoR: RED; +}; + +@not-var { + canChangeCase: @var[@notVarNested][notVar]; + canChangeCase: @var[ @notVarNested][notVar]; + canChangeCase: @var[@notVarNested ][notVar]; + canChangeCase: @var[@notVarNested][ notVar]; + canChangeCase: @var[@notVarNested][notVar ]; + canChangeCase: @var[notVar]; +} + +=====================================output===================================== +// Do not change case of property name if inside a variable declaration + +@var: { + notVar: 0; + @notVarNested: { + notVar: 1; + notVar2: 2; + }; +}; + +@var: { + preserveCase: 5; +}; + +@var: { + preserveCase: 5; +}; + +@var: { + preserveCase: 5; +}; + +@var: /* comment */ { + preserveCase: 5; +}; + +@var: /* comment */ { + preserveCase: 5; +}; + +@var: { + preserveCase: 5; +}; + +@var // comment +: // comment +{ + /* FIXME: should not change case */ + preservecase: 5; +} + +@var: // comment +{ + preserveCase: 5; +}; + +@var // comment +: { + /* FIXME: should not change case */ + preservecase: 5; +} + +// Known css properties +@var: { + COLoR: RED; +}; + +@not-var { + canchangecase: @var[ @notVarNested][notVar]; + canchangecase: @var[ @notVarNested][notVar]; + canchangecase: @var[ @notVarNested ][notVar]; + canchangecase: @var[ @notVarNested][ notVar]; + canchangecase: @var[ @notVarNested][notVar ]; + canchangecase: @var[notVar]; +} + +================================================================================ +`; diff --git a/tests/format/less/case/variable.less b/tests/format/less/case/variable.less new file mode 100644 index 000000000..29fdd9052 --- /dev/null +++ b/tests/format/less/case/variable.less @@ -0,0 +1,65 @@ +// Do not change case of property name if inside a variable declaration + +@var: { + notVar: 0; + @notVarNested: { + notVar: 1; + notVar2: 2; + }; +}; + +@var : { + preserveCase: 5; +}; + +@var: { + preserveCase: 5; +}; + +@var :{ + preserveCase: 5; +}; + +@var /* comment */ : /* comment */ { + preserveCase: 5; +}; + +@var: /* comment */ { + preserveCase: 5; +}; + +@var /* comment */ :{ + preserveCase: 5; +}; + +@var // comment +: // comment +{ + /* FIXME: should not change case */ + preserveCase: 5; +}; + +@var: // comment +{ + preserveCase: 5; +}; + +@var // comment +:{ + /* FIXME: should not change case */ + preserveCase: 5; +}; + +// Known css properties +@var: { + COLoR: RED; +}; + +@not-var { + canChangeCase: @var[@notVarNested][notVar]; + canChangeCase: @var[ @notVarNested][notVar]; + canChangeCase: @var[@notVarNested ][notVar]; + canChangeCase: @var[@notVarNested][ notVar]; + canChangeCase: @var[@notVarNested][notVar ]; + canChangeCase: @var[notVar]; +} diff --git a/tests/format/less/less/__snapshots__/jsfmt.spec.js.snap b/tests/format/less/less/__snapshots__/jsfmt.spec.js.snap index f52a92aa2..1541bb049 100644 --- a/tests/format/less/less/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/less/less/__snapshots__/jsfmt.spec.js.snap @@ -83,6 +83,24 @@ a: b; ================================================================================ `; +exports[`issue-11483--never-append-anything.less format 1`] = ` +====================================options===================================== +parsers: ["less"] +printWidth: 80 + | printWidth +=====================================input====================================== +@variable: { + field: something; +}; + +=====================================output===================================== +@variable: { + field: something; +}; + +================================================================================ +`; + exports[`less.less format 1`] = ` ====================================options===================================== parsers: ["less"] diff --git a/tests/format/less/less/issue-11483--never-append-anything.less b/tests/format/less/less/issue-11483--never-append-anything.less new file mode 100644 index 000000000..c0fbaa614 --- /dev/null +++ b/tests/format/less/less/issue-11483--never-append-anything.less @@ -0,0 +1,3 @@ +@variable: { + field: something; +}; diff --git a/tests/format/typescript/typeof/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/typeof/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..5f6e5fb92 --- /dev/null +++ b/tests/format/typescript/typeof/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typeof.ts format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +a as (typeof node.children)[number] +a as (typeof node.children)[] +a as ((typeof node.children)[number])[] +a as number[(typeof node.children)] + +=====================================output===================================== +a as (typeof node.children)[number]; +a as (typeof node.children)[]; +a as (typeof node.children)[number][]; +a as number[typeof node.children]; + +================================================================================ +`; diff --git a/tests/format/typescript/typeof/jsfmt.spec.js b/tests/format/typescript/typeof/jsfmt.spec.js new file mode 100644 index 000000000..29084a9c8 --- /dev/null +++ b/tests/format/typescript/typeof/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(import.meta, ["typescript"]); diff --git a/tests/format/typescript/typeof/typeof.ts b/tests/format/typescript/typeof/typeof.ts new file mode 100644 index 000000000..accada3df --- /dev/null +++ b/tests/format/typescript/typeof/typeof.ts @@ -0,0 +1,4 @@ +a as (typeof node.children)[number] +a as (typeof node.children)[] +a as ((typeof node.children)[number])[] +a as number[(typeof node.children)]