mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-18 08:46:33 +00:00
Allow leading underscore in sketch filenames
The Arduino Sketch Specification defines the allowed format of sketch folder names and sketch code filenames. Arduino IDE enforces compliance with the specification in order to ensure sketches created with Arduino IDE can be used with any other Arduino development tool. The Arduino Sketch Specification has been changed to allow a leading underscore in sketch folder names and sketch code filenames so IDE's sketch name validation must be updated accordingly.
This commit is contained in:
parent
ec24b6813d
commit
58aac236bf
@ -157,8 +157,6 @@ export namespace Sketch {
|
|||||||
// (non-API) exported for the tests
|
// (non-API) exported for the tests
|
||||||
export const defaultSketchFolderName = 'sketch';
|
export const defaultSketchFolderName = 'sketch';
|
||||||
// (non-API) exported for the tests
|
// (non-API) exported for the tests
|
||||||
export const defaultFallbackFirstChar = '0';
|
|
||||||
// (non-API) exported for the tests
|
|
||||||
export const defaultFallbackChar = '_';
|
export const defaultFallbackChar = '_';
|
||||||
// (non-API) exported for the tests
|
// (non-API) exported for the tests
|
||||||
export function reservedFilename(name: string): string {
|
export function reservedFilename(name: string): string {
|
||||||
@ -176,11 +174,11 @@ export namespace Sketch {
|
|||||||
// (non-API) exported for the tests
|
// (non-API) exported for the tests
|
||||||
export const invalidSketchFolderNameMessage = nls.localize(
|
export const invalidSketchFolderNameMessage = nls.localize(
|
||||||
'arduino/sketch/invalidSketchName',
|
'arduino/sketch/invalidSketchName',
|
||||||
'The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.'
|
'The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.'
|
||||||
);
|
);
|
||||||
const invalidCloudSketchFolderNameMessage = nls.localize(
|
const invalidCloudSketchFolderNameMessage = nls.localize(
|
||||||
'arduino/sketch/invalidCloudSketchName',
|
'arduino/sketch/invalidCloudSketchName',
|
||||||
'The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.'
|
'The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.'
|
||||||
);
|
);
|
||||||
/**
|
/**
|
||||||
* `undefined` if the candidate sketch folder name is valid. Otherwise, the validation error message.
|
* `undefined` if the candidate sketch folder name is valid. Otherwise, the validation error message.
|
||||||
@ -193,7 +191,7 @@ export namespace Sketch {
|
|||||||
if (validFilenameError) {
|
if (validFilenameError) {
|
||||||
return validFilenameError;
|
return validFilenameError;
|
||||||
}
|
}
|
||||||
return /^[0-9a-zA-Z]{1}[0-9a-zA-Z_\.-]{0,62}$/.test(candidate)
|
return /^[0-9a-zA-Z_]{1}[0-9a-zA-Z_\.-]{0,62}$/.test(candidate)
|
||||||
? undefined
|
? undefined
|
||||||
: invalidSketchFolderNameMessage;
|
: invalidSketchFolderNameMessage;
|
||||||
}
|
}
|
||||||
@ -208,7 +206,7 @@ export namespace Sketch {
|
|||||||
if (validFilenameError) {
|
if (validFilenameError) {
|
||||||
return validFilenameError;
|
return validFilenameError;
|
||||||
}
|
}
|
||||||
return /^[0-9a-zA-Z]{1}[0-9a-zA-Z_\.-]{0,35}$/.test(candidate)
|
return /^[0-9a-zA-Z_]{1}[0-9a-zA-Z_\.-]{0,35}$/.test(candidate)
|
||||||
? undefined
|
? undefined
|
||||||
: invalidCloudSketchFolderNameMessage;
|
: invalidCloudSketchFolderNameMessage;
|
||||||
}
|
}
|
||||||
@ -252,10 +250,7 @@ export namespace Sketch {
|
|||||||
return defaultSketchFolderName;
|
return defaultSketchFolderName;
|
||||||
}
|
}
|
||||||
const validName = candidate
|
const validName = candidate
|
||||||
? candidate
|
? candidate.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar).slice(0, 63)
|
||||||
.replace(/^[^0-9a-zA-Z]{1}/g, defaultFallbackFirstChar)
|
|
||||||
.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar)
|
|
||||||
.slice(0, 63)
|
|
||||||
: defaultSketchFolderName;
|
: defaultSketchFolderName;
|
||||||
if (appendTimestampSuffix) {
|
if (appendTimestampSuffix) {
|
||||||
return `${validName.slice(0, 63 - timestampSuffixLength)}${
|
return `${validName.slice(0, 63 - timestampSuffixLength)}${
|
||||||
@ -283,10 +278,7 @@ export namespace Sketch {
|
|||||||
return defaultSketchFolderName;
|
return defaultSketchFolderName;
|
||||||
}
|
}
|
||||||
return candidate
|
return candidate
|
||||||
? candidate
|
? candidate.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar).slice(0, 36)
|
||||||
.replace(/^[^0-9a-zA-Z]{1}/g, defaultFallbackFirstChar)
|
|
||||||
.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar)
|
|
||||||
.slice(0, 36)
|
|
||||||
: defaultSketchFolderName;
|
: defaultSketchFolderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,22 +171,22 @@ describe('workspace-commands', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('code files cannot start with number (no extension)', async () => {
|
it('code files cannot start with number (no extension)', async () => {
|
||||||
const actual = await testMe('_invalid');
|
const actual = await testMe('-invalid');
|
||||||
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('code files cannot start with number (trailing dot)', async () => {
|
it('code files cannot start with number (trailing dot)', async () => {
|
||||||
const actual = await testMe('_invalid.');
|
const actual = await testMe('-invalid.');
|
||||||
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('code files cannot start with number (trailing dot)', async () => {
|
it('code files cannot start with number (trailing dot)', async () => {
|
||||||
const actual = await testMe('_invalid.cpp');
|
const actual = await testMe('-invalid.cpp');
|
||||||
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should warn about invalid extension first', async () => {
|
it('should warn about invalid extension first', async () => {
|
||||||
const actual = await testMe('_invalid.xxx');
|
const actual = await testMe('-invalid.xxx');
|
||||||
expect(actual).to.be.equal(invalidExtensionMessage('.xxx'));
|
expect(actual).to.be.equal(invalidExtensionMessage('.xxx'));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ describe('workspace-commands', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore non-code filename validation from the spec', async () => {
|
it('should ignore non-code filename validation from the spec', async () => {
|
||||||
const actual = await testMe('_invalid.json');
|
const actual = await testMe('-invalid.json');
|
||||||
expect(actual).to.be.empty;
|
expect(actual).to.be.empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ describe('sketch', () => {
|
|||||||
['trailing.dots...', false],
|
['trailing.dots...', false],
|
||||||
['no.trailing.dots.._', true],
|
['no.trailing.dots.._', true],
|
||||||
['No Spaces', false],
|
['No Spaces', false],
|
||||||
['_invalidToStartWithUnderscore', false],
|
['_validToStartWithUnderscore', true],
|
||||||
['Invalid+Char.ino', false],
|
['Invalid+Char.ino', false],
|
||||||
['', false],
|
['', false],
|
||||||
['/', false],
|
['/', false],
|
||||||
@ -81,7 +81,7 @@ describe('sketch', () => {
|
|||||||
['can.contain.dots', true],
|
['can.contain.dots', true],
|
||||||
['-cannot-start-with-dash', false],
|
['-cannot-start-with-dash', false],
|
||||||
['.cannot.start.with.dash', false],
|
['.cannot.start.with.dash', false],
|
||||||
['_cannot_start_with_underscore', false],
|
['_can_start_with_underscore', true],
|
||||||
['No Spaces', false],
|
['No Spaces', false],
|
||||||
['Invalid+Char.ino', false],
|
['Invalid+Char.ino', false],
|
||||||
['', false],
|
['', false],
|
||||||
@ -108,14 +108,14 @@ describe('sketch', () => {
|
|||||||
describe('toValidSketchFolderName', () => {
|
describe('toValidSketchFolderName', () => {
|
||||||
[
|
[
|
||||||
['', Sketch.defaultSketchFolderName],
|
['', Sketch.defaultSketchFolderName],
|
||||||
[' ', Sketch.defaultFallbackFirstChar],
|
[' ', Sketch.defaultFallbackChar],
|
||||||
[' ', Sketch.defaultFallbackFirstChar + Sketch.defaultFallbackChar],
|
[' ', Sketch.defaultFallbackChar + Sketch.defaultFallbackChar],
|
||||||
[
|
[
|
||||||
'0123456789012345678901234567890123456789012345678901234567890123',
|
'0123456789012345678901234567890123456789012345678901234567890123',
|
||||||
'012345678901234567890123456789012345678901234567890123456789012',
|
'012345678901234567890123456789012345678901234567890123456789012',
|
||||||
],
|
],
|
||||||
['foo bar', 'foo_bar'],
|
['foo bar', 'foo_bar'],
|
||||||
['_foobar', '0foobar'],
|
['-foobar', '_foobar'],
|
||||||
['vAlid', 'vAlid'],
|
['vAlid', 'vAlid'],
|
||||||
['COM1', Sketch.defaultSketchFolderName],
|
['COM1', Sketch.defaultSketchFolderName],
|
||||||
['COM1.', 'COM1_'],
|
['COM1.', 'COM1_'],
|
||||||
@ -130,20 +130,18 @@ describe('sketch', () => {
|
|||||||
const epochSuffix = Sketch.timestampSuffix(epoch);
|
const epochSuffix = Sketch.timestampSuffix(epoch);
|
||||||
[
|
[
|
||||||
['', Sketch.defaultSketchFolderName + epochSuffix],
|
['', Sketch.defaultSketchFolderName + epochSuffix],
|
||||||
[' ', Sketch.defaultFallbackFirstChar + epochSuffix],
|
[' ', Sketch.defaultFallbackChar + epochSuffix],
|
||||||
[
|
[
|
||||||
' ',
|
' ',
|
||||||
Sketch.defaultFallbackFirstChar +
|
Sketch.defaultFallbackChar + Sketch.defaultFallbackChar + epochSuffix,
|
||||||
Sketch.defaultFallbackChar +
|
|
||||||
epochSuffix,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'0123456789012345678901234567890123456789012345678901234567890123',
|
'0123456789012345678901234567890123456789012345678901234567890123',
|
||||||
'0123456789012345678901234567890123456789012' + epochSuffix,
|
'0123456789012345678901234567890123456789012' + epochSuffix,
|
||||||
],
|
],
|
||||||
['foo bar', 'foo_bar' + epochSuffix],
|
['foo bar', 'foo_bar' + epochSuffix],
|
||||||
['.foobar', '0foobar' + epochSuffix],
|
['.foobar', '_foobar' + epochSuffix],
|
||||||
['-fooBar', '0fooBar' + epochSuffix],
|
['-fooBar', '_fooBar' + epochSuffix],
|
||||||
['foobar.', 'foobar_' + epochSuffix],
|
['foobar.', 'foobar_' + epochSuffix],
|
||||||
['fooBar-', 'fooBar_' + epochSuffix],
|
['fooBar-', 'fooBar_' + epochSuffix],
|
||||||
['fooBar+', 'fooBar_' + epochSuffix],
|
['fooBar+', 'fooBar_' + epochSuffix],
|
||||||
@ -164,19 +162,17 @@ describe('sketch', () => {
|
|||||||
['only_underscore-is+ok.ino', 'only_underscore_is_ok_ino'],
|
['only_underscore-is+ok.ino', 'only_underscore_is_ok_ino'],
|
||||||
['regex++', 'regex__'],
|
['regex++', 'regex__'],
|
||||||
['dots...', 'dots___'],
|
['dots...', 'dots___'],
|
||||||
['.dots...', '0dots___'],
|
['.dots...', '_dots___'],
|
||||||
['-dashes---', '0dashes___'],
|
['-dashes---', '_dashes___'],
|
||||||
['_underscore___', '0underscore___'],
|
|
||||||
['No Spaces', 'No_Spaces'],
|
['No Spaces', 'No_Spaces'],
|
||||||
['_startsWithUnderscore', '0startsWithUnderscore'],
|
|
||||||
['Invalid+Char.ino', 'Invalid_Char_ino'],
|
['Invalid+Char.ino', 'Invalid_Char_ino'],
|
||||||
['', 'sketch'],
|
['', 'sketch'],
|
||||||
['/', '0'],
|
['/', '_'],
|
||||||
[
|
[
|
||||||
'/-1////////////////////+//////////////-/',
|
'/-1////////////////////+//////////////-/',
|
||||||
'0_1_________________________________',
|
'__1_________________________________',
|
||||||
],
|
],
|
||||||
['//trash/', '0_trash_'],
|
['//trash/', '__trash_'],
|
||||||
[
|
[
|
||||||
'63Length_012345678901234567890123456789012345678901234567890123',
|
'63Length_012345678901234567890123456789012345678901234567890123',
|
||||||
'63Length_012345678901234567890123456',
|
'63Length_012345678901234567890123456',
|
||||||
|
@ -419,11 +419,11 @@
|
|||||||
"editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?",
|
"editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?",
|
||||||
"editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?",
|
"editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?",
|
||||||
"exportBinary": "Export Compiled Binary",
|
"exportBinary": "Export Compiled Binary",
|
||||||
"invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.",
|
"invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.",
|
||||||
"invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.",
|
"invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.",
|
||||||
"invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'",
|
"invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'",
|
||||||
"invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'",
|
"invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'",
|
||||||
"invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.",
|
"invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.",
|
||||||
"moving": "Moving",
|
"moving": "Moving",
|
||||||
"movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?",
|
"movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?",
|
||||||
"new": "New Sketch",
|
"new": "New Sketch",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user