Format <style> containing mustaches
This commit is contained in:
1 parent
891accaaab
commit
05b8f7a0a8
8 files changed
+264
-67
No files matched your search
@@ -1,4 +1,8 @@
|
|||||||
import { isPlainTextStyleOrScriptElement } from "./utilities.js";
|
import { indent, replaceEndOfLine, softline } from "../document/index.js";
|
||||||
|
import { replacePlaceholders } from "../language-js/embed/css.js";
|
||||||
|
import { locEnd, locStart } from "./loc.js";
|
||||||
|
import { printStartingTag } from "./print/tag.js";
|
||||||
|
import { isPlainTextElement } from "./utilities.js";
|
||||||
|
|
||||||
function getAttribute(node, name) {
|
function getAttribute(node, name) {
|
||||||
return node.attributes.find(
|
return node.attributes.find(
|
||||||
@@ -29,16 +33,61 @@ function getScriptTextToDocOptions(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStyleTextToDocOptions(node) {
|
function isEmbedCss(node) {
|
||||||
const langAttribute = getAttribute(node, "lang");
|
if (node.type !== "ElementNode" || node.tag !== "style") {
|
||||||
if (!langAttribute || getTextValue(langAttribute) === "css") {
|
return false;
|
||||||
return { parser: "css" };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const langAttribute = getAttribute(node, "lang");
|
||||||
|
return !langAttribute || getTextValue(langAttribute) === "css";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function printEmbedCss(textToDoc, print, path, options) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
let text = "";
|
||||||
|
const mustacheDocs = [];
|
||||||
|
for (const child of node.children) {
|
||||||
|
if (child.type === "TextNode") {
|
||||||
|
text += child.chars;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
text += `@prettier-placeholder-${mustacheDocs.length}-id`;
|
||||||
|
mustacheDocs.push(
|
||||||
|
replaceEndOfLine(
|
||||||
|
options.originalText.slice(locStart(child), locEnd(child)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!text.trim()) {
|
||||||
|
return [printStartingTag(path, options, print), "</style>"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = await textToDoc(text, { parser: "css" });
|
||||||
|
const contentDoc = replacePlaceholders(doc, mustacheDocs);
|
||||||
|
|
||||||
|
/* c8 ignore next 3 */
|
||||||
|
if (!contentDoc) {
|
||||||
|
throw new Error("Couldn't insert all the mustaches");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
printStartingTag(path, options, print),
|
||||||
|
indent([softline, contentDoc]),
|
||||||
|
softline,
|
||||||
|
"</style>",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function embed(path /* , options*/) {
|
function embed(path /* , options*/) {
|
||||||
const { node } = path;
|
const { node } = path;
|
||||||
|
|
||||||
|
if (isEmbedCss(node)) {
|
||||||
|
return printEmbedCss;
|
||||||
|
}
|
||||||
|
|
||||||
if (node.type !== "TextNode") {
|
if (node.type !== "TextNode") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,15 +95,14 @@ function embed(path /* , options*/) {
|
|||||||
const { parent } = path;
|
const { parent } = path;
|
||||||
|
|
||||||
if (!(
|
if (!(
|
||||||
isPlainTextStyleOrScriptElement(parent) && parent.children[0] === node
|
isPlainTextElement(parent) &&
|
||||||
|
parent.tag === "script" &&
|
||||||
|
parent.children[0] === node
|
||||||
)) {
|
)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const textToDocOptions =
|
const textToDocOptions = getScriptTextToDocOptions(parent);
|
||||||
parent.tag === "style"
|
|
||||||
? getStyleTextToDocOptions(parent)
|
|
||||||
: getScriptTextToDocOptions(parent);
|
|
||||||
|
|
||||||
if (!textToDocOptions) {
|
if (!textToDocOptions) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import htmlWhitespace from "../../utilities/html-whitespace.js";
|
import htmlWhitespace from "../../utilities/html-whitespace.js";
|
||||||
import { isPlainTextStyleOrScriptElement } from "../utilities.js";
|
import { isPlainTextElement } from "../utilities.js";
|
||||||
|
|
||||||
function massageAstNode(original, cloned, parent) {
|
function massageAstNode(original, cloned, parent) {
|
||||||
// (Glimmer/HTML) ignore TextNode
|
// (Glimmer/HTML) ignore TextNode
|
||||||
@@ -11,8 +11,10 @@ function massageAstNode(original, cloned, parent) {
|
|||||||
|
|
||||||
// CSS/JS will be formatted
|
// CSS/JS will be formatted
|
||||||
if (
|
if (
|
||||||
isPlainTextStyleOrScriptElement(parent) &&
|
(parent.type === "ElementNode" && parent.tag === "style") ||
|
||||||
parent.children[0] === original
|
(isPlainTextElement(parent) &&
|
||||||
|
parent.tag === "script" &&
|
||||||
|
parent.children[0] === original)
|
||||||
) {
|
) {
|
||||||
cloned.chars = "";
|
cloned.chars = "";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
group,
|
||||||
|
ifBreak,
|
||||||
|
indent,
|
||||||
|
line,
|
||||||
|
softline,
|
||||||
|
} from "../../document/index.js";
|
||||||
|
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
|
||||||
|
import { locStart } from "../loc.js";
|
||||||
|
import { isVoidElement } from "../utilities.js";
|
||||||
|
|
||||||
|
/* ElementNode print helpers */
|
||||||
|
|
||||||
|
function sortByLoc(a, b) {
|
||||||
|
return locStart(a) - locStart(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printStartingTag(path, options, print) {
|
||||||
|
const { node } = path;
|
||||||
|
|
||||||
|
const types = ["attributes", "modifiers", "comments"].filter((property) =>
|
||||||
|
isNonEmptyArray(node[property]),
|
||||||
|
);
|
||||||
|
const attributes = types.flatMap((type) => node[type]).sort(sortByLoc);
|
||||||
|
|
||||||
|
for (const attributeType of types) {
|
||||||
|
path.each(({ node }) => {
|
||||||
|
const index = attributes.indexOf(node);
|
||||||
|
attributes[index] = [line, print()];
|
||||||
|
}, attributeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNonEmptyArray(node.blockParams)) {
|
||||||
|
attributes.push(line, printBlockParams(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
options.htmlWhitespaceSensitivity === "ignore" &&
|
||||||
|
path.previous?.type === "ElementNode"
|
||||||
|
? softline
|
||||||
|
: "",
|
||||||
|
group(["<", node.tag, indent(attributes), printStartingTagEndMarker(node)]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function printStartingTagEndMarker(node) {
|
||||||
|
if (isVoidElement(node)) {
|
||||||
|
return ifBreak([softline, "/>"], [" />", softline]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifBreak([softline, ">"], ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
function printBlockParams(node) {
|
||||||
|
return ["as |", node.blockParams.join(" "), "|"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export { printBlockParams, printStartingTag };
|
||||||
@@ -3,7 +3,6 @@ import {
|
|||||||
fill,
|
fill,
|
||||||
group,
|
group,
|
||||||
hardline,
|
hardline,
|
||||||
ifBreak,
|
|
||||||
indent,
|
indent,
|
||||||
join,
|
join,
|
||||||
line,
|
line,
|
||||||
@@ -18,6 +17,7 @@ import embed from "./embed.js";
|
|||||||
import getVisitorKeys from "./get-visitor-keys.js";
|
import getVisitorKeys from "./get-visitor-keys.js";
|
||||||
import { locEnd, locStart } from "./loc.js";
|
import { locEnd, locStart } from "./loc.js";
|
||||||
import { massageAstNode } from "./massage-ast/index.js";
|
import { massageAstNode } from "./massage-ast/index.js";
|
||||||
|
import { printBlockParams, printStartingTag } from "./print/tag.js";
|
||||||
import {
|
import {
|
||||||
hasPrettierIgnore,
|
hasPrettierIgnore,
|
||||||
isPlainTextStyleOrScriptElement,
|
isPlainTextStyleOrScriptElement,
|
||||||
@@ -48,12 +48,7 @@ function print(path, options, print) {
|
|||||||
const isWhitespaceSensitive =
|
const isWhitespaceSensitive =
|
||||||
options.htmlWhitespaceSensitivity !== "ignore";
|
options.htmlWhitespaceSensitivity !== "ignore";
|
||||||
|
|
||||||
const startingTag = [
|
const startingTag = printStartingTag(path, options, print);
|
||||||
!isWhitespaceSensitive && path.previous?.type === "ElementNode"
|
|
||||||
? softline
|
|
||||||
: "",
|
|
||||||
group([printStartingTag(path, print)]),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isVoidElement(node)) {
|
if (isVoidElement(node)) {
|
||||||
return [startingTag];
|
return [startingTag];
|
||||||
@@ -424,42 +419,6 @@ function print(path, options, print) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ElementNode print helpers */
|
|
||||||
|
|
||||||
function sortByLoc(a, b) {
|
|
||||||
return locStart(a) - locStart(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
function printStartingTag(path, print) {
|
|
||||||
const { node } = path;
|
|
||||||
|
|
||||||
const types = ["attributes", "modifiers", "comments"].filter((property) =>
|
|
||||||
isNonEmptyArray(node[property]),
|
|
||||||
);
|
|
||||||
const attributes = types.flatMap((type) => node[type]).sort(sortByLoc);
|
|
||||||
|
|
||||||
for (const attributeType of types) {
|
|
||||||
path.each(({ node }) => {
|
|
||||||
const index = attributes.indexOf(node);
|
|
||||||
attributes[index] = [line, print()];
|
|
||||||
}, attributeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNonEmptyArray(node.blockParams)) {
|
|
||||||
attributes.push(line, printBlockParams(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ["<", node.tag, indent(attributes), printStartingTagEndMarker(node)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function printStartingTagEndMarker(node) {
|
|
||||||
if (isVoidElement(node)) {
|
|
||||||
return ifBreak([softline, "/>"], [" />", softline]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ifBreak([softline, ">"], ">");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MustacheStatement print helpers */
|
/* MustacheStatement print helpers */
|
||||||
|
|
||||||
function printOpeningMustache(node) {
|
function printOpeningMustache(node) {
|
||||||
@@ -801,10 +760,6 @@ function printParams(path, print) {
|
|||||||
return join(line, parts);
|
return join(line, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
function printBlockParams(node) {
|
|
||||||
return ["as |", node.blockParams.join(" "), "|"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://handlebarsjs.com/guide/expressions.html#literal-segments
|
// https://handlebarsjs.com/guide/expressions.html#literal-segments
|
||||||
const PATH_EXPRESSION_FORBIDDEN_CHARACTERS = new Set(
|
const PATH_EXPRESSION_FORBIDDEN_CHARACTERS = new Set(
|
||||||
"!\"#%&'()*+,./;<=>@[\\]^`{|}~",
|
"!\"#%&'()*+,./;<=>@[\\]^`{|}~",
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ function hasPrettierIgnore(path) {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
hasPrettierIgnore,
|
hasPrettierIgnore,
|
||||||
|
isPlainTextElement,
|
||||||
isPlainTextStyleOrScriptElement,
|
isPlainTextStyleOrScriptElement,
|
||||||
isVoidElement,
|
isVoidElement,
|
||||||
isWhitespaceNode,
|
isWhitespaceNode,
|
||||||
|
|||||||
@@ -171,4 +171,4 @@ const isEmbedCss = (path /* , options*/) =>
|
|||||||
isCssProp(path) ||
|
isCssProp(path) ||
|
||||||
isAngularComponentStyles(path);
|
isAngularComponentStyles(path);
|
||||||
|
|
||||||
export { isEmbedCss, printEmbedCss };
|
export { isEmbedCss, printEmbedCss, replacePlaceholders };
|
||||||
@@ -218,19 +218,113 @@ parsers: ["glimmer"]
|
|||||||
|
|
||||||
<style>{{foo}}</style>
|
<style>{{foo}}</style>
|
||||||
|
|
||||||
=====================================output=====================================
|
|
||||||
<style>
|
<style>
|
||||||
a { color:
|
.{{className}} { width:{{width}}px;background:url({{url}}) }
|
||||||
{{foo}}
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a::after { content: "{{content}}" }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* {{comment}} */
|
||||||
|
a { color:red }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@media (max-width: {{breakpoint}}px) { a { color: red } }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
{{mixin}}
|
||||||
|
color: red;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.a { color:
|
a {
|
||||||
{{color}}; }
|
{{mixin}};
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.a { color:red }
|
||||||
|
{{#if debug}}
|
||||||
|
.b {color:red}
|
||||||
|
.c {color:red}
|
||||||
|
{{/if}}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
=====================================output=====================================
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
color: {{foo}};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.a {
|
||||||
|
color: {{color}};
|
||||||
|
}
|
||||||
{{#if debug}}.b { color: red; }{{/if}}
|
{{#if debug}}.b { color: red; }{{/if}}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>{{foo}}</style>
|
<style>
|
||||||
|
{{foo}}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.{{className}} {
|
||||||
|
width: {{width}}px;
|
||||||
|
background: url({{url}});
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a::after {
|
||||||
|
content: "{{content}}";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* {{comment}} */
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@media (max-width: {{breakpoint}}px) {
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
{{mixin}}
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
{{mixin}};
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.a {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
{{#if debug}}
|
||||||
|
.b {color:red}
|
||||||
|
.c {color:red}
|
||||||
|
{{/if}}
|
||||||
|
</style>
|
||||||
================================================================================
|
================================================================================
|
||||||
`;
|
`;
|
||||||
@@ -10,3 +10,42 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>{{foo}}</style>
|
<style>{{foo}}</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.{{className}} { width:{{width}}px;background:url({{url}}) }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a::after { content: "{{content}}" }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* {{comment}} */
|
||||||
|
a { color:red }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@media (max-width: {{breakpoint}}px) { a { color: red } }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
{{mixin}}
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
{{mixin}};
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.a { color:red }
|
||||||
|
{{#if debug}}
|
||||||
|
.b {color:red}
|
||||||
|
.c {color:red}
|
||||||
|
{{/if}}
|
||||||
|
</style>
|
||||||
Reference in new issue
Block a user