diff --git a/changelog_unreleased/angular/15968.md b/changelog_unreleased/angular/15968.md new file mode 100644 index 000000000..55b8047a0 --- /dev/null +++ b/changelog_unreleased/angular/15968.md @@ -0,0 +1,32 @@ +#### Support Angular inline styles as single template literal (#15968 by @sosukesuzuki) + +[Angular v17](https://blog.angular.io/introducing-angular-v17-4d7033312e4b) supports single string inline styles. + + +```ts +// Input +@Component({ + template: `
...
`, + styles: `h1 { color: blue; }`, +}) +export class AppComponent {} + +// Prettier stable +@Component({ + template: `
...
`, + styles: `h1 { color: blue; }`, +}) +export class AppComponent {} + +// Prettier main +@Component({ + template: `
...
`, + styles: ` + h1 { + color: blue; + } + `, +}) +export class AppComponent {} + +``` diff --git a/src/language-js/embed/utils.js b/src/language-js/embed/utils.js index eb87cf70d..107fe490b 100644 --- a/src/language-js/embed/utils.js +++ b/src/language-js/embed/utils.js @@ -30,15 +30,25 @@ const angularComponentObjectExpressionPredicates = [ * }) */ function isAngularComponentStyles(path) { - return path.match( - (node) => node.type === "TemplateLiteral", - (node, name) => isArrayOrTupleExpression(node) && name === "elements", - (node, name) => - isObjectProperty(node) && - node.key.type === "Identifier" && - node.key.name === "styles" && - name === "value", - ...angularComponentObjectExpressionPredicates, + const isTemplateLiteral = (node) => node.type === "TemplateLiteral"; + const isObjectPropertyNamedStyles = (node, key) => + isObjectProperty(node) && + !node.computed && + node.key.type === "Identifier" && + node.key.name === "styles" && + key === "value"; + return ( + path.match( + isTemplateLiteral, + (node, name) => isArrayOrTupleExpression(node) && name === "elements", + isObjectPropertyNamedStyles, + ...angularComponentObjectExpressionPredicates, + ) || + path.match( + isTemplateLiteral, + isObjectPropertyNamedStyles, + ...angularComponentObjectExpressionPredicates, + ) ); } function isAngularComponentTemplate(path) { diff --git a/tests/format/typescript/angular-component-examples/15934-computed.component.ts b/tests/format/typescript/angular-component-examples/15934-computed.component.ts new file mode 100644 index 000000000..653f497f3 --- /dev/null +++ b/tests/format/typescript/angular-component-examples/15934-computed.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +const styles = "foobar"; + +@Component({ + selector: 'app-root', + template: ` +

My App

+ + `, + [styles]: `h1 { color: blue }` +}) +export class AppComponent {} diff --git a/tests/format/typescript/angular-component-examples/15934.component.ts b/tests/format/typescript/angular-component-examples/15934.component.ts new file mode 100644 index 000000000..c6c4d66dc --- /dev/null +++ b/tests/format/typescript/angular-component-examples/15934.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: ` +

My App

+ + `, + styles: `h1 { color: blue }` +}) +export class AppComponent {} diff --git a/tests/format/typescript/angular-component-examples/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/angular-component-examples/__snapshots__/jsfmt.spec.js.snap index 21e4afe34..9a41ce0f2 100644 --- a/tests/format/typescript/angular-component-examples/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/angular-component-examples/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,161 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`15934.component.ts - {"trailingComma":"es5"} format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 +trailingComma: "es5" + | printWidth +=====================================input====================================== +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: \` +

My App

+ + \`, + styles: \`h1 { color: blue }\` +}) +export class AppComponent {} + +=====================================output===================================== +import { Component } from "@angular/core"; + +@Component({ + selector: "app-root", + template: \` +

My App

+ + \`, + styles: \` + h1 { + color: blue; + } + \`, +}) +export class AppComponent {} + +================================================================================ +`; + +exports[`15934.component.ts - {"trailingComma":"none"} format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 +trailingComma: "none" + | printWidth +=====================================input====================================== +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: \` +

My App

+ + \`, + styles: \`h1 { color: blue }\` +}) +export class AppComponent {} + +=====================================output===================================== +import { Component } from "@angular/core"; + +@Component({ + selector: "app-root", + template: \` +

My App

+ + \`, + styles: \` + h1 { + color: blue; + } + \` +}) +export class AppComponent {} + +================================================================================ +`; + +exports[`15934-computed.component.ts - {"trailingComma":"es5"} format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 +trailingComma: "es5" + | printWidth +=====================================input====================================== +import { Component } from '@angular/core'; + +const styles = "foobar"; + +@Component({ + selector: 'app-root', + template: \` +

My App

+ + \`, + [styles]: \`h1 { color: blue }\` +}) +export class AppComponent {} + +=====================================output===================================== +import { Component } from "@angular/core"; + +const styles = "foobar"; + +@Component({ + selector: "app-root", + template: \` +

My App

+ + \`, + [styles]: \`h1 { color: blue }\`, +}) +export class AppComponent {} + +================================================================================ +`; + +exports[`15934-computed.component.ts - {"trailingComma":"none"} format 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 +trailingComma: "none" + | printWidth +=====================================input====================================== +import { Component } from '@angular/core'; + +const styles = "foobar"; + +@Component({ + selector: 'app-root', + template: \` +

My App

+ + \`, + [styles]: \`h1 { color: blue }\` +}) +export class AppComponent {} + +=====================================output===================================== +import { Component } from "@angular/core"; + +const styles = "foobar"; + +@Component({ + selector: "app-root", + template: \` +

My App

+ + \`, + [styles]: \`h1 { color: blue }\` +}) +export class AppComponent {} + +================================================================================ +`; + exports[`test.component.ts - {"trailingComma":"es5"} format 1`] = ` ====================================options===================================== parsers: ["typescript"]