@ontrails/warden 1.0.0-beta.14 → 1.0.0-beta.16
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 +149 -0
- package/README.md +77 -34
- package/bin/warden.ts +22 -0
- package/package.json +26 -6
- package/src/ast.ts +28 -0
- package/src/cli.ts +1169 -116
- package/src/command.ts +927 -0
- package/src/config.ts +184 -0
- package/src/drift.ts +76 -34
- package/src/formatters.ts +54 -7
- package/src/guide.ts +234 -0
- package/src/index.ts +151 -38
- 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 +2884 -124
- package/src/rules/circular-refs.ts +154 -0
- package/src/rules/{context-no-trailhead-types.ts → context-no-surface-types.ts} +72 -12
- package/src/rules/contour-exists.ts +251 -0
- package/src/rules/contour-ids.ts +15 -0
- package/src/rules/cross-declarations.ts +277 -69
- package/src/rules/dead-internal-trail.ts +141 -0
- package/src/rules/draft-file-marking.ts +51 -3
- package/src/rules/draft-visible-debt.ts +40 -15
- 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 +1042 -122
- package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
- package/src/rules/incomplete-crud.ts +580 -0
- package/src/rules/index.ts +156 -19
- package/src/rules/intent-propagation.ts +127 -0
- package/src/rules/layer-field-name-drift.ts +96 -0
- package/src/rules/metadata.ts +508 -0
- package/src/rules/missing-reconcile.ts +98 -0
- package/src/rules/missing-visibility.ts +110 -0
- package/src/rules/no-dev-permit-in-source.ts +99 -0
- package/src/rules/no-direct-implementation-call.ts +1 -1
- package/src/rules/no-legacy-layer-imports.ts +193 -0
- package/src/rules/no-native-error-result.ts +111 -0
- package/src/rules/no-sync-result-assumption.ts +1131 -96
- package/src/rules/no-throw-in-detour-recover.ts +225 -0
- package/src/rules/no-throw-in-implementation.ts +6 -4
- 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-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 +113 -0
- package/src/rules/resolved-import-boundary.ts +146 -0
- package/src/rules/{provision-declarations.ts → resource-declarations.ts} +208 -138
- package/src/rules/{provision-exists.ts → resource-exists.ts} +46 -51
- package/src/rules/resource-id-grammar.ts +65 -0
- package/src/rules/scan.ts +0 -26
- package/src/rules/scheduled-destroy-intent.ts +44 -0
- package/src/rules/signal-graph-coaching.ts +191 -0
- package/src/rules/specs.ts +5 -1
- package/src/rules/static-resource-accessor-preference.ts +657 -0
- package/src/rules/types.ts +187 -7
- 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 +81 -0
- package/src/trails/circular-refs.trail.ts +29 -0
- package/src/trails/{context-no-trailhead-types.trail.ts → context-no-surface-types.trail.ts} +4 -4
- package/src/trails/contour-exists.trail.ts +21 -0
- package/src/trails/dead-internal-trail.trail.ts +26 -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/incomplete-accessor-for-standard-op.trail.ts +76 -0
- package/src/trails/incomplete-crud.trail.ts +39 -0
- package/src/trails/index.ts +56 -8
- package/src/trails/intent-propagation.trail.ts +30 -0
- package/src/trails/layer-field-name-drift.trail.ts +39 -0
- package/src/trails/missing-reconcile.trail.ts +33 -0
- package/src/trails/missing-visibility.trail.ts +22 -0
- package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
- package/src/trails/no-legacy-layer-imports.trail.ts +35 -0
- package/src/trails/no-native-error-result.trail.ts +18 -0
- package/src/trails/no-throw-in-detour-recover.trail.ts +24 -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/permit-governance.trail.ts +51 -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/{provision-declarations.trail.ts → resource-declarations.trail.ts} +6 -6
- package/src/trails/{provision-exists.trail.ts → resource-exists.trail.ts} +7 -7
- package/src/trails/resource-id-grammar.trail.ts +39 -0
- package/src/trails/run.ts +133 -24
- package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
- package/src/trails/schema.ts +122 -4
- package/src/trails/signal-graph-coaching.trail.ts +74 -0
- package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
- package/src/trails/unmaterialized-activation-source.trail.ts +69 -0
- package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
- package/src/trails/valid-detour-contract.trail.ts +71 -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 +133 -14
- 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 -247
- package/dist/cli.js.map +0 -1
- package/dist/draft.d.ts +0 -5
- package/dist/draft.d.ts.map +0 -1
- package/dist/draft.js +0 -16
- package/dist/draft.js.map +0 -1
- package/dist/drift.d.ts +0 -29
- package/dist/drift.d.ts.map +0 -1
- package/dist/drift.js +0 -61
- package/dist/drift.js.map +0 -1
- package/dist/formatters.d.ts +0 -30
- package/dist/formatters.d.ts.map +0 -1
- package/dist/formatters.js +0 -98
- package/dist/formatters.js.map +0 -1
- package/dist/index.d.ts +0 -37
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -38
- package/dist/index.js.map +0 -1
- package/dist/rules/ast.d.ts +0 -82
- package/dist/rules/ast.d.ts.map +0 -1
- package/dist/rules/ast.js +0 -363
- 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/context-no-trailhead-types.d.ts +0 -12
- package/dist/rules/context-no-trailhead-types.d.ts.map +0 -1
- package/dist/rules/context-no-trailhead-types.js +0 -96
- package/dist/rules/context-no-trailhead-types.js.map +0 -1
- package/dist/rules/cross-declarations.d.ts +0 -13
- package/dist/rules/cross-declarations.d.ts.map +0 -1
- package/dist/rules/cross-declarations.js +0 -264
- package/dist/rules/cross-declarations.js.map +0 -1
- package/dist/rules/draft-file-marking.d.ts +0 -6
- package/dist/rules/draft-file-marking.d.ts.map +0 -1
- package/dist/rules/draft-file-marking.js +0 -65
- package/dist/rules/draft-file-marking.js.map +0 -1
- package/dist/rules/draft-visible-debt.d.ts +0 -12
- package/dist/rules/draft-visible-debt.d.ts.map +0 -1
- package/dist/rules/draft-visible-debt.js +0 -45
- package/dist/rules/draft-visible-debt.js.map +0 -1
- package/dist/rules/follow-declarations.d.ts +0 -13
- package/dist/rules/follow-declarations.d.ts.map +0 -1
- package/dist/rules/follow-declarations.js +0 -264
- package/dist/rules/follow-declarations.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 -277
- package/dist/rules/implementation-returns-result.js.map +0 -1
- package/dist/rules/index.d.ts +0 -20
- package/dist/rules/index.d.ts.map +0 -1
- package/dist/rules/index.js +0 -49
- 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 -47
- 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/provision-declarations.d.ts +0 -14
- package/dist/rules/provision-declarations.d.ts.map +0 -1
- package/dist/rules/provision-declarations.js +0 -344
- package/dist/rules/provision-declarations.js.map +0 -1
- package/dist/rules/provision-exists.d.ts +0 -6
- package/dist/rules/provision-exists.d.ts.map +0 -1
- package/dist/rules/provision-exists.js +0 -90
- package/dist/rules/provision-exists.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/service-declarations.d.ts +0 -16
- package/dist/rules/service-declarations.d.ts.map +0 -1
- package/dist/rules/service-declarations.js +0 -346
- package/dist/rules/service-declarations.js.map +0 -1
- package/dist/rules/service-exists.d.ts +0 -8
- package/dist/rules/service-exists.d.ts.map +0 -1
- package/dist/rules/service-exists.js +0 -91
- package/dist/rules/service-exists.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 -54
- 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 -117
- package/dist/rules/valid-detour-refs.js.map +0 -1
- package/dist/trails/context-no-surface-types.trail.d.ts +0 -13
- package/dist/trails/context-no-surface-types.trail.d.ts.map +0 -1
- package/dist/trails/context-no-surface-types.trail.js +0 -21
- package/dist/trails/context-no-surface-types.trail.js.map +0 -1
- package/dist/trails/context-no-trailhead-types.trail.d.ts +0 -13
- package/dist/trails/context-no-trailhead-types.trail.d.ts.map +0 -1
- package/dist/trails/context-no-trailhead-types.trail.js +0 -21
- package/dist/trails/context-no-trailhead-types.trail.js.map +0 -1
- package/dist/trails/cross-declarations.trail.d.ts +0 -13
- package/dist/trails/cross-declarations.trail.d.ts.map +0 -1
- package/dist/trails/cross-declarations.trail.js +0 -22
- package/dist/trails/cross-declarations.trail.js.map +0 -1
- package/dist/trails/follow-declarations.trail.d.ts +0 -13
- package/dist/trails/follow-declarations.trail.d.ts.map +0 -1
- package/dist/trails/follow-declarations.trail.js +0 -22
- package/dist/trails/follow-declarations.trail.js.map +0 -1
- package/dist/trails/implementation-returns-result.trail.d.ts +0 -13
- package/dist/trails/implementation-returns-result.trail.d.ts.map +0 -1
- package/dist/trails/implementation-returns-result.trail.js +0 -20
- package/dist/trails/implementation-returns-result.trail.js.map +0 -1
- package/dist/trails/index.d.ts +0 -16
- package/dist/trails/index.d.ts.map +0 -1
- package/dist/trails/index.js +0 -15
- package/dist/trails/index.js.map +0 -1
- package/dist/trails/no-direct-impl-in-route.trail.d.ts +0 -13
- package/dist/trails/no-direct-impl-in-route.trail.d.ts.map +0 -1
- package/dist/trails/no-direct-impl-in-route.trail.js +0 -22
- package/dist/trails/no-direct-impl-in-route.trail.js.map +0 -1
- package/dist/trails/no-direct-implementation-call.trail.d.ts +0 -13
- package/dist/trails/no-direct-implementation-call.trail.d.ts.map +0 -1
- package/dist/trails/no-direct-implementation-call.trail.js +0 -16
- package/dist/trails/no-direct-implementation-call.trail.js.map +0 -1
- package/dist/trails/no-sync-result-assumption.trail.d.ts +0 -13
- package/dist/trails/no-sync-result-assumption.trail.d.ts.map +0 -1
- package/dist/trails/no-sync-result-assumption.trail.js +0 -19
- package/dist/trails/no-sync-result-assumption.trail.js.map +0 -1
- package/dist/trails/no-throw-in-detour-target.trail.d.ts +0 -15
- package/dist/trails/no-throw-in-detour-target.trail.d.ts.map +0 -1
- package/dist/trails/no-throw-in-detour-target.trail.js +0 -20
- package/dist/trails/no-throw-in-detour-target.trail.js.map +0 -1
- package/dist/trails/no-throw-in-implementation.trail.d.ts +0 -13
- package/dist/trails/no-throw-in-implementation.trail.d.ts.map +0 -1
- package/dist/trails/no-throw-in-implementation.trail.js +0 -20
- package/dist/trails/no-throw-in-implementation.trail.js.map +0 -1
- package/dist/trails/prefer-schema-inference.trail.d.ts +0 -13
- package/dist/trails/prefer-schema-inference.trail.d.ts.map +0 -1
- package/dist/trails/prefer-schema-inference.trail.js +0 -21
- package/dist/trails/prefer-schema-inference.trail.js.map +0 -1
- package/dist/trails/provision-declarations.trail.d.ts +0 -13
- package/dist/trails/provision-declarations.trail.d.ts.map +0 -1
- package/dist/trails/provision-declarations.trail.js +0 -25
- package/dist/trails/provision-declarations.trail.js.map +0 -1
- package/dist/trails/provision-exists.trail.d.ts +0 -15
- package/dist/trails/provision-exists.trail.d.ts.map +0 -1
- package/dist/trails/provision-exists.trail.js +0 -27
- package/dist/trails/provision-exists.trail.js.map +0 -1
- package/dist/trails/run.d.ts +0 -17
- package/dist/trails/run.d.ts.map +0 -1
- package/dist/trails/run.js +0 -39
- package/dist/trails/run.js.map +0 -1
- package/dist/trails/schema.d.ts +0 -53
- package/dist/trails/schema.d.ts.map +0 -1
- package/dist/trails/schema.js +0 -42
- package/dist/trails/schema.js.map +0 -1
- package/dist/trails/service-declarations.trail.d.ts +0 -26
- package/dist/trails/service-declarations.trail.d.ts.map +0 -1
- package/dist/trails/service-declarations.trail.js +0 -27
- package/dist/trails/service-declarations.trail.js.map +0 -1
- package/dist/trails/service-exists.trail.d.ts +0 -32
- package/dist/trails/service-exists.trail.d.ts.map +0 -1
- package/dist/trails/service-exists.trail.js +0 -29
- package/dist/trails/service-exists.trail.js.map +0 -1
- package/dist/trails/topo.d.ts +0 -3
- package/dist/trails/topo.d.ts.map +0 -1
- package/dist/trails/topo.js +0 -5
- package/dist/trails/topo.js.map +0 -1
- package/dist/trails/valid-describe-refs.trail.d.ts +0 -15
- package/dist/trails/valid-describe-refs.trail.d.ts.map +0 -1
- package/dist/trails/valid-describe-refs.trail.js +0 -18
- package/dist/trails/valid-describe-refs.trail.js.map +0 -1
- package/dist/trails/valid-detour-refs.trail.d.ts +0 -15
- package/dist/trails/valid-detour-refs.trail.d.ts.map +0 -1
- package/dist/trails/valid-detour-refs.trail.js +0 -24
- package/dist/trails/valid-detour-refs.trail.js.map +0 -1
- package/dist/trails/wrap-rule.d.ts +0 -29
- package/dist/trails/wrap-rule.d.ts.map +0 -1
- package/dist/trails/wrap-rule.js +0 -47
- package/dist/trails/wrap-rule.js.map +0 -1
- package/src/__tests__/cli.test.ts +0 -311
- package/src/__tests__/cross-declarations.test.ts +0 -303
- package/src/__tests__/drift.test.ts +0 -144
- package/src/__tests__/formatters.test.ts +0 -157
- package/src/__tests__/implementation-returns-result.test.ts +0 -129
- 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__/provision-declarations.test.ts +0 -318
- package/src/__tests__/provision-exists.test.ts +0 -122
- package/src/__tests__/rules.test.ts +0 -227
- package/src/__tests__/trails.test.ts +0 -19
- package/src/__tests__/valid-describe-refs.test.ts +0 -60
- package/src/__tests__/wrap-rule.test.ts +0 -41
- package/src/rules/no-direct-impl-in-route.ts +0 -81
- package/src/rules/no-throw-in-detour-target.ts +0 -150
- package/src/rules/valid-detour-refs.ts +0 -189
- package/src/trails/no-direct-impl-in-route.trail.ts +0 -22
- package/src/trails/no-throw-in-detour-target.trail.ts +0 -20
- package/src/trails/valid-detour-refs.trail.ts +0 -24
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import { contextNoTrailheadTypes } from '../rules/context-no-trailhead-types.js';
|
|
4
|
-
import { noDirectImplInRoute } from '../rules/no-direct-impl-in-route.js';
|
|
5
|
-
import { noThrowInImplementation } from '../rules/no-throw-in-implementation.js';
|
|
6
|
-
import { validDetourRefs } from '../rules/valid-detour-refs.js';
|
|
7
|
-
|
|
8
|
-
const TEST_FILE = 'test.ts';
|
|
9
|
-
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
// no-throw-in-implementation
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
describe('no-throw-in-implementation', () => {
|
|
14
|
-
test('flags throw inside implementation body', () => {
|
|
15
|
-
const code = `
|
|
16
|
-
trail("entity.show", {
|
|
17
|
-
blaze: async (input, ctx) => {
|
|
18
|
-
throw new Error("boom");
|
|
19
|
-
}
|
|
20
|
-
})`;
|
|
21
|
-
const diagnostics = noThrowInImplementation.check(code, TEST_FILE);
|
|
22
|
-
expect(diagnostics.length).toBe(1);
|
|
23
|
-
expect(diagnostics[0]?.rule).toBe('no-throw-in-implementation');
|
|
24
|
-
expect(diagnostics[0]?.severity).toBe('error');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('allows Result.err() in implementation', () => {
|
|
28
|
-
const code = `
|
|
29
|
-
trail("entity.show", {
|
|
30
|
-
blaze: async (input, ctx) => {
|
|
31
|
-
return Result.err(new NotFoundError("not found"));
|
|
32
|
-
}
|
|
33
|
-
})`;
|
|
34
|
-
const diagnostics = noThrowInImplementation.check(code, TEST_FILE);
|
|
35
|
-
expect(diagnostics.length).toBe(0);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('does not flag throw outside implementation', () => {
|
|
39
|
-
const code = `
|
|
40
|
-
function helper() {
|
|
41
|
-
throw new Error("boom");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
trail("entity.show", {
|
|
45
|
-
blaze: async (input, ctx) => {
|
|
46
|
-
return Result.ok(data);
|
|
47
|
-
}
|
|
48
|
-
})`;
|
|
49
|
-
const diagnostics = noThrowInImplementation.check(code, TEST_FILE);
|
|
50
|
-
expect(diagnostics.length).toBe(0);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
// context-no-trailhead-types
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
describe('context-no-trailhead-types', () => {
|
|
58
|
-
test('flags express import in trail file', () => {
|
|
59
|
-
const code = `
|
|
60
|
-
import { Request, Response } from "express";
|
|
61
|
-
trail("entity.show", {
|
|
62
|
-
blaze: async (input, ctx) => {
|
|
63
|
-
return Result.ok(data);
|
|
64
|
-
}
|
|
65
|
-
})`;
|
|
66
|
-
const diagnostics = contextNoTrailheadTypes.check(code, TEST_FILE);
|
|
67
|
-
expect(diagnostics.length).toBe(1);
|
|
68
|
-
expect(diagnostics[0]?.rule).toBe('context-no-trailhead-types');
|
|
69
|
-
expect(diagnostics[0]?.message).toContain('express');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('flags McpSession import in trail file', () => {
|
|
73
|
-
const code = `
|
|
74
|
-
import type { McpSession } from "@modelcontextprotocol/sdk";
|
|
75
|
-
trail("entity.show", {
|
|
76
|
-
blaze: async (input, ctx) => {
|
|
77
|
-
return Result.ok(data);
|
|
78
|
-
}
|
|
79
|
-
})`;
|
|
80
|
-
const diagnostics = contextNoTrailheadTypes.check(code, TEST_FILE);
|
|
81
|
-
expect(diagnostics.length).toBe(1);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('allows @ontrails/core imports in trail file', () => {
|
|
85
|
-
const code = `
|
|
86
|
-
import { trail, Result } from "@ontrails/core";
|
|
87
|
-
trail("entity.show", {
|
|
88
|
-
blaze: async (input, ctx) => {
|
|
89
|
-
return Result.ok(data);
|
|
90
|
-
}
|
|
91
|
-
})`;
|
|
92
|
-
const diagnostics = contextNoTrailheadTypes.check(code, TEST_FILE);
|
|
93
|
-
expect(diagnostics.length).toBe(0);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('ignores files without trail() calls', () => {
|
|
97
|
-
const code = `
|
|
98
|
-
import { Request, Response } from "express";
|
|
99
|
-
export function handleRequest(req: Request, res: Response) {}`;
|
|
100
|
-
const diagnostics = contextNoTrailheadTypes.check(code, TEST_FILE);
|
|
101
|
-
expect(diagnostics.length).toBe(0);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
// valid-detour-refs
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
describe('valid-detour-refs', () => {
|
|
109
|
-
test('flags detour target that does not exist', () => {
|
|
110
|
-
const code = `
|
|
111
|
-
trail("entity.show", {
|
|
112
|
-
detours: [{ target: "entity.edit" }],
|
|
113
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
114
|
-
})`;
|
|
115
|
-
const diagnostics = validDetourRefs.check(code, TEST_FILE);
|
|
116
|
-
expect(diagnostics.length).toBe(1);
|
|
117
|
-
expect(diagnostics[0]?.message).toContain('entity.edit');
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test('passes when detour target exists', () => {
|
|
121
|
-
const code = `
|
|
122
|
-
trail("entity.edit", {
|
|
123
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
trail("entity.show", {
|
|
127
|
-
detours: [{ target: "entity.edit" }],
|
|
128
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
129
|
-
})`;
|
|
130
|
-
const diagnostics = validDetourRefs.check(code, TEST_FILE);
|
|
131
|
-
expect(diagnostics.length).toBe(0);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test('uses project context when available', () => {
|
|
135
|
-
const code = `
|
|
136
|
-
trail("entity.show", {
|
|
137
|
-
detours: [{ target: "entity.edit" }],
|
|
138
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
139
|
-
})`;
|
|
140
|
-
const context = { knownTrailIds: new Set(['entity.show', 'entity.edit']) };
|
|
141
|
-
const diagnostics = validDetourRefs.checkWithContext(
|
|
142
|
-
code,
|
|
143
|
-
TEST_FILE,
|
|
144
|
-
context
|
|
145
|
-
);
|
|
146
|
-
expect(diagnostics.length).toBe(0);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test('flags detour target in trail with crossings that does not exist', () => {
|
|
150
|
-
const code = `
|
|
151
|
-
trail("entity.onboard", {
|
|
152
|
-
detours: [{ target: "entity.missing" }],
|
|
153
|
-
crosses: ["entity.create"],
|
|
154
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
155
|
-
})`;
|
|
156
|
-
const diagnostics = validDetourRefs.check(code, TEST_FILE);
|
|
157
|
-
expect(diagnostics.length).toBe(1);
|
|
158
|
-
expect(diagnostics[0]?.message).toContain('entity.missing');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test('passes when trail with crossings detour target exists', () => {
|
|
162
|
-
const code = `
|
|
163
|
-
trail("entity.fallback", {
|
|
164
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
trail("entity.onboard", {
|
|
168
|
-
detours: [{ target: "entity.fallback" }],
|
|
169
|
-
crosses: ["entity.create"],
|
|
170
|
-
blaze: async (input, ctx) => Result.ok(data)
|
|
171
|
-
})`;
|
|
172
|
-
const diagnostics = validDetourRefs.check(code, TEST_FILE);
|
|
173
|
-
expect(diagnostics.length).toBe(0);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// ---------------------------------------------------------------------------
|
|
178
|
-
// no-direct-impl-in-route
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
describe('no-direct-impl-in-route', () => {
|
|
181
|
-
test('warns on direct .blaze() call in trail with crossings', () => {
|
|
182
|
-
const code = `
|
|
183
|
-
trail("entity.onboard", {
|
|
184
|
-
crosses: ["entity.create"],
|
|
185
|
-
blaze: async (input, ctx) => {
|
|
186
|
-
const result = await entityCreate.blaze(data);
|
|
187
|
-
return Result.ok(result);
|
|
188
|
-
}
|
|
189
|
-
})`;
|
|
190
|
-
const diagnostics = noDirectImplInRoute.check(code, TEST_FILE);
|
|
191
|
-
expect(diagnostics.length).toBe(1);
|
|
192
|
-
expect(diagnostics[0]?.severity).toBe('warn');
|
|
193
|
-
expect(diagnostics[0]?.message).toContain('ctx.cross');
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
test('allows ctx.cross() calls', () => {
|
|
197
|
-
const code = `
|
|
198
|
-
trail("entity.onboard", {
|
|
199
|
-
crosses: ["entity.create"],
|
|
200
|
-
blaze: async (input, ctx) => {
|
|
201
|
-
const result = await ctx.cross("entity.create", data);
|
|
202
|
-
return Result.ok(result);
|
|
203
|
-
}
|
|
204
|
-
})`;
|
|
205
|
-
const diagnostics = noDirectImplInRoute.check(code, TEST_FILE);
|
|
206
|
-
expect(diagnostics.length).toBe(0);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
test('ignores trails without crossings', () => {
|
|
210
|
-
const code = `
|
|
211
|
-
trail("entity.show", {
|
|
212
|
-
blaze: async (input, ctx) => {
|
|
213
|
-
const result = await someTrail.blaze(data);
|
|
214
|
-
return Result.ok(result);
|
|
215
|
-
}
|
|
216
|
-
})`;
|
|
217
|
-
const diagnostics = noDirectImplInRoute.check(code, TEST_FILE);
|
|
218
|
-
expect(diagnostics.length).toBe(0);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
test('ignores files without trail() calls', () => {
|
|
222
|
-
const code = `
|
|
223
|
-
const result = await someTrail.blaze(data);`;
|
|
224
|
-
const diagnostics = noDirectImplInRoute.check(code, TEST_FILE);
|
|
225
|
-
expect(diagnostics.length).toBe(0);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import { testAll } from '@ontrails/testing';
|
|
3
|
-
|
|
4
|
-
import { wardenTopo } from '../trails/topo.js';
|
|
5
|
-
|
|
6
|
-
// oxlint-disable-next-line jest/require-hook -- testAll generates describe/test blocks, not setup code
|
|
7
|
-
testAll(wardenTopo);
|
|
8
|
-
|
|
9
|
-
describe('wardenTopo', () => {
|
|
10
|
-
test('contains all 13 rule trails', () => {
|
|
11
|
-
expect(wardenTopo.count).toBe(13);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test('all trail IDs follow warden.rule.* naming', () => {
|
|
15
|
-
for (const id of wardenTopo.ids()) {
|
|
16
|
-
expect(id).toMatch(/^warden\.rule\./);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import { validDescribeRefs } from '../rules/valid-describe-refs.js';
|
|
4
|
-
|
|
5
|
-
describe('valid-describe-refs', () => {
|
|
6
|
-
test('warns when a describe @see tag points to a missing trail', () => {
|
|
7
|
-
const code = `
|
|
8
|
-
trail("entity.show", {
|
|
9
|
-
input: z.object({
|
|
10
|
-
query: z.string().describe("Search query. @see entity.search"),
|
|
11
|
-
}),
|
|
12
|
-
blaze: (input) => Result.ok(input),
|
|
13
|
-
})`;
|
|
14
|
-
|
|
15
|
-
const diagnostics = validDescribeRefs.check(code, 'src/entity.ts');
|
|
16
|
-
|
|
17
|
-
expect(diagnostics).toHaveLength(1);
|
|
18
|
-
expect(diagnostics[0]?.rule).toBe('valid-describe-refs');
|
|
19
|
-
expect(diagnostics[0]?.message).toContain('entity.search');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('allows local @see references that resolve in the same file', () => {
|
|
23
|
-
const code = `
|
|
24
|
-
trail("entity.search", {
|
|
25
|
-
input: z.object({ query: z.string() }),
|
|
26
|
-
blaze: (input) => Result.ok(input),
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
trail("entity.show", {
|
|
30
|
-
input: z.object({
|
|
31
|
-
query: z.string().describe("Search query. @see entity.search"),
|
|
32
|
-
}),
|
|
33
|
-
blaze: (input) => Result.ok(input),
|
|
34
|
-
})`;
|
|
35
|
-
|
|
36
|
-
const diagnostics = validDescribeRefs.check(code, 'src/entity.ts');
|
|
37
|
-
|
|
38
|
-
expect(diagnostics).toHaveLength(0);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('uses project context for cross-file @see references', () => {
|
|
42
|
-
const code = `
|
|
43
|
-
trail("entity.show", {
|
|
44
|
-
input: z.object({
|
|
45
|
-
query: z.string().describe("Search query. @see entity.search"),
|
|
46
|
-
}),
|
|
47
|
-
blaze: (input) => Result.ok(input),
|
|
48
|
-
})`;
|
|
49
|
-
|
|
50
|
-
const diagnostics = validDescribeRefs.checkWithContext(
|
|
51
|
-
code,
|
|
52
|
-
'src/entity.ts',
|
|
53
|
-
{
|
|
54
|
-
knownTrailIds: new Set(['entity.search', 'entity.show']),
|
|
55
|
-
}
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(diagnostics).toHaveLength(0);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import { createTrailContext } from '@ontrails/core';
|
|
4
|
-
|
|
5
|
-
import { wrapRule } from '../trails/wrap-rule.js';
|
|
6
|
-
import type { ProjectAwareWardenRule } from '../rules/types.js';
|
|
7
|
-
|
|
8
|
-
describe('wrapRule', () => {
|
|
9
|
-
test('preserves undefined knownProvisionIds and defaults knownTrailIds to empty set', async () => {
|
|
10
|
-
let capturedContext:
|
|
11
|
-
| {
|
|
12
|
-
readonly knownProvisionIds?: ReadonlySet<string>;
|
|
13
|
-
readonly knownTrailIds?: ReadonlySet<string>;
|
|
14
|
-
}
|
|
15
|
-
| undefined;
|
|
16
|
-
|
|
17
|
-
const rule: ProjectAwareWardenRule = {
|
|
18
|
-
check: () => [],
|
|
19
|
-
checkWithContext: (_sourceCode, _filePath, context) => {
|
|
20
|
-
capturedContext = context;
|
|
21
|
-
return [];
|
|
22
|
-
},
|
|
23
|
-
description: 'dummy rule',
|
|
24
|
-
name: 'dummy-rule',
|
|
25
|
-
severity: 'error',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const wrapped = wrapRule({ examples: [], rule });
|
|
29
|
-
const result = await wrapped.blaze(
|
|
30
|
-
{ filePath: 'entity.ts', sourceCode: '' },
|
|
31
|
-
createTrailContext()
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
expect(result.isOk()).toBe(true);
|
|
35
|
-
expect(result.unwrap()).toEqual({ diagnostics: [] });
|
|
36
|
-
expect(capturedContext).toEqual({
|
|
37
|
-
knownProvisionIds: undefined,
|
|
38
|
-
knownTrailIds: new Set<string>(),
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detects trail implementations with `crosses` that call `.blaze()` directly.
|
|
3
|
-
*
|
|
4
|
-
* Uses AST parsing to find trail definitions that declare `crosses` and check for
|
|
5
|
-
* `.blaze()` call expressions in their bodies.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
findConfigProperty,
|
|
10
|
-
findBlazeBodies,
|
|
11
|
-
findTrailDefinitions,
|
|
12
|
-
isBlazeCall,
|
|
13
|
-
offsetToLine,
|
|
14
|
-
parse,
|
|
15
|
-
walk,
|
|
16
|
-
} from './ast.js';
|
|
17
|
-
import type { WardenDiagnostic, WardenRule } from './types.js';
|
|
18
|
-
|
|
19
|
-
interface AstNode {
|
|
20
|
-
readonly type: string;
|
|
21
|
-
readonly start: number;
|
|
22
|
-
readonly end: number;
|
|
23
|
-
readonly [key: string]: unknown;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const findImplCallsInTrailWithCrosses = (
|
|
27
|
-
def: { readonly config: AstNode },
|
|
28
|
-
filePath: string,
|
|
29
|
-
sourceCode: string,
|
|
30
|
-
diagnostics: WardenDiagnostic[]
|
|
31
|
-
): void => {
|
|
32
|
-
for (const body of findBlazeBodies(def.config as AstNode)) {
|
|
33
|
-
walk(body, (node) => {
|
|
34
|
-
if (isBlazeCall(node as AstNode)) {
|
|
35
|
-
diagnostics.push({
|
|
36
|
-
filePath,
|
|
37
|
-
line: offsetToLine(sourceCode, node.start),
|
|
38
|
-
message:
|
|
39
|
-
'Use ctx.cross("trailId", input) instead of direct .blaze() calls. ctx.cross() validates input and propagates tracing.',
|
|
40
|
-
rule: 'no-direct-impl-in-route',
|
|
41
|
-
severity: 'warn',
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const hasCrossesProperty = (config: AstNode): boolean =>
|
|
49
|
-
findConfigProperty(config as AstNode, 'crosses') !== null;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Detects trails with `crosses` that call another trail's `.blaze()` directly.
|
|
53
|
-
*/
|
|
54
|
-
export const noDirectImplInRoute: WardenRule = {
|
|
55
|
-
check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
|
|
56
|
-
if (!/\btrail\s*\(/.test(sourceCode)) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const ast = parse(filePath, sourceCode);
|
|
61
|
-
if (!ast) {
|
|
62
|
-
return [];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const diagnostics: WardenDiagnostic[] = [];
|
|
66
|
-
const crossDefs = findTrailDefinitions(ast as AstNode).filter((d) =>
|
|
67
|
-
hasCrossesProperty(d.config as AstNode)
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
for (const def of crossDefs) {
|
|
71
|
-
findImplCallsInTrailWithCrosses(def, filePath, sourceCode, diagnostics);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return diagnostics;
|
|
75
|
-
},
|
|
76
|
-
description:
|
|
77
|
-
'Prefer ctx.cross() over direct .blaze() calls in trail bodies with crossings.',
|
|
78
|
-
name: 'no-direct-impl-in-route',
|
|
79
|
-
|
|
80
|
-
severity: 'warn',
|
|
81
|
-
};
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Flags throws in implementations that are used as detour targets.
|
|
3
|
-
*
|
|
4
|
-
* Uses AST parsing for accurate detection of detour target IDs and
|
|
5
|
-
* throw statements within those trail implementations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
findBlazeBodies,
|
|
10
|
-
findTrailDefinitions,
|
|
11
|
-
offsetToLine,
|
|
12
|
-
parse,
|
|
13
|
-
walk,
|
|
14
|
-
} from './ast.js';
|
|
15
|
-
import { isTestFile } from './scan.js';
|
|
16
|
-
import type {
|
|
17
|
-
ProjectAwareWardenRule,
|
|
18
|
-
ProjectContext,
|
|
19
|
-
WardenDiagnostic,
|
|
20
|
-
} from './types.js';
|
|
21
|
-
|
|
22
|
-
interface AstNode {
|
|
23
|
-
readonly type: string;
|
|
24
|
-
readonly start: number;
|
|
25
|
-
readonly end: number;
|
|
26
|
-
readonly [key: string]: unknown;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Collect all trail IDs referenced as detour targets in the AST. */
|
|
30
|
-
const collectDetourTargets = (ast: AstNode): ReadonlySet<string> => {
|
|
31
|
-
const targets = new Set<string>();
|
|
32
|
-
|
|
33
|
-
walk(ast, (node) => {
|
|
34
|
-
if (
|
|
35
|
-
node.type !== 'Property' ||
|
|
36
|
-
node.key?.name !== 'detours' ||
|
|
37
|
-
!node.value
|
|
38
|
-
) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
walk(node.value as AstNode, (inner) => {
|
|
43
|
-
if (inner.type === 'Literal' || inner.type === 'StringLiteral') {
|
|
44
|
-
const { value } = inner as unknown as { value?: unknown };
|
|
45
|
-
if (typeof value === 'string' && value.includes('.')) {
|
|
46
|
-
targets.add(value);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return targets;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/** Find throws in implementation bodies of targeted trails. */
|
|
56
|
-
const findThrowsInTargetedTrails = (
|
|
57
|
-
ast: AstNode,
|
|
58
|
-
sourceCode: string,
|
|
59
|
-
filePath: string,
|
|
60
|
-
detourTargets: ReadonlySet<string>
|
|
61
|
-
): WardenDiagnostic[] => {
|
|
62
|
-
const diagnostics: WardenDiagnostic[] = [];
|
|
63
|
-
|
|
64
|
-
for (const def of findTrailDefinitions(ast)) {
|
|
65
|
-
if (!detourTargets.has(def.id)) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
for (const body of findBlazeBodies(def.config as AstNode)) {
|
|
70
|
-
walk(body, (node) => {
|
|
71
|
-
if (node.type === 'ThrowStatement') {
|
|
72
|
-
diagnostics.push({
|
|
73
|
-
filePath,
|
|
74
|
-
line: offsetToLine(sourceCode, node.start),
|
|
75
|
-
message: `Trail "${def.id}" is a detour target and must not throw. Use Result.err() instead.`,
|
|
76
|
-
rule: 'no-throw-in-detour-target',
|
|
77
|
-
severity: 'error',
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return diagnostics;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const checkThrowInDetourTargets = (
|
|
88
|
-
sourceCode: string,
|
|
89
|
-
filePath: string,
|
|
90
|
-
detourTargets: ReadonlySet<string>
|
|
91
|
-
): readonly WardenDiagnostic[] => {
|
|
92
|
-
if (isTestFile(filePath)) {
|
|
93
|
-
return [];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const ast = parse(filePath, sourceCode);
|
|
97
|
-
if (!ast) {
|
|
98
|
-
return [];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return findThrowsInTargetedTrails(
|
|
102
|
-
ast as AstNode,
|
|
103
|
-
sourceCode,
|
|
104
|
-
filePath,
|
|
105
|
-
detourTargets
|
|
106
|
-
);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Flags throws in implementations that are used as detour targets.
|
|
111
|
-
*/
|
|
112
|
-
export const noThrowInDetourTarget: ProjectAwareWardenRule = {
|
|
113
|
-
check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
|
|
114
|
-
const ast = parse(filePath, sourceCode);
|
|
115
|
-
if (!ast) {
|
|
116
|
-
return [];
|
|
117
|
-
}
|
|
118
|
-
return checkThrowInDetourTargets(
|
|
119
|
-
sourceCode,
|
|
120
|
-
filePath,
|
|
121
|
-
collectDetourTargets(ast as AstNode)
|
|
122
|
-
);
|
|
123
|
-
},
|
|
124
|
-
checkWithContext(
|
|
125
|
-
sourceCode: string,
|
|
126
|
-
filePath: string,
|
|
127
|
-
context: ProjectContext
|
|
128
|
-
): readonly WardenDiagnostic[] {
|
|
129
|
-
if (context.detourTargetTrailIds) {
|
|
130
|
-
return checkThrowInDetourTargets(
|
|
131
|
-
sourceCode,
|
|
132
|
-
filePath,
|
|
133
|
-
context.detourTargetTrailIds
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
const ast = parse(filePath, sourceCode);
|
|
137
|
-
if (!ast) {
|
|
138
|
-
return [];
|
|
139
|
-
}
|
|
140
|
-
return checkThrowInDetourTargets(
|
|
141
|
-
sourceCode,
|
|
142
|
-
filePath,
|
|
143
|
-
collectDetourTargets(ast as AstNode)
|
|
144
|
-
);
|
|
145
|
-
},
|
|
146
|
-
description:
|
|
147
|
-
'Disallow throw statements inside implementations that are referenced as detour targets.',
|
|
148
|
-
name: 'no-throw-in-detour-target',
|
|
149
|
-
severity: 'error',
|
|
150
|
-
};
|