@@ -2,6 +2,7 @@ import { ApplicationError } from '@theia/core/lib/common/application-error';
2
2
import { nls } from '@theia/core/lib/common/nls' ;
3
3
import URI from '@theia/core/lib/common/uri' ;
4
4
import * as dateFormat from 'dateformat' ;
5
+ const filenameReservedRegex = require ( 'filename-reserved-regex' ) ;
5
6
6
7
export namespace SketchesError {
7
8
export const Codes = {
@@ -160,6 +161,19 @@ export namespace Sketch {
160
161
// (non-API) exported for the tests
161
162
export const defaultFallbackChar = '_' ;
162
163
// (non-API) exported for the tests
164
+ export function reservedFilename ( name : string ) : string {
165
+ return nls . localize (
166
+ 'arduino/sketch/reservedFilename' ,
167
+ "'{0}' is a reserved filename." ,
168
+ name
169
+ ) ;
170
+ }
171
+ // (non-API) exported for the tests
172
+ export const noTrailingPeriod = nls . localize (
173
+ 'arduino/sketch/noTrailingPeriod' ,
174
+ 'A filename cannot end with a dot'
175
+ ) ;
176
+ // (non-API) exported for the tests
163
177
export const invalidSketchFolderNameMessage = nls . localize (
164
178
'arduino/sketch/invalidSketchName' ,
165
179
'The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.'
@@ -175,6 +189,10 @@ export namespace Sketch {
175
189
export function validateSketchFolderName (
176
190
candidate : string
177
191
) : string | undefined {
192
+ const validFilenameError = isValidFilename ( candidate ) ;
193
+ if ( validFilenameError ) {
194
+ return validFilenameError ;
195
+ }
178
196
return / ^ [ 0 - 9 a - z A - Z ] { 1 } [ 0 - 9 a - z A - Z _ \. - ] { 0 , 62 } $ / . test ( candidate )
179
197
? undefined
180
198
: invalidSketchFolderNameMessage ;
@@ -186,11 +204,36 @@ export namespace Sketch {
186
204
export function validateCloudSketchFolderName (
187
205
candidate : string
188
206
) : string | undefined {
207
+ const validFilenameError = isValidFilename ( candidate ) ;
208
+ if ( validFilenameError ) {
209
+ return validFilenameError ;
210
+ }
189
211
return / ^ [ 0 - 9 a - z A - Z ] { 1 } [ 0 - 9 a - z A - Z _ \. - ] { 0 , 35 } $ / . test ( candidate )
190
212
? undefined
191
213
: invalidCloudSketchFolderNameMessage ;
192
214
}
193
215
216
+ function isValidFilename ( candidate : string ) : string | undefined {
217
+ if ( isReservedFilename ( candidate ) ) {
218
+ return reservedFilename ( candidate ) ;
219
+ }
220
+ if ( endsWithPeriod ( candidate ) ) {
221
+ return noTrailingPeriod ;
222
+ }
223
+ return undefined ;
224
+ }
225
+
226
+ function endsWithPeriod ( candidate : string ) : boolean {
227
+ return candidate . length > 1 && candidate [ candidate . length - 1 ] === '.' ;
228
+ }
229
+
230
+ function isReservedFilename ( candidate : string ) : boolean {
231
+ return (
232
+ filenameReservedRegex ( ) . test ( candidate ) ||
233
+ filenameReservedRegex . windowsNames ( ) . test ( candidate )
234
+ ) ;
235
+ }
236
+
194
237
/**
195
238
* Transforms the `candidate` argument into a valid sketch folder name by replacing all invalid characters with underscore (`_`) and trimming the string after 63 characters.
196
239
* If the argument is falsy, returns with `"sketch"`.
@@ -202,6 +245,12 @@ export namespace Sketch {
202
245
*/
203
246
appendTimestampSuffix : boolean | Date = false
204
247
) : string {
248
+ if (
249
+ ! appendTimestampSuffix &&
250
+ filenameReservedRegex . windowsNames ( ) . test ( candidate )
251
+ ) {
252
+ return defaultSketchFolderName ;
253
+ }
205
254
const validName = candidate
206
255
? candidate
207
256
. replace ( / ^ [ ^ 0 - 9 a - z A - Z ] { 1 } / g, defaultFallbackFirstChar )
@@ -230,6 +279,9 @@ export namespace Sketch {
230
279
* Transforms the `candidate` argument into a valid cloud sketch folder name by replacing all invalid characters with underscore and trimming the string after 36 characters.
231
280
*/
232
281
export function toValidCloudSketchFolderName ( candidate : string ) : string {
282
+ if ( filenameReservedRegex . windowsNames ( ) . test ( candidate ) ) {
283
+ return defaultSketchFolderName ;
284
+ }
233
285
return candidate
234
286
? candidate
235
287
. replace ( / ^ [ ^ 0 - 9 a - z A - Z ] { 1 } / g, defaultFallbackFirstChar )
0 commit comments