@@ -3,34 +3,39 @@ import * as cp from "child_process";
3
3
const isWsl = require ( "is-wsl" ) ;
4
4
5
5
export default class HtmlBeautifier {
6
+ private logChannel : vscode . LogOutputChannel ;
7
+
8
+ constructor ( ) {
9
+ this . logChannel = vscode . window . createOutputChannel ( "ERB Beautifier" , {
10
+ log : true ,
11
+ } ) ;
12
+ }
13
+
6
14
/**
7
- * Formats the given input using HTML Beautifier
8
- * @param { string } input - The input to be formatted
9
- * @returns { Promise<string> } The formatted input
15
+ * Formats the input string using HTML Beautifier.
16
+ * @param input The input string to be formatted.
17
+ * @returns A promise that resolves to the formatted string.
10
18
*/
11
19
public async format ( input : string ) : Promise < string > {
12
20
try {
13
- const cmd = `${ this . exe } ${ this . cliOptions . join (
14
- " "
15
- ) } with custom env ${ JSON . stringify ( this . customEnvVars ) } `;
16
- console . log ( `Formatting ERB with command: ${ cmd } ` ) ;
17
- console . time ( cmd ) ;
18
-
21
+ const startTime = Date . now ( ) ;
19
22
const result = await this . executeCommand ( input ) ;
20
-
21
- console . timeEnd ( cmd ) ;
23
+ const duration = Date . now ( ) - startTime ;
24
+ this . logChannel . info (
25
+ `Formatting completed successfully in ${ duration } ms.`
26
+ ) ;
22
27
return result ;
23
28
} catch ( error ) {
24
- console . error ( error ) ;
25
- const errorMessage =
26
- error instanceof Error ? error . message : "Unknown error occurred" ;
27
- vscode . window . showErrorMessage (
28
- `Error occurred while formatting: ${ errorMessage } `
29
- ) ;
29
+ this . handleError ( error , "Error occurred while formatting" ) ;
30
30
throw error ;
31
31
}
32
32
}
33
33
34
+ /**
35
+ * Executes the formatting command with the provided input.
36
+ * @param input The input to format.
37
+ * @returns A promise that resolves to the formatted output.
38
+ */
34
39
private executeCommand ( input : string ) : Promise < string > {
35
40
return new Promise ( ( resolve , reject ) => {
36
41
// Handle spawn EINVAL error on Windows. See https://github.com/nodejs/node/issues/52554
@@ -44,53 +49,37 @@ export default class HtmlBeautifier {
44
49
...shellOptions ,
45
50
} ) ;
46
51
47
- if ( htmlbeautifier . stdin === null || htmlbeautifier . stdout === null ) {
48
- const msg = "Couldn't initialize STDIN or STDOUT" ;
49
- console . warn ( msg ) ;
50
- vscode . window . showErrorMessage ( msg ) ;
51
- reject ( new Error ( msg ) ) ;
52
- return ;
53
- }
54
-
55
- let formattedResult = "" ;
56
- let errorMessage = "" ;
57
- let stdoutChunks : Buffer [ ] = [ ] ;
58
- let stderrChunks : Buffer [ ] = [ ] ;
52
+ const fullCommand = `${ this . exe } ${ this . cliOptions . join ( " " ) } (cwd: ${
53
+ vscode . workspace . rootPath || __dirname
54
+ } ) with custom env: ${ JSON . stringify ( this . customEnvVars ) } `;
55
+ this . logChannel . info ( `Formatting ERB with command: ${ fullCommand } ` ) ;
59
56
60
- htmlbeautifier . on ( "error" , ( err ) => {
61
- console . warn ( err ) ;
62
- vscode . window . showErrorMessage (
63
- ` Couldn't run ${ this . exe } ' ${ err . message } '`
57
+ if ( ! htmlbeautifier . stdin || ! htmlbeautifier . stdout ) {
58
+ return this . handleSpawnError (
59
+ reject ,
60
+ " Couldn't initialize STDIN or STDOUT"
64
61
) ;
65
- reject ( err ) ;
66
- } ) ;
67
-
68
- htmlbeautifier . stdout . on ( "data" , ( chunk ) => {
69
- stdoutChunks . push ( chunk ) ;
70
- } ) ;
62
+ }
71
63
72
- htmlbeautifier . stdout . on ( "end" , ( ) => {
73
- let result = Buffer . concat ( stdoutChunks ) . toString ( ) ;
74
- formattedResult = this . handleFinalNewline ( input , result ) ;
75
- } ) ;
64
+ const stdoutChunks : Buffer [ ] = [ ] ;
65
+ const stderrChunks : Buffer [ ] = [ ] ;
76
66
77
- htmlbeautifier . stderr . on ( "data" , ( chunk ) => {
78
- stderrChunks . push ( chunk ) ;
79
- } ) ;
67
+ htmlbeautifier . stdout . on ( "data" , ( chunk ) => stdoutChunks . push ( chunk ) ) ;
68
+ htmlbeautifier . stderr . on ( "data" , ( chunk ) => stderrChunks . push ( chunk ) ) ;
80
69
81
- htmlbeautifier . stderr . on ( "end" , ( ) => {
82
- errorMessage = Buffer . concat ( stderrChunks ) . toString ( ) ;
83
- } ) ;
70
+ htmlbeautifier . on ( "error" , ( err ) =>
71
+ this . handleSpawnError (
72
+ reject ,
73
+ `Couldn't run ${ this . exe } : ${ err . message } ` ,
74
+ err
75
+ )
76
+ ) ;
84
77
85
78
htmlbeautifier . on ( "exit" , ( code ) => {
86
- if ( code ) {
87
- vscode . window . showErrorMessage (
88
- `Failed with exit code: ${ code } . '${ errorMessage } '`
89
- ) ;
90
- reject ( new Error ( `Command failed with exit code ${ code } ` ) ) ;
91
- } else {
92
- resolve ( formattedResult ) ;
93
- }
79
+ const formattedResult = Buffer . concat ( stdoutChunks ) . toString ( ) ;
80
+ const finalResult = this . handleFinalNewline ( input , formattedResult ) ;
81
+ const errorMessage = Buffer . concat ( stderrChunks ) . toString ( ) ;
82
+ this . handleExit ( code , finalResult , errorMessage , resolve , reject ) ;
94
83
} ) ;
95
84
96
85
htmlbeautifier . stdin . write ( input ) ;
@@ -99,8 +88,64 @@ export default class HtmlBeautifier {
99
88
}
100
89
101
90
/**
102
- * Returns the executable path for HTML Beautifier
103
- * @returns {string } The executable path
91
+ * Handles errors during process spawning.
92
+ * @param reject The promise reject function.
93
+ * @param message The error message to log and show to the user.
94
+ * @param err Optional error object.
95
+ */
96
+ private handleSpawnError (
97
+ reject : ( reason ?: any ) => void ,
98
+ message : string ,
99
+ err ?: Error
100
+ ) : void {
101
+ this . logChannel . warn ( message ) ;
102
+ vscode . window . showErrorMessage ( message ) ;
103
+ if ( err ) {
104
+ this . logChannel . warn ( err . message ) ;
105
+ }
106
+ reject ( err || new Error ( message ) ) ;
107
+ }
108
+
109
+ /**
110
+ * Handles the process exit event and resolves or rejects the promise.
111
+ * @param code The process exit code.
112
+ * @param result The formatted result.
113
+ * @param errorMessage The error message, if any.
114
+ * @param resolve The promise resolve function.
115
+ * @param reject The promise reject function.
116
+ */
117
+ private handleExit (
118
+ code : number | null ,
119
+ result : string ,
120
+ errorMessage : string ,
121
+ resolve : ( value : string | PromiseLike < string > ) => void ,
122
+ reject : ( reason ?: any ) => void
123
+ ) : void {
124
+ if ( code && code !== 0 ) {
125
+ const error = `Failed with exit code: ${ code } . ${ errorMessage } ` ;
126
+ this . logChannel . error ( error ) ;
127
+ vscode . window . showErrorMessage ( error ) ;
128
+ reject ( new Error ( error ) ) ;
129
+ } else {
130
+ resolve ( result ) ;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Handles errors by logging and displaying a message to the user.
136
+ * @param error The error object or message.
137
+ * @param userMessage The message to display to the user.
138
+ */
139
+ private handleError ( error : any , userMessage : string ) : void {
140
+ const errorMessage =
141
+ error instanceof Error ? error . message : "Unknown error occurred" ;
142
+ this . logChannel . error ( errorMessage ) ;
143
+ vscode . window . showErrorMessage ( `${ userMessage } : ${ errorMessage } ` ) ;
144
+ }
145
+
146
+ /**
147
+ * Gets the executable path for HTML Beautifier based on the configuration.
148
+ * @returns The path to the executable.
104
149
*/
105
150
private get exe ( ) : string {
106
151
const config = vscode . workspace . getConfiguration ( "vscode-erb-beautify" ) ;
@@ -112,26 +157,26 @@ export default class HtmlBeautifier {
112
157
}
113
158
114
159
/**
115
- * Determines if the current platform is Windows (excluding WSL)
116
- * @returns { boolean } True if the platform is Windows, false otherwise
160
+ * Checks if the current platform is Windows (excluding WSL).
161
+ * @returns True if the platform is Windows; false otherwise.
117
162
*/
118
163
private isWindows ( ) : boolean {
119
164
return process . platform === "win32" && ! isWsl ;
120
165
}
121
166
122
167
/**
123
- * Returns the command-line options for HTML Beautifier
124
- * @returns { string[] } The command-line options
168
+ * Retrieves the command-line options for HTML Beautifier from the configuration.
169
+ * @returns An array of command-line options.
125
170
*/
126
171
private get cliOptions ( ) : string [ ] {
127
172
const config = vscode . workspace . getConfiguration ( "vscode-erb-beautify" ) ;
128
- const acc : string [ ] = [ ] ;
173
+ const options : string [ ] = [ ] ;
129
174
130
175
if ( config . get ( "useBundler" ) ) {
131
- acc . push ( "exec" , "htmlbeautifier" ) ;
176
+ options . push ( "exec" , "htmlbeautifier" ) ;
132
177
}
133
178
134
- return Object . keys ( config ) . reduce ( function ( acc , key ) {
179
+ return Object . keys ( config ) . reduce ( ( acc , key ) => {
135
180
switch ( key ) {
136
181
case "indentBy" :
137
182
acc . push ( "--indent-by" , config [ key ] ) ;
@@ -154,35 +199,31 @@ export default class HtmlBeautifier {
154
199
break ;
155
200
}
156
201
return acc ;
157
- } , acc ) ;
202
+ } , options ) ;
158
203
}
159
204
160
205
/**
161
- * Retrieves the custom environment variables from the configuration
162
- * @returns { Record<string, string> } The custom environment variables
206
+ * Retrieves custom environment variables from the configuration.
207
+ * @returns A record of custom environment variables.
163
208
*/
164
209
private get customEnvVars ( ) : Record < string , string > {
165
210
const config = vscode . workspace . getConfiguration ( "vscode-erb-beautify" ) ;
166
- const customEnvVar = config . get ( "customEnvVar" , { } ) as Record <
167
- string ,
168
- string
169
- > ;
170
- return customEnvVar ;
211
+ return config . get ( "customEnvVar" , { } ) as Record < string , string > ;
171
212
}
172
213
173
214
/**
174
- * Adjusts the final newline of the result string based on the VS Code configuration and the input string .
175
- * @param { string } input - The original input string.
176
- * @param { string } result - The result string to be processed .
177
- * @returns { string } The processed result string.
215
+ * Adjusts the final newline of the result string based on VS Code configuration.
216
+ * @param input The original input string.
217
+ * @param result The formatted result string.
218
+ * @returns The adjusted result string.
178
219
*/
179
220
private handleFinalNewline ( input : string , result : string ) : string {
180
221
// Get the 'insertFinalNewline' setting from VS Code configuration
181
222
const insertFinalNewline = vscode . workspace
182
223
. getConfiguration ( )
183
224
. get ( "files.insertFinalNewline" ) ;
184
225
185
- // Check if the result string ends with a newline
226
+ // Determine if the result ends with a newline
186
227
const resultEndsWithNewline =
187
228
result . endsWith ( "\n" ) || result . endsWith ( "\r\n" ) ;
188
229
@@ -191,11 +232,8 @@ export default class HtmlBeautifier {
191
232
// Get the 'files.eol' setting from VS Code configuration
192
233
const eol = vscode . workspace . getConfiguration ( ) . get ( "files.eol" ) ;
193
234
194
- // Set the newline character(s) based on the 'files.eol' setting and the platform
195
- let newline = eol ;
196
- if ( eol === "auto" ) {
197
- newline = this . isWindows ( ) ? "\r\n" : "\n" ;
198
- }
235
+ // Determine newline character(s) based on the 'files.eol' setting and the platform
236
+ let newline = eol === "auto" ? ( this . isWindows ( ) ? "\r\n" : "\n" ) : eol ;
199
237
200
238
// Append the newline to the result
201
239
result += newline ;
@@ -208,11 +246,8 @@ export default class HtmlBeautifier {
208
246
209
247
// If the input and result use different newline character(s)
210
248
if ( inputNewline !== resultNewline ) {
211
- // Remove the newline from the end of the result
212
- result = result . slice ( 0 , - resultNewline . length ) ;
213
-
214
- // Append the newline from the input to the result
215
- result += inputNewline ;
249
+ // Remove the newline from the end of the result and append the input's newline
250
+ result = result . slice ( 0 , - resultNewline . length ) + inputNewline ;
216
251
}
217
252
}
218
253
@@ -221,20 +256,16 @@ export default class HtmlBeautifier {
221
256
}
222
257
223
258
/**
224
- * Determines the type of newline used in the input string.
225
- * @param { string } input - The input string.
226
- * @returns { string } The newline character(s) used in the input string , or an empty string if the input does not end with a newline .
259
+ * Determines the newline character(s) used in the input string.
260
+ * @param input The input string.
261
+ * @returns The newline character(s) used, or an empty string if none .
227
262
*/
228
263
private getNewline ( input : string ) : string {
229
- // If the input ends with a Windows-style newline, return '\r\n'
230
264
if ( input . endsWith ( "\r\n" ) ) {
231
- return "\r\n" ;
232
- }
233
- // If the input ends with a Unix-style newline, return '\n'
234
- else if ( input . endsWith ( "\n" ) ) {
235
- return "\n" ;
265
+ return "\r\n" ; // Return Windows-style newline
266
+ } else if ( input . endsWith ( "\n" ) ) {
267
+ return "\n" ; // Return Unix-style newline
236
268
}
237
- // If the input does not end with a newline, return an empty string
238
- return "" ;
269
+ return "" ; // Return empty if no newline found
239
270
}
240
271
}
0 commit comments