Angular: Support comments in start tag (#19465)
This commit is contained in:
1 parent
9ed48ccb14
commit
af720efb42
19 files changed
+315
-47
No files matched your search
@@ -51,6 +51,7 @@ function toAngularHtmlParserParseOptions(parseOptions) {
|
||||
const {
|
||||
canSelfClose,
|
||||
allowHtmComponentClosingTags,
|
||||
allowStartTagComments,
|
||||
isTagNameCaseSensitive,
|
||||
shouldParseAsRawText,
|
||||
tokenizeAngularBlocks,
|
||||
@@ -60,6 +61,7 @@ function toAngularHtmlParserParseOptions(parseOptions) {
|
||||
return {
|
||||
canSelfClose,
|
||||
allowHtmComponentClosingTags,
|
||||
allowStartTagComments,
|
||||
isTagNameCaseSensitive,
|
||||
getTagContentType: shouldParseAsRawText
|
||||
? (...args) =>
|
||||
|
||||
@@ -39,6 +39,7 @@ const angularParser = createParser({
|
||||
name: "angular",
|
||||
tokenizeAngularBlocks: true,
|
||||
tokenizeAngularLetDeclaration: true,
|
||||
allowStartTagComments: true,
|
||||
});
|
||||
|
||||
// Vue.js
|
||||
|
||||
@@ -36,6 +36,8 @@ class Visitor extends RecursiveVisitor {
|
||||
}
|
||||
|
||||
function postprocess(rawAst, frontMatter, parseOptions, parseSubHtml) {
|
||||
const isAngular = parseOptions.name === "angular";
|
||||
|
||||
visitAll(new Visitor(), rawAst.children, { parseOptions });
|
||||
|
||||
if (frontMatter) {
|
||||
@@ -53,11 +55,16 @@ function postprocess(rawAst, frontMatter, parseOptions, parseSubHtml) {
|
||||
if (ieConditionalComment) {
|
||||
node.parent.replaceChild(node, ieConditionalComment);
|
||||
}
|
||||
} else if (isAngular && node.kind === "element" && node.comments) {
|
||||
node.startTagComments = node.comments;
|
||||
delete node.comments;
|
||||
}
|
||||
|
||||
normalizeAngularControlFlowBlock(node);
|
||||
normalizeAngularLetDeclaration(node);
|
||||
normalizeAngularIcuExpression(node);
|
||||
if (isAngular) {
|
||||
normalizeAngularControlFlowBlock(node);
|
||||
normalizeAngularLetDeclaration(node);
|
||||
normalizeAngularIcuExpression(node);
|
||||
}
|
||||
});
|
||||
|
||||
return ast;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ParseSourceSpan } from "angular-html-parser";
|
||||
import htmlWhitespace from "../utilities/html-whitespace.js";
|
||||
import isNonEmptyArray from "../utilities/is-non-empty-array.js";
|
||||
import {
|
||||
canHaveInterpolation,
|
||||
getLeadingAndTrailingHtmlWhitespace,
|
||||
@@ -141,6 +142,7 @@ function mergeSimpleElementIntoText(ast /* , options */) {
|
||||
const isSimpleElement = (node) =>
|
||||
node.kind === "element" &&
|
||||
node.attrs.length === 0 &&
|
||||
!isNonEmptyArray(node.startTagComments) &&
|
||||
node.children.length === 1 &&
|
||||
node.firstChild.kind === "text" &&
|
||||
!htmlWhitespace.hasWhitespaceCharacter(node.children[0].value) &&
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { replaceEndOfLine } from "../../document/index.js";
|
||||
|
||||
// Based on JS comment print src/language-js/print/comment.js
|
||||
|
||||
function printStartTagComment(path) {
|
||||
const {
|
||||
node: { value, type },
|
||||
} = path;
|
||||
|
||||
if (type === "single") {
|
||||
return `//${value.trimEnd()}`;
|
||||
}
|
||||
|
||||
// TODO: support indentable block comment
|
||||
|
||||
return ["/*", replaceEndOfLine(value), "*/"];
|
||||
}
|
||||
|
||||
export { printStartTagComment };
|
||||
@@ -221,7 +221,9 @@ function needsToBorrowParentOpeningTagEndMarker(node) {
|
||||
function printAttributes(path, options, print) {
|
||||
const { node } = path;
|
||||
|
||||
if (!isNonEmptyArray(node.attrs)) {
|
||||
const { attrs: attributes = [], startTagComments = [] } = node;
|
||||
|
||||
if (attributes.length === 0 && startTagComments.length === 0) {
|
||||
return node.isSelfClosing
|
||||
? /**
|
||||
* <br />
|
||||
@@ -242,34 +244,53 @@ function printAttributes(path, options, print) {
|
||||
? (attribute) => ignoreAttributeData.includes(attribute.rawName)
|
||||
: () => false;
|
||||
|
||||
const printedAttributes = path.map(
|
||||
({ node: attribute }) =>
|
||||
hasPrettierIgnoreAttribute(attribute)
|
||||
? replaceEndOfLine(
|
||||
options.originalText.slice(locStart(attribute), locEnd(attribute)),
|
||||
)
|
||||
: print(),
|
||||
"attrs",
|
||||
const properties = ["attrs", "startTagComments"].filter((property) =>
|
||||
isNonEmptyArray(node[property]),
|
||||
);
|
||||
const printedAttributes = properties.flatMap((property) =>
|
||||
path.map(
|
||||
({ node }) => ({
|
||||
loc: locStart(node),
|
||||
printed:
|
||||
node.kind === "attribute" && hasPrettierIgnoreAttribute(node)
|
||||
? replaceEndOfLine(
|
||||
options.originalText.slice(locStart(node), locEnd(node)),
|
||||
)
|
||||
: print(),
|
||||
}),
|
||||
property,
|
||||
),
|
||||
);
|
||||
|
||||
if (properties.length > 1) {
|
||||
printedAttributes.sort((a, b) => a.loc - b.loc);
|
||||
}
|
||||
|
||||
const forceNotToBreakAttrContent =
|
||||
node.kind === "element" &&
|
||||
node.fullName === "script" &&
|
||||
node.attrs.length === 1 &&
|
||||
node.attrs[0].fullName === "src" &&
|
||||
node.children.length === 0;
|
||||
|
||||
attributes.length === 1 &&
|
||||
attributes[0].fullName === "src" &&
|
||||
node.children.length === 0 &&
|
||||
startTagComments.length === 0;
|
||||
const shouldForceBreak = startTagComments.some(
|
||||
(comment) => comment.type === "single",
|
||||
);
|
||||
const shouldPrintAttributePerLine =
|
||||
options.singleAttributePerLine &&
|
||||
node.attrs.length > 1 &&
|
||||
!isVueSfcBlock(node, options);
|
||||
shouldForceBreak ||
|
||||
(options.singleAttributePerLine &&
|
||||
attributes.length > 1 &&
|
||||
!isVueSfcBlock(node, options));
|
||||
const attributeLine = shouldPrintAttributePerLine ? hardline : line;
|
||||
|
||||
/** @type {Doc[]} */
|
||||
const parts = [
|
||||
indent([
|
||||
forceNotToBreakAttrContent ? " " : line,
|
||||
join(attributeLine, printedAttributes),
|
||||
forceNotToBreakAttrContent ? " " : shouldForceBreak ? hardline : line,
|
||||
join(
|
||||
attributeLine,
|
||||
printedAttributes.map(({ printed }) => printed),
|
||||
),
|
||||
]),
|
||||
];
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from "./print/angular-icu-expression.js";
|
||||
import { printChildren } from "./print/children.js";
|
||||
import { printElement } from "./print/element.js";
|
||||
import { printStartTagComment } from "./print/start-tag-comment.js";
|
||||
import {
|
||||
printClosingTagEnd,
|
||||
printClosingTagSuffix,
|
||||
@@ -150,6 +151,10 @@ function genericPrint(path, options, print) {
|
||||
quote,
|
||||
];
|
||||
}
|
||||
|
||||
case "startTagComment":
|
||||
return printStartTagComment(path);
|
||||
|
||||
case "frontMatter": // Handled in core
|
||||
case "cdata": // Transformed into `text`
|
||||
default:
|
||||
|
||||
@@ -2,7 +2,7 @@ import { generateReferenceSharedVisitorKeys } from "../utilities/visitor-keys.js
|
||||
|
||||
const visitorKeys = generateReferenceSharedVisitorKeys({
|
||||
root: ["children"],
|
||||
element: ["attrs", "children"],
|
||||
element: ["attrs", "startTagComments", "children"],
|
||||
ieConditionalComment: ["children"],
|
||||
ieConditionalStartComment: [],
|
||||
ieConditionalEndComment: [],
|
||||
@@ -11,6 +11,7 @@ const visitorKeys = generateReferenceSharedVisitorKeys({
|
||||
docType: [],
|
||||
comment: [],
|
||||
attribute: [],
|
||||
startTagComment: [],
|
||||
cdata: [],
|
||||
angularControlFlowBlock: ["children", "parameters"],
|
||||
angularControlFlowBlockParameters: ["children"],
|
||||
|
||||
Reference in new issue
Block a user