@ontrails/warden 1.0.0-beta.2 → 1.0.0-beta.21
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/CHANGELOG.md +497 -6
- package/README.md +77 -26
- package/bin/warden.ts +50 -0
- package/package.json +27 -5
- package/src/adapter-check.ts +136 -0
- package/src/ast.ts +28 -0
- package/src/cli.ts +1374 -103
- package/src/command.ts +953 -0
- package/src/config.ts +184 -0
- package/src/draft.ts +22 -0
- package/src/drift.ts +106 -22
- package/src/fix.ts +120 -0
- package/src/formatters.ts +79 -9
- package/src/guide.ts +245 -0
- package/src/index.ts +206 -14
- package/src/project-context.ts +163 -0
- package/src/resolve.ts +530 -0
- package/src/rules/activation-orphan.ts +97 -0
- package/src/rules/ast.ts +3176 -85
- package/src/rules/circular-refs.ts +154 -0
- package/src/rules/composes-declarations.ts +704 -0
- package/src/rules/context-no-surface-types.ts +68 -8
- package/src/rules/contour-exists.ts +251 -0
- package/src/rules/contour-ids.ts +15 -0
- package/src/rules/dead-internal-trail.ts +154 -0
- package/src/rules/draft-file-marking.ts +160 -0
- package/src/rules/draft-visible-debt.ts +87 -0
- package/src/rules/error-mapping-completeness.ts +288 -0
- package/src/rules/example-valid.ts +401 -0
- package/src/rules/fires-declarations.ts +758 -0
- package/src/rules/implementation-returns-result.ts +1265 -95
- package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
- package/src/rules/incomplete-crud.ts +580 -0
- package/src/rules/index.ts +219 -18
- package/src/rules/intent-propagation.ts +127 -0
- package/src/rules/layer-field-name-drift.ts +96 -0
- package/src/rules/metadata.ts +654 -0
- package/src/rules/missing-reconcile.ts +98 -0
- package/src/rules/missing-visibility.ts +110 -0
- package/src/rules/no-destructured-compose.ts +192 -0
- package/src/rules/no-dev-permit-in-source.ts +99 -0
- package/src/rules/no-direct-implementation-call.ts +7 -7
- package/src/rules/no-legacy-layer-imports.ts +211 -0
- package/src/rules/no-native-error-result.ts +111 -0
- package/src/rules/no-redundant-result-error-wrap.ts +331 -0
- package/src/rules/no-retired-cross-vocabulary.ts +194 -0
- package/src/rules/no-sync-result-assumption.ts +1134 -99
- package/src/rules/no-throw-in-detour-recover.ts +225 -0
- package/src/rules/no-throw-in-implementation.ts +10 -9
- package/src/rules/no-top-level-surface.ts +389 -0
- package/src/rules/on-references-exist.ts +194 -0
- package/src/rules/orphaned-signal.ts +150 -0
- package/src/rules/owner-projection-parity.ts +146 -0
- package/src/rules/permit-governance.ts +25 -0
- package/src/rules/public-export-example-coverage.ts +553 -0
- package/src/rules/public-internal-deep-imports.ts +517 -0
- package/src/rules/public-output-schema.ts +29 -0
- package/src/rules/public-union-output-discriminants.ts +150 -0
- package/src/rules/read-intent-fires.ts +187 -0
- package/src/rules/reference-exists.ts +98 -0
- package/src/rules/registry-names.ts +145 -0
- package/src/rules/resolved-import-boundary.ts +146 -0
- package/src/rules/resource-declarations.ts +704 -0
- package/src/rules/resource-exists.ts +179 -0
- package/src/rules/resource-id-grammar.ts +65 -0
- package/src/rules/resource-mock-coverage.ts +115 -0
- package/src/rules/scan.ts +38 -25
- package/src/rules/scheduled-destroy-intent.ts +44 -0
- package/src/rules/signal-graph-coaching.ts +191 -0
- package/src/rules/specs.ts +9 -5
- package/src/rules/static-resource-accessor-preference.ts +657 -0
- package/src/rules/surface-facet-coherence.ts +370 -0
- package/src/rules/trail-versioning-source.ts +1094 -0
- package/src/rules/trail-versioning-topo.ts +172 -0
- package/src/rules/types.ts +270 -6
- package/src/rules/unmaterialized-activation-source.ts +84 -0
- package/src/rules/unreachable-detour-shadowing.ts +344 -0
- package/src/rules/valid-describe-refs.ts +160 -32
- package/src/rules/valid-detour-contract.ts +78 -0
- package/src/rules/warden-export-symmetry.ts +533 -0
- package/src/rules/warden-rules-use-ast.ts +996 -0
- package/src/rules/webhook-route-collision.ts +243 -0
- package/src/trails/activation-orphan.trail.ts +84 -0
- package/src/trails/circular-refs.trail.ts +29 -0
- package/src/trails/composes-declarations.trail.ts +22 -0
- package/src/trails/context-no-surface-types.trail.ts +21 -0
- package/src/trails/contour-exists.trail.ts +21 -0
- package/src/trails/dead-internal-trail.trail.ts +26 -0
- package/src/trails/deprecation-without-guidance.trail.ts +21 -0
- package/src/trails/draft-file-marking.trail.ts +16 -0
- package/src/trails/draft-visible-debt.trail.ts +16 -0
- package/src/trails/error-mapping-completeness.trail.ts +29 -0
- package/src/trails/example-valid.trail.ts +25 -0
- package/src/trails/fires-declarations.trail.ts +23 -0
- package/src/trails/fork-without-preserved-blaze.trail.ts +31 -0
- package/src/trails/implementation-returns-result.trail.ts +20 -0
- package/src/trails/incomplete-accessor-for-standard-op.trail.ts +76 -0
- package/src/trails/incomplete-crud.trail.ts +39 -0
- package/src/trails/index.ts +78 -0
- package/src/trails/intent-propagation.trail.ts +30 -0
- package/src/trails/layer-field-name-drift.trail.ts +39 -0
- package/src/trails/marker-schema-unsupported.trail.ts +23 -0
- package/src/trails/missing-reconcile.trail.ts +33 -0
- package/src/trails/missing-visibility.trail.ts +22 -0
- package/src/trails/no-destructured-compose.trail.ts +44 -0
- package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
- package/src/trails/no-direct-implementation-call.trail.ts +16 -0
- package/src/trails/no-legacy-layer-imports.trail.ts +41 -0
- package/src/trails/no-native-error-result.trail.ts +18 -0
- package/src/trails/no-redundant-result-error-wrap.trail.ts +55 -0
- package/src/trails/no-retired-cross-vocabulary.trail.ts +42 -0
- package/src/trails/no-sync-result-assumption.trail.ts +19 -0
- package/src/trails/no-throw-in-detour-recover.trail.ts +24 -0
- package/src/trails/no-throw-in-implementation.trail.ts +20 -0
- package/src/trails/no-top-level-surface.trail.ts +43 -0
- package/src/trails/on-references-exist.trail.ts +21 -0
- package/src/trails/orphaned-signal.trail.ts +36 -0
- package/src/trails/owner-projection-parity.trail.ts +26 -0
- package/src/trails/pending-force.trail.ts +21 -0
- package/src/trails/permit-governance.trail.ts +51 -0
- package/src/trails/prefer-schema-inference.trail.ts +21 -0
- package/src/trails/public-export-example-coverage.trail.ts +16 -0
- package/src/trails/public-internal-deep-imports.trail.ts +94 -0
- package/src/trails/public-output-schema.trail.ts +55 -0
- package/src/trails/public-union-output-discriminants.trail.ts +33 -0
- package/src/trails/read-intent-fires.trail.ts +20 -0
- package/src/trails/reference-exists.trail.ts +25 -0
- package/src/trails/resolved-import-boundary.trail.ts +109 -0
- package/src/trails/resource-declarations.trail.ts +25 -0
- package/src/trails/resource-exists.trail.ts +27 -0
- package/src/trails/resource-id-grammar.trail.ts +39 -0
- package/src/trails/resource-mock-coverage.trail.ts +40 -0
- package/src/trails/run.ts +162 -0
- package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
- package/src/trails/schema.ts +194 -0
- package/src/trails/signal-graph-coaching.trail.ts +77 -0
- package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
- package/src/trails/surface-facet-coherence.trail.ts +25 -0
- package/src/trails/topo.ts +6 -0
- package/src/trails/unmaterialized-activation-source.trail.ts +72 -0
- package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
- package/src/trails/valid-describe-refs.trail.ts +18 -0
- package/src/trails/valid-detour-contract.trail.ts +71 -0
- package/src/trails/version-gap.trail.ts +35 -0
- package/src/trails/version-pinned-compose.trail.ts +23 -0
- package/src/trails/version-without-examples.trail.ts +38 -0
- package/src/trails/warden-export-symmetry.trail.ts +16 -0
- package/src/trails/warden-rules-use-ast.trail.ts +45 -0
- package/src/trails/webhook-route-collision.trail.ts +50 -0
- package/src/trails/wrap-rule.ts +213 -0
- package/src/workspaces.ts +238 -0
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/dist/cli.d.ts +0 -46
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -221
- package/dist/cli.js.map +0 -1
- package/dist/drift.d.ts +0 -26
- package/dist/drift.d.ts.map +0 -1
- package/dist/drift.js +0 -27
- package/dist/drift.js.map +0 -1
- package/dist/formatters.d.ts +0 -29
- package/dist/formatters.d.ts.map +0 -1
- package/dist/formatters.js +0 -87
- package/dist/formatters.js.map +0 -1
- package/dist/index.d.ts +0 -26
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -26
- package/dist/index.js.map +0 -1
- package/dist/rules/ast.d.ts +0 -41
- package/dist/rules/ast.d.ts.map +0 -1
- package/dist/rules/ast.js +0 -163
- package/dist/rules/ast.js.map +0 -1
- package/dist/rules/context-no-surface-types.d.ts +0 -12
- package/dist/rules/context-no-surface-types.d.ts.map +0 -1
- package/dist/rules/context-no-surface-types.js +0 -96
- package/dist/rules/context-no-surface-types.js.map +0 -1
- package/dist/rules/implementation-returns-result.d.ts +0 -13
- package/dist/rules/implementation-returns-result.d.ts.map +0 -1
- package/dist/rules/implementation-returns-result.js +0 -231
- package/dist/rules/implementation-returns-result.js.map +0 -1
- package/dist/rules/index.d.ts +0 -22
- package/dist/rules/index.d.ts.map +0 -1
- package/dist/rules/index.js +0 -41
- package/dist/rules/index.js.map +0 -1
- package/dist/rules/no-direct-impl-in-route.d.ts +0 -12
- package/dist/rules/no-direct-impl-in-route.d.ts.map +0 -1
- package/dist/rules/no-direct-impl-in-route.js +0 -46
- package/dist/rules/no-direct-impl-in-route.js.map +0 -1
- package/dist/rules/no-direct-implementation-call.d.ts +0 -12
- package/dist/rules/no-direct-implementation-call.d.ts.map +0 -1
- package/dist/rules/no-direct-implementation-call.js +0 -39
- package/dist/rules/no-direct-implementation-call.js.map +0 -1
- package/dist/rules/no-sync-result-assumption.d.ts +0 -6
- package/dist/rules/no-sync-result-assumption.d.ts.map +0 -1
- package/dist/rules/no-sync-result-assumption.js +0 -98
- package/dist/rules/no-sync-result-assumption.js.map +0 -1
- package/dist/rules/no-throw-in-detour-target.d.ts +0 -12
- package/dist/rules/no-throw-in-detour-target.d.ts.map +0 -1
- package/dist/rules/no-throw-in-detour-target.js +0 -87
- package/dist/rules/no-throw-in-detour-target.js.map +0 -1
- package/dist/rules/no-throw-in-implementation.d.ts +0 -9
- package/dist/rules/no-throw-in-implementation.d.ts.map +0 -1
- package/dist/rules/no-throw-in-implementation.js +0 -34
- package/dist/rules/no-throw-in-implementation.js.map +0 -1
- package/dist/rules/prefer-schema-inference.d.ts +0 -7
- package/dist/rules/prefer-schema-inference.d.ts.map +0 -1
- package/dist/rules/prefer-schema-inference.js +0 -86
- package/dist/rules/prefer-schema-inference.js.map +0 -1
- package/dist/rules/scan.d.ts +0 -8
- package/dist/rules/scan.d.ts.map +0 -1
- package/dist/rules/scan.js +0 -32
- package/dist/rules/scan.js.map +0 -1
- package/dist/rules/specs.d.ts +0 -29
- package/dist/rules/specs.d.ts.map +0 -1
- package/dist/rules/specs.js +0 -192
- package/dist/rules/specs.js.map +0 -1
- package/dist/rules/structure.d.ts +0 -13
- package/dist/rules/structure.d.ts.map +0 -1
- package/dist/rules/structure.js +0 -142
- package/dist/rules/structure.js.map +0 -1
- package/dist/rules/types.d.ts +0 -52
- package/dist/rules/types.d.ts.map +0 -1
- package/dist/rules/types.js +0 -2
- package/dist/rules/types.js.map +0 -1
- package/dist/rules/valid-describe-refs.d.ts +0 -7
- package/dist/rules/valid-describe-refs.d.ts.map +0 -1
- package/dist/rules/valid-describe-refs.js +0 -51
- package/dist/rules/valid-describe-refs.js.map +0 -1
- package/dist/rules/valid-detour-refs.d.ts +0 -6
- package/dist/rules/valid-detour-refs.d.ts.map +0 -1
- package/dist/rules/valid-detour-refs.js +0 -116
- package/dist/rules/valid-detour-refs.js.map +0 -1
- package/src/__tests__/cli.test.ts +0 -198
- package/src/__tests__/drift.test.ts +0 -74
- package/src/__tests__/formatters.test.ts +0 -157
- package/src/__tests__/implementation-returns-result.test.ts +0 -75
- package/src/__tests__/no-direct-implementation-call.test.ts +0 -83
- package/src/__tests__/no-sync-result-assumption.test.ts +0 -85
- package/src/__tests__/no-throw-in-detour-target.test.ts +0 -78
- package/src/__tests__/prefer-schema-inference.test.ts +0 -84
- package/src/__tests__/rules.test.ts +0 -188
- package/src/__tests__/valid-describe-refs.test.ts +0 -60
- package/src/rules/no-direct-impl-in-route.ts +0 -77
- package/src/rules/no-throw-in-detour-target.ts +0 -150
- package/src/rules/valid-detour-refs.ts +0 -187
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# @ontrails/warden
|
|
2
2
|
|
|
3
|
-
AST-based code convention rules for Trails.
|
|
3
|
+
AST-based code convention rules for Trails. Built-in lint rules catch contract violations at development time, alongside lock drift detection and CI formatters.
|
|
4
4
|
|
|
5
|
-
Structural checks (
|
|
5
|
+
Structural checks (compose target existence, declared resource existence, recursive composition, example schema validation) live in `validateTopo()` from `@ontrails/core`. Warden handles the code-level rules that need AST analysis.
|
|
6
|
+
|
|
7
|
+
For rule-home boundaries and authoring doctrine, see the [Warden guide](../../docs/warden.md) and [Warden Rules](../../docs/contributing/warden-rules.md).
|
|
6
8
|
|
|
7
9
|
## Usage
|
|
8
10
|
|
|
9
11
|
From the Trails CLI:
|
|
10
12
|
|
|
11
13
|
```bash
|
|
12
|
-
trails warden
|
|
13
|
-
trails warden --exit-code # Non-zero exit on errors or drift
|
|
14
|
-
trails warden --lint-only # Skip drift detection
|
|
15
|
-
trails warden --drift-only # Skip lint rules
|
|
14
|
+
bunx trails warden # Run all checks
|
|
16
15
|
```
|
|
17
16
|
|
|
18
17
|
Or programmatically:
|
|
@@ -20,35 +19,34 @@ Or programmatically:
|
|
|
20
19
|
```typescript
|
|
21
20
|
import { runWarden, formatWardenReport } from '@ontrails/warden';
|
|
22
21
|
|
|
23
|
-
const report = await runWarden(
|
|
22
|
+
const report = await runWarden({ topo: graph });
|
|
24
23
|
console.log(formatWardenReport(report));
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
## Rules
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
| `valid-describe-refs` | warn | `@see` refs in `.describe()` that do not resolve |
|
|
28
|
+
Built-in rules are registered in `wardenRules` and `wardenTopoRules`; use those registries or `wardenTopo.ids()` for the current rule list instead of copying a static table into docs.
|
|
29
|
+
|
|
30
|
+
Rules cover several families:
|
|
31
|
+
|
|
32
|
+
- blaze and `Result` contract checks
|
|
33
|
+
- compose, fire, resource, and detour declaration drift
|
|
34
|
+
- draft-state containment
|
|
35
|
+
- source-static guardrails such as surface-type leakage
|
|
36
|
+
- topo-aware checks that need the resolved graph or resource mock shape
|
|
37
|
+
|
|
38
|
+
When adding or auditing rules, follow [Warden Rules](../../docs/contributing/warden-rules.md): name the invariant, import owner-held framework data, choose the narrowest Warden tier, and collapse families only when the data model, traversal, and diagnostic shape are shared.
|
|
41
39
|
|
|
42
40
|
## Drift detection
|
|
43
41
|
|
|
44
|
-
Warden integrates with `@ontrails/
|
|
42
|
+
Warden integrates with `@ontrails/topographer` to detect when the topo has changed without updating the lock file:
|
|
45
43
|
|
|
46
44
|
```typescript
|
|
47
45
|
import { checkDrift } from '@ontrails/warden';
|
|
48
46
|
|
|
49
|
-
const drift = await checkDrift(
|
|
47
|
+
const drift = await checkDrift(process.cwd(), graph);
|
|
50
48
|
if (drift.stale) {
|
|
51
|
-
console.log('
|
|
49
|
+
console.log('lock file is stale -- regenerate with `trails compile`');
|
|
52
50
|
}
|
|
53
51
|
```
|
|
54
52
|
|
|
@@ -60,27 +58,80 @@ Add to lefthook for pre-push enforcement:
|
|
|
60
58
|
pre-push:
|
|
61
59
|
commands:
|
|
62
60
|
warden:
|
|
63
|
-
run: trails warden
|
|
61
|
+
run: bunx trails warden
|
|
64
62
|
tags: governance
|
|
65
63
|
```
|
|
66
64
|
|
|
67
65
|
CI formatters for structured output:
|
|
68
66
|
|
|
69
67
|
```typescript
|
|
70
|
-
import {
|
|
68
|
+
import {
|
|
69
|
+
formatGitHubAnnotations,
|
|
70
|
+
formatJson,
|
|
71
|
+
formatSummary,
|
|
72
|
+
} from '@ontrails/warden';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Parser helpers for rule authoring and repo-local tooling live on the dedicated AST entrypoint:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { findStringLiterals, parse, walk } from '@ontrails/warden/ast';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Trail-based API
|
|
82
|
+
|
|
83
|
+
Every built-in warden rule is also available as a composable trail. This makes rules queryable, testable, and invocable through any Trails surface.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import {
|
|
87
|
+
runTopoAwareWardenTrails,
|
|
88
|
+
runWardenTrails,
|
|
89
|
+
wardenTopo,
|
|
90
|
+
} from '@ontrails/warden';
|
|
91
|
+
|
|
92
|
+
// Inspect the warden rule trails
|
|
93
|
+
console.log(wardenTopo.ids()); // ['warden.rule.no-throw-in-implementation', ...]
|
|
94
|
+
|
|
95
|
+
// Run all rule trails against a source file
|
|
96
|
+
const diagnostics = await runWardenTrails(filePath, sourceCode, {
|
|
97
|
+
knownTrailIds: myApp.ids(),
|
|
98
|
+
knownResourceIds: myApp.resourceIds(),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Run built-in topo-aware rule trails once against the resolved graph
|
|
102
|
+
const topoDiagnostics = await runTopoAwareWardenTrails(myApp);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
To wrap a custom rule as a trail, import `wrapRule` from the root package entrypoint:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { wrapRule } from '@ontrails/warden';
|
|
71
109
|
```
|
|
72
110
|
|
|
111
|
+
This is the same factory used internally to build all built-in rule trails.
|
|
112
|
+
|
|
73
113
|
## API
|
|
74
114
|
|
|
75
115
|
| Export | What it does |
|
|
76
116
|
| --- | --- |
|
|
77
|
-
| `runWarden(
|
|
117
|
+
| `runWarden(options?)` | Run all rules and drift checks, return a report |
|
|
78
118
|
| `formatWardenReport(report)` | Human-readable report |
|
|
79
|
-
| `checkDrift(
|
|
119
|
+
| `checkDrift(rootDir, topo?)` | Check if the lock file matches the current topo |
|
|
80
120
|
| `wardenRules` | Registry of all built-in rules |
|
|
121
|
+
| `builtinWardenRuleMetadata` | Tier, scope, lifecycle, and invariant metadata for built-in rules |
|
|
122
|
+
| `getWardenRuleMetadata(ruleOrName)` | Resolve inline or built-in metadata for a Warden rule |
|
|
123
|
+
| `listWardenRuleMetadata()` | List built-in rule metadata entries |
|
|
124
|
+
| `wardenTopo` | `Topo` of all built-in rule trails (one per rule) |
|
|
125
|
+
| `runWardenTrails(filePath, sourceCode, options?)` | Dispatch file-scoped rule trails for a file, collect diagnostics |
|
|
126
|
+
| `runTopoAwareWardenTrails(topo)` | Dispatch built-in topo-aware rule trails once for a resolved topo |
|
|
81
127
|
| `formatGitHubAnnotations(report)` | GitHub Actions annotation format |
|
|
82
128
|
| `formatJson(report)` | Machine-readable JSON |
|
|
83
129
|
| `formatSummary(report)` | Compact summary line |
|
|
130
|
+
| `wrapRule(rule)` | Wrap a custom rule as a trail (same factory used for all built-in rule trails) |
|
|
131
|
+
|
|
132
|
+
AST parser helpers are exported from `@ontrails/warden/ast`, not the root runtime barrel. The stable authoring surface includes `parse`, `walk`, `walkScope`, `offsetToLine`, `findTrailDefinitions`, `findBlazeBodies`, `findContourDefinitions`, `isBlazeCall`, and string-literal helpers.
|
|
133
|
+
|
|
134
|
+
`runWarden({ tier })` can narrow a run to `source-static`, `project-static`, `topo-aware`, `drift`, or `advisory`. Omit `tier` for the default full run.
|
|
84
135
|
|
|
85
136
|
See the [API Reference](../../docs/api-reference.md) for the full list.
|
|
86
137
|
|
package/bin/warden.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/* oxlint-disable eslint-plugin-jest/require-hook -- CLI bin entrypoints execute at module scope */
|
|
3
|
+
|
|
4
|
+
import { runWardenCommand } from '../src/command.js';
|
|
5
|
+
|
|
6
|
+
const HELP = `Usage: warden [options]
|
|
7
|
+
|
|
8
|
+
Run Trails Warden governance checks.
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--ci Apply CI defaults
|
|
12
|
+
--pre-push Apply pre-push defaults
|
|
13
|
+
--apps, -a <names> Comma-delimited Trails app names
|
|
14
|
+
--config-path <path> Path to trails.config.* file
|
|
15
|
+
--root-dir <path> Project root to inspect
|
|
16
|
+
--fix Apply safe source fixes
|
|
17
|
+
--adapter-check Include shared adapter authoring diagnostics
|
|
18
|
+
--depth <value> source, project, topo, or all
|
|
19
|
+
--fail-on <value> error or warning
|
|
20
|
+
--format <value> summary, github, or json
|
|
21
|
+
--drafts <value> include, exclude, or only
|
|
22
|
+
--lock <value> auto, cached, refresh, or skip
|
|
23
|
+
--no-lock-mutation Do not write lock artifacts
|
|
24
|
+
--strict Fail on warnings
|
|
25
|
+
-h, --help Display help for command
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const args = Bun.argv.slice(2);
|
|
29
|
+
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
30
|
+
console.log(HELP);
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const env = { ...process.env } as Record<string, string | undefined>;
|
|
35
|
+
const result = await runWardenCommand({
|
|
36
|
+
args,
|
|
37
|
+
cwd: process.cwd(),
|
|
38
|
+
env,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (result.output.length > 0) {
|
|
42
|
+
console.log(result.output);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const summaryPath = env['GITHUB_STEP_SUMMARY'];
|
|
46
|
+
if (result.writeStepSummary && summaryPath !== undefined) {
|
|
47
|
+
await Bun.write(summaryPath, result.summary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
process.exit(result.exitCode);
|
package/package.json
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/warden",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.21",
|
|
4
|
+
"bin": {
|
|
5
|
+
"warden": "./bin/warden.ts"
|
|
6
|
+
},
|
|
7
|
+
"files": [
|
|
8
|
+
"bin/**/*.ts",
|
|
9
|
+
"src/**/*.ts",
|
|
10
|
+
"!src/**/__tests__/**",
|
|
11
|
+
"!src/**/*.test.ts",
|
|
12
|
+
"!src/**/*.test-d.ts",
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
4
16
|
"type": "module",
|
|
5
17
|
"exports": {
|
|
6
18
|
".": "./src/index.ts",
|
|
19
|
+
"./ast": "./src/ast.ts",
|
|
20
|
+
"./resolve": "./src/resolve.ts",
|
|
7
21
|
"./package.json": "./package.json"
|
|
8
22
|
},
|
|
9
23
|
"scripts": {
|
|
@@ -13,13 +27,21 @@
|
|
|
13
27
|
"lint": "oxlint ./src",
|
|
14
28
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
15
29
|
},
|
|
16
|
-
"
|
|
17
|
-
"@
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@ontrails/adapter-kit": "^1.0.0-beta.21",
|
|
32
|
+
"@ontrails/cli": "^1.0.0-beta.21",
|
|
33
|
+
"@ontrails/permits": "^1.0.0-beta.21",
|
|
34
|
+
"@ontrails/store": "^1.0.0-beta.21",
|
|
18
35
|
"oxc-parser": "^0.121.0",
|
|
36
|
+
"oxc-resolver": "11.19.1",
|
|
19
37
|
"zod": "^4.3.5"
|
|
20
38
|
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@ontrails/config": "^1.0.0-beta.21",
|
|
41
|
+
"@ontrails/testing": "^1.0.0-beta.21"
|
|
42
|
+
},
|
|
21
43
|
"peerDependencies": {
|
|
22
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
23
|
-
"@ontrails/
|
|
44
|
+
"@ontrails/core": "^1.0.0-beta.21",
|
|
45
|
+
"@ontrails/topographer": "^1.0.0-beta.21"
|
|
24
46
|
}
|
|
25
47
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warden projection for shared adapter readiness checks.
|
|
3
|
+
*
|
|
4
|
+
* Adapter facts stay in @ontrails/adapter-kit. Warden only maps those facts
|
|
5
|
+
* into governance diagnostics and severity.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { checkAdapters } from '@ontrails/adapter-kit';
|
|
9
|
+
import type { AdapterCheckDiagnostic } from '@ontrails/adapter-kit';
|
|
10
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
|
|
13
|
+
import type { WardenDiagnostic } from './rules/types.js';
|
|
14
|
+
|
|
15
|
+
export const adapterCheckRuleName = 'adapter-check';
|
|
16
|
+
const adapterCheckRootCode = 'adapter-check-root';
|
|
17
|
+
|
|
18
|
+
const isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>
|
|
19
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
20
|
+
|
|
21
|
+
const toWardenDiagnostic = (
|
|
22
|
+
diagnostic: AdapterCheckDiagnostic
|
|
23
|
+
): WardenDiagnostic => ({
|
|
24
|
+
code: diagnostic.code,
|
|
25
|
+
filePath: diagnostic.packageJsonPath,
|
|
26
|
+
line: 1,
|
|
27
|
+
message: diagnostic.message,
|
|
28
|
+
rule: adapterCheckRuleName,
|
|
29
|
+
severity: 'warn',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const toRootDiagnostic = (
|
|
33
|
+
message: string,
|
|
34
|
+
filePath: string
|
|
35
|
+
): WardenDiagnostic => ({
|
|
36
|
+
code: adapterCheckRootCode,
|
|
37
|
+
filePath,
|
|
38
|
+
line: 1,
|
|
39
|
+
message,
|
|
40
|
+
rule: adapterCheckRuleName,
|
|
41
|
+
severity: 'error',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const workspacePatternsFromManifest = (
|
|
45
|
+
manifest: Readonly<Record<string, unknown>>
|
|
46
|
+
): readonly string[] => {
|
|
47
|
+
const { workspaces } = manifest;
|
|
48
|
+
if (Array.isArray(workspaces)) {
|
|
49
|
+
return workspaces.filter(
|
|
50
|
+
(pattern): pattern is string => typeof pattern === 'string'
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const packages = isRecord(workspaces) ? workspaces['packages'] : undefined;
|
|
55
|
+
return Array.isArray(packages)
|
|
56
|
+
? packages.filter(
|
|
57
|
+
(pattern): pattern is string => typeof pattern === 'string'
|
|
58
|
+
)
|
|
59
|
+
: [];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const validateAdapterCheckRoot = (
|
|
63
|
+
rootDir: string
|
|
64
|
+
): readonly WardenDiagnostic[] => {
|
|
65
|
+
if (!existsSync(rootDir)) {
|
|
66
|
+
return [
|
|
67
|
+
toRootDiagnostic(
|
|
68
|
+
`adapter.check rootDir does not exist: "${rootDir}"`,
|
|
69
|
+
rootDir
|
|
70
|
+
),
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!statSync(rootDir).isDirectory()) {
|
|
75
|
+
return [
|
|
76
|
+
toRootDiagnostic(
|
|
77
|
+
`adapter.check rootDir must be a directory: "${rootDir}"`,
|
|
78
|
+
rootDir
|
|
79
|
+
),
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const packageJsonPath = join(rootDir, 'package.json');
|
|
84
|
+
if (!existsSync(packageJsonPath)) {
|
|
85
|
+
return [
|
|
86
|
+
toRootDiagnostic(
|
|
87
|
+
`adapter.check rootDir must contain a package.json workspace manifest: "${packageJsonPath}"`,
|
|
88
|
+
packageJsonPath
|
|
89
|
+
),
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let manifest: unknown;
|
|
94
|
+
try {
|
|
95
|
+
manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const reason = error instanceof Error ? `: ${error.message}` : '';
|
|
98
|
+
return [
|
|
99
|
+
toRootDiagnostic(
|
|
100
|
+
`adapter.check could not read root package.json: "${packageJsonPath}"${reason}`,
|
|
101
|
+
packageJsonPath
|
|
102
|
+
),
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!isRecord(manifest)) {
|
|
107
|
+
return [
|
|
108
|
+
toRootDiagnostic(
|
|
109
|
+
`adapter.check root package.json must contain a JSON object: "${packageJsonPath}"`,
|
|
110
|
+
packageJsonPath
|
|
111
|
+
),
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (workspacePatternsFromManifest(manifest).length === 0) {
|
|
116
|
+
return [
|
|
117
|
+
toRootDiagnostic(
|
|
118
|
+
`adapter.check root package.json must declare workspace packages: "${packageJsonPath}"`,
|
|
119
|
+
packageJsonPath
|
|
120
|
+
),
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return [];
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const runWardenAdapterChecks = (
|
|
128
|
+
rootDir: string
|
|
129
|
+
): readonly WardenDiagnostic[] => {
|
|
130
|
+
const rootDiagnostics = validateAdapterCheckRoot(rootDir);
|
|
131
|
+
if (rootDiagnostics.length > 0) {
|
|
132
|
+
return rootDiagnostics;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return checkAdapters(rootDir).diagnostics.map(toWardenDiagnostic);
|
|
136
|
+
};
|
package/src/ast.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Warden AST helper surface.
|
|
3
|
+
*
|
|
4
|
+
* These helpers are the supported parser primitives for repo-local tooling and
|
|
5
|
+
* rule authoring. Broader Trails-aware discovery helpers stay internal to the
|
|
6
|
+
* built-in rule implementation until they have a stable public contract.
|
|
7
|
+
*/
|
|
8
|
+
export {
|
|
9
|
+
findBlazeBodies,
|
|
10
|
+
findContourDefinitions,
|
|
11
|
+
findStringLiterals,
|
|
12
|
+
findTrailDefinitions,
|
|
13
|
+
getStringValue,
|
|
14
|
+
isBlazeCall,
|
|
15
|
+
isStringLiteral,
|
|
16
|
+
offsetToLine,
|
|
17
|
+
parse,
|
|
18
|
+
walk,
|
|
19
|
+
walkScope,
|
|
20
|
+
} from './rules/ast.js';
|
|
21
|
+
export type {
|
|
22
|
+
AstNode,
|
|
23
|
+
ContourDefinition,
|
|
24
|
+
FindContourDefinitionsOptions,
|
|
25
|
+
FrameworkNamespaceContext,
|
|
26
|
+
StringLiteralMatch,
|
|
27
|
+
TrailDefinition,
|
|
28
|
+
} from './rules/ast.js';
|