@herb-tools/formatter 0.4.1 → 0.4.3
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 +773 -105
- package/dist/herb-format.js.map +1 -1
- package/dist/index.cjs +758 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +758 -93
- package/dist/index.esm.js.map +1 -1
- package/dist/types/printer.d.ts +71 -0
- package/package.json +3 -2
- package/src/cli.ts +11 -6
- package/src/printer.ts +986 -103
package/dist/types/printer.d.ts
CHANGED
|
@@ -12,11 +12,46 @@ export declare class Printer extends Visitor {
|
|
|
12
12
|
private lines;
|
|
13
13
|
private indentLevel;
|
|
14
14
|
private inlineMode;
|
|
15
|
+
private isInComplexNesting;
|
|
16
|
+
private static readonly INLINE_ELEMENTS;
|
|
15
17
|
constructor(source: string, options: Required<FormatOptions>);
|
|
16
18
|
print(object: Node | Token, indentLevel?: number): string;
|
|
17
19
|
private push;
|
|
18
20
|
private withIndent;
|
|
19
21
|
private indent;
|
|
22
|
+
/**
|
|
23
|
+
* Format ERB content with proper spacing around the inner content.
|
|
24
|
+
* Returns empty string if content is empty, otherwise wraps content with single spaces.
|
|
25
|
+
*/
|
|
26
|
+
private formatERBContent;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a node is an ERB control flow node (if, unless, block, case, while, for)
|
|
29
|
+
*/
|
|
30
|
+
private isERBControlFlow;
|
|
31
|
+
/**
|
|
32
|
+
* Count total attributes including those inside ERB conditionals
|
|
33
|
+
*/
|
|
34
|
+
private getTotalAttributeCount;
|
|
35
|
+
/**
|
|
36
|
+
* Extract HTML attributes from a list of nodes
|
|
37
|
+
*/
|
|
38
|
+
private extractAttributes;
|
|
39
|
+
/**
|
|
40
|
+
* Extract inline nodes (non-attribute, non-whitespace) from a list of nodes
|
|
41
|
+
*/
|
|
42
|
+
private extractInlineNodes;
|
|
43
|
+
/**
|
|
44
|
+
* Render attributes as a space-separated string
|
|
45
|
+
*/
|
|
46
|
+
private renderAttributesString;
|
|
47
|
+
/**
|
|
48
|
+
* Determine if a tag should be rendered inline based on attribute count and other factors
|
|
49
|
+
*/
|
|
50
|
+
private shouldRenderInline;
|
|
51
|
+
/**
|
|
52
|
+
* Render multiline attributes for a tag
|
|
53
|
+
*/
|
|
54
|
+
private renderMultilineAttributes;
|
|
20
55
|
/**
|
|
21
56
|
* Print an ERB tag (<% %> or <%= %>) with single spaces around inner content.
|
|
22
57
|
*/
|
|
@@ -51,6 +86,42 @@ export declare class Printer extends Visitor {
|
|
|
51
86
|
visitERBEnsureNode(node: ERBEnsureNode): void;
|
|
52
87
|
visitERBUnlessNode(node: ERBUnlessNode): void;
|
|
53
88
|
private visitERBGeneric;
|
|
89
|
+
private isNonWhitespaceNode;
|
|
90
|
+
/**
|
|
91
|
+
* Check if an element should be treated as inline based on its tag name
|
|
92
|
+
*/
|
|
93
|
+
private isInlineElement;
|
|
94
|
+
/**
|
|
95
|
+
* Check if we're in a text flow context (parent contains mixed text and inline elements)
|
|
96
|
+
*/
|
|
97
|
+
private visitTextFlowChildren;
|
|
98
|
+
private visitTextFlowChildrenMultiline;
|
|
99
|
+
private isInTextFlowContext;
|
|
54
100
|
private renderInlineOpen;
|
|
55
101
|
renderAttribute(attribute: HTMLAttributeNode): string;
|
|
102
|
+
/**
|
|
103
|
+
* Try to render a complete element inline including opening tag, children, and closing tag
|
|
104
|
+
*/
|
|
105
|
+
private tryRenderInlineFull;
|
|
106
|
+
/**
|
|
107
|
+
* Try to render just the children inline (without tags)
|
|
108
|
+
*/
|
|
109
|
+
private tryRenderChildrenInline;
|
|
110
|
+
/**
|
|
111
|
+
* Try to render children inline if they are simple enough.
|
|
112
|
+
* Returns the inline string if possible, null otherwise.
|
|
113
|
+
*/
|
|
114
|
+
private tryRenderInline;
|
|
115
|
+
/**
|
|
116
|
+
* Estimate the total content length of children nodes for decision making.
|
|
117
|
+
*/
|
|
118
|
+
private estimateContentLength;
|
|
119
|
+
/**
|
|
120
|
+
* Calculate the maximum nesting depth in a subtree of nodes.
|
|
121
|
+
*/
|
|
122
|
+
private getMaxNestingDepth;
|
|
123
|
+
/**
|
|
124
|
+
* Render an HTML element's content inline (without the wrapping tags).
|
|
125
|
+
*/
|
|
126
|
+
private renderElementInline;
|
|
56
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/formatter",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"description": "Auto-formatter for HTML+ERB templates with intelligent indentation, line wrapping, and ERB-aware pretty-printing.",
|
|
4
5
|
"license": "MIT",
|
|
5
6
|
"homepage": "https://herb-tools.dev",
|
|
6
7
|
"bugs": "https://github.com/marcoroth/herb/issues/new?title=Package%20%60@herb-tools/formatter%60:%20",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
}
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"@herb-tools/core": "0.4.
|
|
38
|
+
"@herb-tools/core": "0.4.3",
|
|
38
39
|
"glob": "^11.0.3"
|
|
39
40
|
},
|
|
40
41
|
"files": [
|
package/src/cli.ts
CHANGED
|
@@ -105,13 +105,16 @@ export class CLI {
|
|
|
105
105
|
try {
|
|
106
106
|
const source = readFileSync(filePath, "utf-8")
|
|
107
107
|
const result = formatter.format(source)
|
|
108
|
-
|
|
108
|
+
const output = result.endsWith('\n') ? result : result + '\n'
|
|
109
|
+
|
|
110
|
+
if (output !== source) {
|
|
109
111
|
if (isCheckMode) {
|
|
110
112
|
unformattedFiles.push(filePath)
|
|
111
113
|
} else {
|
|
112
|
-
writeFileSync(filePath,
|
|
114
|
+
writeFileSync(filePath, output, "utf-8")
|
|
113
115
|
console.log(`Formatted: ${filePath}`)
|
|
114
116
|
}
|
|
117
|
+
|
|
115
118
|
formattedCount++
|
|
116
119
|
}
|
|
117
120
|
} catch (error) {
|
|
@@ -134,13 +137,14 @@ export class CLI {
|
|
|
134
137
|
} else {
|
|
135
138
|
const source = readFileSync(file, "utf-8")
|
|
136
139
|
const result = formatter.format(source)
|
|
140
|
+
const output = result.endsWith('\n') ? result : result + '\n'
|
|
137
141
|
|
|
138
|
-
if (
|
|
142
|
+
if (output !== source) {
|
|
139
143
|
if (isCheckMode) {
|
|
140
144
|
console.log(`File is not formatted: ${file}`)
|
|
141
145
|
process.exit(1)
|
|
142
146
|
} else {
|
|
143
|
-
writeFileSync(file,
|
|
147
|
+
writeFileSync(file, output, "utf-8")
|
|
144
148
|
console.log(`Formatted: ${file}`)
|
|
145
149
|
}
|
|
146
150
|
} else if (isCheckMode) {
|
|
@@ -169,12 +173,13 @@ export class CLI {
|
|
|
169
173
|
try {
|
|
170
174
|
const source = readFileSync(filePath, "utf-8")
|
|
171
175
|
const result = formatter.format(source)
|
|
176
|
+
const output = result.endsWith('\n') ? result : result + '\n'
|
|
172
177
|
|
|
173
|
-
if (
|
|
178
|
+
if (output !== source) {
|
|
174
179
|
if (isCheckMode) {
|
|
175
180
|
unformattedFiles.push(filePath)
|
|
176
181
|
} else {
|
|
177
|
-
writeFileSync(filePath,
|
|
182
|
+
writeFileSync(filePath, output, "utf-8")
|
|
178
183
|
console.log(`Formatted: ${filePath}`)
|
|
179
184
|
}
|
|
180
185
|
formattedCount++
|