Time for the next round of functionality I added in my VSCode Extension (the CRS AL Language Extension) – a functionality that manages your filenames (and pre/suffix). Hold your horses – this is going to be a long one ;-). You don’t want to know how many hours I spent on this functionality – many points of feedback from the community, and even some pullrequests from some (for all of which I’m very thankful!) has made it into the functionality it is today.
The problem(s) I wanted to solve
There are multiple problems with filenames, to be honest.
We never cared about this
In a way, we are not used to deal with filenames, because in C/AL, we simply have an object designer – which only needs an object name. So, this is new!
There is a “File name convention”
On top of that, there is even a file name convention that Microsoft wants us to follow. You can find them here on Docs. When you read carefully through it, you’ll see that it gives some practical challenges:
-
Every name has the object ID
- I don’t know that object ID when I create the file?
- But I need to create the file first to give it the al-extension, to put the client in language mode “al”
- What if I renumber my object – then I need to think about renaming the file as well!
- Every name has also the object name – what if I rename my object -then I need to think about renaming the file as well!
And what about subfolders?
Next to that, it is not a good practice to have our files all in the root – so we should be putting that into subfolders. Microsoft’s recommendation is to have:
- \Src – for source code
- \Res – for resources (whatever that means – control addins?)
- \Text – for testability
And within these subfolders, you can create a next level of subfolders. I would recommend subfolders that indicate a certain functionality. Many people create subfolders by object type – but why would one do that? Because C/SIDE did that? It’s much more convenient that you create a structure based on functionality, so that all objects (reports, tables, pages, … ) that belong together, are actually together. Like this example:
-
\Src
- \_FunctionLibrary
- \NotificationMgt
- \InterCompany
- \Sales
- …
-
\Test
- \NotificationMgt
- \InterCompany
- \Sales
You see – you can even follow the same structure in your testability – although there is a lot to say about that (it might be better to do testability in a separate app – it gives you much more flexibility by decoupling/disabling your methods if necessary – but that’s a whole other topic).
And even prefixes
And then there is prefixes. Know that there is a requirement for apps on AppSource – they need to be prefixed! Not only objects, but also fields and controls that you add to existing tables/pages! Simply because of the fact that one field or control can’t be added twice ;-).
Also, you need to make sure your prefix is unique. And to do that, there is a mail address to apply for a prefix: d365val@microsoft.com.
I don’t want to care about this
It adds complexity to my project, and it needs to add discipline to the developers. Complexity and discipline, that’s a dangerous combination to rely on. So I don’t want to.
That’s why I started to build something that can manage this for me.
Rename/Reorganize
Maybe first some vocabulary:
- Rename = Renaming a file following a pattern (which you can configure – the default is the one Microsoft describes).
- Reorganize = Renaming a file, and put it in a subfolder (categorized by object type).
Renaming is very interesting. Reorganizing – to be honest – I don’t use that anymore, because as said before, I believe you should organize your objects per functionality, not per object type. This was just something we were used to from the Object Designer. But now we can do better ;-).
To start with, I added commands to the command palette:
One downside on a command is that you have to manually run this. So every single time you create, renumber, rename, .. an object, you need to think about running one of these as well …
I’m lazy and undisciplined, so this was not automatic enough. So I included a setting that this can be done automatically “OnSaveFile”. But later more about that – let’s first talk about the basic settings…
The Basic Settings
There are quite some settings – but do know you don’t *need* to set up anything – it will just work without settings, as the defaults are the ones that Microsoft describes. Let me try to categorize them a bit:
Setting | Default | Options |
CRS.FileNamePattern | <ObjectTypeShort><ObjectId>.<ObjectNameShort>.al | <Prefix> <Suffix> <ObjectType> <ObjectTypeShort> <ObjectId> <ObjectName><ObjectNameShort><ObjectTypeShortUpper> |
CRS.FileNamePatternExtensions | <ObjectTypeShort><BaseId>-Ext<ObjectId>.<ObjectNameShort>.al | <Prefix> <Suffix> <ObjectType> <ObjectTypeShort> <ObjectId> <ObjectName> <ObjectNameShort> <ObjectTypeShortUpper> <BaseName> <BaseNameShort> <BaseId> |
CRS.FileNamePatternPageCustomizations | <ObjectTypeShort><BaseId>-PageCust.<ObjectNameShort>.al | <Prefix> <Suffix> <ObjectType> <ObjectTypeShort> <ObjectName> <ObjectNameShort> <ObjectTypeShortUpper> <BaseName> <BaseNameShort> <BaseId> |
CRS.AlSubFolderName | Src | “Src” “Source” “Objects” “Al” “None” |
Since a normal file, and extension file and a customization all have a different pattern, I needed to split it in three settings. You can change them at your convenience using the tags you see in the third column.
Some tips that go along these settings
Before you start renaming your files – commit your code to Git first, because that will be the only rollback you will be able to do ;-).
The last setting “AlSubFolderName” is only used to reorganize the file(s). If you don’t ever want to accidentally run that command, just set it up with “None” – that will deactivate the “reorganize” command, and prevent from accidentally disrupting your (manual) folder structure. This is what I do lately.
Automatically rename/reorganize filenames (when you save a file)
As I said, I don’t like to manually run any command, because that demands me being disciplined. I’d like to rely on the opposite, so I also introduced another setting “CRS.OnSaveAlFileAction”:
Default setting is “DoNothing”, but you can set it to “Rename” or “Reorganize” which will simply call the Rename/Reorganize Current File when you save a file.
Tips:
I usually set this on workspace-level, so that I always have a decent filename in my repository, whoever is working on my app.
If you apply your own folder structure, set this setting to “rename” – else your folder structure is going to get automatically messed up ;-).
Prefix/Suffix
It is a good practice to prefix as well, to avoid conflicting names in objects, fields, … a requirement which Microsoft describes here. And it’s best to apply for a prefix by mailing to d365val@microsoft.com – just to make sure your prefix is reserved and unique.
I built that into the “Rename” and “Reorganize” feature mentioned above. So when you try to rename/reorganize a file, it’s also going to check whether you set up a prefix/suffix, and it’s going to apply that to the :
- Object Name
- Actions (only prefix)
- Fields (only prefix)
There are a few settings that make that possible:
- CRS.ObjectNamePrefix
- CRS.RemovePrefixFromFilename
- CRS.ObjectNameSuffix
- CRS.RemoveSuffixFromFilename
As you can see, there are some “Remove” settings as well. They are there to avoid to have the prefix in the filename (as the filename will get the object name by default). This will give you much nicer filenames without prefixes.
Tips:
By default, the system is not going to prefix/suffix anything. You will have to set these settings before anything will be prefixed
Because of the “OnSaveAlFileAction” setting, the prefixes will be applied automatically as well – no extra work needed.
Warning:
If you renumber/reorganize for the first time with a prefix – it’s not actually going to “rename symbols”, which means you will end up with compile errors. They are easy to solve, so don’t panic! – it’s just not possible (yet) to do a decent rename symbol with the VSCode API to prevent this.
That’s it!
That’s all, folks. This has cost quite some hours of my life – and not only my life, also from a few people from the community, that has contributed to the project on github, like Dmitry Katson and Johannes Wikman. I so love this community :-).
Things that need improvement
That doesn’t mean that things doesn’t need improvement. While writing this blog, i realized that I actually never implemented the suffix for fields and actions. Probably because I never needed it – because we always “prefix” our objects.
In any case – if there is anything you lack, might want to have changed – don’t hesitate to file an issue on my repository.
My Settings
Let me conclude with my settings – what I usually use (in terms of this blogpost, obviously). Well, here is an example:
I usually don’t use the “Reorganize”, as I want to organize my files manually in function areas (subfolders). So the “AlSubFolderName” is “None”, which prevents anything to reorganize (it basically disables that function).
I do want to rename everything automatically, therefore the “OnSaveAlFileAction” to “Rename”.
And then I set a prefix, since that’s mandatory by Microsoft. It’s best to have this prefix set all in the beginning. So make sure you apply for a prefix rather sooner than later!
11 comments
5 pings
Skip to comment form
I thought that Microsoft wanted prefix OR suffix. And I prefer sufixes because I don’t need to type it first when I am waiting for intellisense to kick in.
Author
You are right. it’s prefix OR suffix. Did I imply anything else? :-). Just need to finish the suffix-handling on fields and actions…
Also, you need to make sure your prefix is unique. And to do that, there is a mail address to apply for a prefix: d365val@microsoft.com.
That implies prefix only
Great extension! I have my setting for CRS.FileNamePatternExtensions set to -Ext..al
But upon renaming a Page Extension like this:
pageextension 50100 “Item Card Extension” extends “Item Card”
the renamed file has the file name: Pag-Ext50100.ItemCardExtension
But according to the syntax I expected Pag30-Ext50100.ItemCardExtension
What could be wrong?
Author
Well, if you use my snippet for page extension, you’ll notice a comment behind the “Item Card”, where you can add the page number, so I can pick it up. Like:
pageextension 50100 “Item Card Extension” extends “Item Card” //30
I’m not able to get to the page number from the symbols just yet. So you need to provide that… .
I like the approach of grouping objects per functionality. However, how do you deal with objects that are shared across functionalities? E.g. a ‘Customer Table / Page Extension’ containing fields from various functionalities.
Author
Well, those go in a “_Base” folder 😉
I set the following settings:
“CRS.OnSaveAlFileAction”: “Rename”,
“CRS.AlSubFolderName”: “None”,
“CRS.RemovePrefixFromFilename”: true,
“CRS.ObjectNamePrefix”: “123”,
“CRS.ExtensionObjectNamePattern”: ” “,
“CRS.FileNamePattern”: “..al”,
“CRS.FileNamePatternExtensions”: “..al”
Then I expected the file name of following object:
pageextension 50100 “CustCard Test” extends “Customer Card” //50100
To be renamed to:
CustomerCardTest.Page.al
But it renamed to:
CustomerCardTest.Pag.al
It seems that not the latest abrreviation are used?
https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/compliance/apptest-bestpracticesforalcode
Objects where not renamed witht the prefix “123”.
When does it use the prefix? Only for objects in an extension range?
Author
I’m not able to see your settings – please use github and provide screenshots – html is messing up the settings because of the characters, I guess..
but from what I have read, it seems you don’t use “ObjectTypeShortPascalCase” in the pattern, correct?
“ObjectTypeShortPascalCase” seems to do the trick, thanks 🙄
[…] Original URL… […]
[…] Bron : Waldo’s Blog Lees meer… […]
[…] has some guidelines on the expected standards for Extension development. Waldo has not only useful recommendations that build on top of that, but also VS Code Extensions to support it. I’m new to this, but […]
[…] Automatically managing file names (and locations, if you want) […]
[…] you might know – I created a VSCode Extension that makes it possible to easily handle file naming conventions. Because of these new guidelines (and coderules), I recently added a new option […]