prettier-plugin-bootstrap 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,282 +1,4 @@
1
- //#region src/class-order.ts
2
- const BREAKPOINTS = [
3
- "sm",
4
- "md",
5
- "lg",
6
- "xl",
7
- "xxl"
8
- ];
9
- const RESPONSIVE_RE = new RegExp(`^(.+?)-(${BREAKPOINTS.join("|")})-(.+)$`);
10
- const CLASS_ORDER = [
11
- "container-fluid",
12
- "container-sm",
13
- "container-md",
14
- "container-lg",
15
- "container-xl",
16
- "container-xxl",
17
- "container",
18
- "row",
19
- "row-cols-",
20
- "col-auto",
21
- "col-1",
22
- "col-2",
23
- "col-3",
24
- "col-4",
25
- "col-5",
26
- "col-6",
27
- "col-7",
28
- "col-8",
29
- "col-9",
30
- "col-10",
31
- "col-11",
32
- "col-12",
33
- "col",
34
- "offset-",
35
- "g-",
36
- "gx-",
37
- "gy-",
38
- "h1",
39
- "h2",
40
- "h3",
41
- "h4",
42
- "h5",
43
- "h6",
44
- "lead",
45
- "display-",
46
- "list-unstyled",
47
- "list-inline",
48
- "list-inline-item",
49
- "initialism",
50
- "blockquote",
51
- "blockquote-footer",
52
- "img-fluid",
53
- "img-thumbnail",
54
- "figure",
55
- "figure-img",
56
- "figure-caption",
57
- "table",
58
- "table-",
59
- "caption-top",
60
- "form-label",
61
- "col-form-label",
62
- "form-text",
63
- "form-control",
64
- "form-control-",
65
- "form-select",
66
- "form-select-",
67
- "form-check",
68
- "form-check-",
69
- "form-switch",
70
- "form-floating",
71
- "form-range",
72
- "input-group",
73
- "input-group-",
74
- "valid-feedback",
75
- "valid-tooltip",
76
- "invalid-feedback",
77
- "invalid-tooltip",
78
- "was-validated",
79
- "btn",
80
- "btn-",
81
- "btn-close",
82
- "btn-close-",
83
- "fade",
84
- "collapse",
85
- "collapsing",
86
- "show",
87
- "dropdown",
88
- "dropdown-",
89
- "dropup",
90
- "dropend",
91
- "dropstart",
92
- "btn-group",
93
- "btn-group-",
94
- "btn-toolbar",
95
- "nav",
96
- "nav-",
97
- "tab-content",
98
- "tab-pane",
99
- "navbar",
100
- "navbar-",
101
- "card",
102
- "card-",
103
- "accordion",
104
- "accordion-",
105
- "breadcrumb",
106
- "breadcrumb-item",
107
- "pagination",
108
- "pagination-",
109
- "page-item",
110
- "page-link",
111
- "badge",
112
- "alert",
113
- "alert-",
114
- "progress",
115
- "progress-",
116
- "progress-bar",
117
- "progress-bar-",
118
- "list-group",
119
- "list-group-",
120
- "toast",
121
- "toast-",
122
- "modal",
123
- "modal-",
124
- "tooltip",
125
- "tooltip-",
126
- "popover",
127
- "popover-",
128
- "carousel",
129
- "carousel-",
130
- "spinner-border",
131
- "spinner-border-",
132
- "spinner-grow",
133
- "spinner-grow-",
134
- "offcanvas",
135
- "offcanvas-",
136
- "placeholder",
137
- "placeholder-",
138
- "clearfix",
139
- "link-",
140
- "icon-link",
141
- "icon-link-",
142
- "ratio",
143
- "ratio-",
144
- "fixed-top",
145
- "fixed-bottom",
146
- "sticky-top",
147
- "sticky-bottom",
148
- "hstack",
149
- "vstack",
150
- "stretched-link",
151
- "text-truncate",
152
- "vr",
153
- "visually-hidden",
154
- "visually-hidden-focusable",
155
- "align-",
156
- "float-",
157
- "object-fit-",
158
- "opacity-",
159
- "overflow-",
160
- "d-",
161
- "shadow",
162
- "shadow-",
163
- "focus-ring",
164
- "focus-ring-",
165
- "position-",
166
- "top-",
167
- "bottom-",
168
- "start-",
169
- "end-",
170
- "translate-middle",
171
- "translate-middle-",
172
- "border",
173
- "border-",
174
- "w-",
175
- "mw-",
176
- "vw-",
177
- "min-vw-",
178
- "h-",
179
- "mh-",
180
- "vh-",
181
- "min-vh-",
182
- "flex-",
183
- "justify-content-",
184
- "align-items-",
185
- "align-content-",
186
- "align-self-",
187
- "order-",
188
- "m-",
189
- "mx-",
190
- "my-",
191
- "mt-",
192
- "me-",
193
- "mb-",
194
- "ms-",
195
- "p-",
196
- "px-",
197
- "py-",
198
- "pt-",
199
- "pe-",
200
- "pb-",
201
- "ps-",
202
- "gap-",
203
- "row-gap-",
204
- "column-gap-",
205
- "font-monospace",
206
- "fs-",
207
- "fst-",
208
- "fw-",
209
- "lh-",
210
- "text-decoration-",
211
- "text-",
212
- "text-opacity-",
213
- "link-opacity-",
214
- "link-offset-",
215
- "link-underline",
216
- "link-underline-",
217
- "bg-",
218
- "bg-opacity-",
219
- "bg-gradient",
220
- "user-select-",
221
- "pe-none",
222
- "pe-auto",
223
- "rounded",
224
- "rounded-",
225
- "visible",
226
- "invisible",
227
- "z-"
228
- ];
229
- function buildOrderMap() {
230
- const map = /* @__PURE__ */ new Map();
231
- for (const [index, prefix] of CLASS_ORDER.entries()) map.set(prefix, index);
232
- return map;
233
- }
234
- const ORDER_MAP = buildOrderMap();
235
- function classKey(className) {
236
- let base = className;
237
- let breakpointIdx = 0;
238
- const match = className.match(RESPONSIVE_RE);
239
- if (match) {
240
- base = `${match[1]}-${match[3]}`;
241
- breakpointIdx = BREAKPOINTS.indexOf(match[2]) + 1;
242
- }
243
- let bestIdx = -1;
244
- let bestLen = 0;
245
- for (const [prefix, idx] of ORDER_MAP) if (base === prefix || prefix.endsWith("-") && base.startsWith(prefix)) {
246
- if (prefix.length > bestLen) {
247
- bestLen = prefix.length;
248
- bestIdx = idx;
249
- }
250
- }
251
- return [bestIdx === -1 ? Infinity : bestIdx, breakpointIdx];
252
- }
253
- function sortClasses(classes) {
254
- const annotated = classes.map((cls, i) => ({
255
- cls,
256
- key: classKey(cls),
257
- orig: i
258
- }));
259
- annotated.sort((a, b) => {
260
- if (a.key[0] !== b.key[0]) return a.key[0] - b.key[0];
261
- if (a.key[1] !== b.key[1]) return a.key[1] - b.key[1];
262
- return a.orig - b.orig;
263
- });
264
- return annotated.map((entry) => entry.cls);
265
- }
266
- //#endregion
267
- //#region src/sorting.ts
268
- function sortClassString(value) {
269
- if (!value || typeof value !== "string") return value;
270
- const trimmed = value.trim();
271
- if (!trimmed) return value;
272
- const classes = trimmed.split(/\s+/);
273
- if (classes.length <= 1) return value;
274
- const sorted = sortClasses(classes);
275
- const leadingWs = value.match(/^\s*/)[0];
276
- const trailingWs = value.match(/\s*$/)[0];
277
- return `${leadingWs}${sorted.join(" ")}${trailingWs}`;
278
- }
279
- //#endregion
1
+ import { a as sortClasses, i as classKey, n as BREAKPOINTS, r as CLASS_ORDER, t as sortClassString } from "./sorting-BAmBKBim.mjs";
280
2
  //#region src/traversal.ts
281
3
  const AST_KEYS = [
282
4
  "program",
@@ -319,10 +41,10 @@ function walk(node, visitor) {
319
41
  }
320
42
  }
321
43
  }
322
- function sortStringNode(node) {
44
+ function sortStringNode(node, sortOptions) {
323
45
  if (!node) return;
324
46
  if (node.type === "StringLiteral") {
325
- const sorted = sortClassString(node.value);
47
+ const sorted = sortClassString(node.value, sortOptions);
326
48
  node.value = sorted;
327
49
  if (node.extra) {
328
50
  node.extra.rawValue = sorted;
@@ -331,7 +53,7 @@ function sortStringNode(node) {
331
53
  return;
332
54
  }
333
55
  if (node.type === "Literal" && typeof node.value === "string") {
334
- const sorted = sortClassString(node.value);
56
+ const sorted = sortClassString(node.value, sortOptions);
335
57
  node.value = sorted;
336
58
  if (node.raw) {
337
59
  const quote = node.raw[0];
@@ -341,41 +63,41 @@ function sortStringNode(node) {
341
63
  }
342
64
  if (node.type === "TemplateLiteral" && (!node.expressions || node.expressions.length === 0)) {
343
65
  for (const quasi of node.quasis) if (quasi.value && typeof quasi.value.raw === "string") {
344
- const sorted = sortClassString(quasi.value.raw);
66
+ const sorted = sortClassString(quasi.value.raw, sortOptions);
345
67
  quasi.value.raw = sorted;
346
68
  quasi.value.cooked = sorted;
347
69
  }
348
70
  }
349
71
  }
350
- function processHtmlAst(ast, targetAttrs, _targetFunctions) {
72
+ function processHtmlAst(ast, attrMatcher, _targetFunctions, sortOptions) {
73
+ const matchAttr = typeof attrMatcher === "function" ? attrMatcher : (name) => attrMatcher.includes(name);
351
74
  walk(ast, (node) => {
352
75
  if (node.attrs && Array.isArray(node.attrs)) {
353
- for (const attr of node.attrs) if (targetAttrs.includes(attr.name) && typeof attr.value === "string") attr.value = sortClassString(attr.value);
76
+ for (const attr of node.attrs) if (matchAttr(attr.name) && typeof attr.value === "string") attr.value = sortClassString(attr.value, sortOptions);
354
77
  }
355
- if (node.attributes && Array.isArray(node.attributes)) for (const attr of node.attributes) {
356
- const name = attr.name || attr.key && attr.key.value;
357
- if (targetAttrs.includes(name) && attr.value) {
78
+ if (node.attributes && Array.isArray(node.attributes)) {
79
+ for (const attr of node.attributes) if (matchAttr(attr.name || attr.key && attr.key.value) && attr.value) {
358
80
  if (typeof attr.value === "string") {
359
81
  if (attr.kind && attr.kind !== "quoted") continue;
360
82
  if (attr.value.includes("${")) continue;
361
- attr.value = sortClassString(attr.value);
83
+ attr.value = sortClassString(attr.value, sortOptions);
362
84
  } else if (attr.value && typeof attr.value.value === "string") {
363
85
  if (attr.value.value.includes("${")) continue;
364
- attr.value.value = sortClassString(attr.value.value);
86
+ attr.value.value = sortClassString(attr.value.value, sortOptions);
365
87
  }
366
88
  }
367
89
  }
368
90
  });
369
91
  return ast;
370
92
  }
371
- function processJsxAst(ast, targetAttrs, targetFunctions = []) {
93
+ function processJsxAst(ast, attrMatcher, targetFunctions = [], sortOptions) {
94
+ const matchAttr = typeof attrMatcher === "function" ? attrMatcher : (name) => attrMatcher.includes(name);
372
95
  const functionSet = new Set(targetFunctions);
373
96
  walk(ast, (node) => {
374
97
  if (node.type === "JSXAttribute" || node.type === "JSXSpreadAttribute") {
375
- const name = node.name && (node.name.name || node.name.value);
376
- if (targetAttrs.includes(name) && node.value) {
98
+ if (matchAttr(node.name && (node.name.name || node.name.value)) && node.value) {
377
99
  if (node.value.type === "StringLiteral" || node.value.type === "Literal") {
378
- const sorted = sortClassString(node.value.value);
100
+ const sorted = sortClassString(node.value.value, sortOptions);
379
101
  node.value.value = sorted;
380
102
  if (node.value.extra) {
381
103
  node.value.extra.rawValue = sorted;
@@ -390,7 +112,7 @@ function processJsxAst(ast, targetAttrs, targetFunctions = []) {
390
112
  }
391
113
  if (node.type === "CallExpression" && functionSet.size > 0) {
392
114
  const callee = node.callee;
393
- if (callee && callee.type === "Identifier" && functionSet.has(callee.name)) for (const arg of node.arguments || []) sortStringNode(arg);
115
+ if (callee && callee.type === "Identifier" && functionSet.has(callee.name)) for (const arg of node.arguments || []) sortStringNode(arg, sortOptions);
394
116
  }
395
117
  });
396
118
  return ast;
@@ -401,15 +123,16 @@ function walkSvelte(node, visitor) {
401
123
  if (node.fragment && Array.isArray(node.fragment.nodes)) for (const child of node.fragment.nodes) walkSvelte(child, visitor);
402
124
  if (Array.isArray(node.children)) for (const child of node.children) walkSvelte(child, visitor);
403
125
  }
404
- function processSvelteAst(ast, targetAttrs, _targetFunctions) {
126
+ function processSvelteAst(ast, attrMatcher, _targetFunctions, sortOptions) {
127
+ const matchAttr = typeof attrMatcher === "function" ? attrMatcher : (name) => attrMatcher.includes(name);
405
128
  walkSvelte(ast, (node) => {
406
129
  if (!node.attributes || !Array.isArray(node.attributes)) return;
407
130
  for (const attr of node.attributes) {
408
131
  if (attr.type !== "Attribute") continue;
409
- if (!targetAttrs.includes(attr.name)) continue;
132
+ if (!matchAttr(attr.name)) continue;
410
133
  if (Array.isArray(attr.value)) {
411
134
  for (const item of attr.value) if (item.type === "Text" && typeof item.data === "string") {
412
- const sorted = sortClassString(item.data);
135
+ const sorted = sortClassString(item.data, sortOptions);
413
136
  item.data = sorted;
414
137
  if (typeof item.raw === "string") item.raw = sorted;
415
138
  }
@@ -421,6 +144,7 @@ function processSvelteAst(ast, targetAttrs, _targetFunctions) {
421
144
  //#endregion
422
145
  //#region src/index.ts
423
146
  const DEFAULT_ATTRIBUTES = ["class", "className"];
147
+ const IGNORE_RE = /(?:<!--\s*prettier-bootstrap-ignore\s*-->|\/\/\s*prettier-bootstrap-ignore|\/\*\s*prettier-bootstrap-ignore\s*\*\/)/;
424
148
  const options = {
425
149
  bootstrapAttributes: {
426
150
  type: "string",
@@ -435,8 +159,36 @@ const options = {
435
159
  default: [{ value: [] }],
436
160
  category: "Bootstrap",
437
161
  description: "Function names whose arguments are Bootstrap class lists (e.g. clsx, classNames)."
162
+ },
163
+ bootstrapPreserveWhitespace: {
164
+ type: "boolean",
165
+ default: false,
166
+ category: "Bootstrap",
167
+ description: "Preserve original whitespace between classes instead of normalizing to single spaces."
168
+ },
169
+ bootstrapPreserveDuplicates: {
170
+ type: "boolean",
171
+ default: true,
172
+ category: "Bootstrap",
173
+ description: "Keep duplicate class names. Set to false to remove duplicates."
174
+ },
175
+ bootstrapVersion: {
176
+ type: "int",
177
+ default: 5,
178
+ category: "Bootstrap",
179
+ description: "Bootstrap version (for future version-specific sorting rules)."
438
180
  }
439
181
  };
182
+ function buildAttrMatcher(allAttrs) {
183
+ const plainAttrs = [];
184
+ const regexAttrs = [];
185
+ for (const attr of allAttrs) {
186
+ const m = attr.match(/^\/(.+)\/([gimsuy]*)$/);
187
+ if (m) regexAttrs.push(new RegExp(m[1], m[2]));
188
+ else plainAttrs.push(attr);
189
+ }
190
+ return (name) => plainAttrs.includes(name) || regexAttrs.some((re) => re.test(name));
191
+ }
440
192
  function createParserWrapper(parserName, processAst, astFormat) {
441
193
  const wrapper = {
442
194
  astFormat,
@@ -463,7 +215,15 @@ function createParserWrapper(parserName, processAst, astFormat) {
463
215
  if (!originalParser) throw new Error(`prettier-plugin-bootstrap: could not find the "${parserName}" parser. Make sure Prettier and the relevant parser plugin are installed.`);
464
216
  if (originalParser.locStart) wrapper.locStart = originalParser.locStart;
465
217
  if (originalParser.locEnd) wrapper.locEnd = originalParser.locEnd;
466
- return processAst(await originalParser.parse(text, options), [...DEFAULT_ATTRIBUTES, ...options.bootstrapAttributes || []], options.bootstrapFunctions || []);
218
+ if (originalParser.astFormat) wrapper.astFormat = originalParser.astFormat;
219
+ const ast = await originalParser.parse(text, options);
220
+ if (IGNORE_RE.test(text.slice(0, 1500))) return ast;
221
+ const targetAttrs = [...DEFAULT_ATTRIBUTES, ...options.bootstrapAttributes || []];
222
+ const targetFunctions = options.bootstrapFunctions || [];
223
+ return processAst(ast, buildAttrMatcher(targetAttrs), targetFunctions, {
224
+ preserveWhitespace: options.bootstrapPreserveWhitespace ?? false,
225
+ preserveDuplicates: options.bootstrapPreserveDuplicates ?? true
226
+ });
467
227
  }
468
228
  };
469
229
  return wrapper;
@@ -481,4 +241,4 @@ const parsers = {
481
241
  svelte: createParserWrapper("svelte", processSvelteAst, "svelte-ast")
482
242
  };
483
243
  //#endregion
484
- export { BREAKPOINTS, CLASS_ORDER, classKey, options, parsers, sortClasses };
244
+ export { BREAKPOINTS, CLASS_ORDER, buildAttrMatcher, classKey, options, parsers, sortClasses };
@@ -0,0 +1,15 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_sorting = require("./sorting-B-0731KP.cjs");
3
+ //#region src/sorter.ts
4
+ function createSorter(options) {
5
+ return {
6
+ sort: (classString) => require_sorting.sortClassString(classString, options),
7
+ sortClasses: (classes) => {
8
+ return require_sorting.sortClasses(options?.preserveDuplicates === false ? classes.filter((c, i) => classes.indexOf(c) === i) : classes);
9
+ }
10
+ };
11
+ }
12
+ //#endregion
13
+ exports.createSorter = createSorter;
14
+ exports.sortClassString = require_sorting.sortClassString;
15
+ exports.sortClasses = require_sorting.sortClasses;
@@ -0,0 +1,13 @@
1
+ import { i as sortClasses, o as SortOptions } from "./class-order-UKlp_Ej7.cjs";
2
+
3
+ //#region src/sorting.d.ts
4
+ declare function sortClassString(value: string, options?: SortOptions): string;
5
+ //#endregion
6
+ //#region src/sorter.d.ts
7
+ interface Sorter {
8
+ sort(classString: string): string;
9
+ sortClasses(classes: string[]): string[];
10
+ }
11
+ declare function createSorter(options?: SortOptions): Sorter;
12
+ //#endregion
13
+ export { type SortOptions, Sorter, createSorter, sortClassString, sortClasses };
@@ -0,0 +1,13 @@
1
+ import { i as sortClasses, o as SortOptions } from "./class-order-BYtmS-1R.mjs";
2
+
3
+ //#region src/sorting.d.ts
4
+ declare function sortClassString(value: string, options?: SortOptions): string;
5
+ //#endregion
6
+ //#region src/sorter.d.ts
7
+ interface Sorter {
8
+ sort(classString: string): string;
9
+ sortClasses(classes: string[]): string[];
10
+ }
11
+ declare function createSorter(options?: SortOptions): Sorter;
12
+ //#endregion
13
+ export { type SortOptions, Sorter, createSorter, sortClassString, sortClasses };
@@ -0,0 +1,10 @@
1
+ import { sortClasses } from './class-order';
2
+ import { sortClassString } from './sorting';
3
+ import type { SortOptions } from './types';
4
+ export interface Sorter {
5
+ sort(classString: string): string;
6
+ sortClasses(classes: string[]): string[];
7
+ }
8
+ export declare function createSorter(options?: SortOptions): Sorter;
9
+ export { sortClasses, sortClassString };
10
+ export type { SortOptions };
@@ -0,0 +1,12 @@
1
+ import { a as sortClasses, t as sortClassString } from "./sorting-BAmBKBim.mjs";
2
+ //#region src/sorter.ts
3
+ function createSorter(options) {
4
+ return {
5
+ sort: (classString) => sortClassString(classString, options),
6
+ sortClasses: (classes) => {
7
+ return sortClasses(options?.preserveDuplicates === false ? classes.filter((c, i) => classes.indexOf(c) === i) : classes);
8
+ }
9
+ };
10
+ }
11
+ //#endregion
12
+ export { createSorter, sortClassString, sortClasses };