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

@prettier/plugin-xml

Package Overview
Dependencies
Maintainers
12
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 0.2.0 to 0.3.0

test/cdata.test.js

1

.eslintrc.json

@@ -8,2 +8,3 @@ {

"rules": {
"no-cond-assign": "off",
"no-unused-vars": [

@@ -10,0 +11,0 @@ "error",

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

## [0.3.0] - 2019-11-14
### Added
- Support for cdata tags.
- Support for the `locStart` and `locEnd` functions by tracking node metadata in the new parser.
- Support for comment nodes.
- Support for `<?xml ... ?>` and `<?xml-model ... ?>` tags.
### Changed
- Dropped the dependency on `fast-xml-parser` in favor of writing our own for better control over comments and node location.
## [0.2.0] - 2019-11-12

@@ -22,4 +35,5 @@

[unreleased]: https://github.com/prettier/plugin-xml/compare/v0.2.0...HEAD
[unreleased]: https://github.com/prettier/plugin-xml/compare/v0.3.0...HEAD
[0.3.0]: https://github.com/prettier/plugin-xml/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/prettier/plugin-xml/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/prettier/plugin-xml/compare/289f2a...v0.1.0

3

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

@@ -22,3 +22,2 @@ "main": "src/plugin.js",

"dependencies": {
"fast-xml-parser": "^3.14.0",
"prettier": ">=1.10"

@@ -25,0 +24,0 @@ },

@@ -1,48 +0,119 @@

const parser = require("fast-xml-parser");
const attrsPattern = "([^\\s=]+)\\s*(=\\s*(['\"])(.*?)\\3)?";
const attributeNamePrefix = "@_";
const textNodeName = "#text";
const cDataPattern = "(!\\[CDATA\\[([\\s\\S]*?)(]]>))";
const translate = (node, name) => {
if (typeof node !== "object") {
return { type: "leaf", name, attrs: {}, value: node.toString() };
const tagNamePattern = "(([\\w:\\-._]*:)?([\\w:\\-._]+))";
const startTagPattern = `${tagNamePattern}([^>]*)>`;
const endTagPattern = `((\\/)${tagNamePattern}\\s*>)`;
const commentPattern = "(!--)(.+?)-->";
const declPattern = "((\\?xml)(-model)?)(.+)\\?>";
const tagPattern = `<(${cDataPattern}|${startTagPattern}|${endTagPattern}|${commentPattern}|${declPattern})([^<]*)`;
class XMLNode {
constructor(tagname, opts) {
this.tagname = tagname;
this.children = [];
this.parent = opts.parent;
this.value = opts.value || "";
this.locStart = opts.locStart || 0;
this.locEnd = opts.locEnd || 0;
this.attrs = {};
this.parseAttrs(opts.attrs);
}
const attrs = {};
let value = [];
parseAttrs(attrs) {
if (typeof attrs !== "string" || !attrs) {
return;
}
Object.keys(node).forEach(key => {
const children = node[key];
const normal = attrs.replace(/\r?\n/g, " ");
const attrsRegex = new RegExp(attrsPattern, "g");
let match;
if (key.startsWith(attributeNamePrefix)) {
attrs[key.slice(2)] = children;
} else if (Array.isArray(children)) {
value = value.concat(children.map(child => translate(child, key)));
} else if (key !== textNodeName) {
value.push(translate(children, key));
while ((match = attrsRegex.exec(normal))) {
const name = match[1];
if (name.length) {
this.attrs[name] = match[4] === undefined ? true : match[4].trim();
}
}
});
}
}
if (Object.prototype.hasOwnProperty.call(node, textNodeName)) {
return { type: "leaf", name, attrs, value: node[textNodeName] };
const parse = (text, _parsers, _opts) => {
const rootNode = new XMLNode("!root", { locStart: 0, locEnd: text.length });
let node = rootNode;
const tagRegex = new RegExp(tagPattern, "g");
let tag;
while ((tag = tagRegex.exec(text))) {
const value = (tag[20] || "").trim();
if (tag[17] === "?xml") {
node.children.push(
new XMLNode(`!${tag[16]}`, {
parent: node,
attrs: tag[19],
locStart: tag.index,
locEnd: tag.index + tag[0].trim().length
})
);
} else if (tag[14] === "!--") {
node.children.push(
new XMLNode("!comment", {
parent: node,
value: tag[15].trim(),
locStart: tag.index,
locEnd: tag.index + tag[0].trim().length
})
);
} else if (tag[4] === "]]>") {
node.children.push(
new XMLNode("!cdata", {
parent: node,
value: tag[3],
attrs: tag[8],
locStart: tag.index,
locEnd: tag.index + tag[0].trim().length
})
);
node.value += `\\c${value}`;
} else if (tag[10] === "/") {
node.locEnd = tag.index + tag[0].trim().length;
node.parent.value += value;
node = node.parent;
} else if (
typeof tag[8] !== "undefined" &&
tag[8].charAt(tag[8].length - 1) === "/"
) {
node.value += value;
node.children.push(
new XMLNode(tag[5], {
parent: node,
attrs: tag[8].slice(0, -1),
locStart: tag.index,
locEnd: tag.index + tag[0].trim().length
})
);
} else {
node = new XMLNode(tag[5], {
parent: node,
value,
attrs: tag[8],
locStart: tag.index
});
node.parent.children.push(node);
}
}
return { type: "node", name, attrs, value };
return rootNode;
};
const parse = (text, _parsers, _opts) =>
Object.assign(
{},
translate(
parser.parse(text, {
allowBooleanAttributes: true,
attributeNamePrefix,
ignoreAttributes: false,
parseAttributeValue: true,
textNodeName
})
),
{ type: "root" }
);
module.exports = parse;
const parse = require("./parse");
const print = require("./print");
// These functions are necessary or the print with cursor function breaks.
// Eventually we should fill them in with the correct metadata, but the parser
// doesn't provide it at the moment.
const locStart = _node => 0;
const locEnd = _node => 0;
const locStart = node => node.locStart;
const locEnd = node => node.locEnd;

@@ -15,3 +12,4 @@ const plugin = {

parsers: ["xml"],
extensions: [".xml"]
extensions: [".dita", ".ditamap", ".ditaval", ".xml"],
vscodeLanguageIds: ["xml"]
}

@@ -18,0 +16,0 @@ ],

@@ -11,5 +11,2 @@ const {

const getFirstNonBlankLine = originalText =>
originalText.split("\n").find(text => text.trim().length !== 0);
const printAttrs = attrs => {

@@ -32,66 +29,62 @@ if (Object.keys(attrs).length === 0) {

const printSelfClosingTag = (name, attrs) =>
group(concat(["<", name, printAttrs(attrs), line, "/>"]));
const printOpeningTag = (name, attrs) => {
if (name === "!cdata") {
return "<![CDATA[";
}
return group(concat(["<", name, printAttrs(attrs), softline, ">"]));
};
const printSelfClosingTag = (name, attrs) => {
if (name === "!?xml" || name === "!?xml-model") {
return group(concat(["<", name.slice(1), printAttrs(attrs), line, "?>"]));
}
return group(concat(["<", name, printAttrs(attrs), line, "/>"]));
};
const genericPrint = (path, opts, print) => {
const { type, name, attrs, value } = path.getValue();
const { tagname, children, attrs, value } = path.getValue();
switch (type) {
case "leaf": {
if (!value && opts.xmlSelfClosingTags) {
return printSelfClosingTag(name, attrs);
}
if (tagname === "!root") {
return concat([join(hardline, path.map(print, "children")), hardline]);
}
return group(
concat([
group(concat(["<", name, printAttrs(attrs), softline, ">"])),
indent(concat([softline, value])),
softline,
"</",
name,
">"
])
);
}
case "node": {
if (value.length === 0 && opts.xmlSelfClosingTags) {
return printSelfClosingTag(name, attrs);
}
if (tagname === "!comment") {
return group(
concat(["<!--", indent(concat([line, value])), concat([line, "-->"])])
);
}
let inner;
if (Object.keys(children).length === 0 && !value && opts.xmlSelfClosingTags) {
return printSelfClosingTag(tagname, attrs);
}
if (value.length === 0) {
inner = softline;
} else {
inner = concat([
indent(concat([hardline, join(hardline, path.map(print, "value"))])),
hardline
]);
}
const openingTag = printOpeningTag(tagname, attrs);
const closingTag = tagname === "!cdata" ? "]]>" : `</${tagname}>`;
return group(
concat([
group(concat(["<", name, printAttrs(attrs), softline, ">"])),
inner,
"</",
name,
">"
])
);
}
case "root": {
const parts = [join(hardline, path.map(print, "value")), hardline];
if (Object.keys(children).length === 0) {
return group(
concat([
openingTag,
indent(concat([softline, value])),
softline,
closingTag
])
);
}
const firstNonBlankLine = getFirstNonBlankLine(opts.originalText);
if (firstNonBlankLine && firstNonBlankLine.startsWith("<?xml")) {
parts.unshift(firstNonBlankLine, hardline);
}
let inner;
return concat(parts);
}
default:
throw new Error(`Unsupported node encountered: ${type}`);
if (children.length === 0) {
inner = softline;
} else {
inner = concat([
indent(concat([hardline, join(hardline, path.map(print, "children"))])),
hardline
]);
}
return group(concat([openingTag, inner, closingTag]));
};
module.exports = genericPrint;
const { here } = require("./utils");
describe("doctype", () => {
test("prints out first line if it's a doctype", () => {
test("renders appropriately", () => {
const content = here(`
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-model href="model.rnc" type="application/relax-ng-compact-sync-syntax" ?>
<foo />

@@ -8,0 +9,0 @@ `);

Sorry, the diff of this file is not supported yet

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