@comity-dev/validate 0.1.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/dist/run.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ import type { EngineResult, Finding } from "./engines/types.js";
2
+ export interface RunOptions {
3
+ /** The root directory of the repository to validate */
4
+ root: string;
5
+ /** If specified, only run the given category of validation */
6
+ only?: string | null;
7
+ /** If true, print verbose output to stdout */
8
+ verbose?: boolean;
9
+ }
10
+ export interface CategoryResult {
11
+ /** The status of the engine for this category */
12
+ status: EngineResult["status"];
13
+ /** Whether the engine was executed or skipped */
14
+ executed: boolean;
15
+ /** The exit code of the engine process, if applicable */
16
+ exitCode: number | null;
17
+ /** Whether the engine passed or failed */
18
+ passed: boolean;
19
+ /** The number of findings produced by the engine */
20
+ findings: number;
21
+ /** The tool that produced this result, if applicable */
22
+ tool?: string | undefined;
23
+ /** The reason for the engine's status, if applicable */
24
+ reason?: string | undefined;
25
+ }
26
+ export interface RunResult {
27
+ /** Whether the overall validation passed or failed */
28
+ passed: boolean;
29
+ /** The list of all findings across all categories */
30
+ violations: Finding[];
31
+ /** The results of each validation category */
32
+ categories: {
33
+ /** Schema validation results */
34
+ schema: CategoryResult;
35
+ /** Package metadata validation results */
36
+ metadata: CategoryResult;
37
+ /** Comity config validation results */
38
+ config: CategoryResult;
39
+ /** Dependency validation results */
40
+ dependencies: CategoryResult;
41
+ /** ESLint validation results */
42
+ eslint: CategoryResult;
43
+ /** Semgrep validation results */
44
+ semgrep: CategoryResult;
45
+ /** Adapter peers validation results */
46
+ adapterPeers: CategoryResult;
47
+ };
48
+ }
49
+ /**
50
+ * Run validation against a repository. Returns a normalized result.
51
+ *
52
+ * Every category reports either an executed engine with its real exit
53
+ * code, or an explicit NOT-RUN / TOOL-UNAVAILABLE / CONFIGURATION-ERROR
54
+ * state. PASS without execution is impossible.
55
+ */
56
+ export declare function runValidation(options: RunOptions): Promise<RunResult>;
package/dist/run.js ADDED
@@ -0,0 +1,144 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { discoverRepository } from "./discover.js";
4
+ import { runAdapterPeers } from "./engines/adapter-peers.js";
5
+ import { runDepcruise } from "./engines/depcruise.js";
6
+ import { runEslint } from "./engines/eslint.js";
7
+ import { runSchema } from "./engines/schema.js";
8
+ import { runSemgrep } from "./engines/semgrep.js";
9
+ function categoryOf(result) {
10
+ return {
11
+ status: result.status,
12
+ executed: result.executed,
13
+ exitCode: result.exitCode,
14
+ passed: result.passed,
15
+ findings: result.findings.length,
16
+ tool: result.tool,
17
+ reason: result.reason,
18
+ };
19
+ }
20
+ function emptyCategory(reason) {
21
+ return {
22
+ status: "NOT-RUN",
23
+ executed: false,
24
+ exitCode: null,
25
+ passed: false,
26
+ findings: 0,
27
+ reason,
28
+ };
29
+ }
30
+ function findBinDir() {
31
+ const __dirname = dirname(fileURLToPath(import.meta.url));
32
+ // `__dirname` is the directory of the running module. Both the source
33
+ // `src/` and the built `dist/` are direct children of the package root,
34
+ // so the package's own `node_modules/.bin` is always exactly one level
35
+ // up from the running module.
36
+ return resolve(__dirname, "..", "node_modules", ".bin");
37
+ }
38
+ /**
39
+ * Run validation against a repository. Returns a normalized result.
40
+ *
41
+ * Every category reports either an executed engine with its real exit
42
+ * code, or an explicit NOT-RUN / TOOL-UNAVAILABLE / CONFIGURATION-ERROR
43
+ * state. PASS without execution is impossible.
44
+ */
45
+ export async function runValidation(options) {
46
+ const only = options.only ?? null;
47
+ const repo = await discoverRepository({ root: options.root });
48
+ const binDir = findBinDir();
49
+ let schemaResult;
50
+ let metaResult;
51
+ let configResult;
52
+ if (!only || only === "metadata" || only === "config" || only === "schema") {
53
+ schemaResult = runSchema(repo);
54
+ const metaFindings = schemaResult.findings.filter((f) => f.rule === "package-metadata");
55
+ const configFindings = schemaResult.findings.filter((f) => f.rule === "comity-config");
56
+ metaResult = {
57
+ ...schemaResult,
58
+ findings: metaFindings,
59
+ passed: metaFindings.length === 0,
60
+ status: metaFindings.length === 0 ? "PASS" : "FAIL",
61
+ };
62
+ configResult = {
63
+ ...schemaResult,
64
+ findings: configFindings,
65
+ passed: configFindings.length === 0,
66
+ status: configFindings.length === 0 ? "PASS" : "FAIL",
67
+ };
68
+ }
69
+ else {
70
+ schemaResult = emptyEngineResult("schema engine skipped");
71
+ metaResult = emptyEngineResult("schema engine skipped");
72
+ configResult = emptyEngineResult("schema engine skipped");
73
+ }
74
+ let depResult;
75
+ if (!only || only === "dependencies" || only === "depcruise") {
76
+ depResult = runDepcruise(repo, binDir);
77
+ }
78
+ else {
79
+ depResult = emptyEngineResult("dependencies engine skipped");
80
+ }
81
+ let eslintResult;
82
+ if (!only || only === "eslint") {
83
+ eslintResult = runEslint(repo, binDir);
84
+ }
85
+ else {
86
+ eslintResult = emptyEngineResult("eslint engine skipped");
87
+ }
88
+ let semgrepResult;
89
+ if (!only || only === "semgrep") {
90
+ semgrepResult = await runSemgrep(repo);
91
+ }
92
+ else {
93
+ semgrepResult = emptyEngineResult("semgrep engine skipped");
94
+ }
95
+ let adapterResult;
96
+ if (!only || only === "adapter-peers") {
97
+ adapterResult = runAdapterPeers(repo);
98
+ }
99
+ else {
100
+ adapterResult = emptyEngineResult("adapter-peers engine skipped");
101
+ }
102
+ const violations = [];
103
+ for (const r of [
104
+ schemaResult,
105
+ depResult,
106
+ eslintResult,
107
+ semgrepResult,
108
+ adapterResult,
109
+ ]) {
110
+ if (Array.isArray(r.findings)) {
111
+ violations.push(...r.findings);
112
+ }
113
+ }
114
+ const allExecuted = [depResult, eslintResult, semgrepResult, adapterResult];
115
+ const allPassed = allExecuted.every((r) => (r.executed ? r.passed : r.status !== "FAIL")) &&
116
+ (metaResult.executed ? metaResult.passed : metaResult.status !== "FAIL") &&
117
+ (configResult.executed
118
+ ? configResult.passed
119
+ : configResult.status !== "FAIL");
120
+ return {
121
+ passed: allPassed,
122
+ violations,
123
+ categories: {
124
+ schema: categoryOf(schemaResult),
125
+ metadata: categoryOf(metaResult),
126
+ config: categoryOf(configResult),
127
+ dependencies: categoryOf(depResult),
128
+ eslint: categoryOf(eslintResult),
129
+ semgrep: categoryOf(semgrepResult),
130
+ adapterPeers: categoryOf(adapterResult),
131
+ },
132
+ };
133
+ }
134
+ function emptyEngineResult(reason) {
135
+ return {
136
+ executed: false,
137
+ exitCode: null,
138
+ passed: false,
139
+ findings: [],
140
+ duration: 0,
141
+ status: "NOT-RUN",
142
+ reason,
143
+ };
144
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@comity-dev/validate",
3
+ "version": "0.1.0",
4
+ "description": "Thin orchestrator over Comity shared validation tooling. Development tooling.",
5
+ "type": "module",
6
+ "private": false,
7
+ "license": "MIT",
8
+ "comity": {
9
+ "layer": "dev-tooling"
10
+ },
11
+ "engines": {
12
+ "node": ">=24.0.0"
13
+ },
14
+ "bin": {
15
+ "comity-validate": "./dist/bin/comity-validate.js"
16
+ },
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "./dist"
27
+ ],
28
+ "dependencies": {
29
+ "@typescript-eslint/parser": "^8.69.0",
30
+ "dependency-cruiser": "^16.10.4",
31
+ "eslint": "^9.39.5",
32
+ "@comity-dev/semgrep-rules": "0.1.0",
33
+ "@comity-dev/schemas": "0.1.0",
34
+ "@comity-dev/dependency-rules": "0.1.0",
35
+ "@comity-dev/eslint-plugin": "0.1.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^24.13.3",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.json",
43
+ "test": "vitest run"
44
+ }
45
+ }