Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add customizable subfolder paths with placeholder support #300

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ This extension contributes the following settings:
- `<Prefix>`
- `<Suffix>`
- `<ObjectType>`
- `<ObjectTypeLower>` - same as "ObjectType", but lowercased
- `<ObjectTypeShort>` - a short notation of the object type.
- `<ObjectTypeShortPascalCase>` - PascalCased object type
- `<ObjectTypeShortUpper>` - Same as "ObjectTypeShort" but uppercased
Expand All @@ -162,6 +163,7 @@ This extension contributes the following settings:
- `<Prefix>` - just the prefix separately
- `<Suffix>` - just the suffix separately
- `<ObjectType>`
- `<ObjectTypeLower>` - same as "ObjectType", but lowercased
- `<ObjectTypeShort>` - a short notation of the object type.
- `<ObjectTypeShortPascalCase>` - PascalCased object type
- `<ObjectTypeShortUpper>` - Same as "ObjectTypeShort" but uppercased
Expand All @@ -172,6 +174,7 @@ This extension contributes the following settings:
- `<Prefix>` - just the prefix separately
- `<Suffix>` - just the suffix separately
- `<ObjectType>`
- `<ObjectTypeLower>` - same as "ObjectType", but lowercased
- `<ObjectTypeShort>` - a short notation of the object type.
- `<ObjectTypeShortPascalCase>` - PascalCased object type
- `<ObjectTypeShortUpper>` - Same as "ObjectTypeShort" but uppercased
Expand All @@ -198,6 +201,7 @@ tableextension 50100 "Just Some Table Extension" extends Customer //18
- `<Prefix>` - just the prefix separately
- `<Suffix>` - just the suffix separately
- `<ObjectType>`
- `<ObjectTypeLower>` - same as "ObjectType", but lowercased
- `<ObjectTypeShort>` - a short notation of the object type.
- `<ObjectTypeShortPascalCase>` - PascalCased object type
- `<ObjectTypeShortUpper>` - Same as "ObjectTypeShort" but uppercased
Expand All @@ -206,6 +210,19 @@ tableextension 50100 "Just Some Table Extension" extends Customer //18
- `<BaseName>` - weird chars are removed - does NOT include prefix nor suffix
- `<BaseNameShort>` - does NOT include prefix nor suffix
- `<BaseId>` - same remarks as above!
* `CRS.FolderPathPattern`: The pattern of the path containing the file, relative to the app folder. These vars can be used:
- `<Prefix>` - just the prefix separately
- `<Suffix>` - just the suffix separately
- `<ObjectType>`
- `<ObjectTypeLower>` - same as "ObjectType", but lowercased
- `<ObjectTypeShort>` - a short notation of the object type.
- `<ObjectTypeShortPascalCase>` - PascalCased object type
- `<ObjectTypeShortUpper>` - Same as "ObjectTypeShort" but uppercased
- `<ObjectId>`
- `<ObjectName>` - weird chars are removed - includes prefix and suffix
- `<ObjectNameShort>`
- `<AlSubFolder>` - same as "CRS.AlSubFolderName"
- `<ControlAddIn>` - same as "ObjectNameShort" if the object type is "Control Addin", otherwise skipped
* `CRS.ObjectNamePrefix`: When using the Reorganize/Rename-commands, this setting will make sure the object name (and filename) will have a Prefix.
- Tip 1: use as a workspace-setting.
- Tip 2: use an ending-space if you want the prefix to be separated with a space.
Expand Down
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,19 +180,25 @@
"CRS.FileNamePattern": {
"Type": "string",
"default": "<ObjectTypeShort><ObjectId>.<ObjectNameShort>.al",
"description": "The pattern of the filename for non-extension objects.. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectId>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>",
"description": "The pattern of the filename for non-extension objects.. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectId>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<ObjectTypeLower>",
"scope": "resource"
},
"CRS.FileNamePatternExtensions": {
"Type": "string",
"default": "<ObjectTypeShort><BaseId>-Ext<ObjectId>.<ObjectNameShort>.al",
"description": "The pattern of the filename for extension objects. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectId>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<BaseName>,<BaseNameShort>,<BaseId> (If you want this to work, you need to put the Id in comment after the base name, like //21)",
"description": "The pattern of the filename for extension objects. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectId>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<ObjectTypeLower>,<BaseName>,<BaseNameShort>,<BaseId> (If you want this to work, you need to put the Id in comment after the base name, like //21)",
"scope": "resource"
},
"CRS.FileNamePatternPageCustomizations": {
"Type": "string",
"default": "<ObjectTypeShort><BaseId>-PageCust.<ObjectNameShort>.al",
"description": "The pattern of the filename for extension objects. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<BaseName>,<BaseNameShort>,<BaseId> (If you want this to work, you need to put the Id in comment after the base name, like //21)",
"description": "The pattern of the filename for extension objects. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<ObjectTypeLower>,<BaseName>,<BaseNameShort>,<BaseId> (If you want this to work, you need to put the Id in comment after the base name, like //21)",
"scope": "resource"
},
"CRS.FolderPathPattern": {
"Type": "string",
"default": "<AlSubFolder>\\<ObjectTypeLower>\\<ControlAddIn>",
"description": "The pattern of the folder containing the object. These vars can be used: <Prefix>,<Suffix>,<ObjectType>,<ObjectTypeShort>,<ObjectTypeShortPascalCase>,<ObjectId>,<ObjectName>,<ObjectNameShort>,<ObjectTypeShortUpper>,<ObjectTypeLower>,<AlSubFolder>,<ControlAddIn>",
"scope": "resource"
},
"CRS.AlSubFolderName": {
Expand Down
66 changes: 50 additions & 16 deletions src/NAVObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class NAVObject {
public NAVObjectText: string;
private _workSpaceSettings: Settings;
private _objectFileNamePattern: string;
private _objectFolderPathPattern: string;

// Windows chars not allowed in filenames or paths (includes Linux):
// < (less than)
Expand All @@ -44,16 +45,12 @@ export class NAVObject {
}

setObjectProperies(objectType: string, objectId: string, objectName: string) {
this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePattern];
this.objectType = objectType;
this.objectId = objectId;
this.objectName = objectName;
this.extendedObjectName = '';
this.extendedObjectId = '';
this.setObjectExtensionProperies(objectType, objectId, objectName, '', '');
}

setObjectExtensionProperies(objectType: string, objectId: string, objectName: string, extendedObjectId: string, extendedObjectName: string) {
this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePatternExtensions];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];
this.objectType = objectType;
this.objectId = objectId;
this.objectName = objectName;
Expand Down Expand Up @@ -123,6 +120,15 @@ export class NAVObject {
return objectFileNameFixed;
}

get objectFolderPathFixed(): string {
let objectFolderPathFixed = this._objectFolderPathPattern

objectFolderPathFixed = this.ApplyPatternToFolderPath(objectFolderPathFixed);
objectFolderPathFixed = this.RemoveUnderscore(objectFolderPathFixed);

return objectFolderPathFixed;
}

get objectCodeunitSubType(): string {
if (this.objectType.toLowerCase() != 'codeunit') { return null }

Expand Down Expand Up @@ -153,6 +159,7 @@ export class NAVObject {
let ObjectTypeArr = filteredlines.toString().match(patternObjectType);

this._objectFileNamePattern = '';
this._objectFolderPathPattern = '';
this.objectType = '';
this.objectId = '';
this.objectName = '';
Expand Down Expand Up @@ -190,6 +197,7 @@ export class NAVObject {
this.objectName = currObject[3];

this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePattern];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -213,6 +221,7 @@ export class NAVObject {
this.extendedObjectId = currObject[6] ? currObject[6] : '';

this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePatternExtensions];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -226,6 +235,7 @@ export class NAVObject {
this.objectName = currObject[2];

this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePattern];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -239,6 +249,7 @@ export class NAVObject {
this.objectName = currObject[2];

this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePattern];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -251,6 +262,7 @@ export class NAVObject {
this.objectName = currObject[2];

this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePattern];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -265,6 +277,7 @@ export class NAVObject {
this.extendedObjectName = currObject[3];
this.extendedObjectId = currObject[5] ? currObject[5] : '';
this._objectFileNamePattern = this._workSpaceSettings[Settings.FileNamePatternPageCustomizations];
this._objectFolderPathPattern = this._workSpaceSettings[Settings.FolderPathPattern];

break;
}
Expand All @@ -290,6 +303,7 @@ export class NAVObject {
if (!(this.IsValidObjectType(this.objectType))) {
//reset variables
this._objectFileNamePattern = '';
this._objectFolderPathPattern = '';
this.objectType = '';
this.objectId = '';
this.objectName = '';
Expand Down Expand Up @@ -374,6 +388,7 @@ export class NAVObject {
result = StringFunctions.replaceAll(result, '<Prefix>', this._workSpaceSettings[Settings.ObjectNamePrefix]);
result = StringFunctions.replaceAll(result, '<Suffix>', this._workSpaceSettings[Settings.ObjectNameSuffix]);
result = StringFunctions.replaceAll(result, '<ObjectType>', this.objectType)
result = StringFunctions.replaceAll(result, '<ObjectTypeLower>', this.objectType.toLowerCase());
result = StringFunctions.replaceAll(result, '<ObjectTypeShort>', this.objectTypeShort);
result = StringFunctions.replaceAll(result, '<ObjectTypeShortPascalCase>', this.ObjectTypeShortPascalCase);
result = StringFunctions.replaceAll(result, '<ObjectTypeShortUpper>', this.objectTypeShort.toUpperCase());
Expand All @@ -387,19 +402,38 @@ export class NAVObject {
private ApplyPatternToFileName(pattern: string): string {
let result = pattern;

result = StringFunctions.replaceAll(result, '<Prefix>', this._workSpaceSettings[Settings.ObjectNamePrefix]);
result = StringFunctions.replaceAll(result, '<Suffix>', this._workSpaceSettings[Settings.ObjectNameSuffix]);
result = StringFunctions.replaceAll(result, '<ObjectType>', this.objectType)
result = StringFunctions.replaceAll(result, '<ObjectTypeShort>', this.objectTypeShort);
result = StringFunctions.replaceAll(result, '<ObjectTypeShortPascalCase>', this.ObjectTypeShortPascalCase);
result = StringFunctions.replaceAll(result, '<ObjectTypeShortUpper>', this.objectTypeShort.toUpperCase());
result = StringFunctions.replaceAll(result, '<ObjectId>', this.objectId);
result = StringFunctions.replaceAll(result, '<ObjectName>', this.objectNameFixedForFileName);
result = StringFunctions.replaceAll(result, '<ObjectNameShort>', this.objectNameFixedShort);
result = StringFunctions.replaceAll(result, '<BaseName>', this.extendedObjectNameFixedForFileName);
result = StringFunctions.replaceAll(result, '<BaseNameShort>', this.extendedObjectNameFixedShort);
result = StringFunctions.replaceAll(result, '<BaseId>', this.extendedObjectId);
result = this.ApplyPatternToObjectName(result);

return result;
}
private ApplyPatternToFolderPath(pattern: string): string {
let result = pattern;

result = this.replaceControlAddIn(result);
result = StringFunctions.replaceAll(result, '<AlSubFolder>', this._workSpaceSettings[Settings.AlSubFolderName]);
result = this.ApplyPatternToFileName(result);

let folders = result.split('\\');
folders = folders.map(folder => folder.replace(/^\s+|\s+$/g, ''));
result = folders.join('\\');

return result;
}
private replaceControlAddIn(pattern: string): string {
let result = pattern;
let controladdin = '';
const controlAddInPattern = '<ControlAddIn>';
const doubleBackslashPattern = '\\<ControlAddIn>';
if (this.objectType.toLocaleLowerCase() == 'controladdin') {
controladdin = this.objectNameFixedShort;
}
if (controladdin == '' && result.includes(doubleBackslashPattern)) {
result = StringFunctions.replaceAll(result, doubleBackslashPattern, controladdin);
} else {
result = StringFunctions.replaceAll(result, controlAddInPattern, controladdin);
}
return result;
}
private AddPrefixAndSuffixToObjectNameFixed(objectName: string): string {
Expand Down
2 changes: 2 additions & 0 deletions src/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class Settings {
static readonly FileNamePattern = 'FileNamePattern';
static readonly FileNamePatternExtensions = 'FileNamePatternExtensions';
static readonly FileNamePatternPageCustomizations = 'FileNamePatternPageCustomizations';
static readonly FolderPathPattern = 'FolderPathPattern';
static readonly OnSaveAlFileAction = 'OnSaveAlFileAction';
static readonly ObjectNamePrefix = 'ObjectNamePrefix';
static readonly ObjectNameSuffix = 'ObjectNameSuffix';
Expand Down Expand Up @@ -90,6 +91,7 @@ export class Settings {
this.SettingCollection[this.FileNamePattern] = this.getSetting(this.FileNamePattern);
this.SettingCollection[this.FileNamePatternExtensions] = this.getSetting(this.FileNamePatternExtensions);
this.SettingCollection[this.FileNamePatternPageCustomizations] = this.getSetting(this.FileNamePatternPageCustomizations);
this.SettingCollection[this.FolderPathPattern] = this.getSetting(this.FolderPathPattern);
this.SettingCollection[this.ObjectNamePrefix] = this.getSetting(this.ObjectNamePrefix);
this.SettingCollection[this.ObjectNameSuffix] = this.getSetting(this.ObjectNameSuffix);
this.SettingCollection[this.RemovePrefixFromFilename] = this.getSetting(this.RemovePrefixFromFilename);
Expand Down
20 changes: 6 additions & 14 deletions src/WorkspaceFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,20 @@ export class WorkspaceFiles {
let fixedname = navObject.objectFileNameFixed
if (navObject.objectFileName && navObject.objectFileName != '' && fixedname && fixedname != '') {

let objectFolder = path.join(vscode.workspace.getWorkspaceFolder(fileName).uri.fsPath, this.getDestinationFolder(navObject, settings));
let objectTypeFolder = path.join(objectFolder, this.getObjectTypeFolder(navObject, settings));
let objectSubFolder = path.join(objectTypeFolder, this.getObjectSubFolder(navObject));
let destinationFileName = path.join(objectSubFolder, fixedname);
let appFolder = vscode.workspace.getWorkspaceFolder(fileName).uri.fsPath;
let relativeFolderPath = navObject.objectFolderPathFixed;
let absoluteFolderPath = path.join(appFolder, relativeFolderPath);
let destinationFileName = path.join(absoluteFolderPath, fixedname);

if (destinationFileName.toLocaleLowerCase() == fileName.fsPath.toLocaleLowerCase()) {
if (destinationFileName == fileName.fsPath) {
//console.log('paths are the same.');
return fileName.fsPath;
} else {

//(!fs.existsSync(objectFolder)) ? fs.mkdirSync(objectFolder) : '';
//(!fs.existsSync(objectTypeFolder)) ? fs.mkdirSync(objectTypeFolder) : '';
//(!fs.existsSync(objectSubFolder)) ? fs.mkdirSync(objectSubFolder) : '';
this.createDirectoryIfNotExists(objectSubFolder);
this.createDirectoryIfNotExists(absoluteFolderPath);

withGit = withGit ? withGit : (git.isGitRepositorySync() && settings[Settings.RenameWithGit])
this.DoRenameFile(fileName, destinationFileName, withGit)
Expand Down Expand Up @@ -324,14 +324,6 @@ export class WorkspaceFiles {
return navObject.objectType
}

static getObjectSubFolder(navObject: NAVObject): string {
if (navObject.objectType == 'controladdin') {
return navObject.objectNameFixedShort
}

return "";
}

static createDirectoryIfNotExists(dir) {
const segments = dir.split(path.sep);
let currentPath = segments[0];
Expand Down
34 changes: 34 additions & 0 deletions src/test/suite/NAVObject.FilePattern.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,38 @@ suite("NAVObject FilePattern Tests", () => {

assert.strictEqual(navObject.objectFileNameFixed, 'CustomerTop10ListExt.ReportExt.al')
})
test("Folder path - Default folder path", () => {
let testSettings = Settings.GetConfigSettings(null)

let navTestObject = NAVTestObjectLibrary.getPageNoPrefixCorrectNameWithActions();
let navObject = new NAVObject(navTestObject.ObjectText, testSettings, navTestObject.ObjectFileName);

assert.strictEqual(navObject.objectFolderPathFixed,
testSettings[Settings.AlSubFolderName] + '\\' +
navObject.objectType.toLowerCase() + '\\');
})
test("Folder path - Default folder path with control addin", () => {
let testSettings = Settings.GetConfigSettings(null)

let navTestObject = NAVTestObjectLibrary.getControlAddinObject();
let navObject = new NAVObject(navTestObject.ObjectText, testSettings, navTestObject.ObjectFileName);

assert.strictEqual(navObject.objectFolderPathFixed,
testSettings[Settings.AlSubFolderName] + '\\' +
navObject.objectType.toLowerCase() + '\\' +
navObject.objectNameFixedShort);
})
test("Folder path - Custom folder path with prefix", () => {
let testSettings = Settings.GetConfigSettings(null)

testSettings[Settings.FolderPathPattern] = '<AlSubFolder>\\<Prefix>\\<ObjectType>';

let navTestObject = NAVTestObjectLibrary.getTestCodeunitWithPrefix();
let navObject = new NAVObject(navTestObject.ObjectText, testSettings, navTestObject.ObjectFileName);

assert.strictEqual(navObject.objectFolderPathFixed,
testSettings[Settings.AlSubFolderName] + '\\' +
testSettings[Settings.ObjectNamePrefix] + '\\' +
navObject.objectType.toLowerCase());
})
})
Loading