From 4eabf10ee25429b2b9c4893f876bb7257172e7ab Mon Sep 17 00:00:00 2001 From: Thom van den Akker Date: Mon, 31 Mar 2025 23:17:36 +0200 Subject: [PATCH] Allow setting fixed first properties to be sorted first --- src/plugin.js | 8 + src/printer.js | 14 ++ test/__snapshots__/format.test.js.snap | 254 +++++++++++++++++++++++++ test/format.test.js | 18 ++ 4 files changed, 294 insertions(+) diff --git a/src/plugin.js b/src/plugin.js index eb88416..307c680 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -47,6 +47,14 @@ const plugin = { description: "Orders XML attributes by key alphabetically while prioritizing xmlns attributes." }, + xmlSortAttributesFirst: { + type: "string", + category: "XML", + array: true, + default: [{ value: [] }], + description: + "When 'xmlSortAttributesByKey' is enabled, make sure that the given keys are always sorted first. Ignores namespace sorting." + }, xmlQuoteAttributes: { type: "choice", category: "XML", diff --git a/src/printer.js b/src/printer.js index aca9ef4..f96c851 100644 --- a/src/printer.js +++ b/src/printer.js @@ -412,6 +412,20 @@ function printElement(path, opts, print) { if (leftAttr.includes(":")) return -1; if (rightAttr.includes(":")) return 1; + // Check if the attributes need to be sorted first + if ( + Array.isArray(opts.xmlSortAttributesFirst) && + opts.xmlSortAttributesFirst.length > 0 + ) { + const leftFirstIndex = opts.xmlSortAttributesFirst.indexOf(leftAttr); + const rightFirstIndex = + opts.xmlSortAttributesFirst.indexOf(rightAttr); + if (leftFirstIndex !== -1 && rightFirstIndex !== -1) + return leftFirstIndex - rightFirstIndex; + else if (leftFirstIndex !== -1) return -1; + else if (rightFirstIndex !== -1) return 1; + } + return leftAttr.localeCompare(rightAttr); }); } diff --git a/test/__snapshots__/format.test.js.snap b/test/__snapshots__/format.test.js.snap index 130388b..336d5c5 100644 --- a/test/__snapshots__/format.test.js.snap +++ b/test/__snapshots__/format.test.js.snap @@ -1197,6 +1197,260 @@ use { " `; +exports[`xmlSortAttributesFirst => [width] 1`] = ` +" + + + + + Style inheritance and the use element + + &anp; 〹 + + foo + + bar + + + + + + + + + +- 1 + - 2 +- 3 + + + + + + + + + + + + < ignored /> + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at est eget enim consectetur accumsan. Aliquam pretium sodales ipsum quis dignissim. Sed id sem vel diam luctus fringilla. Aliquam quis egestas magna. Curabitur molestie lorem et odio porta, et molestie libero laoreet. Morbi rhoncus sagittis cursus. Nullam vehicula pretium consequat. Praesent porta ante at posuere sollicitudin. Nullam commodo tempor arcu, at condimentum neque elementum ut. +

+ + content + + +
text with space

+ +
+ even more + +
+ +
+ +
+ +
+ +
+ + +
+ + + + + + + + + + + He said, "Don't quote me." + + + + + + slide + + +" +`; + +exports[`xmlSortAttributesFirst => [viewBox, width] 1`] = ` +" + + + + + Style inheritance and the use element + + &anp; 〹 + + foo + + bar + + + + + + + + + +- 1 + - 2 +- 3 + + + + + + + + + + + + < ignored /> + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at est eget enim consectetur accumsan. Aliquam pretium sodales ipsum quis dignissim. Sed id sem vel diam luctus fringilla. Aliquam quis egestas magna. Curabitur molestie lorem et odio porta, et molestie libero laoreet. Morbi rhoncus sagittis cursus. Nullam vehicula pretium consequat. Praesent porta ante at posuere sollicitudin. Nullam commodo tempor arcu, at condimentum neque elementum ut. +

+ + content + + +
text with space

+ +
+ even more + +
+ +
+ +
+ +
+ +
+ + +
+ + + + + + + + + + + He said, "Don't quote me." + + + + + + slide + + +" +`; + exports[`xmlWhitespaceSensitivity => ignore 1`] = ` " true", async () => { expect(formatted).toMatchSnapshot(); }); +test("xmlSortAttributesFirst => [width]", async () => { + const formatted = await format(fixture, { + xmlSortAttributesByKey: true, + xmlSortAttributesFirst: ["width"] + }); + + expect(formatted).toMatchSnapshot(); +}); + +test("xmlSortAttributesFirst => [viewBox, width]", async () => { + const formatted = await format(fixture, { + xmlSortAttributesByKey: true, + xmlSortAttributesFirst: ["viewBox", "width"] + }); + + expect(formatted).toMatchSnapshot(); +}); + test("xmlQuoteAttributes => preserve", async () => { const formatted = await format(fixture, { xmlQuoteAttributes: "preserve"