New: Format Angular Component styles (#4361)

* New: Format Angular Component styles and template

* Clean AST

* Cleanup
master
James Henry 2018-05-23 21:08:40 -04:00 committed by Suchipi
parent 5c6e0802af
commit 88b71481fa
5 changed files with 169 additions and 3 deletions

View File

@ -122,6 +122,24 @@ function clean(ast, newObj, parent) {
newObj.value.expression.quasis.forEach(q => delete q.value);
}
// CSS template literals in Angular Component decorator
if (
ast.type === "Decorator" &&
ast.expression.type === "CallExpression" &&
ast.expression.callee.name === "Component" &&
ast.expression.arguments.length === 1 &&
ast.expression.arguments[0].properties.some(
prop =>
prop.key.name === "styles" && prop.value.type === "ArrayExpression"
)
) {
newObj.expression.arguments[0].properties.forEach(prop => {
if (prop.value.type === "ArrayExpression") {
prop.value.elements[0].quasis.forEach(q => delete q.value);
}
});
}
// styled-components, graphql, markdown
if (
ast.type === "TaggedTemplateExpression" &&

View File

@ -18,9 +18,12 @@ function embed(path, print, textToDoc /*, options */) {
switch (node.type) {
case "TemplateLiteral": {
const isCss = [isStyledJsx, isStyledComponents, isCssProp].some(isIt =>
isIt(path)
);
const isCss = [
isStyledJsx,
isStyledComponents,
isCssProp,
isAngularComponentStyles
].some(isIt => isIt(path));
if (isCss) {
// Get full template literal with expressions replaced by placeholders
@ -176,6 +179,18 @@ function embed(path, print, textToDoc /*, options */) {
}
}
function isPropertyWithinAngularComponentDecorator(path, parentIndexToCheck) {
const parent = path.getParentNode(parentIndexToCheck);
return !!(
parent &&
parent.type === "Decorator" &&
parent.expression &&
parent.expression.type === "CallExpression" &&
parent.expression.callee &&
parent.expression.callee.name === "Component"
);
}
function getIndentation(str) {
const firstMatchedIndent = str.match(/^([^\S\n]*)\S/m);
return firstMatchedIndent === null ? "" : firstMatchedIndent[1];
@ -334,6 +349,41 @@ function isStyledJsx(path) {
);
}
/**
* Angular Components can have:
* - Inline HTML template
* - Inline CSS styles
*
* ...which are both within template literals somewhere
* inside of the Component decorator factory.
*
* TODO: Format HTML template once prettier's HTML
* formatting is "ready"
*
* E.g.
* @Component({
* template: `<div>...</div>`,
* styles: [`h1 { color: blue; }`]
* })
*/
function isAngularComponentStyles(path) {
const parent = path.getParentNode();
const parentParent = path.getParentNode(1);
const isWithinArrayValueFromProperty = !!(
parent &&
(parent.type === "ArrayExpression" && parentParent.type === "Property")
);
if (
isWithinArrayValueFromProperty &&
isPropertyWithinAngularComponentDecorator(path, 4)
) {
if (parentParent.key && parentParent.key.name === "styles") {
return true;
}
}
return false;
}
/**
* styled-components template literals
*/

View File

@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`test.component.ts 1`] = `
@Component({
selector: 'app-test',
template: \`<ul> <li>test</li>
</ul>
\`,
styles: [ \`
:host {
color: red;
}
div { background: blue
}
\`
]
})
class TestComponent {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Component({
selector: "app-test",
template: \`<ul> <li>test</li>
</ul>
\`,
styles: [
\`
:host {
color: red;
}
div {
background: blue;
}
\`
]
})
class TestComponent {}
`;
exports[`test.component.ts 2`] = `
@Component({
selector: 'app-test',
template: \`<ul> <li>test</li>
</ul>
\`,
styles: [ \`
:host {
color: red;
}
div { background: blue
}
\`
]
})
class TestComponent {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Component({
selector: "app-test",
template: \`<ul> <li>test</li>
</ul>
\`,
styles: [
\`
:host {
color: red;
}
div {
background: blue;
}
\`,
],
})
class TestComponent {}
`;

View File

@ -0,0 +1,2 @@
run_spec(__dirname, ["typescript"]);
run_spec(__dirname, ["typescript"], { trailingComma: "es5" });

View File

@ -0,0 +1,17 @@
@Component({
selector: 'app-test',
template: `<ul> <li>test</li>
</ul>
`,
styles: [ `
:host {
color: red;
}
div { background: blue
}
`
]
})
class TestComponent {}