project-structure-lint 1.0.1
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/.validate-structurerc.example.json +45 -0
- package/CHANGELOG.md +42 -0
- package/CONTRIBUTING.md +142 -0
- package/LICENSE +21 -0
- package/PROJECT_SUMMARY.md +252 -0
- package/QUICK_START.md +164 -0
- package/README.md +330 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +121 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +71 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/core/validator.d.ts +16 -0
- package/dist/core/validator.d.ts.map +1 -0
- package/dist/core/validator.js +231 -0
- package/dist/core/validator.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/index.d.ts +5 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +17 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/react.d.ts +3 -0
- package/dist/presets/react.d.ts.map +1 -0
- package/dist/presets/react.js +94 -0
- package/dist/presets/react.js.map +1 -0
- package/dist/reporters/consoleReporter.d.ts +9 -0
- package/dist/reporters/consoleReporter.d.ts.map +1 -0
- package/dist/reporters/consoleReporter.js +98 -0
- package/dist/reporters/consoleReporter.js.map +1 -0
- package/dist/types/index.d.ts +59 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/fileScanner.d.ts +20 -0
- package/dist/utils/fileScanner.d.ts.map +1 -0
- package/dist/utils/fileScanner.js +166 -0
- package/dist/utils/fileScanner.js.map +1 -0
- package/dist/utils/naming.d.ts +4 -0
- package/dist/utils/naming.d.ts.map +1 -0
- package/dist/utils/naming.js +75 -0
- package/dist/utils/naming.js.map +1 -0
- package/jest.config.js +17 -0
- package/package.json +48 -0
- package/src/cli.ts +106 -0
- package/src/config/loader.ts +79 -0
- package/src/core/validator.ts +242 -0
- package/src/index.ts +6 -0
- package/src/presets/index.ts +16 -0
- package/src/presets/react.ts +93 -0
- package/src/reporters/consoleReporter.ts +116 -0
- package/src/types/index.ts +67 -0
- package/src/types/micromatch.d.ts +41 -0
- package/src/utils/__tests__/naming.test.ts +107 -0
- package/src/utils/fileScanner.ts +162 -0
- package/src/utils/naming.ts +99 -0
- package/tsconfig.json +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# project-structure-lint
|
|
2
|
+
|
|
3
|
+
A powerful CLI tool to validate project folder structure and file naming conventions with configurable presets. Perfect for maintaining consistency across React, Vue, Angular, and other JavaScript/TypeScript projects.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **Component Co-location Validation** - Ensures all related files (tests, stories, styles) are in the same folder
|
|
8
|
+
✅ **File Naming Convention Enforcement** - Supports PascalCase, camelCase, kebab-case, snake_case, and UPPER_CASE
|
|
9
|
+
✅ **Folder Structure Validation** - Enforces project directory organization
|
|
10
|
+
✅ **Configurable Presets** - Built-in React preset with easy customization
|
|
11
|
+
✅ **Detailed Error Reporting** - Clear messages with suggestions for fixes
|
|
12
|
+
✅ **CI/CD Integration** - Exit codes for automated workflows
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install --save-dev project-structure-lint
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or use globally:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g project-structure-lint
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Initialize Configuration
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx validate-structure init
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This creates a `.validate-structurerc.json` file with the React preset.
|
|
35
|
+
|
|
36
|
+
### 2. Run Validation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx validate-structure check
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Commands
|
|
45
|
+
|
|
46
|
+
#### `check`
|
|
47
|
+
Validate your project structure:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
validate-structure check [options]
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
-c, --config <path> Path to configuration file
|
|
54
|
+
-r, --root <path> Root directory to validate (default: current directory)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### `init`
|
|
58
|
+
Initialize a configuration file:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
validate-structure init [options]
|
|
62
|
+
|
|
63
|
+
Options:
|
|
64
|
+
-p, --preset <name> Preset to use (default: react)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### `presets`
|
|
68
|
+
List available presets:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
validate-structure presets
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
### Using Presets
|
|
77
|
+
|
|
78
|
+
The easiest way to get started is using a preset:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"preset": "react"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Custom Configuration
|
|
87
|
+
|
|
88
|
+
Create a `.validate-structurerc.json` file:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"preset": "react",
|
|
93
|
+
"rootDir": "src",
|
|
94
|
+
"rules": {
|
|
95
|
+
"componentColocation": {
|
|
96
|
+
"enabled": true,
|
|
97
|
+
"componentDirs": ["components", "pages", "features"],
|
|
98
|
+
"requiredFiles": [
|
|
99
|
+
{
|
|
100
|
+
"pattern": "*.test.{ts,tsx}",
|
|
101
|
+
"required": true,
|
|
102
|
+
"description": "Test file"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"pattern": "*.stories.{ts,tsx}",
|
|
106
|
+
"required": true,
|
|
107
|
+
"description": "Storybook story"
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"namingConvention": "PascalCase"
|
|
111
|
+
},
|
|
112
|
+
"fileNaming": {
|
|
113
|
+
"components/**/*.{tsx,jsx}": {
|
|
114
|
+
"convention": "PascalCase",
|
|
115
|
+
"severity": "error"
|
|
116
|
+
},
|
|
117
|
+
"hooks/**/*.{ts,tsx}": {
|
|
118
|
+
"convention": "camelCase",
|
|
119
|
+
"severity": "error"
|
|
120
|
+
},
|
|
121
|
+
"utils/**/*.{ts,js}": {
|
|
122
|
+
"convention": "camelCase",
|
|
123
|
+
"severity": "error"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"folderStructure": [
|
|
127
|
+
{
|
|
128
|
+
"name": "components",
|
|
129
|
+
"path": "src/components",
|
|
130
|
+
"namingConvention": "PascalCase",
|
|
131
|
+
"allowedExtensions": [".tsx", ".ts", ".css", ".scss"]
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
"ignore": [
|
|
136
|
+
"**/node_modules/**",
|
|
137
|
+
"**/dist/**",
|
|
138
|
+
"**/build/**"
|
|
139
|
+
],
|
|
140
|
+
"severity": "error"
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Configuration Options
|
|
145
|
+
|
|
146
|
+
### `preset`
|
|
147
|
+
- Type: `string`
|
|
148
|
+
- Available: `"react"`
|
|
149
|
+
- Use a predefined configuration preset
|
|
150
|
+
|
|
151
|
+
### `rootDir`
|
|
152
|
+
- Type: `string`
|
|
153
|
+
- Default: `"src"`
|
|
154
|
+
- Root directory for validation
|
|
155
|
+
|
|
156
|
+
### `rules.componentColocation`
|
|
157
|
+
|
|
158
|
+
Validates that component files are co-located with their tests, stories, etc.
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"enabled": true,
|
|
163
|
+
"componentDirs": ["components", "pages"],
|
|
164
|
+
"requiredFiles": [
|
|
165
|
+
{
|
|
166
|
+
"pattern": "*.test.tsx",
|
|
167
|
+
"required": true,
|
|
168
|
+
"description": "Test file"
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"namingConvention": "PascalCase"
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### `rules.fileNaming`
|
|
176
|
+
|
|
177
|
+
Enforces naming conventions for files matching patterns:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"components/**/*.tsx": {
|
|
182
|
+
"convention": "PascalCase",
|
|
183
|
+
"severity": "error"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Supported conventions:**
|
|
189
|
+
- `PascalCase` - `MyComponent.tsx`
|
|
190
|
+
- `camelCase` - `useAuth.ts`
|
|
191
|
+
- `kebab-case` - `my-component.tsx`
|
|
192
|
+
- `snake_case` - `my_component.tsx`
|
|
193
|
+
- `UPPER_CASE` - `API_CONSTANTS.ts`
|
|
194
|
+
|
|
195
|
+
### `rules.folderStructure`
|
|
196
|
+
|
|
197
|
+
Validates directory structure and contents:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"name": "components",
|
|
202
|
+
"path": "src/components",
|
|
203
|
+
"namingConvention": "PascalCase",
|
|
204
|
+
"allowedExtensions": [".tsx", ".ts", ".css"]
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### `ignore`
|
|
209
|
+
|
|
210
|
+
Patterns to ignore (uses glob syntax):
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"ignore": [
|
|
215
|
+
"**/node_modules/**",
|
|
216
|
+
"**/dist/**",
|
|
217
|
+
"**/*.test.ts"
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `severity`
|
|
223
|
+
|
|
224
|
+
Default severity level:
|
|
225
|
+
- `"error"` - Fails validation
|
|
226
|
+
- `"warning"` - Shows warning but passes
|
|
227
|
+
|
|
228
|
+
## Examples
|
|
229
|
+
|
|
230
|
+
### React Component Structure
|
|
231
|
+
|
|
232
|
+
For a component named `Button`, the tool validates:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
components/
|
|
236
|
+
└── Button/
|
|
237
|
+
├── Button.tsx ✓ Main component
|
|
238
|
+
├── Button.test.tsx ✓ Test file
|
|
239
|
+
├── Button.stories.tsx ✓ Storybook story
|
|
240
|
+
├── Button.module.css ✓ Styles
|
|
241
|
+
└── index.ts ✓ Re-export
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Naming Convention Validation
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// ✓ Valid
|
|
248
|
+
components/Button/Button.tsx
|
|
249
|
+
hooks/useAuth.ts
|
|
250
|
+
utils/formatDate.ts
|
|
251
|
+
|
|
252
|
+
// ✗ Invalid
|
|
253
|
+
components/button/button.tsx // Should be PascalCase
|
|
254
|
+
hooks/UseAuth.ts // Should be camelCase
|
|
255
|
+
utils/format_date.ts // Should be camelCase
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## CI/CD Integration
|
|
259
|
+
|
|
260
|
+
Add to your CI pipeline:
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
# GitHub Actions
|
|
264
|
+
- name: Validate Project Structure
|
|
265
|
+
run: npx validate-structure check
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
// package.json
|
|
270
|
+
{
|
|
271
|
+
"scripts": {
|
|
272
|
+
"validate": "validate-structure check",
|
|
273
|
+
"precommit": "validate-structure check"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Programmatic Usage
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
import { ProjectValidator, loadConfig } from 'project-structure-lint';
|
|
282
|
+
|
|
283
|
+
async function validate() {
|
|
284
|
+
const config = await loadConfig();
|
|
285
|
+
const validator = new ProjectValidator(config, process.cwd());
|
|
286
|
+
const result = await validator.validate();
|
|
287
|
+
|
|
288
|
+
console.log(`Valid: ${result.valid}`);
|
|
289
|
+
console.log(`Errors: ${result.errors.length}`);
|
|
290
|
+
console.log(`Warnings: ${result.warnings.length}`);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Output Example
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
Project Structure Validation Results
|
|
298
|
+
──────────────────────────────────────────────────
|
|
299
|
+
Files scanned: 45
|
|
300
|
+
Directories scanned: 12
|
|
301
|
+
|
|
302
|
+
✗ 2 Errors
|
|
303
|
+
|
|
304
|
+
1. Missing required file: Test file for component
|
|
305
|
+
Directory: components/Button
|
|
306
|
+
Expected: Button.test.tsx
|
|
307
|
+
💡 Create Button.test.tsx in components/Button/
|
|
308
|
+
|
|
309
|
+
2. File name doesn't follow PascalCase convention
|
|
310
|
+
File: components/myComponent/myComponent.tsx
|
|
311
|
+
Actual: myComponent.tsx
|
|
312
|
+
Expected: MyComponent.tsx
|
|
313
|
+
💡 Rename to MyComponent.tsx
|
|
314
|
+
|
|
315
|
+
──────────────────────────────────────────────────
|
|
316
|
+
|
|
317
|
+
✗ Validation failed with 2 errors
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Contributing
|
|
321
|
+
|
|
322
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
MIT
|
|
327
|
+
|
|
328
|
+
## Author
|
|
329
|
+
|
|
330
|
+
Created with ❤️ for better project organization
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const loader_1 = require("./config/loader");
|
|
39
|
+
const validator_1 = require("./core/validator");
|
|
40
|
+
const consoleReporter_1 = require("./reporters/consoleReporter");
|
|
41
|
+
const presets_1 = require("./presets");
|
|
42
|
+
const program = new commander_1.Command();
|
|
43
|
+
program
|
|
44
|
+
.name('validate-structure')
|
|
45
|
+
.description('Validate project folder structure and file naming conventions')
|
|
46
|
+
.version('1.0.0');
|
|
47
|
+
program
|
|
48
|
+
.command('check')
|
|
49
|
+
.description('Validate the project structure')
|
|
50
|
+
.option('-c, --config <path>', 'Path to configuration file')
|
|
51
|
+
.option('-r, --root <path>', 'Root directory to validate (default: current directory)')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
const reporter = new consoleReporter_1.ConsoleReporter();
|
|
54
|
+
try {
|
|
55
|
+
// Load configuration
|
|
56
|
+
const config = await (0, loader_1.loadConfig)(options.config);
|
|
57
|
+
// Validate configuration
|
|
58
|
+
const configErrors = (0, loader_1.validateConfig)(config);
|
|
59
|
+
if (configErrors.length > 0) {
|
|
60
|
+
reporter.reportConfigErrors(configErrors);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
// Run validation
|
|
64
|
+
const rootDir = options.root || process.cwd();
|
|
65
|
+
const validator = new validator_1.ProjectValidator(config, rootDir);
|
|
66
|
+
const result = await validator.validate();
|
|
67
|
+
// Report results
|
|
68
|
+
reporter.report(result);
|
|
69
|
+
// Exit with appropriate code
|
|
70
|
+
process.exit(result.valid ? 0 : 1);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
reporter.reportConfigError(error instanceof Error ? error.message : 'Unknown error occurred');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
program
|
|
78
|
+
.command('init')
|
|
79
|
+
.description('Initialize a configuration file')
|
|
80
|
+
.option('-p, --preset <name>', 'Preset to use (default: react)', 'react')
|
|
81
|
+
.action(async (options) => {
|
|
82
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
83
|
+
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
84
|
+
const configPath = path.join(process.cwd(), '.validate-structurerc.json');
|
|
85
|
+
if (fs.existsSync(configPath)) {
|
|
86
|
+
console.log('Configuration file already exists at:', configPath);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const presetName = options.preset;
|
|
90
|
+
const availablePresets = (0, presets_1.listPresets)();
|
|
91
|
+
if (!availablePresets.includes(presetName)) {
|
|
92
|
+
console.log(`Preset "${presetName}" not found.`);
|
|
93
|
+
console.log('Available presets:', availablePresets.join(', '));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const config = {
|
|
97
|
+
preset: presetName,
|
|
98
|
+
// Users can customize these
|
|
99
|
+
rules: {
|
|
100
|
+
componentColocation: {
|
|
101
|
+
enabled: true
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
106
|
+
console.log(`Configuration file created at: ${configPath}`);
|
|
107
|
+
console.log(`Using preset: ${presetName}`);
|
|
108
|
+
});
|
|
109
|
+
program
|
|
110
|
+
.command('presets')
|
|
111
|
+
.description('List available presets')
|
|
112
|
+
.action(() => {
|
|
113
|
+
const presets = (0, presets_1.listPresets)();
|
|
114
|
+
console.log('\nAvailable presets:');
|
|
115
|
+
presets.forEach(preset => {
|
|
116
|
+
console.log(` • ${preset}`);
|
|
117
|
+
});
|
|
118
|
+
console.log('');
|
|
119
|
+
});
|
|
120
|
+
program.parse();
|
|
121
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKzC,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAgC5E;AAyBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAa9D"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfig = loadConfig;
|
|
4
|
+
exports.validateConfig = validateConfig;
|
|
5
|
+
const cosmiconfig_1 = require("cosmiconfig");
|
|
6
|
+
const presets_1 = require("../presets");
|
|
7
|
+
const explorer = (0, cosmiconfig_1.cosmiconfig)('validate-structure');
|
|
8
|
+
async function loadConfig(configPath) {
|
|
9
|
+
let result;
|
|
10
|
+
if (configPath) {
|
|
11
|
+
result = await explorer.load(configPath);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
result = await explorer.search();
|
|
15
|
+
}
|
|
16
|
+
if (!result || !result.config) {
|
|
17
|
+
// Return default React preset if no config found
|
|
18
|
+
const reactPreset = (0, presets_1.getPreset)('react');
|
|
19
|
+
if (!reactPreset) {
|
|
20
|
+
throw new Error('Default React preset not found');
|
|
21
|
+
}
|
|
22
|
+
return reactPreset.config;
|
|
23
|
+
}
|
|
24
|
+
const config = result.config;
|
|
25
|
+
// If preset is specified, merge with preset config
|
|
26
|
+
if (config.preset) {
|
|
27
|
+
const preset = (0, presets_1.getPreset)(config.preset);
|
|
28
|
+
if (!preset) {
|
|
29
|
+
throw new Error(`Preset "${config.preset}" not found`);
|
|
30
|
+
}
|
|
31
|
+
// Merge preset config with user config (user config takes precedence)
|
|
32
|
+
return mergeConfigs(preset.config, config);
|
|
33
|
+
}
|
|
34
|
+
return config;
|
|
35
|
+
}
|
|
36
|
+
function mergeConfigs(preset, user) {
|
|
37
|
+
return {
|
|
38
|
+
...preset,
|
|
39
|
+
...user,
|
|
40
|
+
rules: {
|
|
41
|
+
...preset.rules,
|
|
42
|
+
...user.rules,
|
|
43
|
+
componentColocation: user.rules?.componentColocation
|
|
44
|
+
? {
|
|
45
|
+
...preset.rules?.componentColocation,
|
|
46
|
+
...user.rules.componentColocation
|
|
47
|
+
}
|
|
48
|
+
: preset.rules?.componentColocation,
|
|
49
|
+
fileNaming: {
|
|
50
|
+
...preset.rules?.fileNaming,
|
|
51
|
+
...user.rules?.fileNaming
|
|
52
|
+
},
|
|
53
|
+
folderStructure: user.rules?.folderStructure || preset.rules?.folderStructure
|
|
54
|
+
},
|
|
55
|
+
ignore: [...(preset.ignore || []), ...(user.ignore || [])]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function validateConfig(config) {
|
|
59
|
+
const errors = [];
|
|
60
|
+
if (config.rules?.componentColocation?.enabled) {
|
|
61
|
+
if (!config.rules.componentColocation.componentDirs?.length) {
|
|
62
|
+
errors.push('componentColocation.componentDirs must be specified when enabled');
|
|
63
|
+
}
|
|
64
|
+
if (!config.rules.componentColocation.requiredFiles?.length) {
|
|
65
|
+
errors.push('componentColocation.requiredFiles must be specified when enabled');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return errors;
|
|
69
|
+
}
|
|
70
|
+
// Made with
|
|
71
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":";;AAMA,gCAgCC;AAyBD,wCAaC;AA5ED,6CAA0C;AAE1C,wCAAuC;AAEvC,MAAM,QAAQ,GAAG,IAAA,yBAAW,EAAC,oBAAoB,CAAC,CAAC;AAE5C,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,IAAI,MAAM,CAAC;IAEX,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9B,iDAAiD;QACjD,MAAM,WAAW,GAAG,IAAA,mBAAS,EAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,WAAW,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAuB,CAAC;IAE9C,mDAAmD;IACnD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,MAAM,aAAa,CAAC,CAAC;QACzD,CAAC;QAED,sEAAsE;QACtE,OAAO,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,MAAqB,EAAE,IAAmB;IAC9D,OAAO;QACL,GAAG,MAAM;QACT,GAAG,IAAI;QACP,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK;YACf,GAAG,IAAI,CAAC,KAAK;YACb,mBAAmB,EAAE,IAAI,CAAC,KAAK,EAAE,mBAAmB;gBAClD,CAAC,CAAC;oBACE,GAAG,MAAM,CAAC,KAAK,EAAE,mBAAmB;oBACpC,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB;iBAClC;gBACH,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,mBAAmB;YACrC,UAAU,EAAE;gBACV,GAAG,MAAM,CAAC,KAAK,EAAE,UAAU;gBAC3B,GAAG,IAAI,CAAC,KAAK,EAAE,UAAU;aAC1B;YACD,eAAe,EAAE,IAAI,CAAC,KAAK,EAAE,eAAe,IAAI,MAAM,CAAC,KAAK,EAAE,eAAe;SAC9E;QACD,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;KAC3D,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,MAAqB;IAClD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,MAAM,CAAC,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;YAC5D,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,aAAa"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ProjectConfig, ValidationResult } from '../types';
|
|
2
|
+
export declare class ProjectValidator {
|
|
3
|
+
private config;
|
|
4
|
+
private scanner;
|
|
5
|
+
private errors;
|
|
6
|
+
private warnings;
|
|
7
|
+
constructor(config: ProjectConfig, rootDir?: string);
|
|
8
|
+
validate(): Promise<ValidationResult>;
|
|
9
|
+
private validateComponentColocation;
|
|
10
|
+
private validateFileNaming;
|
|
11
|
+
private validateFolderStructure;
|
|
12
|
+
private isComponentFile;
|
|
13
|
+
private expandPattern;
|
|
14
|
+
private addError;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAmB,gBAAgB,EAAe,MAAM,UAAU,CAAC;AAIzF,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAyB;gBAE7B,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,MAAsB;IAM5D,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;YAgC7B,2BAA2B;YA0E3B,kBAAkB;YAgClB,uBAAuB;IAkErC,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,QAAQ;CAOjB"}
|