|
| 1 | +const PUBLIC_PACKAGES = [ |
| 2 | + "builder", |
| 3 | + "cli", |
| 4 | + "documentation", |
| 5 | + "fs", |
| 6 | + "logger", |
| 7 | + "project", |
| 8 | + "server", |
| 9 | +]; |
| 10 | + |
| 11 | +const INTERNAL_PACKAGES = [ |
| 12 | + "documentation", |
| 13 | + "shrinkwrap-extractor" |
| 14 | +]; |
| 15 | + |
| 16 | +const ALLOWED_TYPE_SCOPE_COMBINATIONS = { |
| 17 | + "build": ["deps-dev"], |
| 18 | + "ci": ["github-actions", "release-please"], |
| 19 | + "deps": [...PUBLIC_PACKAGES, ...INTERNAL_PACKAGES], |
| 20 | + "feat": PUBLIC_PACKAGES, |
| 21 | + "fix": PUBLIC_PACKAGES, |
| 22 | +}; |
| 23 | + |
| 24 | +const ALL_SCOPES = Object.values(ALLOWED_TYPE_SCOPE_COMBINATIONS).flat(); |
| 25 | + |
1 | 26 | export default { |
2 | 27 | extends: [ |
3 | 28 | "@commitlint/config-conventional", |
@@ -31,23 +56,41 @@ export default { |
31 | 56 | "scope-enum": [ |
32 | 57 | 2, |
33 | 58 | "always", |
34 | | - [ |
35 | | - // Package names |
36 | | - "builder", |
37 | | - "cli", |
38 | | - "documentation", |
39 | | - "fs", |
40 | | - "logger", |
41 | | - "project", |
42 | | - "server", |
43 | | - // Special scope for dev dependencies |
44 | | - "deps-dev" |
45 | | - ] |
| 59 | + ALL_SCOPES, |
46 | 60 | ], |
47 | 61 | "scope-case": [2, "always", "lowercase"], |
| 62 | + |
| 63 | + // Enable custom rule for type-scope combinations (see code below) |
| 64 | + "custom/type-scope-combination": [ |
| 65 | + 2, |
| 66 | + "always", |
| 67 | + ], |
48 | 68 | }, |
49 | 69 | ignores: [ |
50 | 70 | // Ignore release commits, as their subject doesn't start with an uppercase letter |
51 | 71 | (message) => message.startsWith("release: v"), |
52 | 72 | ], |
| 73 | + plugins: [ |
| 74 | + { |
| 75 | + rules: { |
| 76 | + "custom/type-scope-combination": ({type, scope}) => { |
| 77 | + // If no scope, it's valid |
| 78 | + if (!scope) { |
| 79 | + return [true]; |
| 80 | + } |
| 81 | + // If type not in restrictions, allow any scope |
| 82 | + if (!ALLOWED_TYPE_SCOPE_COMBINATIONS[type]) { |
| 83 | + return [true]; |
| 84 | + } |
| 85 | + // Check if the combination is allowed |
| 86 | + const isAllowed = ALLOWED_TYPE_SCOPE_COMBINATIONS[type].includes(scope); |
| 87 | + return [ |
| 88 | + isAllowed, |
| 89 | + `Scope "${scope}" is not allowed with type "${type}". ` + |
| 90 | + `Allowed scopes: ${ALLOWED_TYPE_SCOPE_COMBINATIONS[type].join(", ")}` |
| 91 | + ]; |
| 92 | + } |
| 93 | + } |
| 94 | + } |
| 95 | + ] |
53 | 96 | }; |
0 commit comments