@herb-tools/formatter 0.8.6 → 0.8.8
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/herb-format.js +16962 -31496
- package/dist/herb-format.js.map +1 -1
- package/dist/index.cjs +60 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +60 -23
- package/dist/index.esm.js.map +1 -1
- package/package.json +6 -5
- package/src/cli.ts +1 -1
- package/src/format-printer.ts +25 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/formatter",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"description": "Auto-formatter for HTML+ERB templates with intelligent indentation, line wrapping, and ERB-aware pretty-printing.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://herb-tools.dev",
|
|
@@ -35,10 +35,11 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@herb-tools/config": "0.8.
|
|
39
|
-
"@herb-tools/core": "0.8.
|
|
40
|
-
"@herb-tools/printer": "0.8.
|
|
41
|
-
"@herb-tools/rewriter": "0.8.
|
|
38
|
+
"@herb-tools/config": "0.8.8",
|
|
39
|
+
"@herb-tools/core": "0.8.8",
|
|
40
|
+
"@herb-tools/printer": "0.8.8",
|
|
41
|
+
"@herb-tools/rewriter": "0.8.8",
|
|
42
|
+
"tinyglobby": "^0.2.15"
|
|
42
43
|
},
|
|
43
44
|
"files": [
|
|
44
45
|
"package.json",
|
package/src/cli.ts
CHANGED
package/src/format-printer.ts
CHANGED
|
@@ -97,6 +97,12 @@ import {
|
|
|
97
97
|
import type { ERBNode } from "@herb-tools/core"
|
|
98
98
|
import type { FormatOptions } from "./options.js"
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* ASCII whitespace pattern - use instead of \s to preserve Unicode whitespace
|
|
102
|
+
* characters like NBSP (U+00A0) and full-width space (U+3000)
|
|
103
|
+
*/
|
|
104
|
+
const ASCII_WHITESPACE = /[ \t\n\r]+/g
|
|
105
|
+
|
|
100
106
|
/**
|
|
101
107
|
* Printer traverses the Herb AST using the Visitor pattern
|
|
102
108
|
* and emits a formatted string with proper indentation, line breaks, and attribute wrapping.
|
|
@@ -551,7 +557,7 @@ export class FormatPrinter extends Printer {
|
|
|
551
557
|
}
|
|
552
558
|
|
|
553
559
|
private wouldClassAttributeBeMultiline(content: string, indentLength: number): boolean {
|
|
554
|
-
const normalizedContent = content.replace(
|
|
560
|
+
const normalizedContent = content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
555
561
|
const hasActualNewlines = /\r?\n/.test(content)
|
|
556
562
|
|
|
557
563
|
if (hasActualNewlines && normalizedContent.length > 80) {
|
|
@@ -601,7 +607,7 @@ export class FormatPrinter extends Printer {
|
|
|
601
607
|
const name = attribute.name ? getCombinedAttributeName(attribute.name) : ""
|
|
602
608
|
|
|
603
609
|
if (name === "class") {
|
|
604
|
-
const normalizedContent = content.replace(
|
|
610
|
+
const normalizedContent = content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
605
611
|
|
|
606
612
|
return normalizedContent.length > 80
|
|
607
613
|
}
|
|
@@ -609,7 +615,7 @@ export class FormatPrinter extends Printer {
|
|
|
609
615
|
const lines = content.split(/\r?\n/)
|
|
610
616
|
|
|
611
617
|
if (lines.length > 1) {
|
|
612
|
-
return lines.slice(1).some(line =>
|
|
618
|
+
return lines.slice(1).some(line => /^[ \t\n\r]+/.test(line))
|
|
613
619
|
}
|
|
614
620
|
}
|
|
615
621
|
}
|
|
@@ -619,7 +625,7 @@ export class FormatPrinter extends Printer {
|
|
|
619
625
|
}
|
|
620
626
|
|
|
621
627
|
private formatClassAttribute(content: string, name: string, equals: string, open_quote: string, close_quote: string): string {
|
|
622
|
-
const normalizedContent = content.replace(
|
|
628
|
+
const normalizedContent = content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
623
629
|
const hasActualNewlines = /\r?\n/.test(content)
|
|
624
630
|
|
|
625
631
|
if (hasActualNewlines && normalizedContent.length > 80) {
|
|
@@ -658,7 +664,7 @@ export class FormatPrinter extends Printer {
|
|
|
658
664
|
|
|
659
665
|
private formatMultilineAttribute(content: string, name: string, open_quote: string, close_quote: string): string {
|
|
660
666
|
if (name === 'srcset' || name === 'sizes') {
|
|
661
|
-
const normalizedContent = content.replace(
|
|
667
|
+
const normalizedContent = content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
662
668
|
|
|
663
669
|
return open_quote + normalizedContent + close_quote
|
|
664
670
|
}
|
|
@@ -899,7 +905,7 @@ export class FormatPrinter extends Printer {
|
|
|
899
905
|
nodesToRender.forEach(child => {
|
|
900
906
|
if (isNode(child, HTMLTextNode)) {
|
|
901
907
|
if (hasTextFlow) {
|
|
902
|
-
const normalizedContent = child.content.replace(
|
|
908
|
+
const normalizedContent = child.content.replace(ASCII_WHITESPACE, ' ')
|
|
903
909
|
|
|
904
910
|
if (normalizedContent && normalizedContent !== ' ') {
|
|
905
911
|
this.push(normalizedContent)
|
|
@@ -907,7 +913,7 @@ export class FormatPrinter extends Printer {
|
|
|
907
913
|
this.push(' ')
|
|
908
914
|
}
|
|
909
915
|
} else {
|
|
910
|
-
const normalizedContent = child.content.replace(
|
|
916
|
+
const normalizedContent = child.content.replace(ASCII_WHITESPACE, ' ')
|
|
911
917
|
|
|
912
918
|
if (shouldPreserveSpaces && normalizedContent) {
|
|
913
919
|
this.push(normalizedContent)
|
|
@@ -932,8 +938,8 @@ export class FormatPrinter extends Printer {
|
|
|
932
938
|
const content = lines.join('')
|
|
933
939
|
|
|
934
940
|
const inlineContent = shouldPreserveSpaces
|
|
935
|
-
? (hasTextFlow ? content.replace(
|
|
936
|
-
: (hasTextFlow ? content.replace(
|
|
941
|
+
? (hasTextFlow ? content.replace(ASCII_WHITESPACE, ' ') : content)
|
|
942
|
+
: (hasTextFlow ? content.replace(ASCII_WHITESPACE, ' ').trim() : content.trim())
|
|
937
943
|
|
|
938
944
|
if (inlineContent) {
|
|
939
945
|
this.pushToLastLine(inlineContent)
|
|
@@ -1177,7 +1183,7 @@ export class FormatPrinter extends Printer {
|
|
|
1177
1183
|
|
|
1178
1184
|
visitHTMLTextNode(node: HTMLTextNode) {
|
|
1179
1185
|
if (this.inlineMode) {
|
|
1180
|
-
const normalizedContent = node.content.replace(
|
|
1186
|
+
const normalizedContent = node.content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
1181
1187
|
|
|
1182
1188
|
if (normalizedContent) {
|
|
1183
1189
|
this.push(normalizedContent)
|
|
@@ -1191,7 +1197,7 @@ export class FormatPrinter extends Printer {
|
|
|
1191
1197
|
if (!text) return
|
|
1192
1198
|
|
|
1193
1199
|
const wrapWidth = this.maxLineLength - this.indent.length
|
|
1194
|
-
const words = text.split(
|
|
1200
|
+
const words = text.split(/[ \t\n\r]+/)
|
|
1195
1201
|
const lines: string[] = []
|
|
1196
1202
|
|
|
1197
1203
|
let line = ""
|
|
@@ -1813,7 +1819,7 @@ export class FormatPrinter extends Printer {
|
|
|
1813
1819
|
}
|
|
1814
1820
|
}
|
|
1815
1821
|
|
|
1816
|
-
const words = restText.split(
|
|
1822
|
+
const words = restText.split(/[ \t\n\r]+/)
|
|
1817
1823
|
let toMerge = punctuation
|
|
1818
1824
|
let mergedWordCount = 0
|
|
1819
1825
|
|
|
@@ -1999,7 +2005,7 @@ export class FormatPrinter extends Printer {
|
|
|
1999
2005
|
} else if (unit.isAtomic) {
|
|
2000
2006
|
words.push({ word: unit.content, isHerbDisable: unit.isHerbDisable || false })
|
|
2001
2007
|
} else {
|
|
2002
|
-
const text = unit.content.replace(
|
|
2008
|
+
const text = unit.content.replace(ASCII_WHITESPACE, ' ')
|
|
2003
2009
|
const hasLeadingSpace = text.startsWith(' ')
|
|
2004
2010
|
const hasTrailingSpace = text.endsWith(' ')
|
|
2005
2011
|
const trimmedText = text.trim()
|
|
@@ -2055,7 +2061,7 @@ export class FormatPrinter extends Printer {
|
|
|
2055
2061
|
const firstWord = words[0]
|
|
2056
2062
|
const firstChar = firstWord[0]
|
|
2057
2063
|
|
|
2058
|
-
if (
|
|
2064
|
+
if (' \t\n\r'.includes(firstChar)) {
|
|
2059
2065
|
return false
|
|
2060
2066
|
}
|
|
2061
2067
|
|
|
@@ -2125,7 +2131,7 @@ export class FormatPrinter extends Printer {
|
|
|
2125
2131
|
return true
|
|
2126
2132
|
}
|
|
2127
2133
|
|
|
2128
|
-
if (isNode(currentNode, HTMLTextNode) &&
|
|
2134
|
+
if (isNode(currentNode, HTMLTextNode) && /^[ \t\n\r]/.test(currentNode.content)) {
|
|
2129
2135
|
return true
|
|
2130
2136
|
}
|
|
2131
2137
|
|
|
@@ -2542,9 +2548,9 @@ export class FormatPrinter extends Printer {
|
|
|
2542
2548
|
|
|
2543
2549
|
for (const child of children) {
|
|
2544
2550
|
if (isNode(child, HTMLTextNode)) {
|
|
2545
|
-
const normalizedContent = child.content.replace(
|
|
2546
|
-
const hasLeadingSpace =
|
|
2547
|
-
const hasTrailingSpace =
|
|
2551
|
+
const normalizedContent = child.content.replace(ASCII_WHITESPACE, ' ')
|
|
2552
|
+
const hasLeadingSpace = /^[ \t\n\r]/.test(child.content)
|
|
2553
|
+
const hasTrailingSpace = /[ \t\n\r]$/.test(child.content)
|
|
2548
2554
|
const trimmedContent = normalizedContent.trim()
|
|
2549
2555
|
|
|
2550
2556
|
if (trimmedContent) {
|
|
@@ -2675,6 +2681,6 @@ export class FormatPrinter extends Printer {
|
|
|
2675
2681
|
}
|
|
2676
2682
|
}
|
|
2677
2683
|
|
|
2678
|
-
return content.replace(
|
|
2684
|
+
return content.replace(ASCII_WHITESPACE, ' ').trim()
|
|
2679
2685
|
}
|
|
2680
2686
|
}
|