New: Format Angular Component styles (#4361)
* New: Format Angular Component styles and template * Clean AST * Cleanupmaster
parent
5c6e0802af
commit
88b71481fa
|
@ -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" &&
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 {}
|
||||
|
||||
`;
|
|
@ -0,0 +1,2 @@
|
|||
run_spec(__dirname, ["typescript"]);
|
||||
run_spec(__dirname, ["typescript"], { trailingComma: "es5" });
|
|
@ -0,0 +1,17 @@
|
|||
@Component({
|
||||
selector: 'app-test',
|
||||
template: `<ul> <li>test</li>
|
||||
</ul>
|
||||
`,
|
||||
styles: [ `
|
||||
|
||||
:host {
|
||||
color: red;
|
||||
}
|
||||
div { background: blue
|
||||
}
|
||||
`
|
||||
|
||||
]
|
||||
})
|
||||
class TestComponent {}
|
Loading…
Reference in New Issue