Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@prettier/plugin-xml

Package Overview
Dependencies
Maintainers
14
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@prettier/plugin-xml - npm Package Compare versions

Comparing version 3.2.2 to 3.3.0

13

CHANGELOG.md

@@ -9,2 +9,12 @@ # Changelog

## [3.3.0] - 2024-02-09
### Added
- Support for `formatWithCursor`.
### Changed
- Always keep whitespace around in `xsl:text` tags.
## [3.2.2] - 2023-10-27

@@ -249,3 +259,4 @@

[unreleased]: https://github.com/prettier/plugin-xml/compare/v3.2.2...HEAD
[unreleased]: https://github.com/prettier/plugin-xml/compare/v3.3.0...HEAD
[3.3.0]: https://github.com/prettier/plugin-xml/compare/v3.2.2...v3.3.0
[3.2.2]: https://github.com/prettier/plugin-xml/compare/v3.2.1...v3.2.2

@@ -252,0 +263,0 @@ [3.2.1]: https://github.com/prettier/plugin-xml/compare/v3.2.0...v3.2.1

10

package.json
{
"name": "@prettier/plugin-xml",
"version": "3.2.2",
"version": "3.3.0",
"description": "prettier plugin for XML",

@@ -10,3 +10,3 @@ "type": "module",

"prepare": "node bin/languages.js && husky install",
"print": "prettier --plugin=.",
"print": "prettier --plugin=./src/plugin.js",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"

@@ -33,3 +33,3 @@ },

"eslint-config-prettier": "^9.0.0",
"husky": "^8.0.0",
"husky": "^9.0.6",
"jest": "^29.2.1",

@@ -66,6 +66,8 @@ "linguist-languages": "^7.21.0",

"prettier": {
"embeddedLanguageFormatting": "auto",
"plugins": [
"./src/plugin.js"
],
"trailingComma": "none"
"trailingComma": "none",
"xmlWhitespaceSensitivity": "ignore"
},

@@ -72,0 +74,0 @@ "lint-staged": {

@@ -51,3 +51,3 @@ <h1 align="center">Prettier for XML</h1>

| -------------------------- | ------------------------------ | :----------: | ------------------------------------------------------------------------------------------------------------------------ |
| `bracketSameLine` | `--bracket-same-line` | `true` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#bracket-same-line)) |
| `bracketSameLine` | `--bracket-same-line` | `true` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#bracket-line)) |
| `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |

@@ -54,0 +54,0 @@ | `singleAttributePerLine` | `--single-attribute-per-line` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#single-attribute-per-line)) |

@@ -18,10 +18,8 @@ import * as doc from "prettier/doc";

const { OPEN, Name, attribute, START_CLOSE, SLASH_OPEN, END_NAME, END } =
node.children;
node;
const parts = [OPEN[0].image, Name[0].image];
const parts = [OPEN, Name];
if (attribute) {
parts.push(
indent([line, join(line, path.map(print, "children", "attribute"))])
);
if (attribute.length > 0) {
parts.push(indent([line, join(line, path.map(print, "attribute"))]));
}

@@ -34,4 +32,4 @@

return {
openTag: group([...parts, START_CLOSE[0].image]),
closeTag: group([SLASH_OPEN[0].image, END_NAME[0].image, END[0].image])
openTag: group([...parts, START_CLOSE]),
closeTag: group([SLASH_OPEN, END_NAME, END])
};

@@ -43,4 +41,4 @@ }

for (const attribute of attributes) {
if (attribute.children.Name[0].image === "type") {
const value = attribute.children.STRING[0].image;
if (attribute.Name === "type") {
const value = attribute.STRING;

@@ -59,4 +57,4 @@ if (value.startsWith('"text/') && value.endsWith('"')) {

function getParser(node, opts) {
const { Name, attribute } = node.children;
let parser = Name[0].image.toLowerCase();
const { Name, attribute } = node;
let parser = Name.toLowerCase();

@@ -71,3 +69,3 @@ // We don't want to deal with some weird recursive parser situation, so we

// use xxx as the name of the parser
if ((parser === "style" || parser === "script") && attribute) {
if ((parser === "style" || parser === "script") && attribute.length > 0) {
parser = getTagType(attribute);

@@ -104,4 +102,4 @@ }

.map((node) => {
const { SEA_WS, TEXT } = node.children;
const [{ image }] = SEA_WS || TEXT;
const { SEA_WS, TEXT } = node;
const image = SEA_WS || TEXT;

@@ -134,3 +132,3 @@ return {

// If the node is self-closing, then skip
if (!node.children.content) {
if (!node.content) {
return;

@@ -140,5 +138,12 @@ }

// If the node does not actually contain content, or it contains any content
// that is not just plain text, then skip
const content = node.children.content[0].children;
if (Object.keys(content).length !== 1 || !content.chardata) {
// that is not just plain text, then skip.
const content = node.content;
if (
content.chardata.length === 0 ||
content.CData.length > 0 ||
content.Comment.length > 0 ||
content.element.length > 0 ||
content.PROCESSING_INSTRUCTION.length > 0 ||
content.reference.length > 0
) {
return;

@@ -145,0 +150,0 @@ }

@@ -19,2 +19,150 @@ import { parse as xmlToolsParse } from "@xml-tools/parser";

function simplifyCST(node) {
switch (node.name) {
case "attribute": {
const { Name, EQUALS, STRING } = node.children;
return {
name: "attribute",
Name: Name[0].image,
EQUALS: EQUALS[0].image,
STRING: STRING[0].image,
location: node.location
};
}
case "chardata": {
const { SEA_WS, TEXT } = node.children;
return {
name: "chardata",
SEA_WS: SEA_WS ? SEA_WS[0].image : null,
TEXT: TEXT ? TEXT[0].image : null,
location: node.location
};
}
case "content": {
const {
CData,
Comment,
chardata,
element,
PROCESSING_INSTRUCTION,
reference
} = node.children;
return {
name: "content",
CData: CData || [],
Comment: Comment || [],
chardata: (chardata || []).map(simplifyCST),
element: (element || []).map(simplifyCST),
PROCESSING_INSTRUCTION: PROCESSING_INSTRUCTION || [],
reference: (reference || []).map(simplifyCST),
location: node.location
};
}
case "docTypeDecl": {
const { DocType, Name, externalID, CLOSE } = node.children;
return {
name: "docTypeDecl",
DocType: DocType[0].image,
Name: Name[0].image,
externalID: externalID ? simplifyCST(externalID[0]) : null,
CLOSE: CLOSE[0].image,
location: node.location
};
}
case "document": {
const { docTypeDecl, element, misc, prolog } = node.children;
return {
name: "document",
docTypeDecl: docTypeDecl ? simplifyCST(docTypeDecl[0]) : null,
element: element ? simplifyCST(element[0]) : null,
misc: (misc || [])
.filter((child) => !child.children.SEA_WS)
.map(simplifyCST),
prolog: prolog ? simplifyCST(prolog[0]) : null,
location: node.location
};
}
case "element": {
const {
OPEN,
Name,
attribute,
START_CLOSE,
content,
SLASH_OPEN,
END_NAME,
END,
SLASH_CLOSE
} = node.children;
return {
name: "element",
OPEN: OPEN[0].image,
Name: Name[0].image,
attribute: (attribute || []).map(simplifyCST),
START_CLOSE: START_CLOSE ? START_CLOSE[0].image : null,
content: content ? simplifyCST(content[0]) : null,
SLASH_OPEN: SLASH_OPEN ? SLASH_OPEN[0].image : null,
END_NAME: END_NAME ? END_NAME[0].image : null,
END: END ? END[0].image : null,
SLASH_CLOSE: SLASH_CLOSE ? SLASH_CLOSE[0].image : null,
location: node.location
};
}
case "externalID": {
const { Public, PubIDLiteral, System, SystemLiteral } = node.children;
return {
name: "externalID",
Public: Public ? Public[0].image : null,
PubIDLiteral: PubIDLiteral ? PubIDLiteral[0].image : null,
System: System ? System[0].image : null,
SystemLiteral: SystemLiteral ? SystemLiteral[0].image : null,
location: node.location
};
}
case "misc": {
const { Comment, PROCESSING_INSTRUCTION, SEA_WS } = node.children;
return {
name: "misc",
Comment: Comment ? Comment[0].image : null,
PROCESSING_INSTRUCTION: PROCESSING_INSTRUCTION
? PROCESSING_INSTRUCTION[0].image
: null,
SEA_WS: SEA_WS ? SEA_WS[0].image : null,
location: node.location
};
}
case "prolog": {
const { XMLDeclOpen, attribute, SPECIAL_CLOSE } = node.children;
return {
name: "prolog",
XMLDeclOpen: XMLDeclOpen[0].image,
attribute: (attribute || []).map(simplifyCST),
SPECIAL_CLOSE: SPECIAL_CLOSE[0].image,
location: node.location
};
}
case "reference": {
const { CharRef, EntityRef } = node.children;
return {
name: "reference",
CharRef: CharRef ? CharRef[0].image : null,
EntityRef: EntityRef ? EntityRef[0].image : null,
location: node.location
};
}
default:
throw new Error(`Unknown node type: ${node.name}`);
}
}
const parser = {

@@ -56,3 +204,3 @@ parse(text) {

// Otherwise return the CST.
return cst;
return simplifyCST(cst);
},

@@ -59,0 +207,0 @@ astFormat: "xml",

@@ -11,3 +11,3 @@ import * as doc from "prettier/doc";

function hasIgnoreRanges(comments) {
if (!comments || comments.length === 0) {
if (comments.length === 0) {
return false;

@@ -30,3 +30,3 @@ }

function isWhitespaceIgnorable(opts, attributes, content) {
function isWhitespaceIgnorable(opts, name, attributes, content) {
// If the whitespace sensitivity setting is "strict", then we can't ignore the

@@ -38,11 +38,15 @@ // whitespace.

// If we have an xsl:text element, then we cannot ignore the whitespace.
if (name === "xsl:text") {
return false;
}
// If there is an xml:space attribute set to "preserve", then we can't ignore
// the whitespace.
if (
attributes &&
attributes.some(
(attribute) =>
attribute &&
attribute.children.Name[0].image === "xml:space" &&
attribute.children.STRING[0].image.slice(1, -1) === "preserve"
attribute.Name === "xml:space" &&
attribute.STRING.slice(1, -1) === "preserve"
)

@@ -55,3 +59,3 @@ ) {

// can't ignore the whitespace.
if (content.children.CData || content.children.reference) {
if (content.CData.length > 0 || content.reference.length > 0) {
return false;

@@ -62,3 +66,3 @@ }

// then we can't ignore the whitespace.
if (hasIgnoreRanges(content.children.Comment)) {
if (hasIgnoreRanges(content.Comment)) {
return false;

@@ -83,22 +87,22 @@ }

function printAttribute(path, opts, print) {
const { Name, EQUALS, STRING } = path.getValue().children;
const { Name, EQUALS, STRING } = path.getValue();
let attributeValue;
if (opts.xmlQuoteAttributes === "double") {
const content = STRING[0].image.slice(1, -1).replaceAll('"', "&quot;");
const content = STRING.slice(1, -1).replaceAll('"', "&quot;");
attributeValue = `"${content}"`;
} else if (opts.xmlQuoteAttributes === "single") {
const content = STRING[0].image.slice(1, -1).replaceAll("'", "&apos;");
const content = STRING.slice(1, -1).replaceAll("'", "&apos;");
attributeValue = `'${content}'`;
} else {
// preserve
attributeValue = STRING[0].image;
attributeValue = STRING;
}
return [Name[0].image, EQUALS[0].image, attributeValue];
return [Name, EQUALS, attributeValue];
}
function printCharData(path, opts, print) {
const { SEA_WS, TEXT } = path.getValue().children;
const [{ image }] = SEA_WS || TEXT;
const { SEA_WS, TEXT } = path.getValue();
const image = SEA_WS || TEXT;

@@ -111,64 +115,34 @@ return image

function printContentFragments(path, print) {
let response = [];
const children = path.getValue();
return [
...path.map(printIToken, "CData"),
...path.map(printIToken, "Comment"),
...path.map(
(charDataPath) => ({
offset: charDataPath.getValue().location.startOffset,
printed: print(charDataPath)
}),
"chardata"
),
...path.map(
(elementPath) => ({
offset: elementPath.getValue().location.startOffset,
printed: print(elementPath)
}),
"element"
),
...path.map(printIToken, "PROCESSING_INSTRUCTION"),
...path.map((referencePath) => {
const referenceNode = referencePath.getValue();
if (children.CData) {
response = response.concat(path.map(printIToken, "CData"));
}
if (children.Comment) {
response = response.concat(path.map(printIToken, "Comment"));
}
if (children.chardata) {
response = response.concat(
path.map(
(charDataPath) => ({
offset: charDataPath.getValue().location.startOffset,
printed: print(charDataPath)
}),
"chardata"
)
);
}
if (children.element) {
response = response.concat(
path.map(
(elementPath) => ({
offset: elementPath.getValue().location.startOffset,
printed: print(elementPath)
}),
"element"
)
);
}
if (children.PROCESSING_INSTRUCTION) {
response = response.concat(path.map(printIToken, "PROCESSING_INSTRUCTION"));
}
if (children.reference) {
response = response.concat(
path.map((referencePath) => {
const referenceNode = referencePath.getValue();
return {
offset: referenceNode.location.startOffset,
printed: (referenceNode.children.CharRef ||
referenceNode.children.EntityRef)[0].image
};
}, "reference")
);
}
return response;
return {
offset: referenceNode.location.startOffset,
printed: print(referencePath)
};
}, "reference")
];
}
function printContent(path, opts, print) {
let fragments = path.call(
(childrenPath) => printContentFragments(childrenPath, print),
"children"
);
const { Comment } = path.getValue().children;
let fragments = printContentFragments(path, print);
const { Comment } = path.getValue();

@@ -221,14 +195,14 @@ if (hasIgnoreRanges(Comment)) {

function printDocTypeDecl(path, opts, print) {
const { DocType, Name, externalID, CLOSE } = path.getValue().children;
const parts = [DocType[0].image, " ", Name[0].image];
const { DocType, Name, externalID, CLOSE } = path.getValue();
const parts = [DocType, " ", Name];
if (externalID) {
parts.push(" ", path.call(print, "children", "externalID", 0));
parts.push(" ", path.call(print, "externalID"));
}
return group([...parts, CLOSE[0].image]);
return group([...parts, CLOSE]);
}
function printDocument(path, opts, print) {
const { docTypeDecl, element, misc, prolog } = path.getValue().children;
const { docTypeDecl, element, misc, prolog } = path.getValue();
const fragments = [];

@@ -238,4 +212,4 @@

fragments.push({
offset: docTypeDecl[0].location.startOffset,
printed: path.call(print, "children", "docTypeDecl", 0)
offset: docTypeDecl.location.startOffset,
printed: path.call(print, "docTypeDecl")
});

@@ -246,27 +220,20 @@ }

fragments.push({
offset: prolog[0].location.startOffset,
printed: path.call(print, "children", "prolog", 0)
offset: prolog.location.startOffset,
printed: path.call(print, "prolog")
});
}
if (misc) {
misc.forEach((node) => {
if (node.children.PROCESSING_INSTRUCTION) {
fragments.push({
offset: node.location.startOffset,
printed: node.children.PROCESSING_INSTRUCTION[0].image
});
} else if (node.children.Comment) {
fragments.push({
offset: node.location.startOffset,
printed: node.children.Comment[0].image
});
}
path.each((miscPath) => {
const misc = miscPath.getValue();
fragments.push({
offset: misc.location.startOffset,
printed: print(miscPath)
});
}
}, "misc");
if (element) {
fragments.push({
offset: element[0].location.startOffset,
printed: path.call(print, "children", "element", 0)
offset: element.location.startOffset,
printed: path.call(print, "element")
});

@@ -276,2 +243,3 @@ }

fragments.sort((left, right) => left.offset - right.offset);
return [

@@ -326,7 +294,7 @@ join(

const chardata = charDataPath.getValue();
if (!chardata.children.TEXT) {
if (!chardata.TEXT) {
return;
}
const content = chardata.children.TEXT[0].image.trim();
const content = chardata.TEXT.trim();
const printed = group(

@@ -362,9 +330,7 @@ content.split(/(\n)/g).map((value) => {

if (children.Comment) {
response = response.concat(path.map(printIToken, "Comment"));
}
response = response.concat(path.map(printIToken, "Comment"));
if (children.chardata) {
if (children.chardata.length > 0) {
if (
children.chardata.some(({ children }) => !!children.TEXT) &&
children.chardata.some((chardata) => !!chardata.TEXT) &&
opts.xmlWhitespaceSensitivity === "preserve"

@@ -378,21 +344,16 @@ ) {

if (children.element) {
response = response.concat(
path.map((elementPath) => {
const location = elementPath.getValue().location;
response = response.concat(
path.map((elementPath) => {
const location = elementPath.getValue().location;
return {
offset: location.startOffset,
startLine: location.startLine,
endLine: location.endLine,
printed: print(elementPath)
};
}, "element")
);
}
return {
offset: location.startOffset,
startLine: location.startLine,
endLine: location.endLine,
printed: print(elementPath)
};
}, "element")
);
if (children.PROCESSING_INSTRUCTION) {
response = response.concat(path.map(printIToken, "PROCESSING_INSTRUCTION"));
}
response = response.concat(path.map(printIToken, "PROCESSING_INSTRUCTION"));
return response;

@@ -412,7 +373,7 @@ }

SLASH_CLOSE
} = path.getValue().children;
} = path.getValue();
const parts = [OPEN[0].image, Name[0].image];
const parts = [OPEN, Name];
if (attribute) {
if (attribute.length > 0) {
const attributes = path.map(

@@ -423,3 +384,2 @@ (attributePath) => ({

}),
"children",
"attribute"

@@ -430,4 +390,4 @@ );

attributes.sort((left, right) => {
const leftAttr = left.node.children.Name[0].image;
const rightAttr = right.node.children.Name[0].image;
const leftAttr = left.node.Name;
const rightAttr = right.node.Name;

@@ -483,6 +443,13 @@ // Check if the attributes are xmlns.

if (SLASH_CLOSE) {
return group([...parts, space, SLASH_CLOSE[0].image]);
return group([...parts, space, SLASH_CLOSE]);
}
if (Object.keys(content[0].children).length === 0) {
if (
content.chardata.length === 0 &&
content.CData.length === 0 &&
content.Comment.length === 0 &&
content.element.length === 0 &&
content.PROCESSING_INSTRUCTION.length === 0 &&
content.reference.length === 0
) {
return group([...parts, space, "/>"]);

@@ -494,19 +461,13 @@ }

opts.bracketSameLine ? "" : softline,
START_CLOSE[0].image
START_CLOSE
]);
const closeTag = group([
SLASH_OPEN[0].image,
END_NAME[0].image,
END[0].image
]);
const closeTag = group([SLASH_OPEN, END_NAME, END]);
if (isWhitespaceIgnorable(opts, attribute, content[0])) {
if (isWhitespaceIgnorable(opts, Name, attribute, content)) {
const fragments = path.call(
(childrenPath) => printElementFragments(childrenPath, opts, print),
"children",
"content",
0,
"children"
"content"
);
fragments.sort((left, right) => left.offset - right.offset);

@@ -529,5 +490,3 @@

fragments.length === 1 &&
(content[0].children.chardata || []).filter(
(chardata) => chardata.children.TEXT
).length === 1
content.chardata.filter((chardata) => chardata.TEXT).length === 1
) {

@@ -563,31 +522,30 @@ return group([

return group([
openTag,
indent(path.call(print, "children", "content", 0)),
closeTag
]);
return group([openTag, indent(path.call(print, "content")), closeTag]);
}
function printExternalID(path, opts, print) {
const { Public, PubIDLiteral, System, SystemLiteral } =
path.getValue().children;
const { Public, PubIDLiteral, System, SystemLiteral } = path.getValue();
if (System) {
return group([System[0].image, indent([line, SystemLiteral[0].image])]);
return group([System, indent([line, SystemLiteral])]);
}
return group([
group([Public[0].image, indent([line, PubIDLiteral[0].image])]),
indent([line, SystemLiteral[0].image])
group([Public, indent([line, PubIDLiteral])]),
indent([line, SystemLiteral])
]);
}
function printMisc(path, opts, print) {
const { Comment, PROCESSING_INSTRUCTION, SEA_WS } = path.getValue();
return Comment || PROCESSING_INSTRUCTION || SEA_WS;
}
function printProlog(path, opts, print) {
const { XMLDeclOpen, attribute, SPECIAL_CLOSE } = path.getValue().children;
const parts = [XMLDeclOpen[0].image];
const { XMLDeclOpen, attribute, SPECIAL_CLOSE } = path.getValue();
const parts = [XMLDeclOpen];
if (attribute) {
parts.push(
indent([softline, join(line, path.map(print, "children", "attribute"))])
);
parts.push(indent([softline, join(line, path.map(print, "attribute"))]));
}

@@ -598,7 +556,18 @@

opts.xmlSelfClosingSpace ? line : softline,
SPECIAL_CLOSE[0].image
SPECIAL_CLOSE
]);
}
function printReference(path, opts, print) {
const { CharRef, EntityRef } = path.getValue();
return CharRef || EntityRef;
}
const printer = {
getVisitorKeys(node, nonTraversableKeys) {
return Object.keys(node).filter(
(key) => key !== "location" && key !== "tokenType"
);
},
embed,

@@ -623,4 +592,10 @@ print(path, opts, print) {

return printExternalID(path, opts, print);
case "misc":
return printMisc(path, opts, print);
case "prolog":
return printProlog(path, opts, print);
case "reference":
return printReference(path, opts, print);
default:
throw new Error(`Unknown node type: ${node.name}`);
}

@@ -627,0 +602,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc