diff --git a/.changeset/rich-keys-bake.md b/.changeset/rich-keys-bake.md new file mode 100644 index 0000000..1a9d3a4 --- /dev/null +++ b/.changeset/rich-keys-bake.md @@ -0,0 +1,5 @@ +--- +'prettier-plugin-astro': minor +--- + +Updated self-closing behaviour to be more in line with Prettier's HTML formatter diff --git a/src/printer/elements.ts b/src/printer/elements.ts index 041e09c..ee735c3 100644 --- a/src/printer/elements.ts +++ b/src/printer/elements.ts @@ -1,31 +1,50 @@ -export type TagName = keyof HTMLElementTagNameMap | 'svg'; +export type TagName = keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap; -// https://github.com/prettier/prettier/blob/main/vendors/html-void-elements.json -export const selfClosingTags = [ +export const selfClosingTags: TagName[] = [ 'area', 'base', - 'basefont', - 'bgsound', 'br', 'col', - 'command', 'embed', - 'frame', 'hr', 'image', 'img', 'input', - 'isindex', - 'keygen', 'link', - 'menuitem', 'meta', - 'nextid', - 'param', 'slot', 'source', 'track', 'wbr', + + // The SVG spec doesn't really have a concept of void elements, everything is allowed + // However, some tags are very commonly self-closed by users, and as such they find it confusing for them to not be closed + 'circle', + 'ellipse', + 'line', + 'path', + 'polygon', + 'polyline', + 'rect', + 'stop', + 'use', + + // Filters + 'feBlend', + 'feColorMatrix', + 'feComponentTransfer', + 'feComposite', + 'feConvolveMatrix', + 'feDiffuseLighting', + 'feDisplacementMap', + 'feFlood', + 'feGaussianBlur', + 'feMerge', + 'feMorphology', + 'feOffset', + 'feSpecularLighting', + 'feTile', + 'feTurbulence', ]; // https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements#Elements diff --git a/src/printer/index.ts b/src/printer/index.ts index f08cd8a..8a70257 100644 --- a/src/printer/index.ts +++ b/src/printer/index.ts @@ -1,5 +1,5 @@ import { Doc } from 'prettier'; -import { selfClosingTags } from './elements'; +import { selfClosingTags, type TagName } from './elements'; import { TextNode } from './nodes'; import { AstPath, @@ -130,16 +130,18 @@ export function print(path: AstPath, opts: ParserOptions, print: printFn): Doc { /** * An element is allowed to self close only if: + * It's already self-closing OR * It is empty AND * It's a component OR * It's in the HTML spec as a void element OR * It has a `set:*` directive */ const isSelfClosingTag = - isEmpty && - (node.type === 'component' || - selfClosingTags.includes(node.name) || - hasSetDirectives(node)); + (node.position?.end && opts.originalText.at(opts.locEnd(node) - 1) == '/') || + (isEmpty && + (node.type === 'component' || + selfClosingTags.includes(node.name as TagName) || + hasSetDirectives(node))); const isSingleLinePerAttribute = opts.singleAttributePerLine && node.attributes.length > 1; const attributeLine = isSingleLinePerAttribute ? breakParent : '';