@viberails/config 0.2.0 → 0.2.1

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/index.cjs CHANGED
@@ -53,6 +53,70 @@ var DEFAULT_IGNORE = ["**/*.d.ts", "dist/**", "node_modules/**"];
53
53
 
54
54
  // src/generate-config.ts
55
55
  var path = __toESM(require("path"), 1);
56
+
57
+ // src/generate-overrides.ts
58
+ function conventionsDiffer(pkgConventions, globalConventions) {
59
+ const overrides = {};
60
+ let hasDiff = false;
61
+ for (const key of CONVENTION_KEYS) {
62
+ const detected = pkgConventions[key];
63
+ if (!detected) continue;
64
+ const mapped = mapConvention(detected);
65
+ if (mapped === void 0) continue;
66
+ const globalValue = globalConventions[key];
67
+ const globalStr = typeof globalValue === "string" ? globalValue : globalValue?.value;
68
+ if (detected.value !== globalStr) {
69
+ overrides[key] = mapped;
70
+ hasDiff = true;
71
+ }
72
+ }
73
+ return hasDiff ? overrides : void 0;
74
+ }
75
+ function generatePackageOverrides(scanResult, globalConfig) {
76
+ if (!scanResult.packages || scanResult.packages.length <= 1) return void 0;
77
+ const overrides = [];
78
+ for (const pkg of scanResult.packages) {
79
+ const override = {
80
+ name: pkg.name,
81
+ path: pkg.relativePath
82
+ };
83
+ let hasDiff = false;
84
+ const stackOverride = {};
85
+ let hasStackDiff = false;
86
+ const optionalStackFields = [
87
+ "framework",
88
+ "styling",
89
+ "backend",
90
+ "linter",
91
+ "formatter",
92
+ "testRunner"
93
+ ];
94
+ for (const field of optionalStackFields) {
95
+ const pkgItem = pkg.stack[field];
96
+ if (!pkgItem) continue;
97
+ const pkgValue = formatStackItem(pkgItem);
98
+ if (pkgValue !== globalConfig.stack[field]) {
99
+ stackOverride[field] = pkgValue;
100
+ hasStackDiff = true;
101
+ }
102
+ }
103
+ if (hasStackDiff) {
104
+ override.stack = stackOverride;
105
+ hasDiff = true;
106
+ }
107
+ const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);
108
+ if (conventionOverrides) {
109
+ override.conventions = conventionOverrides;
110
+ hasDiff = true;
111
+ }
112
+ if (hasDiff) {
113
+ overrides.push(override);
114
+ }
115
+ }
116
+ return overrides.length > 0 ? overrides : void 0;
117
+ }
118
+
119
+ // src/generate-config.ts
56
120
  function formatStackItem(item) {
57
121
  return item.version ? `${item.name}@${item.version}` : item.name;
58
122
  }
@@ -66,6 +130,7 @@ function mapStack(scanResult) {
66
130
  if (stack.styling) config.styling = formatStackItem(stack.styling);
67
131
  if (stack.backend) config.backend = formatStackItem(stack.backend);
68
132
  if (stack.linter) config.linter = formatStackItem(stack.linter);
133
+ if (stack.formatter) config.formatter = formatStackItem(stack.formatter);
69
134
  if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);
70
135
  return config;
71
136
  }
@@ -123,65 +188,6 @@ function mapConventions(scanResult) {
123
188
  }
124
189
  return config;
125
190
  }
126
- function conventionsDiffer(pkgConventions, globalConventions) {
127
- const overrides = {};
128
- let hasDiff = false;
129
- for (const key of CONVENTION_KEYS) {
130
- const detected = pkgConventions[key];
131
- if (!detected) continue;
132
- const mapped = mapConvention(detected);
133
- if (mapped === void 0) continue;
134
- const globalValue = globalConventions[key];
135
- const globalStr = typeof globalValue === "string" ? globalValue : globalValue?.value;
136
- if (detected.value !== globalStr) {
137
- overrides[key] = mapped;
138
- hasDiff = true;
139
- }
140
- }
141
- return hasDiff ? overrides : void 0;
142
- }
143
- function generatePackageOverrides(scanResult, globalConfig) {
144
- if (!scanResult.packages || scanResult.packages.length <= 1) return void 0;
145
- const overrides = [];
146
- for (const pkg of scanResult.packages) {
147
- const override = {
148
- name: pkg.name,
149
- path: pkg.relativePath
150
- };
151
- let hasDiff = false;
152
- const stackOverride = {};
153
- let hasStackDiff = false;
154
- const optionalStackFields = [
155
- "framework",
156
- "styling",
157
- "backend",
158
- "linter",
159
- "testRunner"
160
- ];
161
- for (const field of optionalStackFields) {
162
- const pkgItem = pkg.stack[field];
163
- if (!pkgItem) continue;
164
- const pkgValue = formatStackItem(pkgItem);
165
- if (pkgValue !== globalConfig.stack[field]) {
166
- stackOverride[field] = pkgValue;
167
- hasStackDiff = true;
168
- }
169
- }
170
- if (hasStackDiff) {
171
- override.stack = stackOverride;
172
- hasDiff = true;
173
- }
174
- const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);
175
- if (conventionOverrides) {
176
- override.conventions = conventionOverrides;
177
- hasDiff = true;
178
- }
179
- if (hasDiff) {
180
- overrides.push(override);
181
- }
182
- }
183
- return overrides.length > 0 ? overrides : void 0;
184
- }
185
191
  function generateConfig(scanResult) {
186
192
  const config = {
187
193
  $schema: "https://viberails.sh/schema/v1.json",
@@ -291,6 +297,7 @@ function mergeStack(existing, fresh) {
291
297
  styling: existing.styling ?? fresh.styling,
292
298
  backend: existing.backend ?? fresh.backend,
293
299
  linter: existing.linter ?? fresh.linter,
300
+ formatter: existing.formatter ?? fresh.formatter,
294
301
  testRunner: existing.testRunner ?? fresh.testRunner
295
302
  };
296
303
  }
@@ -419,6 +426,10 @@ var configSchema = {
419
426
  type: "string",
420
427
  description: 'Linter (e.g. "eslint@9", "biome").'
421
428
  },
429
+ formatter: {
430
+ type: "string",
431
+ description: 'Formatter (e.g. "prettier", "biome").'
432
+ },
422
433
  testRunner: {
423
434
  type: "string",
424
435
  description: 'Test runner (e.g. "vitest", "jest").'
@@ -582,6 +593,7 @@ var configSchema = {
582
593
  backend: { type: "string" },
583
594
  packageManager: { type: "string" },
584
595
  linter: { type: "string" },
596
+ formatter: { type: "string" },
585
597
  testRunner: { type: "string" }
586
598
  },
587
599
  additionalProperties: false
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/defaults.ts","../src/generate-config.ts","../src/load-config.ts","../src/merge-config.ts","../src/schema.ts"],"sourcesContent":["export const VERSION = '0.1.0';\n\nexport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nexport { generateConfig } from './generate-config.js';\nexport { loadConfig, loadConfigSafe } from './load-config.js';\nexport { mergeConfig } from './merge-config.js';\nexport { configSchema } from './schema.js';\n","import type { ConfigRules } from '@viberails/types';\n\n/**\n * Default rule thresholds and toggles for a new viberails config.\n * These values are intentionally conservative to build trust on first run.\n */\nexport const DEFAULT_RULES: ConfigRules = {\n maxFileLines: 300,\n maxFunctionLines: 50,\n requireTests: true,\n enforceNaming: true,\n enforceBoundaries: false,\n};\n\n/**\n * Default glob patterns for files and directories to ignore.\n */\nexport const DEFAULT_IGNORE: string[] = ['**/*.d.ts', 'dist/**', 'node_modules/**'];\n","import * as path from 'node:path';\nimport type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n DetectedConvention,\n DirectoryRole,\n PackageConfigOverrides,\n ScanResult,\n StackItem,\n ViberailsConfig,\n} from '@viberails/types';\nimport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\n\n/**\n * Format a StackItem as a config string: `\"name@version\"` or `\"name\"`.\n */\nfunction formatStackItem(item: StackItem): string {\n return item.version ? `${item.name}@${item.version}` : item.name;\n}\n\n/**\n * Map DetectedStack → ConfigStack by formatting each StackItem.\n */\nfunction mapStack(scanResult: ScanResult): ConfigStack {\n const { stack } = scanResult;\n const config: ConfigStack = {\n language: formatStackItem(stack.language),\n packageManager: formatStackItem(stack.packageManager),\n };\n\n if (stack.framework) config.framework = formatStackItem(stack.framework);\n if (stack.styling) config.styling = formatStackItem(stack.styling);\n if (stack.backend) config.backend = formatStackItem(stack.backend);\n if (stack.linter) config.linter = formatStackItem(stack.linter);\n if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);\n\n return config;\n}\n\n/** Directory roles that map to ConfigStructure fields. */\nconst ROLE_TO_FIELD: Partial<Record<DirectoryRole, keyof ConfigStructure>> = {\n pages: 'pages',\n components: 'components',\n hooks: 'hooks',\n utils: 'utils',\n types: 'types',\n tests: 'tests',\n};\n\n/**\n * Map DetectedStructure → ConfigStructure by finding the first directory\n * for each known role.\n */\nfunction mapStructure(scanResult: ScanResult): ConfigStructure {\n const { structure } = scanResult;\n const config: ConfigStructure = {};\n\n if (structure.srcDir) {\n config.srcDir = structure.srcDir;\n }\n\n for (const dir of structure.directories) {\n const field = ROLE_TO_FIELD[dir.role];\n if (field && config[field] === undefined) {\n (config as Record<string, string>)[field] = dir.path;\n }\n }\n\n if (structure.testPattern) {\n config.testPattern = structure.testPattern.value;\n }\n\n return config;\n}\n\n/**\n * Convert a DetectedConvention to a ConventionValue with metadata.\n * Returns undefined for low-confidence conventions (they are omitted).\n */\nfunction mapConvention(convention: DetectedConvention): ConventionValue | undefined {\n if (convention.confidence === 'low') {\n return undefined;\n }\n\n return {\n value: convention.value,\n _confidence: convention.confidence,\n _consistency: convention.consistency,\n };\n}\n\n/** Convention keys from ScanResult that map to ConfigConventions fields. */\nexport const CONVENTION_KEYS: (keyof ConfigConventions)[] = [\n 'fileNaming',\n 'componentNaming',\n 'hookNaming',\n 'importAlias',\n];\n\n/**\n * Map scanner conventions → ConfigConventions, omitting low-confidence entries.\n */\nfunction mapConventions(scanResult: ScanResult): ConfigConventions {\n const config: ConfigConventions = {};\n\n for (const key of CONVENTION_KEYS) {\n const detected = scanResult.conventions[key];\n if (detected) {\n const value = mapConvention(detected);\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n\n return config;\n}\n\n/**\n * Compare a package's conventions against the global config conventions.\n * Returns only the differing conventions, or undefined if all match.\n */\nfunction conventionsDiffer(\n pkgConventions: Record<string, DetectedConvention>,\n globalConventions: ConfigConventions,\n): Partial<ConfigConventions> | undefined {\n const overrides: Partial<ConfigConventions> = {};\n let hasDiff = false;\n\n for (const key of CONVENTION_KEYS) {\n const detected = pkgConventions[key];\n if (!detected) continue;\n\n const mapped = mapConvention(detected);\n if (mapped === undefined) continue;\n\n const globalValue = globalConventions[key];\n const globalStr = typeof globalValue === 'string' ? globalValue : globalValue?.value;\n if (detected.value !== globalStr) {\n overrides[key] = mapped;\n hasDiff = true;\n }\n }\n\n return hasDiff ? overrides : undefined;\n}\n\n/**\n * Generate per-package config overrides for packages whose stack or\n * conventions differ from the aggregate global config.\n */\nfunction generatePackageOverrides(\n scanResult: ScanResult,\n globalConfig: ViberailsConfig,\n): PackageConfigOverrides[] | undefined {\n if (!scanResult.packages || scanResult.packages.length <= 1) return undefined;\n\n const overrides: PackageConfigOverrides[] = [];\n\n for (const pkg of scanResult.packages) {\n const override: PackageConfigOverrides = {\n name: pkg.name,\n path: pkg.relativePath,\n };\n let hasDiff = false;\n\n // Compare stack fields — only include overrides when the package has a\n // value that differs from the global, not when the package simply lacks the field\n const stackOverride: Partial<ConfigStack> = {};\n let hasStackDiff = false;\n\n const optionalStackFields = [\n 'framework',\n 'styling',\n 'backend',\n 'linter',\n 'testRunner',\n ] as const;\n for (const field of optionalStackFields) {\n const pkgItem = pkg.stack[field];\n if (!pkgItem) continue;\n const pkgValue = formatStackItem(pkgItem);\n if (pkgValue !== globalConfig.stack[field]) {\n stackOverride[field] = pkgValue;\n hasStackDiff = true;\n }\n }\n\n if (hasStackDiff) {\n override.stack = stackOverride;\n hasDiff = true;\n }\n\n // Compare conventions\n const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);\n if (conventionOverrides) {\n override.conventions = conventionOverrides;\n hasDiff = true;\n }\n\n if (hasDiff) {\n overrides.push(override);\n }\n }\n\n return overrides.length > 0 ? overrides : undefined;\n}\n\n/**\n * Generate a ViberailsConfig from scan results.\n *\n * Maps the scanner's DetectedStack, DetectedStructure, and conventions\n * into the config format with smart defaults. Low-confidence conventions\n * are omitted. The project name is derived from the root directory basename.\n *\n * @param scanResult - The output of scanning a project\n * @returns A complete ViberailsConfig ready to be written as JSON\n */\nexport function generateConfig(scanResult: ScanResult): ViberailsConfig {\n const config: ViberailsConfig = {\n $schema: 'https://viberails.sh/schema/v1.json',\n version: 1,\n name: path.basename(scanResult.root),\n enforcement: 'warn',\n stack: mapStack(scanResult),\n structure: mapStructure(scanResult),\n conventions: mapConventions(scanResult),\n rules: { ...DEFAULT_RULES },\n ignore: [...DEFAULT_IGNORE],\n };\n\n if (scanResult.workspace) {\n config.workspace = {\n packages: scanResult.workspace.packages.map((p) => p.relativePath),\n isMonorepo: true,\n };\n config.boundaries = [];\n }\n\n const packageOverrides = generatePackageOverrides(scanResult, config);\n if (packageOverrides) {\n config.packages = packageOverrides;\n }\n\n return config;\n}\n","import * as fs from 'node:fs/promises';\nimport type { ViberailsConfig } from '@viberails/types';\n\n/**\n * Validate that a parsed object has the required ViberailsConfig fields\n * and that their types are correct.\n * Throws a descriptive error if validation fails.\n */\nfunction validateConfig(parsed: Record<string, unknown>, configPath: string): void {\n const errors: string[] = [];\n\n // Required top-level fields\n const required = ['version', 'name', 'stack', 'rules'] as const;\n const missing = required.filter((field) => parsed[field] === undefined);\n if (missing.length > 0) {\n throw new Error(\n `Invalid viberails config at ${configPath}: missing required field(s): ${missing.join(', ')}`,\n );\n }\n\n // Type checks\n if (typeof parsed.version !== 'number') errors.push('\"version\" must be a number');\n if (typeof parsed.name !== 'string') errors.push('\"name\" must be a string');\n if (\n parsed.enforcement !== undefined &&\n parsed.enforcement !== 'warn' &&\n parsed.enforcement !== 'enforce'\n ) {\n errors.push('\"enforcement\" must be \"warn\" or \"enforce\"');\n }\n\n // Stack validation\n if (typeof parsed.stack !== 'object' || parsed.stack === null) {\n errors.push('\"stack\" must be an object');\n } else {\n const stack = parsed.stack as Record<string, unknown>;\n if (typeof stack.language !== 'string') errors.push('\"stack.language\" must be a string');\n if (typeof stack.packageManager !== 'string')\n errors.push('\"stack.packageManager\" must be a string');\n }\n\n // Rules validation\n if (typeof parsed.rules !== 'object' || parsed.rules === null) {\n errors.push('\"rules\" must be an object');\n } else {\n const rules = parsed.rules as Record<string, unknown>;\n if (typeof rules.maxFileLines !== 'number')\n errors.push('\"rules.maxFileLines\" must be a number');\n if (typeof rules.maxFunctionLines !== 'number')\n errors.push('\"rules.maxFunctionLines\" must be a number');\n if (typeof rules.requireTests !== 'boolean')\n errors.push('\"rules.requireTests\" must be a boolean');\n if (typeof rules.enforceNaming !== 'boolean')\n errors.push('\"rules.enforceNaming\" must be a boolean');\n if (typeof rules.enforceBoundaries !== 'boolean')\n errors.push('\"rules.enforceBoundaries\" must be a boolean');\n }\n\n // Ignore validation\n if (parsed.ignore !== undefined && !Array.isArray(parsed.ignore)) {\n errors.push('\"ignore\" must be an array');\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid viberails config at ${configPath}: ${errors.join('; ')}`);\n }\n}\n\n/**\n * Load and parse a viberails config file.\n *\n * Reads the JSON file at the given path, validates that it contains\n * the required fields (version, name, stack, rules), and returns\n * the parsed config.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig\n * @throws If the file doesn't exist, contains invalid JSON, or is missing required fields\n */\nexport async function loadConfig(configPath: string): Promise<ViberailsConfig> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Config file not found: ${configPath}. Run \"npx viberails\" to generate one.`);\n }\n throw new Error(`Failed to read config file at ${configPath}: ${(err as Error).message}`);\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in config file at ${configPath}. Check for syntax errors.`);\n }\n\n validateConfig(parsed, configPath);\n\n // Safe to cast: validateConfig has verified all required fields and types\n return parsed as unknown as ViberailsConfig;\n}\n\n/**\n * Safely load a viberails config file, returning null on any error.\n *\n * Used by the CLI for \"does config already exist?\" checks where\n * failure is an expected case, not an error.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig, or null if loading fails\n */\nexport async function loadConfigSafe(configPath: string): Promise<ViberailsConfig | null> {\n try {\n return await loadConfig(configPath);\n } catch {\n return null;\n }\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, generateConfig } from './generate-config.js';\n\n/**\n * Merge stack: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStack(existing: ConfigStack, fresh: ConfigStack): ConfigStack {\n return {\n language: existing.language,\n packageManager: existing.packageManager,\n framework: existing.framework ?? fresh.framework,\n styling: existing.styling ?? fresh.styling,\n backend: existing.backend ?? fresh.backend,\n linter: existing.linter ?? fresh.linter,\n testRunner: existing.testRunner ?? fresh.testRunner,\n };\n}\n\n/**\n * Merge structure: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStructure(existing: ConfigStructure, fresh: ConfigStructure): ConfigStructure {\n return {\n srcDir: existing.srcDir ?? fresh.srcDir,\n pages: existing.pages ?? fresh.pages,\n components: existing.components ?? fresh.components,\n hooks: existing.hooks ?? fresh.hooks,\n utils: existing.utils ?? fresh.utils,\n types: existing.types ?? fresh.types,\n tests: existing.tests ?? fresh.tests,\n testPattern: existing.testPattern ?? fresh.testPattern,\n };\n}\n\n/**\n * Check if a convention key exists in the existing config\n * (either as a string or as an object with a value).\n */\nfunction hasConvention(conventions: ConfigConventions, key: keyof ConfigConventions): boolean {\n return conventions[key] !== undefined;\n}\n\n/**\n * Mark a ConventionValue as newly detected by adding `_detected: true`.\n * Only applies to object-form values (not plain strings).\n */\nfunction markAsDetected(value: ConventionValue): ConventionValue {\n if (typeof value === 'string') {\n return { value, _confidence: 'high', _consistency: 100, _detected: true };\n }\n return { ...value, _detected: true };\n}\n\n/**\n * Merge conventions: keep all existing values, add new detections with `_detected: true`.\n */\nfunction mergeConventions(\n existing: ConfigConventions,\n fresh: ConfigConventions,\n): ConfigConventions {\n const merged: ConfigConventions = { ...existing };\n\n for (const key of CONVENTION_KEYS) {\n if (!hasConvention(existing, key) && fresh[key] !== undefined) {\n merged[key] = markAsDetected(fresh[key]!);\n }\n }\n\n return merged;\n}\n\n/**\n * Merge a new scan result into an existing config for `viberails sync`.\n *\n * Preserves all developer-confirmed values from the existing config.\n * Adds newly detected conventions with a `_detected: true` annotation\n * so the developer can review them. Never removes rules or values\n * the developer has set.\n *\n * @param existing - The current ViberailsConfig (from viberails.config.json)\n * @param scanResult - Fresh scan results from re-scanning the project\n * @returns A merged config that preserves existing values and adds new detections\n */\nexport function mergeConfig(existing: ViberailsConfig, scanResult: ScanResult): ViberailsConfig {\n const fresh = generateConfig(scanResult);\n\n const merged: ViberailsConfig = {\n $schema: existing.$schema ?? fresh.$schema,\n version: existing.version,\n name: existing.name,\n enforcement: existing.enforcement,\n stack: mergeStack(existing.stack, fresh.stack),\n structure: mergeStructure(existing.structure, fresh.structure),\n conventions: mergeConventions(existing.conventions, fresh.conventions),\n rules: { ...existing.rules },\n ignore: [...existing.ignore],\n };\n\n // Workspace: always take fresh scan (structure can change)\n if (fresh.workspace) {\n merged.workspace = fresh.workspace;\n }\n\n // Boundaries: preserve existing rules (user may have adjusted)\n if (existing.boundaries) {\n merged.boundaries = [...existing.boundaries];\n } else if (fresh.boundaries) {\n merged.boundaries = [...fresh.boundaries];\n }\n\n // Packages: preserve existing overrides, add new ones\n if (existing.packages || fresh.packages) {\n merged.packages = mergePackageOverrides(existing.packages, fresh.packages);\n }\n\n return merged;\n}\n\n/**\n * Merge per-package overrides: keep existing user-edited overrides,\n * add new packages from fresh scan.\n */\nfunction mergePackageOverrides(\n existing?: PackageConfigOverrides[],\n fresh?: PackageConfigOverrides[],\n): PackageConfigOverrides[] | undefined {\n if (!fresh || fresh.length === 0) return existing;\n if (!existing || existing.length === 0) return fresh;\n\n const existingByPath = new Map(existing.map((p) => [p.path, p]));\n const merged: PackageConfigOverrides[] = [...existing];\n\n for (const freshPkg of fresh) {\n if (!existingByPath.has(freshPkg.path)) {\n merged.push(freshPkg);\n }\n }\n\n return merged.length > 0 ? merged : undefined;\n}\n","/**\n * JSON Schema (draft-07) definition for viberails.config.json.\n *\n * This schema will eventually be hosted at https://viberails.sh/schema/v1.json.\n * For now it is exported as a TypeScript object that can be serialized to JSON.\n */\nexport const configSchema = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://viberails.sh/schema/v1.json',\n title: 'viberails configuration',\n description: 'Configuration file for viberails — guardrails for vibe coding.',\n type: 'object',\n required: ['version', 'name', 'stack', 'rules'],\n properties: {\n $schema: {\n type: 'string',\n description: 'JSON Schema URL for editor validation.',\n },\n version: {\n type: 'number',\n const: 1,\n description: 'Config format version. Always 1 for V1.0.',\n },\n name: {\n type: 'string',\n description: 'Project name, typically from package.json.',\n },\n enforcement: {\n type: 'string',\n enum: ['warn', 'enforce'],\n default: 'warn',\n description: 'Whether conventions are warned about or enforced as errors.',\n },\n stack: {\n type: 'object',\n required: ['language', 'packageManager'],\n properties: {\n framework: {\n type: 'string',\n description: 'Primary framework identifier (e.g. \"nextjs@15\", \"remix@2\").',\n },\n language: {\n type: 'string',\n description: 'Primary language (e.g. \"typescript\", \"javascript\").',\n },\n styling: {\n type: 'string',\n description: 'Styling solution (e.g. \"tailwindcss@4\", \"css-modules\").',\n },\n backend: {\n type: 'string',\n description: 'Backend framework (e.g. \"express@5\", \"fastify\").',\n },\n packageManager: {\n type: 'string',\n description: 'Package manager (e.g. \"pnpm\", \"npm\", \"yarn\").',\n },\n linter: {\n type: 'string',\n description: 'Linter (e.g. \"eslint@9\", \"biome\").',\n },\n testRunner: {\n type: 'string',\n description: 'Test runner (e.g. \"vitest\", \"jest\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured technology stack.',\n },\n structure: {\n type: 'object',\n properties: {\n srcDir: {\n type: 'string',\n description: 'Source directory (e.g. \"src\"), or omit for flat structure.',\n },\n pages: {\n type: 'string',\n description: 'Pages or routes directory (e.g. \"src/app\").',\n },\n components: {\n type: 'string',\n description: 'Components directory (e.g. \"src/components\").',\n },\n hooks: {\n type: 'string',\n description: 'Hooks directory (e.g. \"src/hooks\").',\n },\n utils: {\n type: 'string',\n description: 'Utilities directory (e.g. \"src/utils\", \"src/lib\").',\n },\n types: {\n type: 'string',\n description: 'Type definitions directory (e.g. \"src/types\").',\n },\n tests: {\n type: 'string',\n description: 'Tests directory (e.g. \"tests\", \"__tests__\").',\n },\n testPattern: {\n type: 'string',\n description: 'Test file naming pattern (e.g. \"*.test.ts\", \"*.spec.ts\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured directory structure.',\n },\n conventions: {\n type: 'object',\n properties: {\n fileNaming: { $ref: '#/definitions/conventionValue' },\n componentNaming: { $ref: '#/definitions/conventionValue' },\n hookNaming: { $ref: '#/definitions/conventionValue' },\n importAlias: { $ref: '#/definitions/conventionValue' },\n },\n additionalProperties: false,\n description: 'Detected or configured coding conventions.',\n },\n rules: {\n type: 'object',\n required: [\n 'maxFileLines',\n 'maxFunctionLines',\n 'requireTests',\n 'enforceNaming',\n 'enforceBoundaries',\n ],\n properties: {\n maxFileLines: {\n type: 'number',\n default: 300,\n description: 'Maximum number of lines allowed per file.',\n },\n maxFunctionLines: {\n type: 'number',\n default: 50,\n description: 'Maximum number of lines allowed per function.',\n },\n requireTests: {\n type: 'boolean',\n default: true,\n description: 'Whether to require test files for source modules.',\n },\n enforceNaming: {\n type: 'boolean',\n default: true,\n description: 'Whether to enforce detected file naming conventions.',\n },\n enforceBoundaries: {\n type: 'boolean',\n default: false,\n description: 'Whether to enforce module boundary rules.',\n },\n },\n additionalProperties: false,\n description: 'Rule thresholds and toggles for enforcement.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Glob patterns for files and directories to ignore.',\n },\n boundaries: {\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to', 'allow'],\n properties: {\n from: {\n type: 'string',\n description: 'Source package or directory pattern.',\n },\n to: {\n type: 'string',\n description: 'Target package or directory pattern.',\n },\n allow: {\n type: 'boolean',\n description: 'Whether this import direction is allowed or disallowed.',\n },\n reason: {\n type: 'string',\n description: 'Human-readable explanation of why this boundary exists.',\n },\n },\n additionalProperties: false,\n },\n description: 'Module boundary rules for import enforcement.',\n },\n workspace: {\n type: 'object',\n required: ['packages', 'isMonorepo'],\n properties: {\n packages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Relative paths to workspace packages.',\n },\n isMonorepo: {\n type: 'boolean',\n description: 'Whether this project is a monorepo with multiple packages.',\n },\n },\n additionalProperties: false,\n description: 'Workspace configuration for monorepo projects.',\n },\n packages: {\n type: 'array',\n items: {\n type: 'object',\n required: ['name', 'path'],\n properties: {\n name: { type: 'string', description: 'Package name from package.json.' },\n path: { type: 'string', description: 'Relative path to the package.' },\n stack: {\n type: 'object',\n properties: {\n framework: { type: 'string' },\n language: { type: 'string' },\n styling: { type: 'string' },\n backend: { type: 'string' },\n packageManager: { type: 'string' },\n linter: { type: 'string' },\n testRunner: { type: 'string' },\n },\n additionalProperties: false,\n },\n conventions: { $ref: '#/properties/conventions' },\n rules: {\n type: 'object',\n properties: {\n maxFileLines: { type: 'number' },\n maxFunctionLines: { type: 'number' },\n requireTests: { type: 'boolean' },\n enforceNaming: { type: 'boolean' },\n enforceBoundaries: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ignore: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n description: 'Per-package overrides for monorepo projects.',\n },\n },\n additionalProperties: false,\n definitions: {\n conventionValue: {\n description:\n 'A convention value — either a plain string (user-confirmed) or an object with scanner metadata.',\n oneOf: [\n { type: 'string' },\n {\n type: 'object',\n required: ['value', '_confidence', '_consistency'],\n properties: {\n value: {\n type: 'string',\n description: 'The convention value.',\n },\n _confidence: {\n type: 'string',\n enum: ['high', 'medium', 'low'],\n description: 'Scanner confidence level.',\n },\n _consistency: {\n type: 'number',\n minimum: 0,\n maximum: 100,\n description: 'Scanner consistency percentage.',\n },\n _detected: {\n type: 'boolean',\n description: 'Set by mergeConfig when a convention is newly detected during sync.',\n },\n },\n additionalProperties: false,\n },\n ],\n },\n },\n} as const;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/defaults.ts","../src/generate-config.ts","../src/generate-overrides.ts","../src/load-config.ts","../src/merge-config.ts","../src/schema.ts"],"sourcesContent":["export const VERSION = '0.1.0';\n\nexport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nexport { generateConfig } from './generate-config.js';\nexport { loadConfig, loadConfigSafe } from './load-config.js';\nexport { mergeConfig } from './merge-config.js';\nexport { configSchema } from './schema.js';\n","import type { ConfigRules } from '@viberails/types';\n\n/**\n * Default rule thresholds and toggles for a new viberails config.\n * These values are intentionally conservative to build trust on first run.\n */\nexport const DEFAULT_RULES: ConfigRules = {\n maxFileLines: 300,\n maxFunctionLines: 50,\n requireTests: true,\n enforceNaming: true,\n enforceBoundaries: false,\n};\n\n/**\n * Default glob patterns for files and directories to ignore.\n */\nexport const DEFAULT_IGNORE: string[] = ['**/*.d.ts', 'dist/**', 'node_modules/**'];\n","import * as path from 'node:path';\nimport type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n DetectedConvention,\n DirectoryRole,\n ScanResult,\n StackItem,\n ViberailsConfig,\n} from '@viberails/types';\nimport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nimport { generatePackageOverrides } from './generate-overrides.js';\n\n/**\n * Format a StackItem as a config string: `\"name@version\"` or `\"name\"`.\n */\nexport function formatStackItem(item: StackItem): string {\n return item.version ? `${item.name}@${item.version}` : item.name;\n}\n\n/**\n * Map DetectedStack → ConfigStack by formatting each StackItem.\n */\nfunction mapStack(scanResult: ScanResult): ConfigStack {\n const { stack } = scanResult;\n const config: ConfigStack = {\n language: formatStackItem(stack.language),\n packageManager: formatStackItem(stack.packageManager),\n };\n\n if (stack.framework) config.framework = formatStackItem(stack.framework);\n if (stack.styling) config.styling = formatStackItem(stack.styling);\n if (stack.backend) config.backend = formatStackItem(stack.backend);\n if (stack.linter) config.linter = formatStackItem(stack.linter);\n if (stack.formatter) config.formatter = formatStackItem(stack.formatter);\n if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);\n\n return config;\n}\n\n/** Directory roles that map to ConfigStructure fields. */\nconst ROLE_TO_FIELD: Partial<Record<DirectoryRole, keyof ConfigStructure>> = {\n pages: 'pages',\n components: 'components',\n hooks: 'hooks',\n utils: 'utils',\n types: 'types',\n tests: 'tests',\n};\n\n/**\n * Map DetectedStructure → ConfigStructure by finding the first directory\n * for each known role.\n */\nfunction mapStructure(scanResult: ScanResult): ConfigStructure {\n const { structure } = scanResult;\n const config: ConfigStructure = {};\n\n if (structure.srcDir) {\n config.srcDir = structure.srcDir;\n }\n\n for (const dir of structure.directories) {\n const field = ROLE_TO_FIELD[dir.role];\n if (field && config[field] === undefined) {\n (config as Record<string, string>)[field] = dir.path;\n }\n }\n\n if (structure.testPattern) {\n config.testPattern = structure.testPattern.value;\n }\n\n return config;\n}\n\n/**\n * Convert a DetectedConvention to a ConventionValue with metadata.\n * Returns undefined for low-confidence conventions (they are omitted).\n */\nexport function mapConvention(convention: DetectedConvention): ConventionValue | undefined {\n if (convention.confidence === 'low') {\n return undefined;\n }\n\n return {\n value: convention.value,\n _confidence: convention.confidence,\n _consistency: convention.consistency,\n };\n}\n\n/** Convention keys from ScanResult that map to ConfigConventions fields. */\nexport const CONVENTION_KEYS: (keyof ConfigConventions)[] = [\n 'fileNaming',\n 'componentNaming',\n 'hookNaming',\n 'importAlias',\n];\n\n/**\n * Map scanner conventions → ConfigConventions, omitting low-confidence entries.\n */\nfunction mapConventions(scanResult: ScanResult): ConfigConventions {\n const config: ConfigConventions = {};\n\n for (const key of CONVENTION_KEYS) {\n const detected = scanResult.conventions[key];\n if (detected) {\n const value = mapConvention(detected);\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n\n return config;\n}\n\n/**\n * Generate a ViberailsConfig from scan results.\n *\n * Maps the scanner's DetectedStack, DetectedStructure, and conventions\n * into the config format with smart defaults. Low-confidence conventions\n * are omitted. The project name is derived from the root directory basename.\n *\n * @param scanResult - The output of scanning a project\n * @returns A complete ViberailsConfig ready to be written as JSON\n */\nexport function generateConfig(scanResult: ScanResult): ViberailsConfig {\n const config: ViberailsConfig = {\n $schema: 'https://viberails.sh/schema/v1.json',\n version: 1,\n name: path.basename(scanResult.root),\n enforcement: 'warn',\n stack: mapStack(scanResult),\n structure: mapStructure(scanResult),\n conventions: mapConventions(scanResult),\n rules: { ...DEFAULT_RULES },\n ignore: [...DEFAULT_IGNORE],\n };\n\n if (scanResult.workspace) {\n config.workspace = {\n packages: scanResult.workspace.packages.map((p) => p.relativePath),\n isMonorepo: true,\n };\n config.boundaries = [];\n }\n\n const packageOverrides = generatePackageOverrides(scanResult, config);\n if (packageOverrides) {\n config.packages = packageOverrides;\n }\n\n return config;\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n DetectedConvention,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, formatStackItem, mapConvention } from './generate-config.js';\n\n/**\n * Compare a package's conventions against the global config conventions.\n * Returns only the differing conventions, or undefined if all match.\n */\nexport function conventionsDiffer(\n pkgConventions: Record<string, DetectedConvention>,\n globalConventions: ConfigConventions,\n): Partial<ConfigConventions> | undefined {\n const overrides: Partial<ConfigConventions> = {};\n let hasDiff = false;\n\n for (const key of CONVENTION_KEYS) {\n const detected = pkgConventions[key];\n if (!detected) continue;\n\n const mapped = mapConvention(detected);\n if (mapped === undefined) continue;\n\n const globalValue = globalConventions[key];\n const globalStr = typeof globalValue === 'string' ? globalValue : globalValue?.value;\n if (detected.value !== globalStr) {\n overrides[key] = mapped;\n hasDiff = true;\n }\n }\n\n return hasDiff ? overrides : undefined;\n}\n\n/**\n * Generate per-package config overrides for packages whose stack or\n * conventions differ from the aggregate global config.\n */\nexport function generatePackageOverrides(\n scanResult: ScanResult,\n globalConfig: ViberailsConfig,\n): PackageConfigOverrides[] | undefined {\n if (!scanResult.packages || scanResult.packages.length <= 1) return undefined;\n\n const overrides: PackageConfigOverrides[] = [];\n\n for (const pkg of scanResult.packages) {\n const override: PackageConfigOverrides = {\n name: pkg.name,\n path: pkg.relativePath,\n };\n let hasDiff = false;\n\n // Compare stack fields — only include overrides when the package has a\n // value that differs from the global, not when the package simply lacks the field\n const stackOverride: Partial<ConfigStack> = {};\n let hasStackDiff = false;\n\n const optionalStackFields = [\n 'framework',\n 'styling',\n 'backend',\n 'linter',\n 'formatter',\n 'testRunner',\n ] as const;\n for (const field of optionalStackFields) {\n const pkgItem = pkg.stack[field];\n if (!pkgItem) continue;\n const pkgValue = formatStackItem(pkgItem);\n if (pkgValue !== globalConfig.stack[field]) {\n stackOverride[field] = pkgValue;\n hasStackDiff = true;\n }\n }\n\n if (hasStackDiff) {\n override.stack = stackOverride;\n hasDiff = true;\n }\n\n // Compare conventions\n const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);\n if (conventionOverrides) {\n override.conventions = conventionOverrides;\n hasDiff = true;\n }\n\n if (hasDiff) {\n overrides.push(override);\n }\n }\n\n return overrides.length > 0 ? overrides : undefined;\n}\n","import * as fs from 'node:fs/promises';\nimport type { ViberailsConfig } from '@viberails/types';\n\n/**\n * Validate that a parsed object has the required ViberailsConfig fields\n * and that their types are correct.\n * Throws a descriptive error if validation fails.\n */\nfunction validateConfig(parsed: Record<string, unknown>, configPath: string): void {\n const errors: string[] = [];\n\n // Required top-level fields\n const required = ['version', 'name', 'stack', 'rules'] as const;\n const missing = required.filter((field) => parsed[field] === undefined);\n if (missing.length > 0) {\n throw new Error(\n `Invalid viberails config at ${configPath}: missing required field(s): ${missing.join(', ')}`,\n );\n }\n\n // Type checks\n if (typeof parsed.version !== 'number') errors.push('\"version\" must be a number');\n if (typeof parsed.name !== 'string') errors.push('\"name\" must be a string');\n if (\n parsed.enforcement !== undefined &&\n parsed.enforcement !== 'warn' &&\n parsed.enforcement !== 'enforce'\n ) {\n errors.push('\"enforcement\" must be \"warn\" or \"enforce\"');\n }\n\n // Stack validation\n if (typeof parsed.stack !== 'object' || parsed.stack === null) {\n errors.push('\"stack\" must be an object');\n } else {\n const stack = parsed.stack as Record<string, unknown>;\n if (typeof stack.language !== 'string') errors.push('\"stack.language\" must be a string');\n if (typeof stack.packageManager !== 'string')\n errors.push('\"stack.packageManager\" must be a string');\n }\n\n // Rules validation\n if (typeof parsed.rules !== 'object' || parsed.rules === null) {\n errors.push('\"rules\" must be an object');\n } else {\n const rules = parsed.rules as Record<string, unknown>;\n if (typeof rules.maxFileLines !== 'number')\n errors.push('\"rules.maxFileLines\" must be a number');\n if (typeof rules.maxFunctionLines !== 'number')\n errors.push('\"rules.maxFunctionLines\" must be a number');\n if (typeof rules.requireTests !== 'boolean')\n errors.push('\"rules.requireTests\" must be a boolean');\n if (typeof rules.enforceNaming !== 'boolean')\n errors.push('\"rules.enforceNaming\" must be a boolean');\n if (typeof rules.enforceBoundaries !== 'boolean')\n errors.push('\"rules.enforceBoundaries\" must be a boolean');\n }\n\n // Ignore validation\n if (parsed.ignore !== undefined && !Array.isArray(parsed.ignore)) {\n errors.push('\"ignore\" must be an array');\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid viberails config at ${configPath}: ${errors.join('; ')}`);\n }\n}\n\n/**\n * Load and parse a viberails config file.\n *\n * Reads the JSON file at the given path, validates that it contains\n * the required fields (version, name, stack, rules), and returns\n * the parsed config.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig\n * @throws If the file doesn't exist, contains invalid JSON, or is missing required fields\n */\nexport async function loadConfig(configPath: string): Promise<ViberailsConfig> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Config file not found: ${configPath}. Run \"npx viberails\" to generate one.`);\n }\n throw new Error(`Failed to read config file at ${configPath}: ${(err as Error).message}`);\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in config file at ${configPath}. Check for syntax errors.`);\n }\n\n validateConfig(parsed, configPath);\n\n // Safe to cast: validateConfig has verified all required fields and types\n return parsed as unknown as ViberailsConfig;\n}\n\n/**\n * Safely load a viberails config file, returning null on any error.\n *\n * Used by the CLI for \"does config already exist?\" checks where\n * failure is an expected case, not an error.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig, or null if loading fails\n */\nexport async function loadConfigSafe(configPath: string): Promise<ViberailsConfig | null> {\n try {\n return await loadConfig(configPath);\n } catch {\n return null;\n }\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, generateConfig } from './generate-config.js';\n\n/**\n * Merge stack: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStack(existing: ConfigStack, fresh: ConfigStack): ConfigStack {\n return {\n language: existing.language,\n packageManager: existing.packageManager,\n framework: existing.framework ?? fresh.framework,\n styling: existing.styling ?? fresh.styling,\n backend: existing.backend ?? fresh.backend,\n linter: existing.linter ?? fresh.linter,\n formatter: existing.formatter ?? fresh.formatter,\n testRunner: existing.testRunner ?? fresh.testRunner,\n };\n}\n\n/**\n * Merge structure: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStructure(existing: ConfigStructure, fresh: ConfigStructure): ConfigStructure {\n return {\n srcDir: existing.srcDir ?? fresh.srcDir,\n pages: existing.pages ?? fresh.pages,\n components: existing.components ?? fresh.components,\n hooks: existing.hooks ?? fresh.hooks,\n utils: existing.utils ?? fresh.utils,\n types: existing.types ?? fresh.types,\n tests: existing.tests ?? fresh.tests,\n testPattern: existing.testPattern ?? fresh.testPattern,\n };\n}\n\n/**\n * Check if a convention key exists in the existing config\n * (either as a string or as an object with a value).\n */\nfunction hasConvention(conventions: ConfigConventions, key: keyof ConfigConventions): boolean {\n return conventions[key] !== undefined;\n}\n\n/**\n * Mark a ConventionValue as newly detected by adding `_detected: true`.\n * Only applies to object-form values (not plain strings).\n */\nfunction markAsDetected(value: ConventionValue): ConventionValue {\n if (typeof value === 'string') {\n return { value, _confidence: 'high', _consistency: 100, _detected: true };\n }\n return { ...value, _detected: true };\n}\n\n/**\n * Merge conventions: keep all existing values, add new detections with `_detected: true`.\n */\nfunction mergeConventions(\n existing: ConfigConventions,\n fresh: ConfigConventions,\n): ConfigConventions {\n const merged: ConfigConventions = { ...existing };\n\n for (const key of CONVENTION_KEYS) {\n if (!hasConvention(existing, key) && fresh[key] !== undefined) {\n merged[key] = markAsDetected(fresh[key]!);\n }\n }\n\n return merged;\n}\n\n/**\n * Merge a new scan result into an existing config for `viberails sync`.\n *\n * Preserves all developer-confirmed values from the existing config.\n * Adds newly detected conventions with a `_detected: true` annotation\n * so the developer can review them. Never removes rules or values\n * the developer has set.\n *\n * @param existing - The current ViberailsConfig (from viberails.config.json)\n * @param scanResult - Fresh scan results from re-scanning the project\n * @returns A merged config that preserves existing values and adds new detections\n */\nexport function mergeConfig(existing: ViberailsConfig, scanResult: ScanResult): ViberailsConfig {\n const fresh = generateConfig(scanResult);\n\n const merged: ViberailsConfig = {\n $schema: existing.$schema ?? fresh.$schema,\n version: existing.version,\n name: existing.name,\n enforcement: existing.enforcement,\n stack: mergeStack(existing.stack, fresh.stack),\n structure: mergeStructure(existing.structure, fresh.structure),\n conventions: mergeConventions(existing.conventions, fresh.conventions),\n rules: { ...existing.rules },\n ignore: [...existing.ignore],\n };\n\n // Workspace: always take fresh scan (structure can change)\n if (fresh.workspace) {\n merged.workspace = fresh.workspace;\n }\n\n // Boundaries: preserve existing rules (user may have adjusted)\n if (existing.boundaries) {\n merged.boundaries = [...existing.boundaries];\n } else if (fresh.boundaries) {\n merged.boundaries = [...fresh.boundaries];\n }\n\n // Packages: preserve existing overrides, add new ones\n if (existing.packages || fresh.packages) {\n merged.packages = mergePackageOverrides(existing.packages, fresh.packages);\n }\n\n return merged;\n}\n\n/**\n * Merge per-package overrides: keep existing user-edited overrides,\n * add new packages from fresh scan.\n */\nfunction mergePackageOverrides(\n existing?: PackageConfigOverrides[],\n fresh?: PackageConfigOverrides[],\n): PackageConfigOverrides[] | undefined {\n if (!fresh || fresh.length === 0) return existing;\n if (!existing || existing.length === 0) return fresh;\n\n const existingByPath = new Map(existing.map((p) => [p.path, p]));\n const merged: PackageConfigOverrides[] = [...existing];\n\n for (const freshPkg of fresh) {\n if (!existingByPath.has(freshPkg.path)) {\n merged.push(freshPkg);\n }\n }\n\n return merged.length > 0 ? merged : undefined;\n}\n","/**\n * JSON Schema (draft-07) definition for viberails.config.json.\n *\n * This schema will eventually be hosted at https://viberails.sh/schema/v1.json.\n * For now it is exported as a TypeScript object that can be serialized to JSON.\n */\nexport const configSchema = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://viberails.sh/schema/v1.json',\n title: 'viberails configuration',\n description: 'Configuration file for viberails — guardrails for vibe coding.',\n type: 'object',\n required: ['version', 'name', 'stack', 'rules'],\n properties: {\n $schema: {\n type: 'string',\n description: 'JSON Schema URL for editor validation.',\n },\n version: {\n type: 'number',\n const: 1,\n description: 'Config format version. Always 1 for V1.0.',\n },\n name: {\n type: 'string',\n description: 'Project name, typically from package.json.',\n },\n enforcement: {\n type: 'string',\n enum: ['warn', 'enforce'],\n default: 'warn',\n description: 'Whether conventions are warned about or enforced as errors.',\n },\n stack: {\n type: 'object',\n required: ['language', 'packageManager'],\n properties: {\n framework: {\n type: 'string',\n description: 'Primary framework identifier (e.g. \"nextjs@15\", \"remix@2\").',\n },\n language: {\n type: 'string',\n description: 'Primary language (e.g. \"typescript\", \"javascript\").',\n },\n styling: {\n type: 'string',\n description: 'Styling solution (e.g. \"tailwindcss@4\", \"css-modules\").',\n },\n backend: {\n type: 'string',\n description: 'Backend framework (e.g. \"express@5\", \"fastify\").',\n },\n packageManager: {\n type: 'string',\n description: 'Package manager (e.g. \"pnpm\", \"npm\", \"yarn\").',\n },\n linter: {\n type: 'string',\n description: 'Linter (e.g. \"eslint@9\", \"biome\").',\n },\n formatter: {\n type: 'string',\n description: 'Formatter (e.g. \"prettier\", \"biome\").',\n },\n testRunner: {\n type: 'string',\n description: 'Test runner (e.g. \"vitest\", \"jest\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured technology stack.',\n },\n structure: {\n type: 'object',\n properties: {\n srcDir: {\n type: 'string',\n description: 'Source directory (e.g. \"src\"), or omit for flat structure.',\n },\n pages: {\n type: 'string',\n description: 'Pages or routes directory (e.g. \"src/app\").',\n },\n components: {\n type: 'string',\n description: 'Components directory (e.g. \"src/components\").',\n },\n hooks: {\n type: 'string',\n description: 'Hooks directory (e.g. \"src/hooks\").',\n },\n utils: {\n type: 'string',\n description: 'Utilities directory (e.g. \"src/utils\", \"src/lib\").',\n },\n types: {\n type: 'string',\n description: 'Type definitions directory (e.g. \"src/types\").',\n },\n tests: {\n type: 'string',\n description: 'Tests directory (e.g. \"tests\", \"__tests__\").',\n },\n testPattern: {\n type: 'string',\n description: 'Test file naming pattern (e.g. \"*.test.ts\", \"*.spec.ts\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured directory structure.',\n },\n conventions: {\n type: 'object',\n properties: {\n fileNaming: { $ref: '#/definitions/conventionValue' },\n componentNaming: { $ref: '#/definitions/conventionValue' },\n hookNaming: { $ref: '#/definitions/conventionValue' },\n importAlias: { $ref: '#/definitions/conventionValue' },\n },\n additionalProperties: false,\n description: 'Detected or configured coding conventions.',\n },\n rules: {\n type: 'object',\n required: [\n 'maxFileLines',\n 'maxFunctionLines',\n 'requireTests',\n 'enforceNaming',\n 'enforceBoundaries',\n ],\n properties: {\n maxFileLines: {\n type: 'number',\n default: 300,\n description: 'Maximum number of lines allowed per file.',\n },\n maxFunctionLines: {\n type: 'number',\n default: 50,\n description: 'Maximum number of lines allowed per function.',\n },\n requireTests: {\n type: 'boolean',\n default: true,\n description: 'Whether to require test files for source modules.',\n },\n enforceNaming: {\n type: 'boolean',\n default: true,\n description: 'Whether to enforce detected file naming conventions.',\n },\n enforceBoundaries: {\n type: 'boolean',\n default: false,\n description: 'Whether to enforce module boundary rules.',\n },\n },\n additionalProperties: false,\n description: 'Rule thresholds and toggles for enforcement.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Glob patterns for files and directories to ignore.',\n },\n boundaries: {\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to', 'allow'],\n properties: {\n from: {\n type: 'string',\n description: 'Source package or directory pattern.',\n },\n to: {\n type: 'string',\n description: 'Target package or directory pattern.',\n },\n allow: {\n type: 'boolean',\n description: 'Whether this import direction is allowed or disallowed.',\n },\n reason: {\n type: 'string',\n description: 'Human-readable explanation of why this boundary exists.',\n },\n },\n additionalProperties: false,\n },\n description: 'Module boundary rules for import enforcement.',\n },\n workspace: {\n type: 'object',\n required: ['packages', 'isMonorepo'],\n properties: {\n packages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Relative paths to workspace packages.',\n },\n isMonorepo: {\n type: 'boolean',\n description: 'Whether this project is a monorepo with multiple packages.',\n },\n },\n additionalProperties: false,\n description: 'Workspace configuration for monorepo projects.',\n },\n packages: {\n type: 'array',\n items: {\n type: 'object',\n required: ['name', 'path'],\n properties: {\n name: { type: 'string', description: 'Package name from package.json.' },\n path: { type: 'string', description: 'Relative path to the package.' },\n stack: {\n type: 'object',\n properties: {\n framework: { type: 'string' },\n language: { type: 'string' },\n styling: { type: 'string' },\n backend: { type: 'string' },\n packageManager: { type: 'string' },\n linter: { type: 'string' },\n formatter: { type: 'string' },\n testRunner: { type: 'string' },\n },\n additionalProperties: false,\n },\n conventions: { $ref: '#/properties/conventions' },\n rules: {\n type: 'object',\n properties: {\n maxFileLines: { type: 'number' },\n maxFunctionLines: { type: 'number' },\n requireTests: { type: 'boolean' },\n enforceNaming: { type: 'boolean' },\n enforceBoundaries: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ignore: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n description: 'Per-package overrides for monorepo projects.',\n },\n },\n additionalProperties: false,\n definitions: {\n conventionValue: {\n description:\n 'A convention value — either a plain string (user-confirmed) or an object with scanner metadata.',\n oneOf: [\n { type: 'string' },\n {\n type: 'object',\n required: ['value', '_confidence', '_consistency'],\n properties: {\n value: {\n type: 'string',\n description: 'The convention value.',\n },\n _confidence: {\n type: 'string',\n enum: ['high', 'medium', 'low'],\n description: 'Scanner confidence level.',\n },\n _consistency: {\n type: 'number',\n minimum: 0,\n maximum: 100,\n description: 'Scanner consistency percentage.',\n },\n _detected: {\n type: 'boolean',\n description: 'Set by mergeConfig when a convention is newly detected during sync.',\n },\n },\n additionalProperties: false,\n },\n ],\n },\n },\n} as const;\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -120,6 +120,10 @@ declare const configSchema: {
120
120
  readonly type: "string";
121
121
  readonly description: "Linter (e.g. \"eslint@9\", \"biome\").";
122
122
  };
123
+ readonly formatter: {
124
+ readonly type: "string";
125
+ readonly description: "Formatter (e.g. \"prettier\", \"biome\").";
126
+ };
123
127
  readonly testRunner: {
124
128
  readonly type: "string";
125
129
  readonly description: "Test runner (e.g. \"vitest\", \"jest\").";
@@ -307,6 +311,9 @@ declare const configSchema: {
307
311
  readonly linter: {
308
312
  readonly type: "string";
309
313
  };
314
+ readonly formatter: {
315
+ readonly type: "string";
316
+ };
310
317
  readonly testRunner: {
311
318
  readonly type: "string";
312
319
  };
package/dist/index.d.ts CHANGED
@@ -120,6 +120,10 @@ declare const configSchema: {
120
120
  readonly type: "string";
121
121
  readonly description: "Linter (e.g. \"eslint@9\", \"biome\").";
122
122
  };
123
+ readonly formatter: {
124
+ readonly type: "string";
125
+ readonly description: "Formatter (e.g. \"prettier\", \"biome\").";
126
+ };
123
127
  readonly testRunner: {
124
128
  readonly type: "string";
125
129
  readonly description: "Test runner (e.g. \"vitest\", \"jest\").";
@@ -307,6 +311,9 @@ declare const configSchema: {
307
311
  readonly linter: {
308
312
  readonly type: "string";
309
313
  };
314
+ readonly formatter: {
315
+ readonly type: "string";
316
+ };
310
317
  readonly testRunner: {
311
318
  readonly type: "string";
312
319
  };
package/dist/index.js CHANGED
@@ -10,6 +10,70 @@ var DEFAULT_IGNORE = ["**/*.d.ts", "dist/**", "node_modules/**"];
10
10
 
11
11
  // src/generate-config.ts
12
12
  import * as path from "path";
13
+
14
+ // src/generate-overrides.ts
15
+ function conventionsDiffer(pkgConventions, globalConventions) {
16
+ const overrides = {};
17
+ let hasDiff = false;
18
+ for (const key of CONVENTION_KEYS) {
19
+ const detected = pkgConventions[key];
20
+ if (!detected) continue;
21
+ const mapped = mapConvention(detected);
22
+ if (mapped === void 0) continue;
23
+ const globalValue = globalConventions[key];
24
+ const globalStr = typeof globalValue === "string" ? globalValue : globalValue?.value;
25
+ if (detected.value !== globalStr) {
26
+ overrides[key] = mapped;
27
+ hasDiff = true;
28
+ }
29
+ }
30
+ return hasDiff ? overrides : void 0;
31
+ }
32
+ function generatePackageOverrides(scanResult, globalConfig) {
33
+ if (!scanResult.packages || scanResult.packages.length <= 1) return void 0;
34
+ const overrides = [];
35
+ for (const pkg of scanResult.packages) {
36
+ const override = {
37
+ name: pkg.name,
38
+ path: pkg.relativePath
39
+ };
40
+ let hasDiff = false;
41
+ const stackOverride = {};
42
+ let hasStackDiff = false;
43
+ const optionalStackFields = [
44
+ "framework",
45
+ "styling",
46
+ "backend",
47
+ "linter",
48
+ "formatter",
49
+ "testRunner"
50
+ ];
51
+ for (const field of optionalStackFields) {
52
+ const pkgItem = pkg.stack[field];
53
+ if (!pkgItem) continue;
54
+ const pkgValue = formatStackItem(pkgItem);
55
+ if (pkgValue !== globalConfig.stack[field]) {
56
+ stackOverride[field] = pkgValue;
57
+ hasStackDiff = true;
58
+ }
59
+ }
60
+ if (hasStackDiff) {
61
+ override.stack = stackOverride;
62
+ hasDiff = true;
63
+ }
64
+ const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);
65
+ if (conventionOverrides) {
66
+ override.conventions = conventionOverrides;
67
+ hasDiff = true;
68
+ }
69
+ if (hasDiff) {
70
+ overrides.push(override);
71
+ }
72
+ }
73
+ return overrides.length > 0 ? overrides : void 0;
74
+ }
75
+
76
+ // src/generate-config.ts
13
77
  function formatStackItem(item) {
14
78
  return item.version ? `${item.name}@${item.version}` : item.name;
15
79
  }
@@ -23,6 +87,7 @@ function mapStack(scanResult) {
23
87
  if (stack.styling) config.styling = formatStackItem(stack.styling);
24
88
  if (stack.backend) config.backend = formatStackItem(stack.backend);
25
89
  if (stack.linter) config.linter = formatStackItem(stack.linter);
90
+ if (stack.formatter) config.formatter = formatStackItem(stack.formatter);
26
91
  if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);
27
92
  return config;
28
93
  }
@@ -80,65 +145,6 @@ function mapConventions(scanResult) {
80
145
  }
81
146
  return config;
82
147
  }
83
- function conventionsDiffer(pkgConventions, globalConventions) {
84
- const overrides = {};
85
- let hasDiff = false;
86
- for (const key of CONVENTION_KEYS) {
87
- const detected = pkgConventions[key];
88
- if (!detected) continue;
89
- const mapped = mapConvention(detected);
90
- if (mapped === void 0) continue;
91
- const globalValue = globalConventions[key];
92
- const globalStr = typeof globalValue === "string" ? globalValue : globalValue?.value;
93
- if (detected.value !== globalStr) {
94
- overrides[key] = mapped;
95
- hasDiff = true;
96
- }
97
- }
98
- return hasDiff ? overrides : void 0;
99
- }
100
- function generatePackageOverrides(scanResult, globalConfig) {
101
- if (!scanResult.packages || scanResult.packages.length <= 1) return void 0;
102
- const overrides = [];
103
- for (const pkg of scanResult.packages) {
104
- const override = {
105
- name: pkg.name,
106
- path: pkg.relativePath
107
- };
108
- let hasDiff = false;
109
- const stackOverride = {};
110
- let hasStackDiff = false;
111
- const optionalStackFields = [
112
- "framework",
113
- "styling",
114
- "backend",
115
- "linter",
116
- "testRunner"
117
- ];
118
- for (const field of optionalStackFields) {
119
- const pkgItem = pkg.stack[field];
120
- if (!pkgItem) continue;
121
- const pkgValue = formatStackItem(pkgItem);
122
- if (pkgValue !== globalConfig.stack[field]) {
123
- stackOverride[field] = pkgValue;
124
- hasStackDiff = true;
125
- }
126
- }
127
- if (hasStackDiff) {
128
- override.stack = stackOverride;
129
- hasDiff = true;
130
- }
131
- const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);
132
- if (conventionOverrides) {
133
- override.conventions = conventionOverrides;
134
- hasDiff = true;
135
- }
136
- if (hasDiff) {
137
- overrides.push(override);
138
- }
139
- }
140
- return overrides.length > 0 ? overrides : void 0;
141
- }
142
148
  function generateConfig(scanResult) {
143
149
  const config = {
144
150
  $schema: "https://viberails.sh/schema/v1.json",
@@ -248,6 +254,7 @@ function mergeStack(existing, fresh) {
248
254
  styling: existing.styling ?? fresh.styling,
249
255
  backend: existing.backend ?? fresh.backend,
250
256
  linter: existing.linter ?? fresh.linter,
257
+ formatter: existing.formatter ?? fresh.formatter,
251
258
  testRunner: existing.testRunner ?? fresh.testRunner
252
259
  };
253
260
  }
@@ -376,6 +383,10 @@ var configSchema = {
376
383
  type: "string",
377
384
  description: 'Linter (e.g. "eslint@9", "biome").'
378
385
  },
386
+ formatter: {
387
+ type: "string",
388
+ description: 'Formatter (e.g. "prettier", "biome").'
389
+ },
379
390
  testRunner: {
380
391
  type: "string",
381
392
  description: 'Test runner (e.g. "vitest", "jest").'
@@ -539,6 +550,7 @@ var configSchema = {
539
550
  backend: { type: "string" },
540
551
  packageManager: { type: "string" },
541
552
  linter: { type: "string" },
553
+ formatter: { type: "string" },
542
554
  testRunner: { type: "string" }
543
555
  },
544
556
  additionalProperties: false
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defaults.ts","../src/generate-config.ts","../src/load-config.ts","../src/merge-config.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import type { ConfigRules } from '@viberails/types';\n\n/**\n * Default rule thresholds and toggles for a new viberails config.\n * These values are intentionally conservative to build trust on first run.\n */\nexport const DEFAULT_RULES: ConfigRules = {\n maxFileLines: 300,\n maxFunctionLines: 50,\n requireTests: true,\n enforceNaming: true,\n enforceBoundaries: false,\n};\n\n/**\n * Default glob patterns for files and directories to ignore.\n */\nexport const DEFAULT_IGNORE: string[] = ['**/*.d.ts', 'dist/**', 'node_modules/**'];\n","import * as path from 'node:path';\nimport type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n DetectedConvention,\n DirectoryRole,\n PackageConfigOverrides,\n ScanResult,\n StackItem,\n ViberailsConfig,\n} from '@viberails/types';\nimport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\n\n/**\n * Format a StackItem as a config string: `\"name@version\"` or `\"name\"`.\n */\nfunction formatStackItem(item: StackItem): string {\n return item.version ? `${item.name}@${item.version}` : item.name;\n}\n\n/**\n * Map DetectedStack → ConfigStack by formatting each StackItem.\n */\nfunction mapStack(scanResult: ScanResult): ConfigStack {\n const { stack } = scanResult;\n const config: ConfigStack = {\n language: formatStackItem(stack.language),\n packageManager: formatStackItem(stack.packageManager),\n };\n\n if (stack.framework) config.framework = formatStackItem(stack.framework);\n if (stack.styling) config.styling = formatStackItem(stack.styling);\n if (stack.backend) config.backend = formatStackItem(stack.backend);\n if (stack.linter) config.linter = formatStackItem(stack.linter);\n if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);\n\n return config;\n}\n\n/** Directory roles that map to ConfigStructure fields. */\nconst ROLE_TO_FIELD: Partial<Record<DirectoryRole, keyof ConfigStructure>> = {\n pages: 'pages',\n components: 'components',\n hooks: 'hooks',\n utils: 'utils',\n types: 'types',\n tests: 'tests',\n};\n\n/**\n * Map DetectedStructure → ConfigStructure by finding the first directory\n * for each known role.\n */\nfunction mapStructure(scanResult: ScanResult): ConfigStructure {\n const { structure } = scanResult;\n const config: ConfigStructure = {};\n\n if (structure.srcDir) {\n config.srcDir = structure.srcDir;\n }\n\n for (const dir of structure.directories) {\n const field = ROLE_TO_FIELD[dir.role];\n if (field && config[field] === undefined) {\n (config as Record<string, string>)[field] = dir.path;\n }\n }\n\n if (structure.testPattern) {\n config.testPattern = structure.testPattern.value;\n }\n\n return config;\n}\n\n/**\n * Convert a DetectedConvention to a ConventionValue with metadata.\n * Returns undefined for low-confidence conventions (they are omitted).\n */\nfunction mapConvention(convention: DetectedConvention): ConventionValue | undefined {\n if (convention.confidence === 'low') {\n return undefined;\n }\n\n return {\n value: convention.value,\n _confidence: convention.confidence,\n _consistency: convention.consistency,\n };\n}\n\n/** Convention keys from ScanResult that map to ConfigConventions fields. */\nexport const CONVENTION_KEYS: (keyof ConfigConventions)[] = [\n 'fileNaming',\n 'componentNaming',\n 'hookNaming',\n 'importAlias',\n];\n\n/**\n * Map scanner conventions → ConfigConventions, omitting low-confidence entries.\n */\nfunction mapConventions(scanResult: ScanResult): ConfigConventions {\n const config: ConfigConventions = {};\n\n for (const key of CONVENTION_KEYS) {\n const detected = scanResult.conventions[key];\n if (detected) {\n const value = mapConvention(detected);\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n\n return config;\n}\n\n/**\n * Compare a package's conventions against the global config conventions.\n * Returns only the differing conventions, or undefined if all match.\n */\nfunction conventionsDiffer(\n pkgConventions: Record<string, DetectedConvention>,\n globalConventions: ConfigConventions,\n): Partial<ConfigConventions> | undefined {\n const overrides: Partial<ConfigConventions> = {};\n let hasDiff = false;\n\n for (const key of CONVENTION_KEYS) {\n const detected = pkgConventions[key];\n if (!detected) continue;\n\n const mapped = mapConvention(detected);\n if (mapped === undefined) continue;\n\n const globalValue = globalConventions[key];\n const globalStr = typeof globalValue === 'string' ? globalValue : globalValue?.value;\n if (detected.value !== globalStr) {\n overrides[key] = mapped;\n hasDiff = true;\n }\n }\n\n return hasDiff ? overrides : undefined;\n}\n\n/**\n * Generate per-package config overrides for packages whose stack or\n * conventions differ from the aggregate global config.\n */\nfunction generatePackageOverrides(\n scanResult: ScanResult,\n globalConfig: ViberailsConfig,\n): PackageConfigOverrides[] | undefined {\n if (!scanResult.packages || scanResult.packages.length <= 1) return undefined;\n\n const overrides: PackageConfigOverrides[] = [];\n\n for (const pkg of scanResult.packages) {\n const override: PackageConfigOverrides = {\n name: pkg.name,\n path: pkg.relativePath,\n };\n let hasDiff = false;\n\n // Compare stack fields — only include overrides when the package has a\n // value that differs from the global, not when the package simply lacks the field\n const stackOverride: Partial<ConfigStack> = {};\n let hasStackDiff = false;\n\n const optionalStackFields = [\n 'framework',\n 'styling',\n 'backend',\n 'linter',\n 'testRunner',\n ] as const;\n for (const field of optionalStackFields) {\n const pkgItem = pkg.stack[field];\n if (!pkgItem) continue;\n const pkgValue = formatStackItem(pkgItem);\n if (pkgValue !== globalConfig.stack[field]) {\n stackOverride[field] = pkgValue;\n hasStackDiff = true;\n }\n }\n\n if (hasStackDiff) {\n override.stack = stackOverride;\n hasDiff = true;\n }\n\n // Compare conventions\n const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);\n if (conventionOverrides) {\n override.conventions = conventionOverrides;\n hasDiff = true;\n }\n\n if (hasDiff) {\n overrides.push(override);\n }\n }\n\n return overrides.length > 0 ? overrides : undefined;\n}\n\n/**\n * Generate a ViberailsConfig from scan results.\n *\n * Maps the scanner's DetectedStack, DetectedStructure, and conventions\n * into the config format with smart defaults. Low-confidence conventions\n * are omitted. The project name is derived from the root directory basename.\n *\n * @param scanResult - The output of scanning a project\n * @returns A complete ViberailsConfig ready to be written as JSON\n */\nexport function generateConfig(scanResult: ScanResult): ViberailsConfig {\n const config: ViberailsConfig = {\n $schema: 'https://viberails.sh/schema/v1.json',\n version: 1,\n name: path.basename(scanResult.root),\n enforcement: 'warn',\n stack: mapStack(scanResult),\n structure: mapStructure(scanResult),\n conventions: mapConventions(scanResult),\n rules: { ...DEFAULT_RULES },\n ignore: [...DEFAULT_IGNORE],\n };\n\n if (scanResult.workspace) {\n config.workspace = {\n packages: scanResult.workspace.packages.map((p) => p.relativePath),\n isMonorepo: true,\n };\n config.boundaries = [];\n }\n\n const packageOverrides = generatePackageOverrides(scanResult, config);\n if (packageOverrides) {\n config.packages = packageOverrides;\n }\n\n return config;\n}\n","import * as fs from 'node:fs/promises';\nimport type { ViberailsConfig } from '@viberails/types';\n\n/**\n * Validate that a parsed object has the required ViberailsConfig fields\n * and that their types are correct.\n * Throws a descriptive error if validation fails.\n */\nfunction validateConfig(parsed: Record<string, unknown>, configPath: string): void {\n const errors: string[] = [];\n\n // Required top-level fields\n const required = ['version', 'name', 'stack', 'rules'] as const;\n const missing = required.filter((field) => parsed[field] === undefined);\n if (missing.length > 0) {\n throw new Error(\n `Invalid viberails config at ${configPath}: missing required field(s): ${missing.join(', ')}`,\n );\n }\n\n // Type checks\n if (typeof parsed.version !== 'number') errors.push('\"version\" must be a number');\n if (typeof parsed.name !== 'string') errors.push('\"name\" must be a string');\n if (\n parsed.enforcement !== undefined &&\n parsed.enforcement !== 'warn' &&\n parsed.enforcement !== 'enforce'\n ) {\n errors.push('\"enforcement\" must be \"warn\" or \"enforce\"');\n }\n\n // Stack validation\n if (typeof parsed.stack !== 'object' || parsed.stack === null) {\n errors.push('\"stack\" must be an object');\n } else {\n const stack = parsed.stack as Record<string, unknown>;\n if (typeof stack.language !== 'string') errors.push('\"stack.language\" must be a string');\n if (typeof stack.packageManager !== 'string')\n errors.push('\"stack.packageManager\" must be a string');\n }\n\n // Rules validation\n if (typeof parsed.rules !== 'object' || parsed.rules === null) {\n errors.push('\"rules\" must be an object');\n } else {\n const rules = parsed.rules as Record<string, unknown>;\n if (typeof rules.maxFileLines !== 'number')\n errors.push('\"rules.maxFileLines\" must be a number');\n if (typeof rules.maxFunctionLines !== 'number')\n errors.push('\"rules.maxFunctionLines\" must be a number');\n if (typeof rules.requireTests !== 'boolean')\n errors.push('\"rules.requireTests\" must be a boolean');\n if (typeof rules.enforceNaming !== 'boolean')\n errors.push('\"rules.enforceNaming\" must be a boolean');\n if (typeof rules.enforceBoundaries !== 'boolean')\n errors.push('\"rules.enforceBoundaries\" must be a boolean');\n }\n\n // Ignore validation\n if (parsed.ignore !== undefined && !Array.isArray(parsed.ignore)) {\n errors.push('\"ignore\" must be an array');\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid viberails config at ${configPath}: ${errors.join('; ')}`);\n }\n}\n\n/**\n * Load and parse a viberails config file.\n *\n * Reads the JSON file at the given path, validates that it contains\n * the required fields (version, name, stack, rules), and returns\n * the parsed config.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig\n * @throws If the file doesn't exist, contains invalid JSON, or is missing required fields\n */\nexport async function loadConfig(configPath: string): Promise<ViberailsConfig> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Config file not found: ${configPath}. Run \"npx viberails\" to generate one.`);\n }\n throw new Error(`Failed to read config file at ${configPath}: ${(err as Error).message}`);\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in config file at ${configPath}. Check for syntax errors.`);\n }\n\n validateConfig(parsed, configPath);\n\n // Safe to cast: validateConfig has verified all required fields and types\n return parsed as unknown as ViberailsConfig;\n}\n\n/**\n * Safely load a viberails config file, returning null on any error.\n *\n * Used by the CLI for \"does config already exist?\" checks where\n * failure is an expected case, not an error.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig, or null if loading fails\n */\nexport async function loadConfigSafe(configPath: string): Promise<ViberailsConfig | null> {\n try {\n return await loadConfig(configPath);\n } catch {\n return null;\n }\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, generateConfig } from './generate-config.js';\n\n/**\n * Merge stack: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStack(existing: ConfigStack, fresh: ConfigStack): ConfigStack {\n return {\n language: existing.language,\n packageManager: existing.packageManager,\n framework: existing.framework ?? fresh.framework,\n styling: existing.styling ?? fresh.styling,\n backend: existing.backend ?? fresh.backend,\n linter: existing.linter ?? fresh.linter,\n testRunner: existing.testRunner ?? fresh.testRunner,\n };\n}\n\n/**\n * Merge structure: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStructure(existing: ConfigStructure, fresh: ConfigStructure): ConfigStructure {\n return {\n srcDir: existing.srcDir ?? fresh.srcDir,\n pages: existing.pages ?? fresh.pages,\n components: existing.components ?? fresh.components,\n hooks: existing.hooks ?? fresh.hooks,\n utils: existing.utils ?? fresh.utils,\n types: existing.types ?? fresh.types,\n tests: existing.tests ?? fresh.tests,\n testPattern: existing.testPattern ?? fresh.testPattern,\n };\n}\n\n/**\n * Check if a convention key exists in the existing config\n * (either as a string or as an object with a value).\n */\nfunction hasConvention(conventions: ConfigConventions, key: keyof ConfigConventions): boolean {\n return conventions[key] !== undefined;\n}\n\n/**\n * Mark a ConventionValue as newly detected by adding `_detected: true`.\n * Only applies to object-form values (not plain strings).\n */\nfunction markAsDetected(value: ConventionValue): ConventionValue {\n if (typeof value === 'string') {\n return { value, _confidence: 'high', _consistency: 100, _detected: true };\n }\n return { ...value, _detected: true };\n}\n\n/**\n * Merge conventions: keep all existing values, add new detections with `_detected: true`.\n */\nfunction mergeConventions(\n existing: ConfigConventions,\n fresh: ConfigConventions,\n): ConfigConventions {\n const merged: ConfigConventions = { ...existing };\n\n for (const key of CONVENTION_KEYS) {\n if (!hasConvention(existing, key) && fresh[key] !== undefined) {\n merged[key] = markAsDetected(fresh[key]!);\n }\n }\n\n return merged;\n}\n\n/**\n * Merge a new scan result into an existing config for `viberails sync`.\n *\n * Preserves all developer-confirmed values from the existing config.\n * Adds newly detected conventions with a `_detected: true` annotation\n * so the developer can review them. Never removes rules or values\n * the developer has set.\n *\n * @param existing - The current ViberailsConfig (from viberails.config.json)\n * @param scanResult - Fresh scan results from re-scanning the project\n * @returns A merged config that preserves existing values and adds new detections\n */\nexport function mergeConfig(existing: ViberailsConfig, scanResult: ScanResult): ViberailsConfig {\n const fresh = generateConfig(scanResult);\n\n const merged: ViberailsConfig = {\n $schema: existing.$schema ?? fresh.$schema,\n version: existing.version,\n name: existing.name,\n enforcement: existing.enforcement,\n stack: mergeStack(existing.stack, fresh.stack),\n structure: mergeStructure(existing.structure, fresh.structure),\n conventions: mergeConventions(existing.conventions, fresh.conventions),\n rules: { ...existing.rules },\n ignore: [...existing.ignore],\n };\n\n // Workspace: always take fresh scan (structure can change)\n if (fresh.workspace) {\n merged.workspace = fresh.workspace;\n }\n\n // Boundaries: preserve existing rules (user may have adjusted)\n if (existing.boundaries) {\n merged.boundaries = [...existing.boundaries];\n } else if (fresh.boundaries) {\n merged.boundaries = [...fresh.boundaries];\n }\n\n // Packages: preserve existing overrides, add new ones\n if (existing.packages || fresh.packages) {\n merged.packages = mergePackageOverrides(existing.packages, fresh.packages);\n }\n\n return merged;\n}\n\n/**\n * Merge per-package overrides: keep existing user-edited overrides,\n * add new packages from fresh scan.\n */\nfunction mergePackageOverrides(\n existing?: PackageConfigOverrides[],\n fresh?: PackageConfigOverrides[],\n): PackageConfigOverrides[] | undefined {\n if (!fresh || fresh.length === 0) return existing;\n if (!existing || existing.length === 0) return fresh;\n\n const existingByPath = new Map(existing.map((p) => [p.path, p]));\n const merged: PackageConfigOverrides[] = [...existing];\n\n for (const freshPkg of fresh) {\n if (!existingByPath.has(freshPkg.path)) {\n merged.push(freshPkg);\n }\n }\n\n return merged.length > 0 ? merged : undefined;\n}\n","/**\n * JSON Schema (draft-07) definition for viberails.config.json.\n *\n * This schema will eventually be hosted at https://viberails.sh/schema/v1.json.\n * For now it is exported as a TypeScript object that can be serialized to JSON.\n */\nexport const configSchema = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://viberails.sh/schema/v1.json',\n title: 'viberails configuration',\n description: 'Configuration file for viberails — guardrails for vibe coding.',\n type: 'object',\n required: ['version', 'name', 'stack', 'rules'],\n properties: {\n $schema: {\n type: 'string',\n description: 'JSON Schema URL for editor validation.',\n },\n version: {\n type: 'number',\n const: 1,\n description: 'Config format version. Always 1 for V1.0.',\n },\n name: {\n type: 'string',\n description: 'Project name, typically from package.json.',\n },\n enforcement: {\n type: 'string',\n enum: ['warn', 'enforce'],\n default: 'warn',\n description: 'Whether conventions are warned about or enforced as errors.',\n },\n stack: {\n type: 'object',\n required: ['language', 'packageManager'],\n properties: {\n framework: {\n type: 'string',\n description: 'Primary framework identifier (e.g. \"nextjs@15\", \"remix@2\").',\n },\n language: {\n type: 'string',\n description: 'Primary language (e.g. \"typescript\", \"javascript\").',\n },\n styling: {\n type: 'string',\n description: 'Styling solution (e.g. \"tailwindcss@4\", \"css-modules\").',\n },\n backend: {\n type: 'string',\n description: 'Backend framework (e.g. \"express@5\", \"fastify\").',\n },\n packageManager: {\n type: 'string',\n description: 'Package manager (e.g. \"pnpm\", \"npm\", \"yarn\").',\n },\n linter: {\n type: 'string',\n description: 'Linter (e.g. \"eslint@9\", \"biome\").',\n },\n testRunner: {\n type: 'string',\n description: 'Test runner (e.g. \"vitest\", \"jest\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured technology stack.',\n },\n structure: {\n type: 'object',\n properties: {\n srcDir: {\n type: 'string',\n description: 'Source directory (e.g. \"src\"), or omit for flat structure.',\n },\n pages: {\n type: 'string',\n description: 'Pages or routes directory (e.g. \"src/app\").',\n },\n components: {\n type: 'string',\n description: 'Components directory (e.g. \"src/components\").',\n },\n hooks: {\n type: 'string',\n description: 'Hooks directory (e.g. \"src/hooks\").',\n },\n utils: {\n type: 'string',\n description: 'Utilities directory (e.g. \"src/utils\", \"src/lib\").',\n },\n types: {\n type: 'string',\n description: 'Type definitions directory (e.g. \"src/types\").',\n },\n tests: {\n type: 'string',\n description: 'Tests directory (e.g. \"tests\", \"__tests__\").',\n },\n testPattern: {\n type: 'string',\n description: 'Test file naming pattern (e.g. \"*.test.ts\", \"*.spec.ts\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured directory structure.',\n },\n conventions: {\n type: 'object',\n properties: {\n fileNaming: { $ref: '#/definitions/conventionValue' },\n componentNaming: { $ref: '#/definitions/conventionValue' },\n hookNaming: { $ref: '#/definitions/conventionValue' },\n importAlias: { $ref: '#/definitions/conventionValue' },\n },\n additionalProperties: false,\n description: 'Detected or configured coding conventions.',\n },\n rules: {\n type: 'object',\n required: [\n 'maxFileLines',\n 'maxFunctionLines',\n 'requireTests',\n 'enforceNaming',\n 'enforceBoundaries',\n ],\n properties: {\n maxFileLines: {\n type: 'number',\n default: 300,\n description: 'Maximum number of lines allowed per file.',\n },\n maxFunctionLines: {\n type: 'number',\n default: 50,\n description: 'Maximum number of lines allowed per function.',\n },\n requireTests: {\n type: 'boolean',\n default: true,\n description: 'Whether to require test files for source modules.',\n },\n enforceNaming: {\n type: 'boolean',\n default: true,\n description: 'Whether to enforce detected file naming conventions.',\n },\n enforceBoundaries: {\n type: 'boolean',\n default: false,\n description: 'Whether to enforce module boundary rules.',\n },\n },\n additionalProperties: false,\n description: 'Rule thresholds and toggles for enforcement.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Glob patterns for files and directories to ignore.',\n },\n boundaries: {\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to', 'allow'],\n properties: {\n from: {\n type: 'string',\n description: 'Source package or directory pattern.',\n },\n to: {\n type: 'string',\n description: 'Target package or directory pattern.',\n },\n allow: {\n type: 'boolean',\n description: 'Whether this import direction is allowed or disallowed.',\n },\n reason: {\n type: 'string',\n description: 'Human-readable explanation of why this boundary exists.',\n },\n },\n additionalProperties: false,\n },\n description: 'Module boundary rules for import enforcement.',\n },\n workspace: {\n type: 'object',\n required: ['packages', 'isMonorepo'],\n properties: {\n packages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Relative paths to workspace packages.',\n },\n isMonorepo: {\n type: 'boolean',\n description: 'Whether this project is a monorepo with multiple packages.',\n },\n },\n additionalProperties: false,\n description: 'Workspace configuration for monorepo projects.',\n },\n packages: {\n type: 'array',\n items: {\n type: 'object',\n required: ['name', 'path'],\n properties: {\n name: { type: 'string', description: 'Package name from package.json.' },\n path: { type: 'string', description: 'Relative path to the package.' },\n stack: {\n type: 'object',\n properties: {\n framework: { type: 'string' },\n language: { type: 'string' },\n styling: { type: 'string' },\n backend: { type: 'string' },\n packageManager: { type: 'string' },\n linter: { type: 'string' },\n testRunner: { type: 'string' },\n },\n additionalProperties: false,\n },\n conventions: { $ref: '#/properties/conventions' },\n rules: {\n type: 'object',\n properties: {\n maxFileLines: { type: 'number' },\n maxFunctionLines: { type: 'number' },\n requireTests: { type: 'boolean' },\n enforceNaming: { type: 'boolean' },\n enforceBoundaries: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ignore: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n description: 'Per-package overrides for monorepo projects.',\n },\n },\n additionalProperties: false,\n definitions: {\n conventionValue: {\n description:\n 'A convention value — either a plain string (user-confirmed) or an object with scanner metadata.',\n oneOf: [\n { type: 'string' },\n {\n type: 'object',\n required: ['value', '_confidence', '_consistency'],\n properties: {\n value: {\n type: 'string',\n description: 'The convention value.',\n },\n _confidence: {\n type: 'string',\n enum: ['high', 'medium', 'low'],\n description: 'Scanner confidence level.',\n },\n _consistency: {\n type: 'number',\n minimum: 0,\n maximum: 100,\n description: 'Scanner consistency percentage.',\n },\n _detected: {\n type: 'boolean',\n description: 'Set by mergeConfig when a convention is newly detected during sync.',\n },\n },\n additionalProperties: false,\n },\n ],\n },\n },\n} as const;\n","export const VERSION = '0.1.0';\n\nexport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nexport { generateConfig } from './generate-config.js';\nexport { loadConfig, loadConfigSafe } from './load-config.js';\nexport { mergeConfig } from './merge-config.js';\nexport { configSchema } from './schema.js';\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/defaults.ts","../src/generate-config.ts","../src/generate-overrides.ts","../src/load-config.ts","../src/merge-config.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import type { ConfigRules } from '@viberails/types';\n\n/**\n * Default rule thresholds and toggles for a new viberails config.\n * These values are intentionally conservative to build trust on first run.\n */\nexport const DEFAULT_RULES: ConfigRules = {\n maxFileLines: 300,\n maxFunctionLines: 50,\n requireTests: true,\n enforceNaming: true,\n enforceBoundaries: false,\n};\n\n/**\n * Default glob patterns for files and directories to ignore.\n */\nexport const DEFAULT_IGNORE: string[] = ['**/*.d.ts', 'dist/**', 'node_modules/**'];\n","import * as path from 'node:path';\nimport type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n DetectedConvention,\n DirectoryRole,\n ScanResult,\n StackItem,\n ViberailsConfig,\n} from '@viberails/types';\nimport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nimport { generatePackageOverrides } from './generate-overrides.js';\n\n/**\n * Format a StackItem as a config string: `\"name@version\"` or `\"name\"`.\n */\nexport function formatStackItem(item: StackItem): string {\n return item.version ? `${item.name}@${item.version}` : item.name;\n}\n\n/**\n * Map DetectedStack → ConfigStack by formatting each StackItem.\n */\nfunction mapStack(scanResult: ScanResult): ConfigStack {\n const { stack } = scanResult;\n const config: ConfigStack = {\n language: formatStackItem(stack.language),\n packageManager: formatStackItem(stack.packageManager),\n };\n\n if (stack.framework) config.framework = formatStackItem(stack.framework);\n if (stack.styling) config.styling = formatStackItem(stack.styling);\n if (stack.backend) config.backend = formatStackItem(stack.backend);\n if (stack.linter) config.linter = formatStackItem(stack.linter);\n if (stack.formatter) config.formatter = formatStackItem(stack.formatter);\n if (stack.testRunner) config.testRunner = formatStackItem(stack.testRunner);\n\n return config;\n}\n\n/** Directory roles that map to ConfigStructure fields. */\nconst ROLE_TO_FIELD: Partial<Record<DirectoryRole, keyof ConfigStructure>> = {\n pages: 'pages',\n components: 'components',\n hooks: 'hooks',\n utils: 'utils',\n types: 'types',\n tests: 'tests',\n};\n\n/**\n * Map DetectedStructure → ConfigStructure by finding the first directory\n * for each known role.\n */\nfunction mapStructure(scanResult: ScanResult): ConfigStructure {\n const { structure } = scanResult;\n const config: ConfigStructure = {};\n\n if (structure.srcDir) {\n config.srcDir = structure.srcDir;\n }\n\n for (const dir of structure.directories) {\n const field = ROLE_TO_FIELD[dir.role];\n if (field && config[field] === undefined) {\n (config as Record<string, string>)[field] = dir.path;\n }\n }\n\n if (structure.testPattern) {\n config.testPattern = structure.testPattern.value;\n }\n\n return config;\n}\n\n/**\n * Convert a DetectedConvention to a ConventionValue with metadata.\n * Returns undefined for low-confidence conventions (they are omitted).\n */\nexport function mapConvention(convention: DetectedConvention): ConventionValue | undefined {\n if (convention.confidence === 'low') {\n return undefined;\n }\n\n return {\n value: convention.value,\n _confidence: convention.confidence,\n _consistency: convention.consistency,\n };\n}\n\n/** Convention keys from ScanResult that map to ConfigConventions fields. */\nexport const CONVENTION_KEYS: (keyof ConfigConventions)[] = [\n 'fileNaming',\n 'componentNaming',\n 'hookNaming',\n 'importAlias',\n];\n\n/**\n * Map scanner conventions → ConfigConventions, omitting low-confidence entries.\n */\nfunction mapConventions(scanResult: ScanResult): ConfigConventions {\n const config: ConfigConventions = {};\n\n for (const key of CONVENTION_KEYS) {\n const detected = scanResult.conventions[key];\n if (detected) {\n const value = mapConvention(detected);\n if (value !== undefined) {\n config[key] = value;\n }\n }\n }\n\n return config;\n}\n\n/**\n * Generate a ViberailsConfig from scan results.\n *\n * Maps the scanner's DetectedStack, DetectedStructure, and conventions\n * into the config format with smart defaults. Low-confidence conventions\n * are omitted. The project name is derived from the root directory basename.\n *\n * @param scanResult - The output of scanning a project\n * @returns A complete ViberailsConfig ready to be written as JSON\n */\nexport function generateConfig(scanResult: ScanResult): ViberailsConfig {\n const config: ViberailsConfig = {\n $schema: 'https://viberails.sh/schema/v1.json',\n version: 1,\n name: path.basename(scanResult.root),\n enforcement: 'warn',\n stack: mapStack(scanResult),\n structure: mapStructure(scanResult),\n conventions: mapConventions(scanResult),\n rules: { ...DEFAULT_RULES },\n ignore: [...DEFAULT_IGNORE],\n };\n\n if (scanResult.workspace) {\n config.workspace = {\n packages: scanResult.workspace.packages.map((p) => p.relativePath),\n isMonorepo: true,\n };\n config.boundaries = [];\n }\n\n const packageOverrides = generatePackageOverrides(scanResult, config);\n if (packageOverrides) {\n config.packages = packageOverrides;\n }\n\n return config;\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n DetectedConvention,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, formatStackItem, mapConvention } from './generate-config.js';\n\n/**\n * Compare a package's conventions against the global config conventions.\n * Returns only the differing conventions, or undefined if all match.\n */\nexport function conventionsDiffer(\n pkgConventions: Record<string, DetectedConvention>,\n globalConventions: ConfigConventions,\n): Partial<ConfigConventions> | undefined {\n const overrides: Partial<ConfigConventions> = {};\n let hasDiff = false;\n\n for (const key of CONVENTION_KEYS) {\n const detected = pkgConventions[key];\n if (!detected) continue;\n\n const mapped = mapConvention(detected);\n if (mapped === undefined) continue;\n\n const globalValue = globalConventions[key];\n const globalStr = typeof globalValue === 'string' ? globalValue : globalValue?.value;\n if (detected.value !== globalStr) {\n overrides[key] = mapped;\n hasDiff = true;\n }\n }\n\n return hasDiff ? overrides : undefined;\n}\n\n/**\n * Generate per-package config overrides for packages whose stack or\n * conventions differ from the aggregate global config.\n */\nexport function generatePackageOverrides(\n scanResult: ScanResult,\n globalConfig: ViberailsConfig,\n): PackageConfigOverrides[] | undefined {\n if (!scanResult.packages || scanResult.packages.length <= 1) return undefined;\n\n const overrides: PackageConfigOverrides[] = [];\n\n for (const pkg of scanResult.packages) {\n const override: PackageConfigOverrides = {\n name: pkg.name,\n path: pkg.relativePath,\n };\n let hasDiff = false;\n\n // Compare stack fields — only include overrides when the package has a\n // value that differs from the global, not when the package simply lacks the field\n const stackOverride: Partial<ConfigStack> = {};\n let hasStackDiff = false;\n\n const optionalStackFields = [\n 'framework',\n 'styling',\n 'backend',\n 'linter',\n 'formatter',\n 'testRunner',\n ] as const;\n for (const field of optionalStackFields) {\n const pkgItem = pkg.stack[field];\n if (!pkgItem) continue;\n const pkgValue = formatStackItem(pkgItem);\n if (pkgValue !== globalConfig.stack[field]) {\n stackOverride[field] = pkgValue;\n hasStackDiff = true;\n }\n }\n\n if (hasStackDiff) {\n override.stack = stackOverride;\n hasDiff = true;\n }\n\n // Compare conventions\n const conventionOverrides = conventionsDiffer(pkg.conventions, globalConfig.conventions);\n if (conventionOverrides) {\n override.conventions = conventionOverrides;\n hasDiff = true;\n }\n\n if (hasDiff) {\n overrides.push(override);\n }\n }\n\n return overrides.length > 0 ? overrides : undefined;\n}\n","import * as fs from 'node:fs/promises';\nimport type { ViberailsConfig } from '@viberails/types';\n\n/**\n * Validate that a parsed object has the required ViberailsConfig fields\n * and that their types are correct.\n * Throws a descriptive error if validation fails.\n */\nfunction validateConfig(parsed: Record<string, unknown>, configPath: string): void {\n const errors: string[] = [];\n\n // Required top-level fields\n const required = ['version', 'name', 'stack', 'rules'] as const;\n const missing = required.filter((field) => parsed[field] === undefined);\n if (missing.length > 0) {\n throw new Error(\n `Invalid viberails config at ${configPath}: missing required field(s): ${missing.join(', ')}`,\n );\n }\n\n // Type checks\n if (typeof parsed.version !== 'number') errors.push('\"version\" must be a number');\n if (typeof parsed.name !== 'string') errors.push('\"name\" must be a string');\n if (\n parsed.enforcement !== undefined &&\n parsed.enforcement !== 'warn' &&\n parsed.enforcement !== 'enforce'\n ) {\n errors.push('\"enforcement\" must be \"warn\" or \"enforce\"');\n }\n\n // Stack validation\n if (typeof parsed.stack !== 'object' || parsed.stack === null) {\n errors.push('\"stack\" must be an object');\n } else {\n const stack = parsed.stack as Record<string, unknown>;\n if (typeof stack.language !== 'string') errors.push('\"stack.language\" must be a string');\n if (typeof stack.packageManager !== 'string')\n errors.push('\"stack.packageManager\" must be a string');\n }\n\n // Rules validation\n if (typeof parsed.rules !== 'object' || parsed.rules === null) {\n errors.push('\"rules\" must be an object');\n } else {\n const rules = parsed.rules as Record<string, unknown>;\n if (typeof rules.maxFileLines !== 'number')\n errors.push('\"rules.maxFileLines\" must be a number');\n if (typeof rules.maxFunctionLines !== 'number')\n errors.push('\"rules.maxFunctionLines\" must be a number');\n if (typeof rules.requireTests !== 'boolean')\n errors.push('\"rules.requireTests\" must be a boolean');\n if (typeof rules.enforceNaming !== 'boolean')\n errors.push('\"rules.enforceNaming\" must be a boolean');\n if (typeof rules.enforceBoundaries !== 'boolean')\n errors.push('\"rules.enforceBoundaries\" must be a boolean');\n }\n\n // Ignore validation\n if (parsed.ignore !== undefined && !Array.isArray(parsed.ignore)) {\n errors.push('\"ignore\" must be an array');\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid viberails config at ${configPath}: ${errors.join('; ')}`);\n }\n}\n\n/**\n * Load and parse a viberails config file.\n *\n * Reads the JSON file at the given path, validates that it contains\n * the required fields (version, name, stack, rules), and returns\n * the parsed config.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig\n * @throws If the file doesn't exist, contains invalid JSON, or is missing required fields\n */\nexport async function loadConfig(configPath: string): Promise<ViberailsConfig> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Config file not found: ${configPath}. Run \"npx viberails\" to generate one.`);\n }\n throw new Error(`Failed to read config file at ${configPath}: ${(err as Error).message}`);\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid JSON in config file at ${configPath}. Check for syntax errors.`);\n }\n\n validateConfig(parsed, configPath);\n\n // Safe to cast: validateConfig has verified all required fields and types\n return parsed as unknown as ViberailsConfig;\n}\n\n/**\n * Safely load a viberails config file, returning null on any error.\n *\n * Used by the CLI for \"does config already exist?\" checks where\n * failure is an expected case, not an error.\n *\n * @param configPath - Absolute or relative path to viberails.config.json\n * @returns The parsed ViberailsConfig, or null if loading fails\n */\nexport async function loadConfigSafe(configPath: string): Promise<ViberailsConfig | null> {\n try {\n return await loadConfig(configPath);\n } catch {\n return null;\n }\n}\n","import type {\n ConfigConventions,\n ConfigStack,\n ConfigStructure,\n ConventionValue,\n PackageConfigOverrides,\n ScanResult,\n ViberailsConfig,\n} from '@viberails/types';\nimport { CONVENTION_KEYS, generateConfig } from './generate-config.js';\n\n/**\n * Merge stack: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStack(existing: ConfigStack, fresh: ConfigStack): ConfigStack {\n return {\n language: existing.language,\n packageManager: existing.packageManager,\n framework: existing.framework ?? fresh.framework,\n styling: existing.styling ?? fresh.styling,\n backend: existing.backend ?? fresh.backend,\n linter: existing.linter ?? fresh.linter,\n formatter: existing.formatter ?? fresh.formatter,\n testRunner: existing.testRunner ?? fresh.testRunner,\n };\n}\n\n/**\n * Merge structure: keep existing values, fill in undefined fields from fresh scan.\n */\nfunction mergeStructure(existing: ConfigStructure, fresh: ConfigStructure): ConfigStructure {\n return {\n srcDir: existing.srcDir ?? fresh.srcDir,\n pages: existing.pages ?? fresh.pages,\n components: existing.components ?? fresh.components,\n hooks: existing.hooks ?? fresh.hooks,\n utils: existing.utils ?? fresh.utils,\n types: existing.types ?? fresh.types,\n tests: existing.tests ?? fresh.tests,\n testPattern: existing.testPattern ?? fresh.testPattern,\n };\n}\n\n/**\n * Check if a convention key exists in the existing config\n * (either as a string or as an object with a value).\n */\nfunction hasConvention(conventions: ConfigConventions, key: keyof ConfigConventions): boolean {\n return conventions[key] !== undefined;\n}\n\n/**\n * Mark a ConventionValue as newly detected by adding `_detected: true`.\n * Only applies to object-form values (not plain strings).\n */\nfunction markAsDetected(value: ConventionValue): ConventionValue {\n if (typeof value === 'string') {\n return { value, _confidence: 'high', _consistency: 100, _detected: true };\n }\n return { ...value, _detected: true };\n}\n\n/**\n * Merge conventions: keep all existing values, add new detections with `_detected: true`.\n */\nfunction mergeConventions(\n existing: ConfigConventions,\n fresh: ConfigConventions,\n): ConfigConventions {\n const merged: ConfigConventions = { ...existing };\n\n for (const key of CONVENTION_KEYS) {\n if (!hasConvention(existing, key) && fresh[key] !== undefined) {\n merged[key] = markAsDetected(fresh[key]!);\n }\n }\n\n return merged;\n}\n\n/**\n * Merge a new scan result into an existing config for `viberails sync`.\n *\n * Preserves all developer-confirmed values from the existing config.\n * Adds newly detected conventions with a `_detected: true` annotation\n * so the developer can review them. Never removes rules or values\n * the developer has set.\n *\n * @param existing - The current ViberailsConfig (from viberails.config.json)\n * @param scanResult - Fresh scan results from re-scanning the project\n * @returns A merged config that preserves existing values and adds new detections\n */\nexport function mergeConfig(existing: ViberailsConfig, scanResult: ScanResult): ViberailsConfig {\n const fresh = generateConfig(scanResult);\n\n const merged: ViberailsConfig = {\n $schema: existing.$schema ?? fresh.$schema,\n version: existing.version,\n name: existing.name,\n enforcement: existing.enforcement,\n stack: mergeStack(existing.stack, fresh.stack),\n structure: mergeStructure(existing.structure, fresh.structure),\n conventions: mergeConventions(existing.conventions, fresh.conventions),\n rules: { ...existing.rules },\n ignore: [...existing.ignore],\n };\n\n // Workspace: always take fresh scan (structure can change)\n if (fresh.workspace) {\n merged.workspace = fresh.workspace;\n }\n\n // Boundaries: preserve existing rules (user may have adjusted)\n if (existing.boundaries) {\n merged.boundaries = [...existing.boundaries];\n } else if (fresh.boundaries) {\n merged.boundaries = [...fresh.boundaries];\n }\n\n // Packages: preserve existing overrides, add new ones\n if (existing.packages || fresh.packages) {\n merged.packages = mergePackageOverrides(existing.packages, fresh.packages);\n }\n\n return merged;\n}\n\n/**\n * Merge per-package overrides: keep existing user-edited overrides,\n * add new packages from fresh scan.\n */\nfunction mergePackageOverrides(\n existing?: PackageConfigOverrides[],\n fresh?: PackageConfigOverrides[],\n): PackageConfigOverrides[] | undefined {\n if (!fresh || fresh.length === 0) return existing;\n if (!existing || existing.length === 0) return fresh;\n\n const existingByPath = new Map(existing.map((p) => [p.path, p]));\n const merged: PackageConfigOverrides[] = [...existing];\n\n for (const freshPkg of fresh) {\n if (!existingByPath.has(freshPkg.path)) {\n merged.push(freshPkg);\n }\n }\n\n return merged.length > 0 ? merged : undefined;\n}\n","/**\n * JSON Schema (draft-07) definition for viberails.config.json.\n *\n * This schema will eventually be hosted at https://viberails.sh/schema/v1.json.\n * For now it is exported as a TypeScript object that can be serialized to JSON.\n */\nexport const configSchema = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n $id: 'https://viberails.sh/schema/v1.json',\n title: 'viberails configuration',\n description: 'Configuration file for viberails — guardrails for vibe coding.',\n type: 'object',\n required: ['version', 'name', 'stack', 'rules'],\n properties: {\n $schema: {\n type: 'string',\n description: 'JSON Schema URL for editor validation.',\n },\n version: {\n type: 'number',\n const: 1,\n description: 'Config format version. Always 1 for V1.0.',\n },\n name: {\n type: 'string',\n description: 'Project name, typically from package.json.',\n },\n enforcement: {\n type: 'string',\n enum: ['warn', 'enforce'],\n default: 'warn',\n description: 'Whether conventions are warned about or enforced as errors.',\n },\n stack: {\n type: 'object',\n required: ['language', 'packageManager'],\n properties: {\n framework: {\n type: 'string',\n description: 'Primary framework identifier (e.g. \"nextjs@15\", \"remix@2\").',\n },\n language: {\n type: 'string',\n description: 'Primary language (e.g. \"typescript\", \"javascript\").',\n },\n styling: {\n type: 'string',\n description: 'Styling solution (e.g. \"tailwindcss@4\", \"css-modules\").',\n },\n backend: {\n type: 'string',\n description: 'Backend framework (e.g. \"express@5\", \"fastify\").',\n },\n packageManager: {\n type: 'string',\n description: 'Package manager (e.g. \"pnpm\", \"npm\", \"yarn\").',\n },\n linter: {\n type: 'string',\n description: 'Linter (e.g. \"eslint@9\", \"biome\").',\n },\n formatter: {\n type: 'string',\n description: 'Formatter (e.g. \"prettier\", \"biome\").',\n },\n testRunner: {\n type: 'string',\n description: 'Test runner (e.g. \"vitest\", \"jest\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured technology stack.',\n },\n structure: {\n type: 'object',\n properties: {\n srcDir: {\n type: 'string',\n description: 'Source directory (e.g. \"src\"), or omit for flat structure.',\n },\n pages: {\n type: 'string',\n description: 'Pages or routes directory (e.g. \"src/app\").',\n },\n components: {\n type: 'string',\n description: 'Components directory (e.g. \"src/components\").',\n },\n hooks: {\n type: 'string',\n description: 'Hooks directory (e.g. \"src/hooks\").',\n },\n utils: {\n type: 'string',\n description: 'Utilities directory (e.g. \"src/utils\", \"src/lib\").',\n },\n types: {\n type: 'string',\n description: 'Type definitions directory (e.g. \"src/types\").',\n },\n tests: {\n type: 'string',\n description: 'Tests directory (e.g. \"tests\", \"__tests__\").',\n },\n testPattern: {\n type: 'string',\n description: 'Test file naming pattern (e.g. \"*.test.ts\", \"*.spec.ts\").',\n },\n },\n additionalProperties: false,\n description: 'Detected or configured directory structure.',\n },\n conventions: {\n type: 'object',\n properties: {\n fileNaming: { $ref: '#/definitions/conventionValue' },\n componentNaming: { $ref: '#/definitions/conventionValue' },\n hookNaming: { $ref: '#/definitions/conventionValue' },\n importAlias: { $ref: '#/definitions/conventionValue' },\n },\n additionalProperties: false,\n description: 'Detected or configured coding conventions.',\n },\n rules: {\n type: 'object',\n required: [\n 'maxFileLines',\n 'maxFunctionLines',\n 'requireTests',\n 'enforceNaming',\n 'enforceBoundaries',\n ],\n properties: {\n maxFileLines: {\n type: 'number',\n default: 300,\n description: 'Maximum number of lines allowed per file.',\n },\n maxFunctionLines: {\n type: 'number',\n default: 50,\n description: 'Maximum number of lines allowed per function.',\n },\n requireTests: {\n type: 'boolean',\n default: true,\n description: 'Whether to require test files for source modules.',\n },\n enforceNaming: {\n type: 'boolean',\n default: true,\n description: 'Whether to enforce detected file naming conventions.',\n },\n enforceBoundaries: {\n type: 'boolean',\n default: false,\n description: 'Whether to enforce module boundary rules.',\n },\n },\n additionalProperties: false,\n description: 'Rule thresholds and toggles for enforcement.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Glob patterns for files and directories to ignore.',\n },\n boundaries: {\n type: 'array',\n items: {\n type: 'object',\n required: ['from', 'to', 'allow'],\n properties: {\n from: {\n type: 'string',\n description: 'Source package or directory pattern.',\n },\n to: {\n type: 'string',\n description: 'Target package or directory pattern.',\n },\n allow: {\n type: 'boolean',\n description: 'Whether this import direction is allowed or disallowed.',\n },\n reason: {\n type: 'string',\n description: 'Human-readable explanation of why this boundary exists.',\n },\n },\n additionalProperties: false,\n },\n description: 'Module boundary rules for import enforcement.',\n },\n workspace: {\n type: 'object',\n required: ['packages', 'isMonorepo'],\n properties: {\n packages: {\n type: 'array',\n items: { type: 'string' },\n description: 'Relative paths to workspace packages.',\n },\n isMonorepo: {\n type: 'boolean',\n description: 'Whether this project is a monorepo with multiple packages.',\n },\n },\n additionalProperties: false,\n description: 'Workspace configuration for monorepo projects.',\n },\n packages: {\n type: 'array',\n items: {\n type: 'object',\n required: ['name', 'path'],\n properties: {\n name: { type: 'string', description: 'Package name from package.json.' },\n path: { type: 'string', description: 'Relative path to the package.' },\n stack: {\n type: 'object',\n properties: {\n framework: { type: 'string' },\n language: { type: 'string' },\n styling: { type: 'string' },\n backend: { type: 'string' },\n packageManager: { type: 'string' },\n linter: { type: 'string' },\n formatter: { type: 'string' },\n testRunner: { type: 'string' },\n },\n additionalProperties: false,\n },\n conventions: { $ref: '#/properties/conventions' },\n rules: {\n type: 'object',\n properties: {\n maxFileLines: { type: 'number' },\n maxFunctionLines: { type: 'number' },\n requireTests: { type: 'boolean' },\n enforceNaming: { type: 'boolean' },\n enforceBoundaries: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ignore: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n description: 'Per-package overrides for monorepo projects.',\n },\n },\n additionalProperties: false,\n definitions: {\n conventionValue: {\n description:\n 'A convention value — either a plain string (user-confirmed) or an object with scanner metadata.',\n oneOf: [\n { type: 'string' },\n {\n type: 'object',\n required: ['value', '_confidence', '_consistency'],\n properties: {\n value: {\n type: 'string',\n description: 'The convention value.',\n },\n _confidence: {\n type: 'string',\n enum: ['high', 'medium', 'low'],\n description: 'Scanner confidence level.',\n },\n _consistency: {\n type: 'number',\n minimum: 0,\n maximum: 100,\n description: 'Scanner consistency percentage.',\n },\n _detected: {\n type: 'boolean',\n description: 'Set by mergeConfig when a convention is newly detected during sync.',\n },\n },\n additionalProperties: false,\n },\n ],\n },\n },\n} as const;\n","export const VERSION = '0.1.0';\n\nexport { DEFAULT_IGNORE, DEFAULT_RULES } from './defaults.js';\nexport { generateConfig } from './generate-config.js';\nexport { loadConfig, loadConfigSafe } from './load-config.js';\nexport { mergeConfig } from './merge-config.js';\nexport { configSchema } from './schema.js';\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viberails/config",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Config generation and loading for viberails",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -25,11 +25,11 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@viberails/types": "0.2.0"
28
+ "ajv": "^8.18.0",
29
+ "@viberails/types": "0.2.1"
29
30
  },
30
31
  "devDependencies": {
31
- "@types/node": "^25.3.5",
32
- "ajv": "^8.18.0"
32
+ "@types/node": "^25.3.5"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsup",