@australiangreens/ag-arch-rules
v1.1.1
Published
Architectural lint rules for Australian Greens TypeScript frontend projects, run as Vitest tests.
Keywords
Readme
@australiangreens/ag-arch-rules
Architectural lint rules for Australian Greens TypeScript frontend projects, run as Vitest tests.
The package encodes agreed conventions around layer dependencies, project structure, naming, and file metrics. Rules run alongside your normal test suite (or as a separate command), and violations are reported or enforced depending on how you configure them.
Installation
npm install --save-dev @australiangreens/ag-arch-rulesThe package is published to npmjs.com.
Quick start
Create two files in your project root (not inside src/).
arch.check.ts — your rule configuration:
import { agFrontendPreset, defineArchConfig, runArchRules } from '@australiangreens/ag-arch-rules';
runArchRules(defineArchConfig({
root: './src',
mode: 'report',
rules: {
...agFrontendPreset.rules,
},
}));arch.vitest.config.ts — Vitest settings for the arch check:
import { defineArchVitestConfig } from '@australiangreens/ag-arch-rules';
export default defineArchVitestConfig();Add a script to package.json:
"scripts": {
"arch:check": "vitest run --config arch.vitest.config.ts --reporter=verbose"
}Run with:
npm run arch:checkIn report mode, violations are logged to stderr but tests still pass — useful when first adopting the rules on an existing codebase. Switch to enforce when you're ready to make violations fail the build.
Configuration
defineArchConfig
A typed identity function that provides TypeScript inference and IDE autocomplete on your config object.
runArchRules
Registers one Vitest it() block per enabled rule under a describe('Architecture') suite. Call it at the top level of your check file — not inside a test block.
defineArchVitestConfig
Returns a Vitest inline config object with defaults suited to running arch checks. Pass its result as the default export of your arch.vitest.config.ts.
import { defineArchVitestConfig } from '@australiangreens/ag-arch-rules';
export default defineArchVitestConfig();All options are optional:
| Option | Type | Default | Description |
|---|---|---|---|
| checkFile | string | 'arch.check.ts' | Path to the arch check file to run |
| pool | string | 'forks' | Vitest worker pool. 'forks' is required for the dependency-graph rules that use native Node.js APIs |
| testTimeout | number | 30000 | Test timeout in milliseconds. Arch checks analyse the full dependency graph and can take several seconds |
globals: true is always set — archunit extends Vitest's expect at startup and requires it to be available globally.
Override individual options as needed:
export default defineArchVitestConfig({
checkFile: 'my.arch.check.ts',
testTimeout: 60000,
});mode
| Value | Effect |
|---|---|
| 'report' | Violations are logged; no tests fail |
| 'enforce' | error-severity violations fail their test; warn-severity violations are logged |
Rule configuration
Each rule can be set to a severity string or a [severity, options] tuple:
rules: {
'max-file-lines': 'off', // disabled
'require-hook-prefix': 'warn', // default severity
'max-file-lines': ['warn', { tsx: 500, ts: 400 }], // with options
}tsConfigPath
By default the rules locate the nearest tsconfig.json by walking up the directory tree from root. This works for most projects and no explicit tsConfigPath is needed.
If you find analysis is slow on a project with many path aliases or project references, you can point the rules at a leaner dedicated config:
runArchRules(defineArchConfig({
root: './src',
tsConfigPath: './tsconfig.arch.json',
mode: 'enforce',
rules: { ...agFrontendPreset.rules },
}));A minimal tsconfig.arch.json strips out references, declaration, and unrelated types, keeping only what the import resolver needs:
{
"compilerOptions": {
"module": "ES2022",
"moduleResolution": "Node",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"paths": { "@/*": ["./src/*"] }
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}except patterns
All rules accept an except array of glob patterns (CWD-relative) to exclude specific files from the rule:
'no-components-depend-on-pages': ['error', {
except: [
'src/components/LegacyWidget/**',
],
}],The agFrontendPreset
A ready-made config covering all 14 rules with sensible defaults:
import { agFrontendPreset, defineArchConfig, runArchRules } from '@australiangreens/ag-arch-rules';
runArchRules(defineArchConfig({
root: './src',
mode: 'enforce',
rules: {
...agFrontendPreset.rules,
// override individual rules below
},
}));Default severities in the preset:
| Rule | Default |
|---|---|
| no-apis-depend-on-components | error |
| no-apis-depend-on-pages | error |
| no-components-depend-on-pages | error |
| no-hooks-depend-on-pages | error |
| no-types-depend-on-runtime-layers | error |
| no-constants-depend-on-runtime-layers | error |
| no-circular-dependencies | error |
| require-barrel-exports | warn |
| require-path-alias | warn |
| require-error-hierarchy | error |
| errors-extend-ag-error | error |
| require-test-type-suffix | warn |
| require-hook-prefix | warn |
| max-file-lines | warn (tsx: 400, ts: 300) |
Adopting on an existing codebase
Start in report mode so you can see what violations exist without breaking CI. Use except patterns to acknowledge known violations you're not ready to fix, then tighten incrementally. When a rule has no remaining violations, switch it to enforce or rename the file to arch.test.ts and set mode: 'enforce' globally.
Rule reference
See docs/RULES.md for a description of each rule with examples.
Requirements
- Node.js 18+
- Vitest 1.0+ (peer dependency)
- TypeScript project with a
tsconfig.json
