Closed budarin closed 7 months ago
also have strange error for the file from src/utils/initApplication.ts
:
File is not of any known element typeeslint[boundaries/no-unknown-files](https://github.com/javierbrea/eslint-plugin-boundaries/blob/master/docs/rules/no-unknown-files.md)
debug info
[boundaries]: 'src/utils/initApplication.ts' is of unknown type
{
"source": "utils/initApplication.ts",
"path": "src/utils/initApplication.ts",
"isIgnored": false,
"isLocal": true,
"isBuiltIn": false,
"isExternal": false,
"baseModule": null,
"type": null,
"elementPath": null,
"capture": null,
"capturedValues": null,
"internalPath": null,
"parents": []
}
settings: {
'boundaries/elements': [
...
{
type: 'utils',
pattern: 'src/utils/*',
},
...
]
}
rules: {
'boundaries/element-types': [
...
{
from: 'utils',
allow: '*',
},
...
],
}
Hi @budarin , the plugin is able to work with structures of any level. The problem in your configuration seems to be that you are trying to assign multiple types to the same files, and this is not supported. The type of each file is unique, and the plugin will assign to it the first one that matches. The key is that you can also use the "capture" feature to assign more custom categories to each file. Afterwards you can also use those categories in your rules.
For example:
module.exports = {
settings: {
'boundaries/elements': [
{
type: 'root',
pattern: 'src/index.ts',
mode: 'full',
},
{
type: 'contracts',
pattern: 'src/*/contracts/*',
capture: ["category"],
},
{
type: 'domain',
pattern: 'src/*/domain/*',
capture: ["category"],
},
],
},
};
In this example, I'm capturing the first folder as "category". So, you can now have "contracts" and "domain" types in any "category".
Then, you could define the rules as in:
module.exports = {
rules: {
'boundaries/element-types': [
2,
{
default: 'disallow',
rules: [
{
from: [['contracts', { category: "core" }]],
allow: [['domain', { category: "core" }]],
importKind: 'type',
},
{
from: [['entities', { category: "core" }]],
allow: [['shared', { category: "core" }]],
},
],
},
],
},
};
Here I'm defining that contracts with category "core" can import "domain" with category core, etc. You could use even templates for defining more generic rules, for example allowing elements to import other elements, but always having same "category":
module.exports = {
rules: {
'boundaries/element-types': [
2,
{
default: 'disallow',
rules: [
{
from: "contracts",
allow: [['domain', { category: "${from.category}" }]],
importKind: 'type',
},
{
from: "entities",
allow: [['shared', { category: "${from.category}" }]],
},
],
},
],
},
};
So, you can use multiple levels both when categorizing elements, and when defining rules, making the plugin very customizable to any structure.
I recommend you to read the documentation about this respect at:
Maybe it can be interesting for you also to read the advanced example: https://github.com/javierbrea/eslint-plugin-boundaries#advanced-example-of-a-rule-configuration
About your second comment, the problem is that the file is not recognized as any "element type". So, it does not match any pattern in the settings. If you want to have "unrecognized" types in your project, you can disable the rule "no-unknown-files".
Hi @javierbrea ! Thanks for the response!
I 'm sorry for the issue. I could not catch the basic idea of the plugin from the documentation - there is still something to improve in the documentation :)
The idea of capturing is quite non-trivial and difficult to understand from the first reading.
I will try to study capture and try to apply it, but it seems to me that it is probably possible to change the algorithm of work a little to simplify the use cases.
My 2nd comment was because I don't understand why the plugin decided that the files in src/utils
and src/services
are unknown - I described them
settings: {
'boundaries/elements': [
...
{
type: 'services',
pattern: 'src/services/*',
},
{
type: 'utils',
pattern: 'src/utils/*',
},
],
},
from debugger output
[boundaries]: 'src/services/index.ts' is of unknown type
{
"source": "services/index.ts",
"path": "src/services/index.ts",
"isIgnored": false,
"isLocal": true,
"isBuiltIn": false,
"isExternal": false,
"baseModule": null,
"type": null,
"elementPath": null,
"capture": null,
"capturedValues": null,
"internalPath": null,
"parents": []
}
[boundaries]: 'src/utils/initialStoreData.ts' is of unknown type
{
"source": "utils/initialStoreData.ts",
"path": "src/utils/initialStoreData.ts",
"isIgnored": false,
"isLocal": true,
"isBuiltIn": false,
"isExternal": false,
"baseModule": null,
"type": null,
"elementPath": null,
"capture": null,
"capturedValues": null,
"internalPath": null,
"parents": []
}
@budarin , You're right, It could probably be simplified, but then it probably won't cover the million of different use cases that users require. About improving the documentation, you're also right, for sure it can be improved as well. Anyway, this is an opensource project, and any contribution will be welcome, so, feel free to open PRs with any kind of specific suggestion or improvement, they will be welcome 😃 .
@javierbrea
I'm trying to debug the configuration you suggested and I can't match it with the debugging information
module.exports = {
settings: {
'boundaries/elements': [
{
type: 'contracts',
// src/core/contracts
pattern: 'src/*/contracts/*',
capture: ["category"], // category === 'core'
},
{
type: 'domain',
// src/core/domain
pattern: 'src/*/domain/*',
capture: ['category'], // category === 'core'
},
{
type: 'store',
// src/core/domain/store
pattern: 'src/*/*/store/*',
capture: ['category', 'subcategory'], // category === 'core' subcategory === 'domain`
},
],
},
};
module.exports = {
rules: {
'boundaries/element-types': [
2,
{
default: 'disallow',
rules: [
{
from: [['contracts', { category: "core" }]],
allow: [['domain', { category: "core" }]],
importKind: 'type',
},
],
},
],
},
};
there is no reflection of the keys from capture in it
[boundaries]: 'src/core/contracts/api.ts' is of type 'core'
{
"path": "src/core/contracts/api.ts",
"isIgnored": false,
"type": "core",
"elementPath": "src/core/contracts",
"capture": [
"contracts",
"",
"api.ts"
],
"capturedValues": null,
"internalPath": "api.ts",
"parents": []
}
[boundaries]: 'src/core/domain/store/types.ts' is of type 'core'
{
"source": "store/types.ts",
"path": "src/core/domain/store/types.ts",
"isIgnored": false,
"isLocal": true,
"isBuiltIn": false,
"isExternal": false,
"baseModule": null,
"type": "core",
"elementPath": "src/core/domain",
"capture": [
"domain",
"store",
"types.ts"
],
"capturedValues": null,
"internalPath": "store/types.ts",
"parents": []
}
so I still have the errors in code
and it's unclear for me why files from src/utils
counted as unknow
'boundaries/elements': [
...
{
type: 'utils',
pattern: 'src/utils/*',
},
],
[boundaries]: 'src/utils/initialStoreData.ts' is of unknown type
{
"source": "utils/initialStoreData.ts",
"path": "src/utils/initialStoreData.ts",
"isIgnored": false,
"isLocal": true,
"isBuiltIn": false,
"isExternal": false,
"baseModule": null,
"type": null,
"elementPath": null,
"capture": null,
"capturedValues": null,
"internalPath": null,
"parents": []
}
It's a bug!
Here is the dummy project for testing
You can take the project as a real example of using a plugin on a tree structure
Now the plugin works with a flat project structure - folders in the root of src, but sometimes not all projects have such a flat structure.
For example, we have the following structure that reflects the vision of a clean architecture:
Described each folder in boundaries/elements and tried to write rules for them
But unfortunately it didn't work (
Rule for
contracts
is not workingPlugin shows the error:
Info from debugger:
We are using aliases for known paths in tsconfig.json