@webpieces/dev-config 0.2.80 ā 0.2.82
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/architecture/executors/validate-code/executor.d.ts +7 -0
- package/architecture/executors/validate-code/executor.js +13 -2
- package/architecture/executors/validate-code/executor.js.map +1 -1
- package/architecture/executors/validate-code/executor.ts +23 -2
- package/architecture/executors/validate-code/schema.json +23 -2
- package/architecture/executors/validate-dtos/executor.d.ts +4 -2
- package/architecture/executors/validate-dtos/executor.js +126 -10
- package/architecture/executors/validate-dtos/executor.js.map +1 -1
- package/architecture/executors/validate-dtos/executor.ts +146 -11
- package/architecture/executors/validate-dtos/schema.json +2 -2
- package/architecture/executors/validate-prisma-converters/executor.d.ts +56 -0
- package/architecture/executors/validate-prisma-converters/executor.js +489 -0
- package/architecture/executors/validate-prisma-converters/executor.js.map +1 -0
- package/architecture/executors/validate-prisma-converters/executor.ts +615 -0
- package/architecture/executors/validate-prisma-converters/schema.json +24 -0
- package/executors.json +5 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-dtos/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate DTOs Executor\n *\n * Validates that every non-deprecated field in a XxxDto class/interface exists\n * in the corresponding XxxDbo Prisma model. This catches AI agents inventing\n * field names that don't match the database schema.\n *\n * ============================================================================\n * MODES\n * ============================================================================\n * - OFF: Skip validation entirely\n * - MODIFIED_FILES: Validate Dto files that were modified in the diff\n *\n * ============================================================================\n * SKIP CONDITIONS\n * ============================================================================\n * - If schema.prisma itself is modified, validation is skipped (schema in flux)\n * - Dto classes ending with \"JoinDto\" are skipped (they compose other Dtos)\n * - Fields marked @deprecated in a comment are exempt\n *\n * ============================================================================\n * MATCHING\n * ============================================================================\n * - UserDto matches UserDbo by case-insensitive prefix (\"user\")\n * - Dto fields must be a subset of Dbo fields\n * - Extra Dbo fields are allowed (e.g., password)\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nexport type ValidateDtosMode = 'OFF' | 'MODIFIED_FILES';\n\nexport interface ValidateDtosOptions {\n mode?: ValidateDtosMode;\n prismaSchemaPath?: string;\n dtoSourcePaths?: string[];\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface DtoFieldInfo {\n name: string;\n line: number;\n deprecated: boolean;\n}\n\ninterface DtoInfo {\n name: string;\n file: string;\n fields: DtoFieldInfo[];\n}\n\ninterface DtoViolation {\n file: string;\n line: number;\n dtoName: string;\n fieldName: string;\n dboName: string;\n availableFields: string[];\n}\n\ninterface DboEntry {\n name: string;\n fields: Set<string>;\n}\n\n/**\n * Auto-detect the base branch by finding the merge-base with origin/main.\n */\nfunction detectBase(workspaceRoot: string): string | null {\n try {\n const mergeBase = execSync('git merge-base HEAD origin/main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n try {\n const mergeBase = execSync('git merge-base HEAD main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n // Ignore\n }\n }\n return null;\n}\n\n/**\n * Get changed files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f.length > 0);\n\n if (!head) {\n try {\n const untrackedOutput = execSync('git ls-files --others --exclude-standard', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput\n .trim()\n .split('\\n')\n .filter((f) => f.length > 0);\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Parse schema.prisma to build a map of Dbo model name -> set of field names.\n * Only models whose name ends with \"Dbo\" are included.\n */\nfunction parsePrismaSchema(schemaPath: string): Map<string, Set<string>> {\n const models = new Map<string, Set<string>>();\n\n if (!fs.existsSync(schemaPath)) {\n return models;\n }\n\n const content = fs.readFileSync(schemaPath, 'utf-8');\n const lines = content.split('\\n');\n\n let currentModel: string | null = null;\n let currentFields: Set<string> | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Match model declaration: model XxxDbo {\n const modelMatch = trimmed.match(/^model\\s+(\\w+Dbo)\\s*\\{/);\n if (modelMatch) {\n currentModel = modelMatch[1];\n currentFields = new Set<string>();\n continue;\n }\n\n // End of model block\n if (currentModel && trimmed === '}') {\n models.set(currentModel, currentFields!);\n currentModel = null;\n currentFields = null;\n continue;\n }\n\n // Inside a model block - extract field names\n if (currentModel && currentFields) {\n // Skip empty lines, comments, and model-level attributes (@@)\n if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('@@')) {\n continue;\n }\n\n // Field name is the first word on the line\n const fieldMatch = trimmed.match(/^(\\w+)\\s/);\n if (fieldMatch) {\n currentFields.add(fieldMatch[1]);\n }\n }\n }\n\n return models;\n}\n\n/**\n * Check if a field has @deprecated in a comment above it (within 3 lines).\n */\nfunction isFieldDeprecated(fileLines: string[], fieldLine: number): boolean {\n const start = Math.max(0, fieldLine - 4);\n for (let i = start; i <= fieldLine - 1; i++) {\n const line = fileLines[i]?.trim() ?? '';\n if (line.includes('@deprecated')) return true;\n }\n return false;\n}\n\n/**\n * Parse a TypeScript file to find Dto class/interface declarations and their fields.\n * Skips classes ending with \"JoinDto\" since they compose other Dtos.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal for both class and interface Dto detection with field extraction\nfunction findDtosInFile(filePath: string, workspaceRoot: string): DtoInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const dtos: DtoInfo[] = [];\n\n function visit(node: ts.Node): void {\n const isClass = ts.isClassDeclaration(node);\n const isInterface = ts.isInterfaceDeclaration(node);\n\n if ((isClass || isInterface) && node.name) {\n const name = node.name.text;\n\n // Must end with Dto but NOT with JoinDto\n if (name.endsWith('Dto') && !name.endsWith('JoinDto')) {\n const fields: DtoFieldInfo[] = [];\n\n for (const member of node.members) {\n if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {\n if (member.name && ts.isIdentifier(member.name)) {\n const fieldName = member.name.text;\n const startPos = member.getStart(sourceFile);\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const deprecated = isFieldDeprecated(fileLines, line);\n\n fields.push({ name: fieldName, line, deprecated });\n }\n }\n }\n\n dtos.push({ name, file: filePath, fields });\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return dtos;\n}\n\n/**\n * Extract the prefix from a Dto/Dbo name by removing the suffix.\n * e.g., \"UserDto\" -> \"user\", \"UserDbo\" -> \"user\"\n */\nfunction extractPrefix(name: string, suffix: string): string {\n return name.slice(0, -suffix.length).toLowerCase();\n}\n\n/**\n * Find violations: Dto fields that don't exist in the corresponding Dbo.\n */\nfunction findViolations(\n dtos: DtoInfo[],\n dboModels: Map<string, Set<string>>\n): DtoViolation[] {\n const violations: DtoViolation[] = [];\n\n // Build a lowercase prefix -> Dbo info map\n const dboByPrefix = new Map<string, DboEntry>();\n for (const [dboName, fields] of dboModels) {\n const prefix = extractPrefix(dboName, 'Dbo');\n dboByPrefix.set(prefix, { name: dboName, fields });\n }\n\n for (const dto of dtos) {\n const prefix = extractPrefix(dto.name, 'Dto');\n const dbo = dboByPrefix.get(prefix);\n\n if (!dbo) {\n // No matching Dbo found - skip (might be a Dto without a DB table)\n continue;\n }\n\n for (const field of dto.fields) {\n if (field.deprecated) continue;\n\n if (!dbo.fields.has(field.name)) {\n violations.push({\n file: dto.file,\n line: field.line,\n dtoName: dto.name,\n fieldName: field.name,\n dboName: dbo.name,\n availableFields: Array.from(dbo.fields).sort(),\n });\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: DtoViolation[]): void {\n console.error('');\n console.error('ā DTO fields don\\'t match Prisma Dbo models!');\n console.error('');\n console.error('š Every non-deprecated field in a Dto must exist in the corresponding Dbo.');\n console.error(' This prevents AI from inventing field names that don\\'t match the database schema.');\n console.error(' Dbo can have extra fields (e.g., password) - Dto cannot.');\n console.error('');\n\n for (const v of violations) {\n console.error(` ā ${v.file}:${v.line}`);\n console.error(` ${v.dtoName}.${v.fieldName} does not exist in ${v.dboName}`);\n console.error(` Available Dbo fields: ${v.availableFields.join(', ')}`);\n }\n console.error('');\n\n console.error(' Dto fields must be a subset of Dbo fields (matching TypeScript field names from schema.prisma).');\n console.error(' Fields marked @deprecated in the Dto are exempt from this check.');\n console.error('');\n console.error(' When needing fields from multiple tables (e.g., a join), use a XxxJoinDto that');\n console.error(' contains YYDto and ZZDto fields from the other tables instead of flattening.');\n console.error('');\n}\n\n/**\n * Filter changed files to only TypeScript Dto source files within configured paths.\n */\nfunction filterDtoFiles(changedFiles: string[], dtoSourcePaths: string[]): string[] {\n return changedFiles.filter((f) => {\n if (!f.endsWith('.ts') && !f.endsWith('.tsx')) return false;\n if (f.includes('.spec.ts') || f.includes('.test.ts')) return false;\n return dtoSourcePaths.some((srcPath) => f.startsWith(srcPath));\n });\n}\n\n/**\n * Collect all Dto definitions from the given files.\n */\nfunction collectDtos(dtoFiles: string[], workspaceRoot: string): DtoInfo[] {\n const allDtos: DtoInfo[] = [];\n for (const file of dtoFiles) {\n const dtos = findDtosInFile(file, workspaceRoot);\n allDtos.push(...dtos);\n }\n return allDtos;\n}\n\n/**\n * Resolve git base ref from env vars or auto-detection.\n */\nfunction resolveBase(workspaceRoot: string): string | undefined {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n return detectBase(workspaceRoot) ?? undefined;\n}\n\n/**\n * Run the core validation after early-exit checks have passed.\n */\nfunction validateDtoFiles(\n workspaceRoot: string,\n prismaSchemaPath: string,\n changedFiles: string[],\n dtoSourcePaths: string[]\n): ExecutorResult {\n if (changedFiles.some((f) => f.endsWith(prismaSchemaPath))) {\n console.log('āļø Skipping validate-dtos (schema.prisma is modified - schema in flux)');\n console.log('');\n return { success: true };\n }\n\n const dtoFiles = filterDtoFiles(changedFiles, dtoSourcePaths);\n\n if (dtoFiles.length === 0) {\n console.log('ā
No Dto files changed');\n return { success: true };\n }\n\n console.log(`š Checking ${dtoFiles.length} changed file(s) for Dto definitions...`);\n\n const fullSchemaPath = path.join(workspaceRoot, prismaSchemaPath);\n const dboModels = parsePrismaSchema(fullSchemaPath);\n\n if (dboModels.size === 0) {\n console.log('āļø No Dbo models found in schema.prisma');\n console.log('');\n return { success: true };\n }\n\n console.log(` Found ${dboModels.size} Dbo model(s) in schema.prisma`);\n\n const allDtos = collectDtos(dtoFiles, workspaceRoot);\n\n if (allDtos.length === 0) {\n console.log('ā
No Dto definitions found in changed files');\n return { success: true };\n }\n\n console.log(` Found ${allDtos.length} Dto definition(s) in changed files`);\n\n const violations = findViolations(allDtos, dboModels);\n\n if (violations.length === 0) {\n console.log('ā
All Dto fields match their Dbo models');\n return { success: true };\n }\n\n reportViolations(violations);\n return { success: false };\n}\n\nexport default async function runExecutor(\n options: ValidateDtosOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const mode: ValidateDtosMode = options.mode ?? 'OFF';\n\n if (mode === 'OFF') {\n console.log('\\nāļø Skipping validate-dtos (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n const prismaSchemaPath = options.prismaSchemaPath;\n const dtoSourcePaths = options.dtoSourcePaths ?? [];\n\n if (!prismaSchemaPath || dtoSourcePaths.length === 0) {\n const reason = !prismaSchemaPath ? 'no prismaSchemaPath configured' : 'no dtoSourcePaths configured';\n console.log(`\\nāļø Skipping validate-dtos (${reason})`);\n console.log('');\n return { success: true };\n }\n\n console.log('\\nš Validating DTOs match Prisma Dbo models\\n');\n console.log(` Mode: ${mode}`);\n console.log(` Schema: ${prismaSchemaPath}`);\n console.log(` Dto paths: ${dtoSourcePaths.join(', ')}`);\n\n const base = resolveBase(workspaceRoot);\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n console.log('\\nāļø Skipping validate-dtos (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n return validateDtoFiles(workspaceRoot, prismaSchemaPath, changedFiles, dtoSourcePaths);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/architecture/executors/validate-dtos/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate DTOs Executor\n *\n * Validates that every non-deprecated field in a XxxDto class/interface exists\n * in the corresponding XxxDbo Prisma model. This catches AI agents inventing\n * field names that don't match the database schema.\n *\n * ============================================================================\n * MODES\n * ============================================================================\n * - OFF: Skip validation entirely\n * - MODIFIED_CLASS: Only validate Dto classes that have changed lines in the diff\n * - MODIFIED_FILES: Validate ALL Dto classes in files that were modified\n *\n * ============================================================================\n * SKIP CONDITIONS\n * ============================================================================\n * - If schema.prisma itself is modified, validation is skipped (schema in flux)\n * - Dto classes ending with \"JoinDto\" are skipped (they compose other Dtos)\n * - Fields marked @deprecated in a comment are exempt\n *\n * ============================================================================\n * MATCHING\n * ============================================================================\n * - UserDto matches UserDbo by case-insensitive prefix (\"user\")\n * - Dbo field names are converted from snake_case to camelCase for comparison\n * - Dto fields must be a subset of Dbo fields\n * - Extra Dbo fields are allowed (e.g., password)\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\n\nexport type ValidateDtosMode = 'OFF' | 'MODIFIED_CLASS' | 'MODIFIED_FILES';\n\nexport interface ValidateDtosOptions {\n mode?: ValidateDtosMode;\n prismaSchemaPath?: string;\n dtoSourcePaths?: string[];\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\ninterface DtoFieldInfo {\n name: string;\n line: number;\n deprecated: boolean;\n}\n\ninterface DtoInfo {\n name: string;\n file: string;\n startLine: number;\n endLine: number;\n fields: DtoFieldInfo[];\n}\n\ninterface DtoViolation {\n file: string;\n line: number;\n dtoName: string;\n fieldName: string;\n dboName: string;\n availableFields: string[];\n}\n\ninterface DboEntry {\n name: string;\n fields: Set<string>;\n}\n\n/**\n * Auto-detect the base branch by finding the merge-base with origin/main.\n */\nfunction detectBase(workspaceRoot: string): string | null {\n try {\n const mergeBase = execSync('git merge-base HEAD origin/main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n try {\n const mergeBase = execSync('git merge-base HEAD main', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n if (mergeBase) {\n return mergeBase;\n }\n } catch {\n // Ignore\n }\n }\n return null;\n}\n\n/**\n * Get changed files between base and head (or working tree if head not specified).\n */\n// webpieces-disable max-lines-new-methods -- Git command handling with untracked files requires multiple code paths\nfunction getChangedFiles(workspaceRoot: string, base: string, head?: string): string[] {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const output = execSync(`git diff --name-only ${diffTarget}`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const changedFiles = output\n .trim()\n .split('\\n')\n .filter((f) => f.length > 0);\n\n if (!head) {\n try {\n const untrackedOutput = execSync('git ls-files --others --exclude-standard', {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n const untrackedFiles = untrackedOutput\n .trim()\n .split('\\n')\n .filter((f) => f.length > 0);\n const allFiles = new Set([...changedFiles, ...untrackedFiles]);\n return Array.from(allFiles);\n } catch {\n return changedFiles;\n }\n }\n\n return changedFiles;\n } catch {\n return [];\n }\n}\n\n/**\n * Get the diff content for a specific file.\n */\nfunction getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {\n try {\n const diffTarget = head ? `${base} ${head}` : base;\n const diff = execSync(`git diff ${diffTarget} -- \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n });\n\n if (!diff && !head) {\n const fullPath = path.join(workspaceRoot, file);\n if (fs.existsSync(fullPath)) {\n const isUntracked = execSync(`git ls-files --others --exclude-standard \"${file}\"`, {\n cwd: workspaceRoot,\n encoding: 'utf-8',\n }).trim();\n\n if (isUntracked) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n return lines.map((line) => `+${line}`).join('\\n');\n }\n }\n }\n\n return diff;\n } catch {\n return '';\n }\n}\n\n/**\n * Parse diff to extract changed line numbers (additions only - lines starting with +).\n */\nfunction getChangedLineNumbers(diffContent: string): Set<number> {\n const changedLines = new Set<number>();\n const lines = diffContent.split('\\n');\n let currentLine = 0;\n\n for (const line of lines) {\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith('+') && !line.startsWith('+++')) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n // Deletions don't increment line number\n } else {\n currentLine++;\n }\n }\n\n return changedLines;\n}\n\n/**\n * Convert a snake_case string to camelCase.\n * e.g., \"version_number\" -> \"versionNumber\", \"id\" -> \"id\"\n */\nfunction snakeToCamel(s: string): string {\n return s.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());\n}\n\n/**\n * Parse schema.prisma to build a map of Dbo model name -> set of field names (camelCase).\n * Only models whose name ends with \"Dbo\" are included.\n * Field names are converted from snake_case to camelCase since Dto fields use camelCase.\n */\nfunction parsePrismaSchema(schemaPath: string): Map<string, Set<string>> {\n const models = new Map<string, Set<string>>();\n\n if (!fs.existsSync(schemaPath)) {\n return models;\n }\n\n const content = fs.readFileSync(schemaPath, 'utf-8');\n const lines = content.split('\\n');\n\n let currentModel: string | null = null;\n let currentFields: Set<string> | null = null;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Match model declaration: model XxxDbo {\n const modelMatch = trimmed.match(/^model\\s+(\\w+Dbo)\\s*\\{/);\n if (modelMatch) {\n currentModel = modelMatch[1];\n currentFields = new Set<string>();\n continue;\n }\n\n // End of model block\n if (currentModel && trimmed === '}') {\n models.set(currentModel, currentFields!);\n currentModel = null;\n currentFields = null;\n continue;\n }\n\n // Inside a model block - extract field names\n if (currentModel && currentFields) {\n // Skip empty lines, comments, and model-level attributes (@@)\n if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('@@')) {\n continue;\n }\n\n // Field name is the first word on the line, converted to camelCase\n const fieldMatch = trimmed.match(/^(\\w+)\\s/);\n if (fieldMatch) {\n currentFields.add(snakeToCamel(fieldMatch[1]));\n }\n }\n }\n\n return models;\n}\n\n/**\n * Check if a field has @deprecated in a comment above it (within 3 lines).\n */\nfunction isFieldDeprecated(fileLines: string[], fieldLine: number): boolean {\n const start = Math.max(0, fieldLine - 4);\n for (let i = start; i <= fieldLine - 1; i++) {\n const line = fileLines[i]?.trim() ?? '';\n if (line.includes('@deprecated')) return true;\n }\n return false;\n}\n\n/**\n * Parse a TypeScript file to find Dto class/interface declarations and their fields.\n * Skips classes ending with \"JoinDto\" since they compose other Dtos.\n */\n// webpieces-disable max-lines-new-methods -- AST traversal for both class and interface Dto detection with field extraction\nfunction findDtosInFile(filePath: string, workspaceRoot: string): DtoInfo[] {\n const fullPath = path.join(workspaceRoot, filePath);\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n const fileLines = content.split('\\n');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n const dtos: DtoInfo[] = [];\n\n function visit(node: ts.Node): void {\n const isClass = ts.isClassDeclaration(node);\n const isInterface = ts.isInterfaceDeclaration(node);\n\n if ((isClass || isInterface) && node.name) {\n const name = node.name.text;\n\n // Must end with Dto but NOT with JoinDto\n if (name.endsWith('Dto') && !name.endsWith('JoinDto')) {\n const fields: DtoFieldInfo[] = [];\n const nodeStart = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));\n const nodeEnd = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n\n for (const member of node.members) {\n if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {\n if (member.name && ts.isIdentifier(member.name)) {\n const fieldName = member.name.text;\n const startPos = member.getStart(sourceFile);\n const pos = sourceFile.getLineAndCharacterOfPosition(startPos);\n const line = pos.line + 1;\n const deprecated = isFieldDeprecated(fileLines, line);\n\n fields.push({ name: fieldName, line, deprecated });\n }\n }\n }\n\n dtos.push({\n name,\n file: filePath,\n startLine: nodeStart.line + 1,\n endLine: nodeEnd.line + 1,\n fields,\n });\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return dtos;\n}\n\n/**\n * Extract the prefix from a Dto/Dbo name by removing the suffix.\n * e.g., \"UserDto\" -> \"user\", \"UserDbo\" -> \"user\"\n */\nfunction extractPrefix(name: string, suffix: string): string {\n return name.slice(0, -suffix.length).toLowerCase();\n}\n\n/**\n * Find violations: Dto fields that don't exist in the corresponding Dbo.\n */\nfunction findViolations(\n dtos: DtoInfo[],\n dboModels: Map<string, Set<string>>\n): DtoViolation[] {\n const violations: DtoViolation[] = [];\n\n // Build a lowercase prefix -> Dbo info map\n const dboByPrefix = new Map<string, DboEntry>();\n for (const [dboName, fields] of dboModels) {\n const prefix = extractPrefix(dboName, 'Dbo');\n dboByPrefix.set(prefix, { name: dboName, fields });\n }\n\n for (const dto of dtos) {\n const prefix = extractPrefix(dto.name, 'Dto');\n const dbo = dboByPrefix.get(prefix);\n\n if (!dbo) {\n // No matching Dbo found - skip (might be a Dto without a DB table)\n continue;\n }\n\n for (const field of dto.fields) {\n if (field.deprecated) continue;\n\n if (!dbo.fields.has(field.name)) {\n violations.push({\n file: dto.file,\n line: field.line,\n dtoName: dto.name,\n fieldName: field.name,\n dboName: dbo.name,\n availableFields: Array.from(dbo.fields).sort(),\n });\n }\n }\n }\n\n return violations;\n}\n\n/**\n * Report violations to console.\n */\nfunction reportViolations(violations: DtoViolation[]): void {\n console.error('');\n console.error('ā DTO fields don\\'t match Prisma Dbo models!');\n console.error('');\n console.error('š Every non-deprecated field in a Dto must exist in the corresponding Dbo.');\n console.error(' This prevents AI from inventing field names that don\\'t match the database schema.');\n console.error(' Dbo can have extra fields (e.g., password) - Dto cannot.');\n console.error('');\n\n for (const v of violations) {\n console.error(` ā ${v.file}:${v.line}`);\n console.error(` ${v.dtoName}.${v.fieldName} does not exist in ${v.dboName}`);\n console.error(` Available Dbo fields: ${v.availableFields.join(', ')}`);\n }\n console.error('');\n\n console.error(' Dto fields must be a subset of Dbo fields (matching camelCase field names).');\n console.error(' Fields marked @deprecated in the Dto are exempt from this check.');\n console.error('');\n console.error(' When needing fields from multiple tables (e.g., a join), use a XxxJoinDto that');\n console.error(' contains YYDto and ZZDto fields from the other tables instead of flattening.');\n console.error('');\n}\n\n/**\n * Filter changed files to only TypeScript Dto source files within configured paths.\n */\nfunction filterDtoFiles(changedFiles: string[], dtoSourcePaths: string[]): string[] {\n return changedFiles.filter((f) => {\n if (!f.endsWith('.ts') && !f.endsWith('.tsx')) return false;\n if (f.includes('.spec.ts') || f.includes('.test.ts')) return false;\n return dtoSourcePaths.some((srcPath) => f.startsWith(srcPath));\n });\n}\n\n/**\n * Collect all Dto definitions from the given files.\n */\nfunction collectDtos(dtoFiles: string[], workspaceRoot: string): DtoInfo[] {\n const allDtos: DtoInfo[] = [];\n for (const file of dtoFiles) {\n const dtos = findDtosInFile(file, workspaceRoot);\n allDtos.push(...dtos);\n }\n return allDtos;\n}\n\n/**\n * Check if a Dto class overlaps with any changed lines in the diff.\n */\nfunction isDtoTouched(dto: DtoInfo, changedLines: Set<number>): boolean {\n for (let line = dto.startLine; line <= dto.endLine; line++) {\n if (changedLines.has(line)) return true;\n }\n return false;\n}\n\n/**\n * Filter Dtos to only those that have changed lines in the diff (MODIFIED_CLASS mode).\n */\nfunction filterTouchedDtos(\n dtos: DtoInfo[],\n workspaceRoot: string,\n base: string,\n head?: string\n): DtoInfo[] {\n // Group dtos by file to avoid re-fetching diffs\n const byFile = new Map<string, DtoInfo[]>();\n for (const dto of dtos) {\n const list = byFile.get(dto.file) ?? [];\n list.push(dto);\n byFile.set(dto.file, list);\n }\n\n const touched: DtoInfo[] = [];\n for (const [file, fileDtos] of byFile) {\n const diff = getFileDiff(workspaceRoot, file, base, head);\n const changedLines = getChangedLineNumbers(diff);\n for (const dto of fileDtos) {\n if (isDtoTouched(dto, changedLines)) {\n touched.push(dto);\n }\n }\n }\n return touched;\n}\n\n/**\n * Resolve git base ref from env vars or auto-detection.\n */\nfunction resolveBase(workspaceRoot: string): string | undefined {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n return detectBase(workspaceRoot) ?? undefined;\n}\n\n/**\n * Run the core validation after early-exit checks have passed.\n */\n// webpieces-disable max-lines-new-methods -- Core validation orchestration with multiple early-exit checks\nfunction validateDtoFiles(\n workspaceRoot: string,\n prismaSchemaPath: string,\n changedFiles: string[],\n dtoSourcePaths: string[],\n mode: ValidateDtosMode,\n base: string,\n head?: string\n): ExecutorResult {\n if (changedFiles.some((f) => f.endsWith(prismaSchemaPath))) {\n console.log('āļø Skipping validate-dtos (schema.prisma is modified - schema in flux)');\n console.log('');\n return { success: true };\n }\n\n const dtoFiles = filterDtoFiles(changedFiles, dtoSourcePaths);\n\n if (dtoFiles.length === 0) {\n console.log('ā
No Dto files changed');\n return { success: true };\n }\n\n console.log(`š Checking ${dtoFiles.length} changed file(s) for Dto definitions...`);\n\n const fullSchemaPath = path.join(workspaceRoot, prismaSchemaPath);\n const dboModels = parsePrismaSchema(fullSchemaPath);\n\n if (dboModels.size === 0) {\n console.log('āļø No Dbo models found in schema.prisma');\n console.log('');\n return { success: true };\n }\n\n console.log(` Found ${dboModels.size} Dbo model(s) in schema.prisma`);\n\n let allDtos = collectDtos(dtoFiles, workspaceRoot);\n\n if (allDtos.length === 0) {\n console.log('ā
No Dto definitions found in changed files');\n return { success: true };\n }\n\n // In MODIFIED_CLASS mode, narrow to only Dtos with changed lines\n if (mode === 'MODIFIED_CLASS') {\n allDtos = filterTouchedDtos(allDtos, workspaceRoot, base, head);\n if (allDtos.length === 0) {\n console.log('ā
No Dto classes were modified');\n return { success: true };\n }\n }\n\n console.log(` Validating ${allDtos.length} Dto definition(s)`);\n\n const violations = findViolations(allDtos, dboModels);\n\n if (violations.length === 0) {\n console.log('ā
All Dto fields match their Dbo models');\n return { success: true };\n }\n\n reportViolations(violations);\n return { success: false };\n}\n\nexport default async function runExecutor(\n options: ValidateDtosOptions,\n context: ExecutorContext\n): Promise<ExecutorResult> {\n const workspaceRoot = context.root;\n const mode: ValidateDtosMode = options.mode ?? 'OFF';\n\n if (mode === 'OFF') {\n console.log('\\nāļø Skipping validate-dtos (mode: OFF)');\n console.log('');\n return { success: true };\n }\n\n const prismaSchemaPath = options.prismaSchemaPath;\n const dtoSourcePaths = options.dtoSourcePaths ?? [];\n\n if (!prismaSchemaPath || dtoSourcePaths.length === 0) {\n const reason = !prismaSchemaPath ? 'no prismaSchemaPath configured' : 'no dtoSourcePaths configured';\n console.log(`\\nāļø Skipping validate-dtos (${reason})`);\n console.log('');\n return { success: true };\n }\n\n console.log('\\nš Validating DTOs match Prisma Dbo models\\n');\n console.log(` Mode: ${mode}`);\n console.log(` Schema: ${prismaSchemaPath}`);\n console.log(` Dto paths: ${dtoSourcePaths.join(', ')}`);\n\n const base = resolveBase(workspaceRoot);\n const head = process.env['NX_HEAD'];\n\n if (!base) {\n console.log('\\nāļø Skipping validate-dtos (could not detect base branch)');\n console.log('');\n return { success: true };\n }\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n\n return validateDtoFiles(workspaceRoot, prismaSchemaPath, changedFiles, dtoSourcePaths, mode, base, head);\n}\n"]}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* MODES
|
|
10
10
|
* ============================================================================
|
|
11
11
|
* - OFF: Skip validation entirely
|
|
12
|
-
* -
|
|
12
|
+
* - MODIFIED_CLASS: Only validate Dto classes that have changed lines in the diff
|
|
13
|
+
* - MODIFIED_FILES: Validate ALL Dto classes in files that were modified
|
|
13
14
|
*
|
|
14
15
|
* ============================================================================
|
|
15
16
|
* SKIP CONDITIONS
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
* MATCHING
|
|
23
24
|
* ============================================================================
|
|
24
25
|
* - UserDto matches UserDbo by case-insensitive prefix ("user")
|
|
26
|
+
* - Dbo field names are converted from snake_case to camelCase for comparison
|
|
25
27
|
* - Dto fields must be a subset of Dbo fields
|
|
26
28
|
* - Extra Dbo fields are allowed (e.g., password)
|
|
27
29
|
*/
|
|
@@ -32,7 +34,7 @@ import * as fs from 'fs';
|
|
|
32
34
|
import * as path from 'path';
|
|
33
35
|
import * as ts from 'typescript';
|
|
34
36
|
|
|
35
|
-
export type ValidateDtosMode = 'OFF' | 'MODIFIED_FILES';
|
|
37
|
+
export type ValidateDtosMode = 'OFF' | 'MODIFIED_CLASS' | 'MODIFIED_FILES';
|
|
36
38
|
|
|
37
39
|
export interface ValidateDtosOptions {
|
|
38
40
|
mode?: ValidateDtosMode;
|
|
@@ -53,6 +55,8 @@ interface DtoFieldInfo {
|
|
|
53
55
|
interface DtoInfo {
|
|
54
56
|
name: string;
|
|
55
57
|
file: string;
|
|
58
|
+
startLine: number;
|
|
59
|
+
endLine: number;
|
|
56
60
|
fields: DtoFieldInfo[];
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -142,8 +146,78 @@ function getChangedFiles(workspaceRoot: string, base: string, head?: string): st
|
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
/**
|
|
145
|
-
*
|
|
149
|
+
* Get the diff content for a specific file.
|
|
150
|
+
*/
|
|
151
|
+
function getFileDiff(workspaceRoot: string, file: string, base: string, head?: string): string {
|
|
152
|
+
try {
|
|
153
|
+
const diffTarget = head ? `${base} ${head}` : base;
|
|
154
|
+
const diff = execSync(`git diff ${diffTarget} -- "${file}"`, {
|
|
155
|
+
cwd: workspaceRoot,
|
|
156
|
+
encoding: 'utf-8',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (!diff && !head) {
|
|
160
|
+
const fullPath = path.join(workspaceRoot, file);
|
|
161
|
+
if (fs.existsSync(fullPath)) {
|
|
162
|
+
const isUntracked = execSync(`git ls-files --others --exclude-standard "${file}"`, {
|
|
163
|
+
cwd: workspaceRoot,
|
|
164
|
+
encoding: 'utf-8',
|
|
165
|
+
}).trim();
|
|
166
|
+
|
|
167
|
+
if (isUntracked) {
|
|
168
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
169
|
+
const lines = content.split('\n');
|
|
170
|
+
return lines.map((line) => `+${line}`).join('\n');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return diff;
|
|
176
|
+
} catch {
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Parse diff to extract changed line numbers (additions only - lines starting with +).
|
|
183
|
+
*/
|
|
184
|
+
function getChangedLineNumbers(diffContent: string): Set<number> {
|
|
185
|
+
const changedLines = new Set<number>();
|
|
186
|
+
const lines = diffContent.split('\n');
|
|
187
|
+
let currentLine = 0;
|
|
188
|
+
|
|
189
|
+
for (const line of lines) {
|
|
190
|
+
const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
191
|
+
if (hunkMatch) {
|
|
192
|
+
currentLine = parseInt(hunkMatch[1], 10);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
197
|
+
changedLines.add(currentLine);
|
|
198
|
+
currentLine++;
|
|
199
|
+
} else if (line.startsWith('-') && !line.startsWith('---')) {
|
|
200
|
+
// Deletions don't increment line number
|
|
201
|
+
} else {
|
|
202
|
+
currentLine++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return changedLines;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Convert a snake_case string to camelCase.
|
|
211
|
+
* e.g., "version_number" -> "versionNumber", "id" -> "id"
|
|
212
|
+
*/
|
|
213
|
+
function snakeToCamel(s: string): string {
|
|
214
|
+
return s.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Parse schema.prisma to build a map of Dbo model name -> set of field names (camelCase).
|
|
146
219
|
* Only models whose name ends with "Dbo" are included.
|
|
220
|
+
* Field names are converted from snake_case to camelCase since Dto fields use camelCase.
|
|
147
221
|
*/
|
|
148
222
|
function parsePrismaSchema(schemaPath: string): Map<string, Set<string>> {
|
|
149
223
|
const models = new Map<string, Set<string>>();
|
|
@@ -184,10 +258,10 @@ function parsePrismaSchema(schemaPath: string): Map<string, Set<string>> {
|
|
|
184
258
|
continue;
|
|
185
259
|
}
|
|
186
260
|
|
|
187
|
-
// Field name is the first word on the line
|
|
261
|
+
// Field name is the first word on the line, converted to camelCase
|
|
188
262
|
const fieldMatch = trimmed.match(/^(\w+)\s/);
|
|
189
263
|
if (fieldMatch) {
|
|
190
|
-
currentFields.add(fieldMatch[1]);
|
|
264
|
+
currentFields.add(snakeToCamel(fieldMatch[1]));
|
|
191
265
|
}
|
|
192
266
|
}
|
|
193
267
|
}
|
|
@@ -232,6 +306,8 @@ function findDtosInFile(filePath: string, workspaceRoot: string): DtoInfo[] {
|
|
|
232
306
|
// Must end with Dto but NOT with JoinDto
|
|
233
307
|
if (name.endsWith('Dto') && !name.endsWith('JoinDto')) {
|
|
234
308
|
const fields: DtoFieldInfo[] = [];
|
|
309
|
+
const nodeStart = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
310
|
+
const nodeEnd = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
235
311
|
|
|
236
312
|
for (const member of node.members) {
|
|
237
313
|
if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {
|
|
@@ -247,7 +323,13 @@ function findDtosInFile(filePath: string, workspaceRoot: string): DtoInfo[] {
|
|
|
247
323
|
}
|
|
248
324
|
}
|
|
249
325
|
|
|
250
|
-
dtos.push({
|
|
326
|
+
dtos.push({
|
|
327
|
+
name,
|
|
328
|
+
file: filePath,
|
|
329
|
+
startLine: nodeStart.line + 1,
|
|
330
|
+
endLine: nodeEnd.line + 1,
|
|
331
|
+
fields,
|
|
332
|
+
});
|
|
251
333
|
}
|
|
252
334
|
}
|
|
253
335
|
|
|
@@ -329,7 +411,7 @@ function reportViolations(violations: DtoViolation[]): void {
|
|
|
329
411
|
}
|
|
330
412
|
console.error('');
|
|
331
413
|
|
|
332
|
-
console.error(' Dto fields must be a subset of Dbo fields (matching
|
|
414
|
+
console.error(' Dto fields must be a subset of Dbo fields (matching camelCase field names).');
|
|
333
415
|
console.error(' Fields marked @deprecated in the Dto are exempt from this check.');
|
|
334
416
|
console.error('');
|
|
335
417
|
console.error(' When needing fields from multiple tables (e.g., a join), use a XxxJoinDto that');
|
|
@@ -360,6 +442,46 @@ function collectDtos(dtoFiles: string[], workspaceRoot: string): DtoInfo[] {
|
|
|
360
442
|
return allDtos;
|
|
361
443
|
}
|
|
362
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Check if a Dto class overlaps with any changed lines in the diff.
|
|
447
|
+
*/
|
|
448
|
+
function isDtoTouched(dto: DtoInfo, changedLines: Set<number>): boolean {
|
|
449
|
+
for (let line = dto.startLine; line <= dto.endLine; line++) {
|
|
450
|
+
if (changedLines.has(line)) return true;
|
|
451
|
+
}
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Filter Dtos to only those that have changed lines in the diff (MODIFIED_CLASS mode).
|
|
457
|
+
*/
|
|
458
|
+
function filterTouchedDtos(
|
|
459
|
+
dtos: DtoInfo[],
|
|
460
|
+
workspaceRoot: string,
|
|
461
|
+
base: string,
|
|
462
|
+
head?: string
|
|
463
|
+
): DtoInfo[] {
|
|
464
|
+
// Group dtos by file to avoid re-fetching diffs
|
|
465
|
+
const byFile = new Map<string, DtoInfo[]>();
|
|
466
|
+
for (const dto of dtos) {
|
|
467
|
+
const list = byFile.get(dto.file) ?? [];
|
|
468
|
+
list.push(dto);
|
|
469
|
+
byFile.set(dto.file, list);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const touched: DtoInfo[] = [];
|
|
473
|
+
for (const [file, fileDtos] of byFile) {
|
|
474
|
+
const diff = getFileDiff(workspaceRoot, file, base, head);
|
|
475
|
+
const changedLines = getChangedLineNumbers(diff);
|
|
476
|
+
for (const dto of fileDtos) {
|
|
477
|
+
if (isDtoTouched(dto, changedLines)) {
|
|
478
|
+
touched.push(dto);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return touched;
|
|
483
|
+
}
|
|
484
|
+
|
|
363
485
|
/**
|
|
364
486
|
* Resolve git base ref from env vars or auto-detection.
|
|
365
487
|
*/
|
|
@@ -372,11 +494,15 @@ function resolveBase(workspaceRoot: string): string | undefined {
|
|
|
372
494
|
/**
|
|
373
495
|
* Run the core validation after early-exit checks have passed.
|
|
374
496
|
*/
|
|
497
|
+
// webpieces-disable max-lines-new-methods -- Core validation orchestration with multiple early-exit checks
|
|
375
498
|
function validateDtoFiles(
|
|
376
499
|
workspaceRoot: string,
|
|
377
500
|
prismaSchemaPath: string,
|
|
378
501
|
changedFiles: string[],
|
|
379
|
-
dtoSourcePaths: string[]
|
|
502
|
+
dtoSourcePaths: string[],
|
|
503
|
+
mode: ValidateDtosMode,
|
|
504
|
+
base: string,
|
|
505
|
+
head?: string
|
|
380
506
|
): ExecutorResult {
|
|
381
507
|
if (changedFiles.some((f) => f.endsWith(prismaSchemaPath))) {
|
|
382
508
|
console.log('āļø Skipping validate-dtos (schema.prisma is modified - schema in flux)');
|
|
@@ -404,14 +530,23 @@ function validateDtoFiles(
|
|
|
404
530
|
|
|
405
531
|
console.log(` Found ${dboModels.size} Dbo model(s) in schema.prisma`);
|
|
406
532
|
|
|
407
|
-
|
|
533
|
+
let allDtos = collectDtos(dtoFiles, workspaceRoot);
|
|
408
534
|
|
|
409
535
|
if (allDtos.length === 0) {
|
|
410
536
|
console.log('ā
No Dto definitions found in changed files');
|
|
411
537
|
return { success: true };
|
|
412
538
|
}
|
|
413
539
|
|
|
414
|
-
|
|
540
|
+
// In MODIFIED_CLASS mode, narrow to only Dtos with changed lines
|
|
541
|
+
if (mode === 'MODIFIED_CLASS') {
|
|
542
|
+
allDtos = filterTouchedDtos(allDtos, workspaceRoot, base, head);
|
|
543
|
+
if (allDtos.length === 0) {
|
|
544
|
+
console.log('ā
No Dto classes were modified');
|
|
545
|
+
return { success: true };
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
console.log(` Validating ${allDtos.length} Dto definition(s)`);
|
|
415
550
|
|
|
416
551
|
const violations = findViolations(allDtos, dboModels);
|
|
417
552
|
|
|
@@ -467,5 +602,5 @@ export default async function runExecutor(
|
|
|
467
602
|
|
|
468
603
|
const changedFiles = getChangedFiles(workspaceRoot, base, head);
|
|
469
604
|
|
|
470
|
-
return validateDtoFiles(workspaceRoot, prismaSchemaPath, changedFiles, dtoSourcePaths);
|
|
605
|
+
return validateDtoFiles(workspaceRoot, prismaSchemaPath, changedFiles, dtoSourcePaths, mode, base, head);
|
|
471
606
|
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"properties": {
|
|
7
7
|
"mode": {
|
|
8
8
|
"type": "string",
|
|
9
|
-
"enum": ["OFF", "MODIFIED_FILES"],
|
|
10
|
-
"description": "OFF: skip validation.
|
|
9
|
+
"enum": ["OFF", "MODIFIED_CLASS", "MODIFIED_FILES"],
|
|
10
|
+
"description": "OFF: skip validation. MODIFIED_CLASS: only validate Dto classes with changed lines. MODIFIED_FILES: validate all Dtos in modified files.",
|
|
11
11
|
"default": "OFF"
|
|
12
12
|
},
|
|
13
13
|
"prismaSchemaPath": {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate Prisma Converters Executor
|
|
3
|
+
*
|
|
4
|
+
* Validates that Prisma converter methods follow a scalable pattern:
|
|
5
|
+
* methods returning XxxDto (where XxxDbo exists in schema.prisma) must
|
|
6
|
+
* accept that exact XxxDbo as the first parameter. This keeps single-table
|
|
7
|
+
* converters clean and forces join converters to compose them.
|
|
8
|
+
*
|
|
9
|
+
* ============================================================================
|
|
10
|
+
* RULES
|
|
11
|
+
* ============================================================================
|
|
12
|
+
*
|
|
13
|
+
* 1. First param must be exact Dbo:
|
|
14
|
+
* If method returns XxxDto and XxxDbo exists in schema.prisma,
|
|
15
|
+
* the first parameter must be of type XxxDbo.
|
|
16
|
+
*
|
|
17
|
+
* 2. Extra params must be booleans:
|
|
18
|
+
* Additional parameters beyond the Dbo are allowed but must be boolean
|
|
19
|
+
* (used for filtering payloads / security info).
|
|
20
|
+
*
|
|
21
|
+
* 3. No async converters:
|
|
22
|
+
* Methods returning Promise<XxxDto> are flagged ā converters should be
|
|
23
|
+
* pure data mapping, no async work.
|
|
24
|
+
*
|
|
25
|
+
* 4. No standalone functions:
|
|
26
|
+
* Standalone functions in converter files are flagged ā must be class
|
|
27
|
+
* methods so the converter class can be injected (dependency tree tracing).
|
|
28
|
+
*
|
|
29
|
+
* 5. Dto creation outside converters directory:
|
|
30
|
+
* Files outside the configured convertersPath that create `new XxxDto(...)`
|
|
31
|
+
* where XxxDbo exists in schema.prisma are flagged ā Dto instances tied to
|
|
32
|
+
* a Dbo must only be created via a converter class.
|
|
33
|
+
*
|
|
34
|
+
* ============================================================================
|
|
35
|
+
* SKIP CONDITIONS
|
|
36
|
+
* ============================================================================
|
|
37
|
+
* - Methods with @deprecated decorator or JSDoc tag
|
|
38
|
+
* - Lines with: // webpieces-disable prisma-converter -- [reason]
|
|
39
|
+
*
|
|
40
|
+
* ============================================================================
|
|
41
|
+
* MODES
|
|
42
|
+
* ============================================================================
|
|
43
|
+
* - OFF: Skip validation entirely
|
|
44
|
+
* - MODIFIED_FILES: Validate converter files that were modified in the diff
|
|
45
|
+
*/
|
|
46
|
+
import type { ExecutorContext } from '@nx/devkit';
|
|
47
|
+
export type PrismaConverterMode = 'OFF' | 'MODIFIED_FILES';
|
|
48
|
+
export interface ValidatePrismaConvertersOptions {
|
|
49
|
+
mode?: PrismaConverterMode;
|
|
50
|
+
schemaPath?: string;
|
|
51
|
+
convertersPaths?: string[];
|
|
52
|
+
}
|
|
53
|
+
export interface ExecutorResult {
|
|
54
|
+
success: boolean;
|
|
55
|
+
}
|
|
56
|
+
export default function runExecutor(options: ValidatePrismaConvertersOptions, context: ExecutorContext): Promise<ExecutorResult>;
|