@@ -10,6 +10,40 @@ const path = require('path');
10
10
11
11
const parseRawData = require ( './src/parse-raw-data.js' ) ;
12
12
13
+ /**
14
+ * OPTIONAL: console.error is called by default.
15
+ *
16
+ * Your own custom logging function called with helpful warning/error
17
+ * messages from the internal validators.
18
+ *
19
+ * @typedef {Function } CUSTOMLOGGER
20
+ * @callback {Function } CUSTOMLOGGER
21
+ * @param {string } message The human readable warning/error message
22
+ * @param {object } [error] Sometimes an error or options object is passed
23
+ * @return {void }
24
+ */
25
+
26
+ /**
27
+ * @typedef {object } SHORTCUTPROPERITES
28
+ * @property {string } FullName 'C:\\Users\\Owner\\Desktop\\DaVinci Resolve.lnk'
29
+ * @property {string } Arguments '--foo=bar'
30
+ * @property {string } Description 'Video Editor'
31
+ * @property {string } Hotkey 'CTRL+SHIFT+F10'
32
+ * @property {string } IconLocation 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\ResolveIcon.exe,0'
33
+ * @property {string } RelativePath ''
34
+ * @property {string } TargetPath 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\Resolve.exe'
35
+ * @property {string } WindowStyle '1'
36
+ * @property {string } WorkingDirectory 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\'
37
+ */
38
+
39
+ /**
40
+ * A generic function for errors/warnings. It will either call the passed in customLoger,
41
+ * or use console.error to notify the user of this library of errors or validation warnings.
42
+ *
43
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
44
+ * @param {string } message A human readable message describing an error/warning
45
+ * @param {any } error A programmatic error message or object, may be undefined
46
+ */
13
47
function throwError ( customLogger , message , error ) {
14
48
if ( typeof ( customLogger ) === 'function' ) {
15
49
customLogger ( message , error ) ;
@@ -23,41 +57,93 @@ function throwError (customLogger, message, error) {
23
57
}
24
58
}
25
59
26
- function generateCommands ( filePaths , customLogger ) {
27
- const commands = [ ] ;
28
-
29
- for ( let filePath of filePaths ) {
30
- const normalizedFile = normalizeFile ( filePath , customLogger ) ;
31
- if ( normalizedFile ) {
32
- // Escape (') and (’) in the file path for PowerShell syntax
33
- const safeFilePath = normalizedFile
34
- . replace ( / ' / g, "''" )
35
- . replace ( / ’ / g, "’’" ) ;
36
-
37
- const command = [
38
- '(New-Object -COM WScript.Shell).CreateShortcut(\'' ,
39
- safeFilePath ,
40
- '\');'
41
- ] . join ( '' ) ;
42
- commands . push ( command ) ;
43
- }
60
+ /**
61
+ * Generic type validation function. Ensures value passed in is an array
62
+ * that contains at least one string, and only strings.
63
+ *
64
+ * @param {any } arr A value to be validated as an array of strings
65
+ * @return {boolean } true = valid
66
+ */
67
+ function isArrayOfStrings ( arr ) {
68
+ let isValidArray = false ;
69
+ if ( Array . isArray ( arr ) && arr . length ) {
70
+ isValidArray = arr . every ( function ( item ) {
71
+ return typeof ( item ) === 'string' ;
72
+ } ) ;
44
73
}
74
+ return isValidArray ;
75
+ }
45
76
46
- return commands ;
77
+ /**
78
+ * Generic type validation function. Ensures value passed in is an array
79
+ * that contains at least one object, and only objects.
80
+ *
81
+ * @param {any } arr A value to be validated as an array of objects
82
+ * @return {boolean } true = valid
83
+ */
84
+ function isArrayOfObjects ( arr ) {
85
+ let isValidArray = false ;
86
+ if ( Array . isArray ( arr ) && arr . length ) {
87
+ isValidArray = arr . every ( function ( item ) {
88
+ return ! Array . isArray ( item ) && typeof ( item ) === 'object' ;
89
+ } ) ;
90
+ }
91
+ return isValidArray ;
47
92
}
48
93
49
- function inputsAreValid ( filePath , customLogger ) {
50
- let valid = true ;
94
+ /**
95
+ * If a customLogger is passed in, ensures it is a valid function.
96
+ *
97
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
98
+ * @return {boolean } True if valid, false if invalid
99
+ */
100
+ function customLoggerIsValid ( customLogger ) {
51
101
if ( customLogger && typeof ( customLogger ) !== 'function' ) {
52
102
throwError ( customLogger , 'The customLogger must be a function or undefined' ) ;
103
+ return false ;
104
+ }
105
+ return true ;
106
+ }
107
+
108
+ /**
109
+ * Validates that shortcutProperties and customLogger are the correct expected types.
110
+ *
111
+ * @param {SHORTCUTPROPERITES[] } shortcutProperties Array of objects, each representing a successful or failed shortcut property
112
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
113
+ * @return {boolean } True if valid, false if invalid
114
+ */
115
+ function translateInputsAreValid ( shortcutProperties , customLogger ) {
116
+ let valid = true ;
117
+ valid = customLoggerIsValid ( customLogger ) ;
118
+ if ( ! isArrayOfObjects ( shortcutProperties ) ) {
119
+ throwError ( customLogger , 'The shortcutProperties must be an array of objects' ) ;
53
120
valid = false ;
54
121
}
122
+ return valid ;
123
+ }
124
+
125
+ /**
126
+ * Validates that the filePath and customLogger are the correct expected types.
127
+ * Validates that this Windows specific library is actually being ran on Windows.
128
+ *
129
+ * @param {(string|string[]) } filePath String or array of strings for the filepaths to shortcut files
130
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
131
+ * @return {boolean } True if valid, false if invalid
132
+ */
133
+ function syncInputsAreValid ( filePath , customLogger ) {
134
+ let valid = true ;
135
+ valid = customLoggerIsValid ( customLogger ) ;
55
136
if ( process . platform !== 'win32' ) {
56
137
throwError ( customLogger , 'Platform is not Windows' ) ;
57
138
valid = false ;
58
139
}
140
+
59
141
if (
60
142
! filePath ||
143
+ (
144
+ Array . isArray ( filePath ) &&
145
+ ! isArrayOfStrings ( filePath )
146
+ ) ||
61
147
(
62
148
! Array . isArray ( filePath ) &&
63
149
typeof ( filePath ) !== 'string'
@@ -69,6 +155,14 @@ function inputsAreValid (filePath, customLogger) {
69
155
return valid ;
70
156
}
71
157
158
+ /**
159
+ * Normalizes a file path and ensures it exists and ends with .lnk or .url.
160
+ * Warns and returns false if filePath does not meet these requirements.
161
+ *
162
+ * @param {string } filePath Path to a .lnk or .url Windows shortcut file
163
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
164
+ * @return {string } The normalized full path to a Windows shortcut that is known to exist
165
+ */
72
166
function normalizeFile ( filePath , customLogger ) {
73
167
const normalizedFile = path . normalize ( path . resolve ( filePath ) ) ;
74
168
if (
@@ -87,53 +181,113 @@ function normalizeFile (filePath, customLogger) {
87
181
}
88
182
89
183
/**
90
- * @callback customLoggerCallback
91
- * @param {string } message
92
- * @param {Error } error
93
- *
94
- * @typedef {{
95
- * FullName: string,
96
- * Arguments: string,
97
- * Description: string,
98
- * Hotkey: string,
99
- * IconLocation: string,
100
- * RelativePath: string,
101
- * TargetPath: string,
102
- * WindowStyle: string,
103
- * WorkingDirectory: string
104
- * }[] } shortcutProperties
184
+ * Creates strings of PowerShell commands for each filePath to get the file properties.
185
+ * Stores strings in a returned Array.
186
+ *
187
+ * @param {string[] } filePaths Array of strings for the filepaths to shortcut files
188
+ * @param {CUSTOMLOGGER } customLogger Optional function to handle logging human readable errors/warnings
189
+ * @return {string[] } Array of strings of PowerShell commands to get shortcut properties
105
190
*/
191
+ function generateCommands ( filePaths , customLogger ) {
192
+ const commands = [ ] ;
106
193
107
- /**
108
- * @param {string } filePath
109
- * @param {customLoggerCallback } customLogger
110
- * @returns {shortcutProperties }
111
- */
112
- function getWindowsShortcutProperties ( filePath , customLogger ) {
113
- if ( ! inputsAreValid ( filePath , customLogger ) ) {
114
- return ;
115
- }
116
- if ( typeof ( filePath ) === 'string' ) {
117
- filePath = [ filePath ] ;
118
- }
194
+ for ( let filePath of filePaths ) {
195
+ const normalizedFile = normalizeFile ( filePath , customLogger ) ;
196
+ if ( normalizedFile ) {
197
+ // Escape (') and (’) in the file path for PowerShell syntax
198
+ const safeFilePath = normalizedFile
199
+ . replace ( / ' / g, '\'\'' )
200
+ . replace ( / ’ / g, '’’' ) ;
119
201
120
- const commands = generateCommands ( filePath , customLogger ) . join ( '' ) ;
121
- if ( ! commands || ! commands . length ) {
122
- return ;
123
- }
124
- const command = 'powershell.exe -command "' + commands + '"' ;
125
- try {
126
- const rawData = exec ( command ) ;
127
- const parsed = parseRawData ( rawData ) ;
128
- return parsed ;
129
- } catch ( err ) {
130
- if ( err ) {
131
- throwError ( customLogger , 'Failed to run powershell command to get shortcut properties' , err ) ;
132
- return ;
202
+ const command = [
203
+ '(New-Object -COM WScript.Shell).CreateShortcut(\'' ,
204
+ safeFilePath ,
205
+ '\');'
206
+ ] . join ( '' ) ;
207
+ commands . push ( command ) ;
133
208
}
134
209
}
210
+
211
+ return commands ;
135
212
}
136
213
137
214
module . exports = {
138
- sync : getWindowsShortcutProperties
215
+ /**
216
+ * Retrieves the details of OS based Windows shortcuts.
217
+ *
218
+ * @example
219
+ * const output = getWindowsShortcutProperties.sync([
220
+ * '../Sublime Text.lnk',
221
+ * 'C:\\Users\\Public\\Desktop\\Firefox.lnk'
222
+ * ]);
223
+ *
224
+ * @param {(string|string[]) } filePath String or array of strings for the filepaths to shortcut files
225
+ * @param {CUSTOMLOGGER } customLogger Optional function to handle logging human readable errors/warnings
226
+ * @return {SHORTCUTPROPERITES[] } Array of objects or undefined, each representing a successful or failed shortcut property
227
+ */
228
+ sync : function ( filePath , customLogger ) {
229
+ if ( ! syncInputsAreValid ( filePath , customLogger ) ) {
230
+ return ;
231
+ }
232
+ if ( typeof ( filePath ) === 'string' ) {
233
+ filePath = [ filePath ] ;
234
+ }
235
+
236
+ const commands = generateCommands ( filePath , customLogger ) . join ( '' ) ;
237
+ if ( ! commands || ! commands . length ) {
238
+ return ;
239
+ }
240
+ const command = 'powershell.exe -command "' + commands + '"' ;
241
+ try {
242
+ const rawData = exec ( command ) ;
243
+ const parsed = parseRawData ( rawData ) ;
244
+ return parsed ;
245
+ } catch ( err ) {
246
+ if ( err ) {
247
+ throwError ( customLogger , 'Failed to run powershell command to get shortcut properties' , err ) ;
248
+ return ;
249
+ }
250
+ }
251
+ } ,
252
+ /**
253
+ * Translates the official Microsoft shortcut property names to something more human readable and familiar to JavaScript developers.
254
+ *
255
+ * @param {SHORTCUTPROPERITES[] } shortcutProperties Array of objects, each representing a successful or failed shortcut property
256
+ * @param {CUSTOMLOGGER } customLogger User provided function to handle logging human readable errors/warnings
257
+ * @return {boolean } True if valid, false if invalid
258
+ */
259
+ translate : function ( shortcutProperties , customLogger ) {
260
+ if ( ! translateInputsAreValid ( shortcutProperties , customLogger ) ) {
261
+ return ;
262
+ }
263
+ const windowModes = {
264
+ 1 : 'normal' ,
265
+ 3 : 'maximized' ,
266
+ 7 : 'minimized'
267
+ } ;
268
+ const translatedProperties = shortcutProperties . map ( function ( shortcut ) {
269
+ const translatedShortcut = {
270
+ // 'C:\\Users\\Owner\\Desktop\\DaVinci Resolve.lnk',
271
+ filePath : shortcut . FullName || '' ,
272
+ // '--foo=bar',
273
+ arguments : shortcut . Arguments || '' ,
274
+ // 'Video Editor',
275
+ comment : shortcut . Description || '' ,
276
+ // 'CTRL+SHIFT+F10',
277
+ hotkey : shortcut . Hotkey || '' ,
278
+ // 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\ResolveIcon.exe,0',
279
+ icon : shortcut . IconLocation || '' ,
280
+ // '',
281
+ relativePath : shortcut . RelativePath || '' ,
282
+ // 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\Resolve.exe',
283
+ targetPath : shortcut . TargetPath || '' ,
284
+ // '1',
285
+ windowMode : windowModes [ shortcut . WindowStyle ] || 'normal' ,
286
+ // 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\',
287
+ workingDirectory : shortcut . WorkingDirectory || ''
288
+ } ;
289
+ return translatedShortcut ;
290
+ } ) ;
291
+ return translatedProperties ;
292
+ }
139
293
} ;
0 commit comments