@leancodepl/folder-structure-cruiser 9.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dependency-cruiser.json +30 -0
- package/CHANGELOG.md +41 -0
- package/README.md +139 -0
- package/package.json +54 -0
- package/src/bin.d.ts +2 -0
- package/src/bin.js +35 -0
- package/src/bin.js.map +1 -0
- package/src/commands/validateCrossFeatureImports.d.ts +59 -0
- package/src/commands/validateCrossFeatureImports.js +80 -0
- package/src/commands/validateCrossFeatureImports.js.map +1 -0
- package/src/commands/validateSharedComponent.d.ts +59 -0
- package/src/commands/validateSharedComponent.js +78 -0
- package/src/commands/validateSharedComponent.js.map +1 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +3 -0
- package/src/index.js.map +1 -0
- package/src/lib/checkCrossFeatureImports.d.ts +8 -0
- package/src/lib/checkCrossFeatureImports.js +31 -0
- package/src/lib/checkCrossFeatureImports.js.map +1 -0
- package/src/lib/checkSharedComponents.d.ts +8 -0
- package/src/lib/checkSharedComponents.js +48 -0
- package/src/lib/checkSharedComponents.js.map +1 -0
- package/src/lib/findCommonPathsPrefix.d.ts +2 -0
- package/src/lib/findCommonPathsPrefix.js +22 -0
- package/src/lib/findCommonPathsPrefix.js.map +1 -0
- package/src/lib/formatMessages.d.ts +9 -0
- package/src/lib/formatMessages.js +9 -0
- package/src/lib/formatMessages.js.map +1 -0
- package/src/lib/getCruiseResult.d.ts +7 -0
- package/src/lib/getCruiseResult.js +14 -0
- package/src/lib/getCruiseResult.js.map +1 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"forbidden": [
|
|
3
|
+
{
|
|
4
|
+
"name": "no-orphans",
|
|
5
|
+
"from": {
|
|
6
|
+
"orphan": true
|
|
7
|
+
},
|
|
8
|
+
"to": {}
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"options": {
|
|
12
|
+
"doNotFollow": {
|
|
13
|
+
"path": [
|
|
14
|
+
"node_modules",
|
|
15
|
+
"(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$",
|
|
16
|
+
"[.]d[.]ts$",
|
|
17
|
+
"(^|/)tsconfig[.]json$"
|
|
18
|
+
],
|
|
19
|
+
"dependencyTypes": ["npm-no-pkg", "npm-unknown"]
|
|
20
|
+
},
|
|
21
|
+
"exclude": {
|
|
22
|
+
"path": ["node_modules", "(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$", "[.]d[.]ts$", "(^|/)tsconfig[.]json$"]
|
|
23
|
+
},
|
|
24
|
+
"tsPreCompilationDeps": true,
|
|
25
|
+
"enhancedResolveOptions": {
|
|
26
|
+
"exportsFields": ["exports"],
|
|
27
|
+
"conditionNames": ["import", "require", "node", "default"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. See
|
|
4
|
+
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [9.5.2](https://github.com/leancodepl/js_corelibrary/compare/v9.5.1...v9.5.2) (2025-08-13)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- add missing new line
|
|
11
|
+
([e8ce9e1](https://github.com/leancodepl/js_corelibrary/commit/e8ce9e1836981fe68ddd8095e7c7f874ca93b750))
|
|
12
|
+
- adjust linting file
|
|
13
|
+
([b05100c](https://github.com/leancodepl/js_corelibrary/commit/b05100cb6264c4bd6f33eb7434cd34610a191d6b))
|
|
14
|
+
- adjust readme
|
|
15
|
+
([51cab7f](https://github.com/leancodepl/js_corelibrary/commit/51cab7fdf3d937a62bb39c5b637b01fa8bb71954))
|
|
16
|
+
- adjust readme
|
|
17
|
+
([7be4027](https://github.com/leancodepl/js_corelibrary/commit/7be4027d466889a0474b183f091b2e8431c50b2a))
|
|
18
|
+
- bring back output encoding
|
|
19
|
+
([2e45613](https://github.com/leancodepl/js_corelibrary/commit/2e456135762ca3c52e5a277328b39f34704868ae))
|
|
20
|
+
- consoleSpy types
|
|
21
|
+
([82ec3dd](https://github.com/leancodepl/js_corelibrary/commit/82ec3ddc1442bc9ea977cf0faec6ff20d003109c))
|
|
22
|
+
- enhance regex
|
|
23
|
+
([e18fe68](https://github.com/leancodepl/js_corelibrary/commit/e18fe6822a36792b74c98250b916139ee841cb13))
|
|
24
|
+
- extensions ([98606c9](https://github.com/leancodepl/js_corelibrary/commit/98606c98403c6151b97c22c1e8a1b262a073474e))
|
|
25
|
+
- make tests compatible with es modules
|
|
26
|
+
([7df498a](https://github.com/leancodepl/js_corelibrary/commit/7df498abef57ee133ed666ca4c29dd9ec953ae65))
|
|
27
|
+
- no-orphans tests
|
|
28
|
+
([901d3a4](https://github.com/leancodepl/js_corelibrary/commit/901d3a4150bead4899993d8d6994facb4e103f91))
|
|
29
|
+
- remove type module
|
|
30
|
+
([cfc0baa](https://github.com/leancodepl/js_corelibrary/commit/cfc0baa1ee3f7da29628b8d29cf6a32b11ffb78c))
|
|
31
|
+
- test project.json target
|
|
32
|
+
([75ee897](https://github.com/leancodepl/js_corelibrary/commit/75ee897ea1930a4b4e9283141c7c8aaa4f1c4240))
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
- create cross feature imports check
|
|
37
|
+
([53d0bb1](https://github.com/leancodepl/js_corelibrary/commit/53d0bb19067fc5bc1212ae1ba9fe536e2d664a4c))
|
|
38
|
+
- create folder structure dependency cruiser rules
|
|
39
|
+
([6c8b90c](https://github.com/leancodepl/js_corelibrary/commit/6c8b90c15fec9099478d189bf2261c9f0e6b3189))
|
|
40
|
+
- create folder structure dependency cruiser rules
|
|
41
|
+
([673bc11](https://github.com/leancodepl/js_corelibrary/commit/673bc1107d73b522c3c77d81b53f35ce92008532))
|
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# @leancodepl/folder-structure-cruiser
|
|
2
|
+
|
|
3
|
+
Validates folder structure rules and enforces cross-feature import restrictions in TypeScript/JavaScript projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install -D dependency-cruiser @leancodepl/folder-structure-cruiser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### `validateCrossFeatureImports(cruiseParams)`
|
|
14
|
+
|
|
15
|
+
Validates cross-feature nested imports according to folder structure rules.
|
|
16
|
+
|
|
17
|
+
**Parameters:**
|
|
18
|
+
|
|
19
|
+
- `cruiseParams: CruiseParams` - Configuration parameters for the dependency analysis
|
|
20
|
+
- `directory: string` - Directory to analyze. Defaults to `".*"` if not provided
|
|
21
|
+
- `configPath: string` - Path to the dependency-cruiser configuration file (e.g., `.dependency-cruiser.js`)
|
|
22
|
+
- `tsConfigPath: string` - Optional path to TypeScript configuration file for enhanced type resolution
|
|
23
|
+
- `webpackConfigPath?: string` - Optional path to webpack configuration file for webpack alias resolution
|
|
24
|
+
|
|
25
|
+
**Returns:** `Promise<void>` - The function doesn't return a value but outputs results to console
|
|
26
|
+
|
|
27
|
+
**Throws:** `Error` - Throws an error if the dependency analysis fails or configuration is invalid
|
|
28
|
+
|
|
29
|
+
### `validateSharedComponent(cruiseParams)`
|
|
30
|
+
|
|
31
|
+
Validates if shared components are located at the first shared level.
|
|
32
|
+
|
|
33
|
+
**Parameters:**
|
|
34
|
+
|
|
35
|
+
- `cruiseParams: CruiseParams` - Configuration parameters for the dependency analysis
|
|
36
|
+
- `directory: string` - Directory to analyze. Defaults to `".*"` if not provided
|
|
37
|
+
- `configPath: string` - Path to the dependency-cruiser configuration file (e.g., `.dependency-cruiser.js`)
|
|
38
|
+
- `tsConfigPath: string` - Optional path to TypeScript configuration file for enhanced type resolution
|
|
39
|
+
- `webpackConfigPath?: string` - Optional path to webpack configuration file for webpack alias resolution
|
|
40
|
+
|
|
41
|
+
**Returns:** `Promise<void>` - The function doesn't return a value but outputs results to console
|
|
42
|
+
|
|
43
|
+
**Throws:** `Error` - Throws an error if the dependency analysis fails or configuration is invalid
|
|
44
|
+
|
|
45
|
+
## Usage Examples
|
|
46
|
+
|
|
47
|
+
### Cross-Feature Import Validation
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
# Basic validation
|
|
51
|
+
npx @leancodepl/folder-structure-cruiser validate-cross-feature-imports --directory "packages/admin" --config "./.dependency-cruiser.json"
|
|
52
|
+
|
|
53
|
+
# With both TypeScript and webpack config
|
|
54
|
+
npx @leancodepl/folder-structure-cruiser validate-cross-feature-imports --directory "packages/admin" --config "./.dependency-cruiser.json" --tsConfig "./tsconfig.base.json" --webpackConfig "./webpack.config.js"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Shared Component Validation
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
# Basic validation
|
|
61
|
+
npx @leancodepl/folder-structure-cruiser validate-shared-components --directory "packages/admin" --config "./.dependency-cruiser.json"
|
|
62
|
+
|
|
63
|
+
# With both TypeScript and webpack config
|
|
64
|
+
npx @leancodepl/folder-structure-cruiser validate-shared-components --directory "packages/admin" --config "./.dependency-cruiser.json" --tsConfig "./tsconfig.base.json" --webpackConfig "./webpack.config.js"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### No-Orphan Rule Validation
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
# Use dependency-cruiser directly for no-orphan rule
|
|
71
|
+
npx depcruise --config ./.dependency-cruiser.json ./packages/admin/.*
|
|
72
|
+
|
|
73
|
+
# With TypeScript config
|
|
74
|
+
npx depcruise --ts-config ./tsconfig.base.json --config ./.dependency-cruiser.json ./packages/admin/.*
|
|
75
|
+
|
|
76
|
+
# With both TypeScript and webpack config
|
|
77
|
+
npx depcruise --ts-config ./tsconfig.base.json --webpack-config ./webpack.config.js --config ./.dependency-cruiser.json ./packages/admin/.*
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Configuration:**
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"extends": ["@leancodepl/folder-structure-cruiser/.dependency-cruiser.json"]
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Features
|
|
89
|
+
|
|
90
|
+
### Cross-Feature Import Rules
|
|
91
|
+
|
|
92
|
+
Imports are allowed only if they meet one of these conditions:
|
|
93
|
+
|
|
94
|
+
1. **Inside module directory**: Import is within the same module
|
|
95
|
+
- ✅ `src/feature1/subfeature1/ComponentA` → `src/feature1/subfeature1/ComponentB`
|
|
96
|
+
|
|
97
|
+
2. **Sibling's immediate child**: Import is from an immediate sibling's or ancestors siblings' child
|
|
98
|
+
- ✅ `src/feature1/subfeature1/ComponentA` → `src/feature1/subfeature2/ComponentB`
|
|
99
|
+
|
|
100
|
+
### Shared Component Detection
|
|
101
|
+
|
|
102
|
+
Identifies components that should be moved to shared levels when:
|
|
103
|
+
|
|
104
|
+
- Multiple dependents use the same component
|
|
105
|
+
- The component is not positioned at the first shared level among its dependents
|
|
106
|
+
|
|
107
|
+
## Configuration
|
|
108
|
+
|
|
109
|
+
Create a `.dependency-cruiser.json` file in your project root:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"extends": ["@leancodepl/folder-structure-cruiser/.dependency-cruiser.json"]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This configuration serves as a base config that can be extended with your own rules.
|
|
118
|
+
|
|
119
|
+
## Nx Configuration
|
|
120
|
+
|
|
121
|
+
Configure folder-structure-cruiser commands as Nx target in your `project.json`. Example configuration:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
"folder-structure": {
|
|
125
|
+
"executor": "nx:run-commands",
|
|
126
|
+
"defaultConfiguration": "validate-cross-feature-imports",
|
|
127
|
+
"configurations": {
|
|
128
|
+
"validate-cross-feature-imports": {
|
|
129
|
+
"command": "npx @leancodepl/folder-structure-cruiser validate-cross-feature-imports --config ./.dependency-cruiser.json --ts-config ./tsconfig.base.json --directory '{projectRoot}'"
|
|
130
|
+
},
|
|
131
|
+
"validate-shared-components": {
|
|
132
|
+
"command": "npx @leancodepl/folder-structure-cruiser validate-shared-components --config ./.dependency-cruiser.json --ts-config ./tsconfig.base.json --directory '{projectRoot}'"
|
|
133
|
+
},
|
|
134
|
+
"validate-no-orphans": {
|
|
135
|
+
"command": "npx depcruise --ts-config ./tsconfig.base.json --config ./.dependency-cruiser.json '{projectRoot}/.*'"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@leancodepl/folder-structure-cruiser",
|
|
3
|
+
"version": "9.5.2",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"folder-structure-cruiser": "src/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"commander": "^14.0.0",
|
|
11
|
+
"picocolors": "^1.1.1"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"dependency-cruiser": "^17.0.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@jest/globals": "^30.0.5",
|
|
18
|
+
"jest": "^29.0.0"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public",
|
|
22
|
+
"registry": "https://registry.npmjs.org/"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.0.0"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/leancodepl/js_corelibrary.git",
|
|
30
|
+
"directory": "packages/linters/folder-structure-cruiser"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/leancodepl/js_corelibrary",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/leancodepl/js_corelibrary/issues"
|
|
35
|
+
},
|
|
36
|
+
"description": "Dependency-cruiser configuration for enforcing folder structure rules. Requires dependency-cruiser to be installed in your project.",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"dependency-cruiser",
|
|
39
|
+
"folder-structure",
|
|
40
|
+
"import-rules",
|
|
41
|
+
"linting",
|
|
42
|
+
"javascript",
|
|
43
|
+
"typescript",
|
|
44
|
+
"leancode"
|
|
45
|
+
],
|
|
46
|
+
"author": {
|
|
47
|
+
"name": "LeanCode",
|
|
48
|
+
"url": "https://leancode.co"
|
|
49
|
+
},
|
|
50
|
+
"sideEffects": false,
|
|
51
|
+
"types": "./src/index.d.ts",
|
|
52
|
+
"module": "./src/index.js",
|
|
53
|
+
"main": "./src/index.js"
|
|
54
|
+
}
|
package/src/bin.d.ts
ADDED
package/src/bin.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { validateCrossFeatureImports } from "./commands/validateCrossFeatureImports.js";
|
|
4
|
+
import { validateSharedComponent } from "./commands/validateSharedComponent.js";
|
|
5
|
+
program.name("folder-structure-cruiser").description("CLI tool for validating folder structure rules");
|
|
6
|
+
program
|
|
7
|
+
.command("validate-shared-components")
|
|
8
|
+
.description("Validate if shared components are located at the first shared level")
|
|
9
|
+
.option("-d, --directory <dir>", "Directory to analyze", ".")
|
|
10
|
+
.option("-c, --config <path_to_config>", "Path to config file")
|
|
11
|
+
.option("-t, --tsConfig <path_to_ts_config>", "Path to ts config file")
|
|
12
|
+
.option("-w, --webpackConfig <path_to_webpack_config>", "Path to webpack config file")
|
|
13
|
+
.action(async (options) => {
|
|
14
|
+
const directories = options.directory ? [options.directory] : [".*"];
|
|
15
|
+
const configPath = options.config ?? "";
|
|
16
|
+
const tsConfigPath = options.tsConfig;
|
|
17
|
+
const webpackConfigPath = options.webpackConfig;
|
|
18
|
+
await validateSharedComponent({ directories, configPath, tsConfigPath, webpackConfigPath });
|
|
19
|
+
});
|
|
20
|
+
program
|
|
21
|
+
.command("validate-cross-feature-imports")
|
|
22
|
+
.description("Validate if cross-feature nested imports are allowed")
|
|
23
|
+
.option("-d, --directory <dir>", "Directory to analyze", ".")
|
|
24
|
+
.option("-c, --config <path_to_config>", "Path to config file")
|
|
25
|
+
.option("-t, --tsConfig <path_to_ts_config>", "Path to ts config file")
|
|
26
|
+
.option("-w, --webpackConfig <path_to_webpack_config>", "Path to webpack config file")
|
|
27
|
+
.action(async (options) => {
|
|
28
|
+
const directories = options.directory ? [options.directory] : [".*"];
|
|
29
|
+
const configPath = options.config ?? "";
|
|
30
|
+
const tsConfigPath = options.tsConfig;
|
|
31
|
+
const webpackConfigPath = options.webpackConfig;
|
|
32
|
+
await validateCrossFeatureImports({ directories, configPath, tsConfigPath, webpackConfigPath });
|
|
33
|
+
});
|
|
34
|
+
program.parse();
|
|
35
|
+
//# sourceMappingURL=bin.js.map
|
package/src/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../../../packages/folder-structure-cruiser/src/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAA;AACvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAA;AAEtG,OAAO;KACJ,OAAO,CAAC,4BAA4B,CAAC;KACrC,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,uBAAuB,EAAE,sBAAsB,EAAE,GAAG,CAAC;KAC5D,MAAM,CAAC,+BAA+B,EAAE,qBAAqB,CAAC;KAC9D,MAAM,CAAC,oCAAoC,EAAE,wBAAwB,CAAC;KACtE,MAAM,CAAC,8CAA8C,EAAE,6BAA6B,CAAC;KAErF,MAAM,CAAC,KAAK,EAAC,OAAO,EAAC,EAAE;IACtB,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACpE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;IACvC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAA;IACrC,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAA;IAE/C,MAAM,uBAAuB,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,CAAA;AAC7F,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,gCAAgC,CAAC;KACzC,WAAW,CAAC,sDAAsD,CAAC;KACnE,MAAM,CAAC,uBAAuB,EAAE,sBAAsB,EAAE,GAAG,CAAC;KAC5D,MAAM,CAAC,+BAA+B,EAAE,qBAAqB,CAAC;KAC9D,MAAM,CAAC,oCAAoC,EAAE,wBAAwB,CAAC;KACtE,MAAM,CAAC,8CAA8C,EAAE,6BAA6B,CAAC;KACrF,MAAM,CAAC,KAAK,EAAC,OAAO,EAAC,EAAE;IACtB,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACpE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;IACvC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAA;IACrC,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAA;IAE/C,MAAM,2BAA2B,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,CAAA;AACjG,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { CruiseParams } from "../lib/getCruiseResult.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validates cross-feature nested imports according to folder structure rules.
|
|
4
|
+
*
|
|
5
|
+
* This function analyzes the codebase using dependency-cruiser to identify violations
|
|
6
|
+
* of cross-feature import restrictions. It checks if modules with multiple dependents
|
|
7
|
+
* are properly structured to avoid cross-feature nested imports that violate the
|
|
8
|
+
* established folder structure rules.
|
|
9
|
+
*
|
|
10
|
+
* The function will output violations to the console, showing which modules have
|
|
11
|
+
* cross-feature import issues that need to be resolved.
|
|
12
|
+
*
|
|
13
|
+
* @param cruiseParams - Configuration parameters for the dependency analysis
|
|
14
|
+
* @param cruiseParams.directories - Array of directory paths to analyze. Defaults to [".*"] if not provided
|
|
15
|
+
* @param cruiseParams.configPath - Path to the dependency-cruiser configuration file (e.g., .dependency-cruiser.js)
|
|
16
|
+
* @param cruiseParams.tsConfigPath - Optional path to TypeScript configuration file for enhanced type resolution
|
|
17
|
+
* @param cruiseParams.webpackConfigPath - Optional path to webpack configuration file for webpack alias resolution
|
|
18
|
+
*
|
|
19
|
+
* @returns Promise<void> - The function doesn't return a value but outputs results to console
|
|
20
|
+
*
|
|
21
|
+
* @throws {Error} - Throws an error if the dependency analysis fails or configuration is invalid
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Basic usage with default settings
|
|
26
|
+
* await validateCrossFeatureImports({
|
|
27
|
+
* directories: ["src"],
|
|
28
|
+
* configPath: ".dependency-cruiser.js",
|
|
29
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Advanced usage with webpack support
|
|
33
|
+
* await validateCrossFeatureImports({
|
|
34
|
+
* directories: ["src", "packages"],
|
|
35
|
+
* configPath: ".dependency-cruiser.js",
|
|
36
|
+
* tsConfigPath: "./tsconfig.base.json",
|
|
37
|
+
* webpackConfigPath: "./webpack.config.js"
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // Using in a build script
|
|
44
|
+
* import { validateCrossFeatureImports } from "@leancodepl/folder-structure-cruiser";
|
|
45
|
+
*
|
|
46
|
+
* try {
|
|
47
|
+
* await validateCrossFeatureImports({
|
|
48
|
+
* directories: ["src"],
|
|
49
|
+
* configPath: ".dependency-cruiser.js",
|
|
50
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
51
|
+
* });
|
|
52
|
+
* console.log("✅ Cross-feature import validation passed");
|
|
53
|
+
* } catch (error) {
|
|
54
|
+
* console.error("❌ Cross-feature import validation failed:", error);
|
|
55
|
+
* process.exit(1);
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function validateCrossFeatureImports(cruiseParams: CruiseParams): Promise<void>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { checkCrossFeatureImports } from "../lib/checkCrossFeatureImports.js";
|
|
3
|
+
import { formatMessages } from "../lib/formatMessages.js";
|
|
4
|
+
import { getCruiseResult } from "../lib/getCruiseResult.js";
|
|
5
|
+
const { red } = pc;
|
|
6
|
+
/**
|
|
7
|
+
* Validates cross-feature nested imports according to folder structure rules.
|
|
8
|
+
*
|
|
9
|
+
* This function analyzes the codebase using dependency-cruiser to identify violations
|
|
10
|
+
* of cross-feature import restrictions. It checks if modules with multiple dependents
|
|
11
|
+
* are properly structured to avoid cross-feature nested imports that violate the
|
|
12
|
+
* established folder structure rules.
|
|
13
|
+
*
|
|
14
|
+
* The function will output violations to the console, showing which modules have
|
|
15
|
+
* cross-feature import issues that need to be resolved.
|
|
16
|
+
*
|
|
17
|
+
* @param cruiseParams - Configuration parameters for the dependency analysis
|
|
18
|
+
* @param cruiseParams.directories - Array of directory paths to analyze. Defaults to [".*"] if not provided
|
|
19
|
+
* @param cruiseParams.configPath - Path to the dependency-cruiser configuration file (e.g., .dependency-cruiser.js)
|
|
20
|
+
* @param cruiseParams.tsConfigPath - Optional path to TypeScript configuration file for enhanced type resolution
|
|
21
|
+
* @param cruiseParams.webpackConfigPath - Optional path to webpack configuration file for webpack alias resolution
|
|
22
|
+
*
|
|
23
|
+
* @returns Promise<void> - The function doesn't return a value but outputs results to console
|
|
24
|
+
*
|
|
25
|
+
* @throws {Error} - Throws an error if the dependency analysis fails or configuration is invalid
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // Basic usage with default settings
|
|
30
|
+
* await validateCrossFeatureImports({
|
|
31
|
+
* directories: ["src"],
|
|
32
|
+
* configPath: ".dependency-cruiser.js",
|
|
33
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Advanced usage with webpack support
|
|
37
|
+
* await validateCrossFeatureImports({
|
|
38
|
+
* directories: ["src", "packages"],
|
|
39
|
+
* configPath: ".dependency-cruiser.js",
|
|
40
|
+
* tsConfigPath: "./tsconfig.base.json",
|
|
41
|
+
* webpackConfigPath: "./webpack.config.js"
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Using in a build script
|
|
48
|
+
* import { validateCrossFeatureImports } from "@leancodepl/folder-structure-cruiser";
|
|
49
|
+
*
|
|
50
|
+
* try {
|
|
51
|
+
* await validateCrossFeatureImports({
|
|
52
|
+
* directories: ["src"],
|
|
53
|
+
* configPath: ".dependency-cruiser.js",
|
|
54
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
55
|
+
* });
|
|
56
|
+
* console.log("✅ Cross-feature import validation passed");
|
|
57
|
+
* } catch (error) {
|
|
58
|
+
* console.error("❌ Cross-feature import validation failed:", error);
|
|
59
|
+
* process.exit(1);
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export async function validateCrossFeatureImports(cruiseParams) {
|
|
64
|
+
try {
|
|
65
|
+
const cruiseResult = await getCruiseResult(cruiseParams);
|
|
66
|
+
const { messages: errorMessages, totalCruised } = checkCrossFeatureImports(cruiseResult);
|
|
67
|
+
if (errorMessages.length === 0) {
|
|
68
|
+
console.info("\n✅ No issues found!");
|
|
69
|
+
}
|
|
70
|
+
if (errorMessages.length > 0) {
|
|
71
|
+
const messages = formatMessages(errorMessages);
|
|
72
|
+
console.error(messages.join("\n"));
|
|
73
|
+
console.error(`\n${red(`x Found ${errorMessages.length} violations(s). ${totalCruised} modules cruised.`)}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (pError) {
|
|
77
|
+
console.error(pError);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=validateCrossFeatureImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateCrossFeatureImports.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/commands/validateCrossFeatureImports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAgB,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEzE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;AAElB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,YAA0B;IAC1E,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,CAAA;QAExD,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,wBAAwB,CAAC,YAAY,CAAC,CAAA;QAExF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;QACtC,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,cAAc,CAAC,aAAa,CAAC,CAAA;YAC9C,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YAClC,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,WAAW,aAAa,CAAC,MAAM,mBAAmB,YAAY,mBAAmB,CAAC,EAAE,CAAC,CAAA;QAC9G,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { CruiseParams } from "../lib/getCruiseResult.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validates if shared components are located at the first shared level.
|
|
4
|
+
*
|
|
5
|
+
* This function analyzes the codebase using dependency-cruiser to identify components
|
|
6
|
+
* that should be moved to shared levels. It checks if components that are used across
|
|
7
|
+
* multiple features are properly placed at the appropriate shared level in the folder
|
|
8
|
+
* structure, following the established architectural patterns.
|
|
9
|
+
*
|
|
10
|
+
* The function will output recommendations to the console, showing which components
|
|
11
|
+
* should be moved to shared levels for better code organization and reusability.
|
|
12
|
+
*
|
|
13
|
+
* @param cruiseParams - Configuration parameters for the dependency analysis
|
|
14
|
+
* @param cruiseParams.directories - Array of directory paths to analyze. Defaults to [".*"] if not provided
|
|
15
|
+
* @param cruiseParams.configPath - Path to the dependency-cruiser configuration file (e.g., .dependency-cruiser.js)
|
|
16
|
+
* @param cruiseParams.tsConfigPath - Optional path to TypeScript configuration file for enhanced type resolution
|
|
17
|
+
* @param cruiseParams.webpackConfigPath - Optional path to webpack configuration file for webpack alias resolution
|
|
18
|
+
*
|
|
19
|
+
* @returns Promise<void> - The function doesn't return a value but outputs results to console
|
|
20
|
+
*
|
|
21
|
+
* @throws {Error} - Throws an error if the dependency analysis fails or configuration is invalid
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Basic usage with default settings
|
|
26
|
+
* await validateSharedComponent({
|
|
27
|
+
* directories: ["src"],
|
|
28
|
+
* configPath: ".dependency-cruiser.js",
|
|
29
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Advanced usage with webpack support
|
|
33
|
+
* await validateSharedComponent({
|
|
34
|
+
* directories: ["src", "packages"],
|
|
35
|
+
* configPath: ".dependency-cruiser.js",
|
|
36
|
+
* tsConfigPath: "./tsconfig.base.json",
|
|
37
|
+
* webpackConfigPath: "./webpack.config.js"
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // Using in a build script
|
|
44
|
+
* import { validateSharedComponent } from "@leancodepl/folder-structure-cruiser";
|
|
45
|
+
*
|
|
46
|
+
* try {
|
|
47
|
+
* await validateSharedComponent({
|
|
48
|
+
* directories: ["src"],
|
|
49
|
+
* configPath: ".dependency-cruiser.js",
|
|
50
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
51
|
+
* });
|
|
52
|
+
* console.log("✅ Shared component validation passed");
|
|
53
|
+
* } catch (error) {
|
|
54
|
+
* console.error("❌ Shared component validation failed:", error);
|
|
55
|
+
* process.exit(1);
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function validateSharedComponent(cruiseParams: CruiseParams): Promise<void>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { checkSharedComponents } from "../lib/checkSharedComponents.js";
|
|
2
|
+
import { formatMessages } from "../lib/formatMessages.js";
|
|
3
|
+
import { getCruiseResult } from "../lib/getCruiseResult.js";
|
|
4
|
+
/**
|
|
5
|
+
* Validates if shared components are located at the first shared level.
|
|
6
|
+
*
|
|
7
|
+
* This function analyzes the codebase using dependency-cruiser to identify components
|
|
8
|
+
* that should be moved to shared levels. It checks if components that are used across
|
|
9
|
+
* multiple features are properly placed at the appropriate shared level in the folder
|
|
10
|
+
* structure, following the established architectural patterns.
|
|
11
|
+
*
|
|
12
|
+
* The function will output recommendations to the console, showing which components
|
|
13
|
+
* should be moved to shared levels for better code organization and reusability.
|
|
14
|
+
*
|
|
15
|
+
* @param cruiseParams - Configuration parameters for the dependency analysis
|
|
16
|
+
* @param cruiseParams.directories - Array of directory paths to analyze. Defaults to [".*"] if not provided
|
|
17
|
+
* @param cruiseParams.configPath - Path to the dependency-cruiser configuration file (e.g., .dependency-cruiser.js)
|
|
18
|
+
* @param cruiseParams.tsConfigPath - Optional path to TypeScript configuration file for enhanced type resolution
|
|
19
|
+
* @param cruiseParams.webpackConfigPath - Optional path to webpack configuration file for webpack alias resolution
|
|
20
|
+
*
|
|
21
|
+
* @returns Promise<void> - The function doesn't return a value but outputs results to console
|
|
22
|
+
*
|
|
23
|
+
* @throws {Error} - Throws an error if the dependency analysis fails or configuration is invalid
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Basic usage with default settings
|
|
28
|
+
* await validateSharedComponent({
|
|
29
|
+
* directories: ["src"],
|
|
30
|
+
* configPath: ".dependency-cruiser.js",
|
|
31
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Advanced usage with webpack support
|
|
35
|
+
* await validateSharedComponent({
|
|
36
|
+
* directories: ["src", "packages"],
|
|
37
|
+
* configPath: ".dependency-cruiser.js",
|
|
38
|
+
* tsConfigPath: "./tsconfig.base.json",
|
|
39
|
+
* webpackConfigPath: "./webpack.config.js"
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Using in a build script
|
|
46
|
+
* import { validateSharedComponent } from "@leancodepl/folder-structure-cruiser";
|
|
47
|
+
*
|
|
48
|
+
* try {
|
|
49
|
+
* await validateSharedComponent({
|
|
50
|
+
* directories: ["src"],
|
|
51
|
+
* configPath: ".dependency-cruiser.js",
|
|
52
|
+
* tsConfigPath: "./tsconfig.base.json"
|
|
53
|
+
* });
|
|
54
|
+
* console.log("✅ Shared component validation passed");
|
|
55
|
+
* } catch (error) {
|
|
56
|
+
* console.error("❌ Shared component validation failed:", error);
|
|
57
|
+
* process.exit(1);
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export async function validateSharedComponent(cruiseParams) {
|
|
62
|
+
try {
|
|
63
|
+
const cruiseResult = await getCruiseResult(cruiseParams);
|
|
64
|
+
const { messages: infoMessages, totalCruised } = checkSharedComponents(cruiseResult);
|
|
65
|
+
if (infoMessages.length === 0) {
|
|
66
|
+
console.info("\n✅ No issues found!");
|
|
67
|
+
}
|
|
68
|
+
if (infoMessages.length > 0) {
|
|
69
|
+
const messages = formatMessages(infoMessages);
|
|
70
|
+
console.info(messages.join("\n"));
|
|
71
|
+
console.info(`\nx Found ${infoMessages.length} violations(s). ${totalCruised} modules cruised.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (pError) {
|
|
75
|
+
console.error(pError);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=validateSharedComponent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateSharedComponent.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/commands/validateSharedComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAgB,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,YAA0B;IACtE,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,CAAA;QAExD,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAA;QAEpF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;QACtC,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,cAAc,CAAC,YAAY,CAAC,CAAA;YAC7C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YACjC,OAAO,CAAC,IAAI,CAAC,aAAa,YAAY,CAAC,MAAM,mBAAmB,YAAY,mBAAmB,CAAC,CAAA;QAClG,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;AACH,CAAC"}
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/folder-structure-cruiser/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2CAA2C,CAAA;AACzD,cAAc,uCAAuC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IReporterOutput } from "dependency-cruiser";
|
|
2
|
+
import { Message } from "./formatMessages.js";
|
|
3
|
+
type CheckResult = {
|
|
4
|
+
messages: Message[];
|
|
5
|
+
totalCruised: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function checkCrossFeatureImports(result: IReporterOutput): CheckResult;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { findCommonPathsPrefixLength } from "./findCommonPathsPrefix.js";
|
|
2
|
+
export function checkCrossFeatureImports(result) {
|
|
3
|
+
const output = typeof result.output === "object" ? result.output : undefined;
|
|
4
|
+
const modules = output?.modules ?? [];
|
|
5
|
+
const errorMessages = [];
|
|
6
|
+
for (const module of modules) {
|
|
7
|
+
if (module.coreModule) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
const dependencies = module.dependencies || [];
|
|
11
|
+
const modulePath = module.source.split("/");
|
|
12
|
+
dependencies.forEach(dependency => {
|
|
13
|
+
const dependencyPath = dependency.resolved.split("/");
|
|
14
|
+
const commonPrefixPathLength = findCommonPathsPrefixLength([modulePath, dependencyPath]);
|
|
15
|
+
if (!commonPrefixPathLength ||
|
|
16
|
+
(commonPrefixPathLength < modulePath.length && dependencyPath.length > commonPrefixPathLength + 2)) {
|
|
17
|
+
errorMessages.push({
|
|
18
|
+
source: module.source,
|
|
19
|
+
target: dependency.resolved,
|
|
20
|
+
rule: "cross-feature-nested-imports",
|
|
21
|
+
severity: "error",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
messages: errorMessages,
|
|
28
|
+
totalCruised: output?.summary.totalCruised ?? 0,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=checkCrossFeatureImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkCrossFeatureImports.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/lib/checkCrossFeatureImports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAKxE,MAAM,UAAU,wBAAwB,CAAC,MAAuB;IAC9D,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5E,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAA;IAErC,MAAM,aAAa,GAAc,EAAE,CAAA;IAEnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,SAAQ;QACV,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,EAAE,CAAA;QAE9C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAE3C,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAChC,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACrD,MAAM,sBAAsB,GAAG,2BAA2B,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAA;YAExF,IACE,CAAC,sBAAsB;gBACvB,CAAC,sBAAsB,GAAG,UAAU,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,GAAG,sBAAsB,GAAG,CAAC,CAAC,EAClG,CAAC;gBACD,aAAa,CAAC,IAAI,CAAC;oBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,MAAM,EAAE,UAAU,CAAC,QAAQ;oBAC3B,IAAI,EAAE,8BAA8B;oBACpC,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,IAAI,CAAC;KAChD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IReporterOutput } from "dependency-cruiser";
|
|
2
|
+
import { Message } from "./formatMessages.js";
|
|
3
|
+
type CheckResult = {
|
|
4
|
+
messages: Message[];
|
|
5
|
+
totalCruised: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function checkSharedComponents(result: IReporterOutput): CheckResult;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { findCommonPathsPrefix, findCommonPathsPrefixLength } from "./findCommonPathsPrefix.js";
|
|
2
|
+
function isIndexFileProperlyPositioned(pathParts, commonDependentPrefix, commonPrefixLength) {
|
|
3
|
+
const fileName = pathParts.at(-1) ?? "";
|
|
4
|
+
if (!/index\.(tsx?|jsx?|ts|js)$/.test(fileName)) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const parentFolder = pathParts.at(-3) ?? "";
|
|
8
|
+
const expectedParentFolder = commonDependentPrefix.at(-1);
|
|
9
|
+
return parentFolder === expectedParentFolder && commonPrefixLength === pathParts.length - 2;
|
|
10
|
+
}
|
|
11
|
+
export function checkSharedComponents(result) {
|
|
12
|
+
const output = typeof result.output === "object" ? result.output : undefined;
|
|
13
|
+
const modules = output?.modules ?? [];
|
|
14
|
+
const infoMessages = [];
|
|
15
|
+
for (const module of modules) {
|
|
16
|
+
if (module.coreModule) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const dependents = module.dependents || [];
|
|
20
|
+
if (dependents.length <= 1) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const pathParts = module.source.split("/");
|
|
24
|
+
const pathPartsLength = pathParts.length;
|
|
25
|
+
if (pathPartsLength <= 2) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const dependentPathParts = dependents.map(dep => dep.split("/"));
|
|
29
|
+
const commonDependentPrefix = findCommonPathsPrefix(dependentPathParts);
|
|
30
|
+
const commonPrefixLength = findCommonPathsPrefixLength([pathParts, commonDependentPrefix]);
|
|
31
|
+
if (isIndexFileProperlyPositioned(pathParts, commonDependentPrefix, commonPrefixLength)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (commonPrefixLength < pathPartsLength - 1) {
|
|
35
|
+
infoMessages.push({
|
|
36
|
+
source: module.source,
|
|
37
|
+
target: commonDependentPrefix.join("/"),
|
|
38
|
+
rule: "not-shared-level",
|
|
39
|
+
severity: "info",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
messages: infoMessages,
|
|
45
|
+
totalCruised: output?.summary.totalCruised ?? 0,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=checkSharedComponents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkSharedComponents.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/lib/checkSharedComponents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAK/F,SAAS,6BAA6B,CACpC,SAAmB,EACnB,qBAA+B,EAC/B,kBAA0B;IAE1B,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAEvC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,YAAY,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3C,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAEzD,OAAO,YAAY,KAAK,oBAAoB,IAAI,kBAAkB,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,CAAA;AAC7F,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5E,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAA;IACrC,MAAM,YAAY,GAAc,EAAE,CAAA;IAElC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,SAAQ;QACV,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAA;QAE1C,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC3B,SAAQ;QACV,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC1C,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAA;QAExC,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;YACzB,SAAQ;QACV,CAAC;QAED,MAAM,kBAAkB,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;QAChE,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;QAEvE,MAAM,kBAAkB,GAAG,2BAA2B,CAAC,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC,CAAA;QAE1F,IAAI,6BAA6B,CAAC,SAAS,EAAE,qBAAqB,EAAE,kBAAkB,CAAC,EAAE,CAAC;YACxF,SAAQ;QACV,CAAC;QAED,IAAI,kBAAkB,GAAG,eAAe,GAAG,CAAC,EAAE,CAAC;YAC7C,YAAY,CAAC,IAAI,CAAC;gBAChB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC;gBACvC,IAAI,EAAE,kBAAkB;gBACxB,QAAQ,EAAE,MAAM;aACjB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,IAAI,CAAC;KAChD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function findCommonPathsPrefix(paths) {
|
|
2
|
+
if (paths.length === 0)
|
|
3
|
+
return [];
|
|
4
|
+
if (paths.length === 1)
|
|
5
|
+
return paths[0];
|
|
6
|
+
const commonPrefix = [];
|
|
7
|
+
const minLength = Math.min(...paths.map(path => path.length));
|
|
8
|
+
for (let i = 0; i < minLength; i++) {
|
|
9
|
+
const segment = paths[0][i];
|
|
10
|
+
if (paths.every(path => path[i] === segment)) {
|
|
11
|
+
commonPrefix.push(segment);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return commonPrefix;
|
|
18
|
+
}
|
|
19
|
+
export function findCommonPathsPrefixLength(paths) {
|
|
20
|
+
return findCommonPathsPrefix(paths).length;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=findCommonPathsPrefix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findCommonPathsPrefix.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/lib/findCommonPathsPrefix.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,KAAiB;IACrD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAE7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC3B,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,EAAE,CAAC;YAC7C,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,MAAK;QACP,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAiB;IAC3D,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;AAC5C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
const { blue, bold, red } = pc;
|
|
3
|
+
const colorSeverity = (type) => (type === "info" ? blue(type) : red(type));
|
|
4
|
+
export function formatMessages(messages) {
|
|
5
|
+
return messages.map(message => {
|
|
6
|
+
return ` ${colorSeverity(message.severity)} ${message.rule}: ${bold(message.source)} → ${bold(message.target)}`;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=formatMessages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatMessages.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/lib/formatMessages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAE3B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;AAI9B,MAAM,aAAa,GAAG,CAAC,IAAc,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;AASpF,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,OAAO,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;QAC5B,OAAO,KAAK,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAA;IAClH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type CruiseParams = {
|
|
2
|
+
directories: string[];
|
|
3
|
+
configPath: string;
|
|
4
|
+
tsConfigPath?: string;
|
|
5
|
+
webpackConfigPath?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function getCruiseResult({ directories, configPath, tsConfigPath, webpackConfigPath, }: CruiseParams): Promise<import("dependency-cruiser").IReporterOutput>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { cruise } from "dependency-cruiser";
|
|
2
|
+
import extractDepcruiseOptions from "dependency-cruiser/config-utl/extract-depcruise-options";
|
|
3
|
+
import extractTSConfig from "dependency-cruiser/config-utl/extract-ts-config";
|
|
4
|
+
import extractWebpackResolveConfig from "dependency-cruiser/config-utl/extract-webpack-resolve-config";
|
|
5
|
+
export async function getCruiseResult({ directories = [".*"], configPath, tsConfigPath, webpackConfigPath, }) {
|
|
6
|
+
const depcruiseOptions = await extractDepcruiseOptions(configPath);
|
|
7
|
+
const webpackConfig = webpackConfigPath ? await extractWebpackResolveConfig(webpackConfigPath) : undefined;
|
|
8
|
+
const tsConfig = tsConfigPath ? extractTSConfig(tsConfigPath) : undefined;
|
|
9
|
+
const cruiseResult = await cruise(directories, { ...depcruiseOptions }, webpackConfig, {
|
|
10
|
+
tsConfig,
|
|
11
|
+
});
|
|
12
|
+
return cruiseResult;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=getCruiseResult.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getCruiseResult.js","sourceRoot":"","sources":["../../../../../packages/folder-structure-cruiser/src/lib/getCruiseResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,oBAAoB,CAAA;AAC5E,OAAO,uBAAuB,MAAM,yDAAyD,CAAA;AAC7F,OAAO,eAAe,MAAM,iDAAiD,CAAA;AAC7E,OAAO,2BAA2B,MAAM,8DAA8D,CAAA;AAStG,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EACpC,WAAW,GAAG,CAAC,IAAI,CAAC,EACpB,UAAU,EACV,YAAY,EACZ,iBAAiB,GACJ;IACb,MAAM,gBAAgB,GAAmB,MAAM,uBAAuB,CAAC,UAAU,CAAC,CAAA;IAClF,MAAM,aAAa,GAAG,iBAAiB,CAAC,CAAC,CAAC,MAAM,2BAA2B,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1G,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEzE,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,gBAAgB,EAAE,EAAE,aAAgC,EAAE;QACxG,QAAQ;KACT,CAAC,CAAA;IAEF,OAAO,YAAY,CAAA;AACrB,CAAC"}
|