@alimaandev/ripple 0.1.0 → 0.2.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.
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ import { z } from 'zod';
3
+
4
+ // src/config/defaults.ts
5
+ var DEFAULT_CONFIG = {
6
+ include: ["**/*.{ts,tsx,js,jsx}"],
7
+ ignore: ["node_modules", "dist", "build", "coverage", ".next", "out", ".git"],
8
+ aliases: {},
9
+ tsconfigPath: "tsconfig.json",
10
+ risk: {
11
+ weights: {
12
+ affectedFiles: 0.3,
13
+ entryPoint: 0.15,
14
+ sharedUtility: 0.15,
15
+ publicExports: 0.1,
16
+ tests: 0.1,
17
+ routes: 0.1,
18
+ cycleMembership: 0.1
19
+ },
20
+ thresholds: {
21
+ medium: 30,
22
+ high: 55,
23
+ critical: 80
24
+ }
25
+ }
26
+ };
27
+
28
+ // src/config/schema.ts
29
+ var fraction = z.number().min(0).max(1);
30
+ var score = z.number().min(0).max(100);
31
+ var riskWeightsSchema = z.object({
32
+ affectedFiles: fraction.default(DEFAULT_CONFIG.risk.weights.affectedFiles),
33
+ entryPoint: fraction.default(DEFAULT_CONFIG.risk.weights.entryPoint),
34
+ sharedUtility: fraction.default(DEFAULT_CONFIG.risk.weights.sharedUtility),
35
+ publicExports: fraction.default(DEFAULT_CONFIG.risk.weights.publicExports),
36
+ tests: fraction.default(DEFAULT_CONFIG.risk.weights.tests),
37
+ routes: fraction.default(DEFAULT_CONFIG.risk.weights.routes),
38
+ cycleMembership: fraction.default(DEFAULT_CONFIG.risk.weights.cycleMembership)
39
+ }).strict();
40
+ var riskThresholdsSchema = z.object({
41
+ medium: score.default(DEFAULT_CONFIG.risk.thresholds.medium),
42
+ high: score.default(DEFAULT_CONFIG.risk.thresholds.high),
43
+ critical: score.default(DEFAULT_CONFIG.risk.thresholds.critical)
44
+ }).strict();
45
+ var riskConfigSchema = z.object({
46
+ weights: riskWeightsSchema.default(DEFAULT_CONFIG.risk.weights),
47
+ thresholds: riskThresholdsSchema.default(DEFAULT_CONFIG.risk.thresholds)
48
+ }).strict();
49
+ var rippleConfigSchema = z.object({
50
+ include: z.array(z.string().min(1)).min(1).default(DEFAULT_CONFIG.include),
51
+ ignore: z.array(z.string()).default(DEFAULT_CONFIG.ignore),
52
+ aliases: z.record(z.string(), z.string()).default(DEFAULT_CONFIG.aliases),
53
+ tsconfigPath: z.string().min(1).default(DEFAULT_CONFIG.tsconfigPath),
54
+ risk: riskConfigSchema.default(DEFAULT_CONFIG.risk)
55
+ }).strict();
56
+ function formatSchemaIssues(error) {
57
+ return error.issues.map((issue) => {
58
+ const path = issue.path.join(".");
59
+ const location = path === "" ? "config" : `config.${path}`;
60
+ return `${location}: ${issue.message}`;
61
+ });
62
+ }
63
+
64
+ export { DEFAULT_CONFIG, formatSchemaIssues, rippleConfigSchema };
65
+ //# sourceMappingURL=chunk-OOERV74D.js.map
66
+ //# sourceMappingURL=chunk-OOERV74D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/defaults.ts","../src/config/schema.ts"],"names":[],"mappings":"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","file":"chunk-OOERV74D.js","sourcesContent":["import type { RippleConfig } from \"../types/config.js\";\n\n/**\n * Built-in defaults. A user config only overrides fields it sets; anything\n * else keeps these values.\n */\nexport const DEFAULT_CONFIG: RippleConfig = {\n include: [\"**/*.{ts,tsx,js,jsx}\"],\n ignore: [\"node_modules\", \"dist\", \"build\", \"coverage\", \".next\", \"out\", \".git\"],\n aliases: {},\n tsconfigPath: \"tsconfig.json\",\n risk: {\n weights: {\n affectedFiles: 0.3,\n entryPoint: 0.15,\n sharedUtility: 0.15,\n publicExports: 0.1,\n tests: 0.1,\n routes: 0.1,\n cycleMembership: 0.1,\n },\n thresholds: {\n medium: 30,\n high: 55,\n critical: 80,\n },\n },\n};\n","import { z } from \"zod\";\nimport type { RippleConfig } from \"../types/config.js\";\nimport { DEFAULT_CONFIG } from \"./defaults.js\";\n\n/**\n * Zod schema for `ripple.config.ts`. Every field has a default, so parsing a\n * partial user config yields a complete validated `RippleConfig`.\n *\n * Note: outer objects default to their *full* default object. `.default({})`\n * would skip inner field defaults, since zod uses the default value as-is\n * without re-parsing it.\n */\n\nconst fraction = z.number().min(0).max(1);\nconst score = z.number().min(0).max(100);\n\nconst riskWeightsSchema = z\n .object({\n affectedFiles: fraction.default(DEFAULT_CONFIG.risk.weights.affectedFiles),\n entryPoint: fraction.default(DEFAULT_CONFIG.risk.weights.entryPoint),\n sharedUtility: fraction.default(DEFAULT_CONFIG.risk.weights.sharedUtility),\n publicExports: fraction.default(DEFAULT_CONFIG.risk.weights.publicExports),\n tests: fraction.default(DEFAULT_CONFIG.risk.weights.tests),\n routes: fraction.default(DEFAULT_CONFIG.risk.weights.routes),\n cycleMembership: fraction.default(DEFAULT_CONFIG.risk.weights.cycleMembership),\n })\n .strict();\n\nconst riskThresholdsSchema = z\n .object({\n medium: score.default(DEFAULT_CONFIG.risk.thresholds.medium),\n high: score.default(DEFAULT_CONFIG.risk.thresholds.high),\n critical: score.default(DEFAULT_CONFIG.risk.thresholds.critical),\n })\n .strict();\n\nconst riskConfigSchema = z\n .object({\n weights: riskWeightsSchema.default(DEFAULT_CONFIG.risk.weights),\n thresholds: riskThresholdsSchema.default(DEFAULT_CONFIG.risk.thresholds),\n })\n .strict();\n\nexport const rippleConfigSchema: z.ZodType<RippleConfig> = z\n .object({\n include: z.array(z.string().min(1)).min(1).default(DEFAULT_CONFIG.include),\n ignore: z.array(z.string()).default(DEFAULT_CONFIG.ignore),\n aliases: z.record(z.string(), z.string()).default(DEFAULT_CONFIG.aliases),\n tsconfigPath: z.string().min(1).default(DEFAULT_CONFIG.tsconfigPath),\n risk: riskConfigSchema.default(DEFAULT_CONFIG.risk),\n })\n .strict();\n\n/** Human-readable list of validation problems, for friendly error output. */\nexport function formatSchemaIssues(error: z.ZodError): string[] {\n return error.issues.map((issue) => {\n const path = issue.path.join(\".\");\n const location = path === \"\" ? \"config\" : `config.${path}`;\n return `${location}: ${issue.message}`;\n });\n}\n"]}
@@ -0,0 +1,119 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * User-facing configuration for Ripple, validated by `src/config/schema.ts`.
5
+ *
6
+ * Every field has a default; a user config only overrides what it sets.
7
+ */
8
+ interface RiskWeights {
9
+ /** Weight of the (log-scaled) number of affected files. */
10
+ affectedFiles: number;
11
+ /** Weight of whether an entry point is affected. */
12
+ entryPoint: number;
13
+ /** Weight of how many shared utilities are affected. */
14
+ sharedUtility: number;
15
+ /** Weight of the target file's public export surface. */
16
+ publicExports: number;
17
+ /** Weight of affected test files. */
18
+ tests: number;
19
+ /** Weight of affected API routes. */
20
+ routes: number;
21
+ /** Weight of the target file being part of a circular dependency. */
22
+ cycleMembership: number;
23
+ }
24
+ /**
25
+ * Score thresholds that map a 0-100 risk score to a level.
26
+ * A score >= `critical` is CRITICAL, >= `high` is HIGH, >= `medium` is MEDIUM,
27
+ * anything below is LOW.
28
+ */
29
+ interface RiskThresholds {
30
+ medium: number;
31
+ high: number;
32
+ critical: number;
33
+ }
34
+ interface RiskConfig {
35
+ weights: RiskWeights;
36
+ thresholds: RiskThresholds;
37
+ }
38
+ /**
39
+ * The validated `ripple.config.ts` shape.
40
+ */
41
+ interface RippleConfig {
42
+ /** Glob patterns (relative to the project root) of source files to analyze. */
43
+ include: string[];
44
+ /** Glob patterns / directory names to exclude from analysis. */
45
+ ignore: string[];
46
+ /** Path aliases, e.g. `{ "@": "./src" }`. Merged with tsconfig `paths`. */
47
+ aliases: Record<string, string>;
48
+ /** Path to tsconfig.json, relative to the project root. Default: `tsconfig.json`. */
49
+ tsconfigPath: string;
50
+ /** Risk engine tuning. */
51
+ risk: RiskConfig;
52
+ }
53
+ /**
54
+ * Normalized alias map used by the resolver: pattern → absolute target.
55
+ * Both sides support a single `*` wildcard (`"@/*"` → `"C:/proj/src/*"`).
56
+ */
57
+ type AliasMap = Record<string, string>;
58
+
59
+ /**
60
+ * tsconfig.json facts Ripple consumes. Loaded via `src/utils/tsconfig.ts`.
61
+ */
62
+ interface TsconfigInfo {
63
+ /** Absolute path of the tsconfig file. */
64
+ path: string;
65
+ /** Directory containing the tsconfig (the resolution base for aliases). */
66
+ dir: string;
67
+ /** Absolute `baseUrl`, if configured. */
68
+ baseUrl?: string;
69
+ /** `paths` mappings: pattern → replacement patterns. */
70
+ paths: Record<string, string[]>;
71
+ include: string[];
72
+ exclude: string[];
73
+ }
74
+ /**
75
+ * Everything the analysis pipeline needs to know about the project it runs
76
+ * in. Built once by `src/config/loader.ts` and passed down explicitly.
77
+ */
78
+ interface ProjectContext {
79
+ /** Absolute project root (config file location or cwd). */
80
+ rootDir: string;
81
+ /** Validated user config. */
82
+ config: RippleConfig;
83
+ /** tsconfig facts, when a tsconfig was found. */
84
+ tsconfig?: TsconfigInfo;
85
+ /** Normalized alias map (user aliases + tsconfig paths). */
86
+ aliases: AliasMap;
87
+ }
88
+
89
+ /**
90
+ * Risk engine types: a deterministic weighted heuristic that maps graph
91
+ * signals to a 0-100 score and a level.
92
+ */
93
+ type RiskLevel = "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
94
+ /** One contributing factor of the score, for transparency in `--verbose`. */
95
+ interface RiskFactor {
96
+ /** Stable machine-readable factor name. */
97
+ name: string;
98
+ /** Human-readable label. */
99
+ label: string;
100
+ /** Configured weight (0-1). */
101
+ weight: number;
102
+ /** Normalized signal value (0-1). */
103
+ value: number;
104
+ /** `weight * value * 100`, the points this factor contributes. */
105
+ contribution: number;
106
+ }
107
+ interface RiskResult {
108
+ /** Final score, 0-100. */
109
+ score: number;
110
+ level: RiskLevel;
111
+ /** Every factor and its contribution. */
112
+ factors: RiskFactor[];
113
+ }
114
+
115
+ declare const rippleConfigSchema: z.ZodType<RippleConfig>;
116
+ /** Human-readable list of validation problems, for friendly error output. */
117
+ declare function formatSchemaIssues(error: z.ZodError): string[];
118
+
119
+ export { type AliasMap, type ProjectContext, type RippleConfig, type RiskFactor, type RiskLevel, type RiskResult, type TsconfigInfo, formatSchemaIssues, rippleConfigSchema };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ export { formatSchemaIssues, rippleConfigSchema } from './chunk-OOERV74D.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alimaandev/ripple",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Dependency impact analysis for TypeScript projects. Answers the question: what will break if I change this file?",
5
5
  "keywords": [
6
6
  "cli",
@@ -21,6 +21,18 @@
21
21
  "url": "https://github.com/alimaandev/ripple/issues"
22
22
  },
23
23
  "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
24
36
  "bin": {
25
37
  "ripple": "./dist/bin.js"
26
38
  },
@@ -45,9 +57,11 @@
45
57
  "prepublishOnly": "pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run build"
46
58
  },
47
59
  "dependencies": {
60
+ "boxen": "^8.0.1",
48
61
  "chalk": "^6.0.0",
49
62
  "commander": "^15.0.0",
50
63
  "fast-glob": "^3.3.3",
64
+ "figures": "^6.1.0",
51
65
  "jiti": "^2.7.0",
52
66
  "ora": "^9.4.1",
53
67
  "treeify": "^1.1.0",