@@ -2,6 +2,7 @@ import { ApplicationError } from '@theia/core/lib/common/application-error';
22import { nls } from '@theia/core/lib/common/nls' ;
33import URI from '@theia/core/lib/common/uri' ;
44import * as dateFormat from 'dateformat' ;
5+ const filenameReservedRegex = require ( 'filename-reserved-regex' ) ;
56
67export namespace SketchesError {
78 export const Codes = {
@@ -160,6 +161,19 @@ export namespace Sketch {
160161 // (non-API) exported for the tests
161162 export const defaultFallbackChar = '_' ;
162163 // (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
163177 export const invalidSketchFolderNameMessage = nls . localize (
164178 'arduino/sketch/invalidSketchName' ,
165179 '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 {
175189 export function validateSketchFolderName (
176190 candidate : string
177191 ) : string | undefined {
192+ const validFilenameError = isValidFilename ( candidate ) ;
193+ if ( validFilenameError ) {
194+ return validFilenameError ;
195+ }
178196 return / ^ [ 0 - 9 a - z A - Z ] { 1 } [ 0 - 9 a - z A - Z _ \. - ] { 0 , 62 } $ / . test ( candidate )
179197 ? undefined
180198 : invalidSketchFolderNameMessage ;
@@ -186,11 +204,36 @@ export namespace Sketch {
186204 export function validateCloudSketchFolderName (
187205 candidate : string
188206 ) : string | undefined {
207+ const validFilenameError = isValidFilename ( candidate ) ;
208+ if ( validFilenameError ) {
209+ return validFilenameError ;
210+ }
189211 return / ^ [ 0 - 9 a - z A - Z ] { 1 } [ 0 - 9 a - z A - Z _ \. - ] { 0 , 35 } $ / . test ( candidate )
190212 ? undefined
191213 : invalidCloudSketchFolderNameMessage ;
192214 }
193215
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+
194237 /**
195238 * Transforms the `candidate` argument into a valid sketch folder name by replacing all invalid characters with underscore (`_`) and trimming the string after 63 characters.
196239 * If the argument is falsy, returns with `"sketch"`.
@@ -202,6 +245,12 @@ export namespace Sketch {
202245 */
203246 appendTimestampSuffix : boolean | Date = false
204247 ) : string {
248+ if (
249+ ! appendTimestampSuffix &&
250+ filenameReservedRegex . windowsNames ( ) . test ( candidate )
251+ ) {
252+ return defaultSketchFolderName ;
253+ }
205254 const validName = candidate
206255 ? candidate
207256 . replace ( / ^ [ ^ 0 - 9 a - z A - Z ] { 1 } / g, defaultFallbackFirstChar )
@@ -230,6 +279,9 @@ export namespace Sketch {
230279 * 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.
231280 */
232281 export function toValidCloudSketchFolderName ( candidate : string ) : string {
282+ if ( filenameReservedRegex . windowsNames ( ) . test ( candidate ) ) {
283+ return defaultSketchFolderName ;
284+ }
233285 return candidate
234286 ? candidate
235287 . replace ( / ^ [ ^ 0 - 9 a - z A - Z ] { 1 } / g, defaultFallbackFirstChar )
0 commit comments