stratifyjs 1.0.0
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/LICENSE +21 -0
- package/README.md +354 -0
- package/lib/adapters/config-file-loader.d.ts +8 -0
- package/lib/adapters/config-file-loader.js +55 -0
- package/lib/adapters/file-system-discovery.d.ts +22 -0
- package/lib/adapters/file-system-discovery.js +61 -0
- package/lib/api/api.d.ts +42 -0
- package/lib/api/api.js +75 -0
- package/lib/api/index.d.ts +15 -0
- package/lib/api/index.js +12 -0
- package/lib/cli/command-handler.d.ts +6 -0
- package/lib/cli/command-handler.js +50 -0
- package/lib/cli/index.d.ts +2 -0
- package/lib/cli/index.js +23 -0
- package/lib/cli/options.d.ts +18 -0
- package/lib/cli/options.js +21 -0
- package/lib/cli/output-helpers.d.ts +9 -0
- package/lib/cli/output-helpers.js +22 -0
- package/lib/core/config-defaults.d.ts +7 -0
- package/lib/core/config-defaults.js +22 -0
- package/lib/core/config-schema.d.ts +11 -0
- package/lib/core/config-schema.js +102 -0
- package/lib/core/errors.d.ts +44 -0
- package/lib/core/errors.js +25 -0
- package/lib/core/formatters/console-formatter.d.ts +3 -0
- package/lib/core/formatters/console-formatter.js +34 -0
- package/lib/core/formatters/json-formatter.d.ts +5 -0
- package/lib/core/formatters/json-formatter.js +11 -0
- package/lib/core/package-parser.d.ts +11 -0
- package/lib/core/package-parser.js +37 -0
- package/lib/core/report-builder.d.ts +18 -0
- package/lib/core/report-builder.js +17 -0
- package/lib/core/result.d.ts +33 -0
- package/lib/core/result.js +24 -0
- package/lib/core/rules.d.ts +14 -0
- package/lib/core/rules.js +19 -0
- package/lib/core/validation.d.ts +5 -0
- package/lib/core/validation.js +51 -0
- package/lib/types/types.d.ts +66 -0
- package/lib/types/types.js +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { hasRequiredLayer, isKnownLayer, isDependencyAllowed } from './rules.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validate all packages against layer configuration.
|
|
4
|
+
*/
|
|
5
|
+
export function validatePackages(packages, config) {
|
|
6
|
+
const violations = [];
|
|
7
|
+
const packageMap = new Map(packages.map(pkg => [pkg.name, pkg]));
|
|
8
|
+
for (const pkg of packages) {
|
|
9
|
+
// Rule 1: Check if package has a layer field
|
|
10
|
+
if (!hasRequiredLayer(pkg)) {
|
|
11
|
+
violations.push({
|
|
12
|
+
type: 'missing-layer',
|
|
13
|
+
package: pkg.name,
|
|
14
|
+
message: `Package "${pkg.name}" is missing the required "layer" field in package.json`,
|
|
15
|
+
});
|
|
16
|
+
continue; // Cannot validate further without layer
|
|
17
|
+
}
|
|
18
|
+
const layer = pkg.layer;
|
|
19
|
+
// Rule 2: Layer must be defined in config
|
|
20
|
+
if (!isKnownLayer(layer, config.layers)) {
|
|
21
|
+
violations.push({
|
|
22
|
+
type: 'unknown-layer',
|
|
23
|
+
package: pkg.name,
|
|
24
|
+
message: `Package "${pkg.name}" has unknown layer "${layer}". Valid layers: ${Object.keys(config.layers).join(', ')}`,
|
|
25
|
+
});
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Rule 3: Each dependency must target an allowed layer
|
|
29
|
+
const layerDef = config.layers[layer];
|
|
30
|
+
for (const depName of pkg.dependencies) {
|
|
31
|
+
const depPkg = packageMap.get(depName);
|
|
32
|
+
if (!depPkg || !depPkg.layer) {
|
|
33
|
+
continue; // Skip dependencies that are not discovered or have no layer
|
|
34
|
+
}
|
|
35
|
+
if (!isDependencyAllowed(layer, depPkg.layer, layerDef.allowedDependencies)) {
|
|
36
|
+
violations.push({
|
|
37
|
+
type: 'invalid-dependency',
|
|
38
|
+
package: pkg.name,
|
|
39
|
+
message: `Layer violation: "${pkg.name}" (${layer}) cannot depend on "${depPkg.name}" (${depPkg.layer})`,
|
|
40
|
+
details: {
|
|
41
|
+
fromLayer: layer,
|
|
42
|
+
toPackage: depPkg.name,
|
|
43
|
+
toLayer: depPkg.layer,
|
|
44
|
+
allowedLayers: layerDef.allowedDependencies,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return violations;
|
|
51
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a discovered package in the monorepo
|
|
3
|
+
*/
|
|
4
|
+
export interface Package {
|
|
5
|
+
name: string;
|
|
6
|
+
layer?: string;
|
|
7
|
+
dependencies: string[];
|
|
8
|
+
path: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Layer definition in the configuration
|
|
12
|
+
*/
|
|
13
|
+
export interface LayerDefinition {
|
|
14
|
+
description?: string;
|
|
15
|
+
allowedDependencies: string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Map of layer names to their definitions
|
|
19
|
+
*/
|
|
20
|
+
export type LayerMap = Record<string, LayerDefinition>;
|
|
21
|
+
/**
|
|
22
|
+
* Enforcement configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface EnforcementConfig {
|
|
25
|
+
mode: 'error' | 'warn' | 'off';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Workspace discovery configuration
|
|
29
|
+
*/
|
|
30
|
+
export interface WorkspaceConfig {
|
|
31
|
+
patterns: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Layer configuration file (as written by user)
|
|
35
|
+
*/
|
|
36
|
+
export interface LayerConfig {
|
|
37
|
+
layers: LayerMap;
|
|
38
|
+
workspaces?: Partial<WorkspaceConfig>;
|
|
39
|
+
enforcement?: Partial<EnforcementConfig>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolved config with all defaults applied
|
|
43
|
+
*/
|
|
44
|
+
export interface ResolvedConfig {
|
|
45
|
+
layers: LayerMap;
|
|
46
|
+
workspaces: WorkspaceConfig;
|
|
47
|
+
enforcement: EnforcementConfig;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Violation types
|
|
51
|
+
*/
|
|
52
|
+
export type ViolationType = 'missing-layer' | 'unknown-layer' | 'invalid-dependency';
|
|
53
|
+
/**
|
|
54
|
+
* A single validation violation
|
|
55
|
+
*/
|
|
56
|
+
export interface Violation {
|
|
57
|
+
type: ViolationType;
|
|
58
|
+
package: string;
|
|
59
|
+
message: string;
|
|
60
|
+
details?: {
|
|
61
|
+
fromLayer?: string;
|
|
62
|
+
toPackage?: string;
|
|
63
|
+
toLayer?: string;
|
|
64
|
+
allowedLayers?: string[];
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stratifyjs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Enforce architectural layer boundaries in monorepos",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"stratify": "./lib/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./lib/api/index.js",
|
|
10
|
+
"types": "./lib/api/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"source": "./src/api/index.ts",
|
|
14
|
+
"types": "./lib/api/index.d.ts",
|
|
15
|
+
"default": "./lib/api/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./cli": {
|
|
18
|
+
"source": "./src/cli/index.ts",
|
|
19
|
+
"types": "./lib/cli/index.d.ts",
|
|
20
|
+
"default": "./lib/cli/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -p tsconfig.json",
|
|
25
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
26
|
+
"start": "node lib/cli/index.js",
|
|
27
|
+
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
|
|
28
|
+
"test:watch": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --watch",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"prepublishOnly": "yarn build"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/smikula/stratifyjs.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/smikula/stratifyjs/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/smikula/stratifyjs#readme",
|
|
40
|
+
"keywords": [
|
|
41
|
+
"monorepo",
|
|
42
|
+
"architecture",
|
|
43
|
+
"layers",
|
|
44
|
+
"dependency",
|
|
45
|
+
"enforcement"
|
|
46
|
+
],
|
|
47
|
+
"files": [
|
|
48
|
+
"lib/",
|
|
49
|
+
"bin/",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"commander": "^14.0.3",
|
|
55
|
+
"glob": "^10.0.0",
|
|
56
|
+
"picocolors": "^1.1.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/jest": "^30.0.0",
|
|
60
|
+
"@types/node": "^25.2.3",
|
|
61
|
+
"jest": "^29.5.0",
|
|
62
|
+
"prettier": "^3.8.1",
|
|
63
|
+
"ts-jest": "^29.4.6",
|
|
64
|
+
"typescript": "^5.3.2"
|
|
65
|
+
},
|
|
66
|
+
"license": "MIT"
|
|
67
|
+
}
|