code-auditor-mcp 3.4.11 → 3.4.13

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.
Files changed (254) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +119 -1
  3. package/dist/analyzers/__verify_self_probe.d.ts +2 -0
  4. package/dist/analyzers/__verify_self_probe.d.ts.map +1 -0
  5. package/dist/analyzers/__verify_self_probe.js +5 -0
  6. package/dist/analyzers/__verify_self_probe.js.map +1 -0
  7. package/dist/analyzers/analyzerUtils.d.ts +34 -1
  8. package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
  9. package/dist/analyzers/analyzerUtils.js +61 -22
  10. package/dist/analyzers/analyzerUtils.js.map +1 -1
  11. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +18 -23
  12. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  13. package/dist/analyzers/cross-language/APIContractAnalyzer.js +198 -186
  14. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
  15. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +78 -55
  16. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  17. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +244 -243
  18. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  19. package/dist/analyzers/cross-language/SchemaValidator.d.ts +27 -37
  20. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  21. package/dist/analyzers/cross-language/SchemaValidator.js +314 -275
  22. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  23. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +17 -46
  24. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  25. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +620 -523
  26. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  27. package/dist/analyzers/documentationAnalyzer.d.ts +7 -2
  28. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  29. package/dist/analyzers/documentationAnalyzer.js +259 -198
  30. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  31. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/invariantsAnalyzer.js +59 -46
  33. package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
  34. package/dist/analyzers/orm/adapterRegistry.d.ts +10 -0
  35. package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -1
  36. package/dist/analyzers/orm/adapterRegistry.js +10 -0
  37. package/dist/analyzers/orm/adapterRegistry.js.map +1 -1
  38. package/dist/analyzers/orm/drizzleAdapter.d.ts +22 -0
  39. package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -1
  40. package/dist/analyzers/orm/drizzleAdapter.js +42 -44
  41. package/dist/analyzers/orm/drizzleAdapter.js.map +1 -1
  42. package/dist/analyzers/orm/prismaAdapter.d.ts +30 -0
  43. package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -1
  44. package/dist/analyzers/orm/prismaAdapter.js +30 -0
  45. package/dist/analyzers/orm/prismaAdapter.js.map +1 -1
  46. package/dist/analyzers/provenance.d.ts +72 -2
  47. package/dist/analyzers/provenance.d.ts.map +1 -1
  48. package/dist/analyzers/provenance.js +462 -338
  49. package/dist/analyzers/provenance.js.map +1 -1
  50. package/dist/analyzers/reactAnalyzer.d.ts +11 -0
  51. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  52. package/dist/analyzers/reactAnalyzer.js +188 -125
  53. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  54. package/dist/analyzers/ruleRegistry.d.ts +118 -1
  55. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  56. package/dist/analyzers/ruleRegistry.js +1717 -104
  57. package/dist/analyzers/ruleRegistry.js.map +1 -1
  58. package/dist/analyzers/ruleTiming.d.ts +54 -0
  59. package/dist/analyzers/ruleTiming.d.ts.map +1 -0
  60. package/dist/analyzers/ruleTiming.js +71 -0
  61. package/dist/analyzers/ruleTiming.js.map +1 -0
  62. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +13 -0
  63. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  64. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +362 -283
  65. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  66. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +26 -68
  67. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  68. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +430 -391
  69. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  70. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +24 -186
  71. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  72. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +1081 -1061
  73. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  74. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -49
  75. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  76. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +414 -340
  77. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  78. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +48 -5
  79. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  80. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +262 -134
  81. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  82. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +23 -212
  83. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  84. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +139 -1518
  85. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  86. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +78 -79
  87. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  88. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +613 -472
  89. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  90. package/dist/analyzers/universal/schema/codeAnalysis.d.ts +307 -0
  91. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -0
  92. package/dist/analyzers/universal/schema/codeAnalysis.js +965 -0
  93. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -0
  94. package/dist/analyzers/universal/schema/config.d.ts +31 -0
  95. package/dist/analyzers/universal/schema/config.d.ts.map +1 -0
  96. package/dist/analyzers/universal/schema/config.js +57 -0
  97. package/dist/analyzers/universal/schema/config.js.map +1 -0
  98. package/dist/analyzers/universal/schema/discovery.d.ts +167 -0
  99. package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -0
  100. package/dist/analyzers/universal/schema/discovery.js +616 -0
  101. package/dist/analyzers/universal/schema/discovery.js.map +1 -0
  102. package/dist/analyzers/universal/schema/jsonSchema.d.ts +27 -0
  103. package/dist/analyzers/universal/schema/jsonSchema.d.ts.map +1 -0
  104. package/dist/analyzers/universal/schema/jsonSchema.js +368 -0
  105. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -0
  106. package/dist/analyzers/universal/schema/migrations.d.ts +90 -0
  107. package/dist/analyzers/universal/schema/migrations.d.ts.map +1 -0
  108. package/dist/analyzers/universal/schema/migrations.js +238 -0
  109. package/dist/analyzers/universal/schema/migrations.js.map +1 -0
  110. package/dist/analyzers/universal/schema/types.d.ts +131 -0
  111. package/dist/analyzers/universal/schema/types.d.ts.map +1 -0
  112. package/dist/analyzers/universal/schema/types.js +10 -0
  113. package/dist/analyzers/universal/schema/types.js.map +1 -0
  114. package/dist/analyzers/universal/schema/violations.d.ts +44 -0
  115. package/dist/analyzers/universal/schema/violations.d.ts.map +1 -0
  116. package/dist/analyzers/universal/schema/violations.js +54 -0
  117. package/dist/analyzers/universal/schema/violations.js.map +1 -0
  118. package/dist/auditRunner.d.ts.map +1 -1
  119. package/dist/auditRunner.js +101 -39
  120. package/dist/auditRunner.js.map +1 -1
  121. package/dist/cli.js +348 -40
  122. package/dist/cli.js.map +1 -1
  123. package/dist/config/configLoader.d.ts.map +1 -1
  124. package/dist/config/configLoader.js +9 -7
  125. package/dist/config/configLoader.js.map +1 -1
  126. package/dist/config/defaults.d.ts +12 -3
  127. package/dist/config/defaults.d.ts.map +1 -1
  128. package/dist/config/defaults.js +15 -5
  129. package/dist/config/defaults.js.map +1 -1
  130. package/dist/config/effectiveConfig.d.ts +75 -0
  131. package/dist/config/effectiveConfig.d.ts.map +1 -0
  132. package/dist/config/effectiveConfig.js +213 -0
  133. package/dist/config/effectiveConfig.js.map +1 -0
  134. package/dist/config/pathProfiles.d.ts +7 -4
  135. package/dist/config/pathProfiles.d.ts.map +1 -1
  136. package/dist/config/pathProfiles.js +8 -10
  137. package/dist/config/pathProfiles.js.map +1 -1
  138. package/dist/config/thresholdRationales.d.ts +45 -0
  139. package/dist/config/thresholdRationales.d.ts.map +1 -0
  140. package/dist/config/thresholdRationales.js +67 -0
  141. package/dist/config/thresholdRationales.js.map +1 -0
  142. package/dist/conventions/conventionMiner.d.ts.map +1 -1
  143. package/dist/conventions/conventionMiner.js +6 -2
  144. package/dist/conventions/conventionMiner.js.map +1 -1
  145. package/dist/enforcement/diffGate.d.ts +55 -0
  146. package/dist/enforcement/diffGate.d.ts.map +1 -0
  147. package/dist/enforcement/diffGate.js +136 -0
  148. package/dist/enforcement/diffGate.js.map +1 -0
  149. package/dist/enforcement/gate.d.ts +36 -0
  150. package/dist/enforcement/gate.d.ts.map +1 -0
  151. package/dist/enforcement/gate.js +72 -0
  152. package/dist/enforcement/gate.js.map +1 -0
  153. package/dist/enforcement/suppressions.d.ts +41 -0
  154. package/dist/enforcement/suppressions.d.ts.map +1 -0
  155. package/dist/enforcement/suppressions.js +170 -0
  156. package/dist/enforcement/suppressions.js.map +1 -0
  157. package/dist/fingerprint.d.ts.map +1 -1
  158. package/dist/fingerprint.js +4 -1
  159. package/dist/fingerprint.js.map +1 -1
  160. package/dist/grammars/tree-sitter-scss.wasm +0 -0
  161. package/dist/invariants/ruleEngine.d.ts +3 -4
  162. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  163. package/dist/invariants/ruleEngine.js +2 -2
  164. package/dist/invariants/ruleEngine.js.map +1 -1
  165. package/dist/languages/LanguageOrchestrator.d.ts +14 -0
  166. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  167. package/dist/languages/LanguageOrchestrator.js +93 -55
  168. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  169. package/dist/languages/LanguageRegistry.d.ts +8 -0
  170. package/dist/languages/LanguageRegistry.d.ts.map +1 -1
  171. package/dist/languages/LanguageRegistry.js +8 -0
  172. package/dist/languages/LanguageRegistry.js.map +1 -1
  173. package/dist/languages/RuntimeManager.d.ts +82 -60
  174. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  175. package/dist/languages/RuntimeManager.js +404 -349
  176. package/dist/languages/RuntimeManager.js.map +1 -1
  177. package/dist/languages/UniversalAnalyzer.d.ts +51 -6
  178. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
  179. package/dist/languages/UniversalAnalyzer.js +127 -88
  180. package/dist/languages/UniversalAnalyzer.js.map +1 -1
  181. package/dist/languages/adapterBridge.d.ts +36 -0
  182. package/dist/languages/adapterBridge.d.ts.map +1 -1
  183. package/dist/languages/adapterBridge.js +89 -35
  184. package/dist/languages/adapterBridge.js.map +1 -1
  185. package/dist/languages/go/GoAdapter.d.ts +66 -23
  186. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  187. package/dist/languages/go/GoAdapter.js +553 -474
  188. package/dist/languages/go/GoAdapter.js.map +1 -1
  189. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +38 -9
  190. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
  191. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +111 -74
  192. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
  193. package/dist/languages/tree-sitter/converter.d.ts +18 -0
  194. package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
  195. package/dist/languages/tree-sitter/converter.js +18 -0
  196. package/dist/languages/tree-sitter/converter.js.map +1 -1
  197. package/dist/languages/tree-sitter/parser.d.ts +39 -2
  198. package/dist/languages/tree-sitter/parser.d.ts.map +1 -1
  199. package/dist/languages/tree-sitter/parser.js +95 -12
  200. package/dist/languages/tree-sitter/parser.js.map +1 -1
  201. package/dist/languages/types.d.ts +67 -2
  202. package/dist/languages/types.d.ts.map +1 -1
  203. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +253 -62
  204. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  205. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +1461 -791
  206. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  207. package/dist/mcp-tools/whitelistTools.d.ts +1 -1
  208. package/dist/mcp-tools-shared.d.ts.map +1 -1
  209. package/dist/mcp-tools-shared.js +1 -0
  210. package/dist/mcp-tools-shared.js.map +1 -1
  211. package/dist/mcpAuditJobs.d.ts.map +1 -1
  212. package/dist/mcpAuditJobs.js +1 -0
  213. package/dist/mcpAuditJobs.js.map +1 -1
  214. package/dist/pipeline.d.ts +30 -1
  215. package/dist/pipeline.d.ts.map +1 -1
  216. package/dist/pipeline.js +527 -203
  217. package/dist/pipeline.js.map +1 -1
  218. package/dist/pipelineAdapters.d.ts +5 -12
  219. package/dist/pipelineAdapters.d.ts.map +1 -1
  220. package/dist/pipelineAdapters.js +175 -100
  221. package/dist/pipelineAdapters.js.map +1 -1
  222. package/dist/presets/presets.d.ts +54 -0
  223. package/dist/presets/presets.d.ts.map +1 -0
  224. package/dist/presets/presets.js +181 -0
  225. package/dist/presets/presets.js.map +1 -0
  226. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  227. package/dist/reporting/sarifReportGenerator.js +0 -2
  228. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  229. package/dist/ruleAliases.d.ts +67 -0
  230. package/dist/ruleAliases.d.ts.map +1 -0
  231. package/dist/ruleAliases.js +79 -0
  232. package/dist/ruleAliases.js.map +1 -0
  233. package/dist/styles/cssAstExtractor.d.ts +20 -5
  234. package/dist/styles/cssAstExtractor.d.ts.map +1 -1
  235. package/dist/styles/cssAstExtractor.js +247 -9
  236. package/dist/styles/cssAstExtractor.js.map +1 -1
  237. package/dist/styles/styleIndexer.js +13 -4
  238. package/dist/styles/styleIndexer.js.map +1 -1
  239. package/dist/styles/tailwindConfigLoader.d.ts +8 -6
  240. package/dist/styles/tailwindConfigLoader.d.ts.map +1 -1
  241. package/dist/styles/tailwindConfigLoader.js +61 -15
  242. package/dist/styles/tailwindConfigLoader.js.map +1 -1
  243. package/dist/styles/tailwindUtilityExpander.d.ts.map +1 -1
  244. package/dist/styles/tailwindUtilityExpander.js +13 -1
  245. package/dist/styles/tailwindUtilityExpander.js.map +1 -1
  246. package/dist/types.d.ts +201 -1
  247. package/dist/types.d.ts.map +1 -1
  248. package/dist/types.js +8 -0
  249. package/dist/types.js.map +1 -1
  250. package/package.json +7 -4
  251. package/plugin/.claude-plugin/plugin.json +1 -1
  252. package/plugin/hooks/hooks.json +1 -1
  253. package/plugin/scripts/hook-audit.sh +25 -7
  254. package/plugin/skills/code-auditor/SKILL.md +5 -5
@@ -2,8 +2,15 @@
2
2
  * Cross-Language Schema Validator
3
3
  * Validates schema consistency across language boundaries
4
4
  */
5
+ /**
6
+ * Schema validator.
7
+ */
5
8
  export class SchemaValidator {
6
9
  options;
10
+ /**
11
+ * Constructor.
12
+ * @param options
13
+ */
7
14
  constructor(options = {}) {
8
15
  this.options = {
9
16
  strictTypeChecking: true,
@@ -16,11 +23,13 @@ export class SchemaValidator {
16
23
  }
17
24
  /**
18
25
  * Validate schema consistency across multiple languages
26
+ * @param schemas
27
+ * @returns
19
28
  */
20
29
  async validateSchemas(schemas) {
21
30
  const violations = [];
22
31
  // Group schemas by name (different language implementations of same schema)
23
- const schemaGroups = this.groupSchemasByName(schemas);
32
+ const schemaGroups = groupSchemasByName(schemas);
24
33
  for (const [schemaName, groupSchemas] of schemaGroups) {
25
34
  if (groupSchemas.length > 1) {
26
35
  violations.push(...await this.validateSchemaGroup(schemaName, groupSchemas));
@@ -32,45 +41,6 @@ export class SchemaValidator {
32
41
  }
33
42
  return violations;
34
43
  }
35
- /**
36
- * Extract schema definitions from entities
37
- */
38
- static extractSchemas(entities) {
39
- const schemas = [];
40
- for (const entity of entities) {
41
- // TypeScript interfaces
42
- if (entity.language === 'typescript' && entity.type === 'interface') {
43
- const schema = this.extractTypeScriptInterface(entity);
44
- if (schema)
45
- schemas.push(schema);
46
- }
47
- // Go structs
48
- if (entity.language === 'go' && entity.type === 'struct') {
49
- const schema = this.extractGoStruct(entity);
50
- if (schema)
51
- schemas.push(schema);
52
- }
53
- // Protocol buffer definitions
54
- if (entity.file.endsWith('.proto')) {
55
- const schema = this.extractProtobufMessage(entity);
56
- if (schema)
57
- schemas.push(schema);
58
- }
59
- // GraphQL types
60
- if (entity.file.endsWith('.graphql') || entity.file.endsWith('.gql')) {
61
- const schema = this.extractGraphQLType(entity);
62
- if (schema)
63
- schemas.push(schema);
64
- }
65
- // JSON Schema
66
- if (entity.file.endsWith('.json') && entity.name.toLowerCase().includes('schema')) {
67
- const schema = this.extractJSONSchema(entity);
68
- if (schema)
69
- schemas.push(schema);
70
- }
71
- }
72
- return schemas;
73
- }
74
44
  /**
75
45
  * Validate a group of schemas that should be equivalent
76
46
  */
@@ -98,54 +68,75 @@ export class SchemaValidator {
98
68
  // Create field maps for easier comparison
99
69
  const refFields = new Map(reference.fields.map(f => [f.name, f]));
100
70
  const curFields = new Map(current.fields.map(f => [f.name, f]));
101
- // Check for missing required fields
71
+ violations.push(...this.checkMissingFields(refFields, curFields, reference, current));
72
+ violations.push(...this.checkExtraFields(refFields, curFields, reference, current));
73
+ violations.push(...this.checkFieldTypes(refFields, curFields, reference, current));
74
+ return violations;
75
+ }
76
+ /**
77
+ * Check for required fields missing from the current schema.
78
+ */
79
+ checkMissingFields(refFields, curFields, reference, current) {
80
+ const violations = [];
102
81
  for (const [fieldName, refField] of refFields) {
103
- if (refField.required && !curFields.has(fieldName)) {
104
- violations.push({
105
- file: current.file,
106
- line: current.line,
107
- severity: 'warning',
108
- message: `Missing required field '${fieldName}' in ${current.type} ${current.name}`,
109
- rule: "missing-field",
110
- violationType: 'missing-field',
111
- schemas: [reference, current],
112
- fieldName,
113
- suggestion: `Add field '${fieldName}: ${refField.type}' to ${current.name}`,
114
- analyzer: 'schema-validator',
115
- category: 'cross-language-schema'
116
- });
117
- }
82
+ if (!refField.required || curFields.has(fieldName))
83
+ continue;
84
+ violations.push({
85
+ file: current.file,
86
+ line: current.line,
87
+ severity: 'warning',
88
+ message: `Missing required field '${fieldName}' in ${current.type} ${current.name}`,
89
+ rule: "missing-field",
90
+ violationType: 'missing-field',
91
+ schemas: [reference, current],
92
+ fieldName,
93
+ suggestion: `Add field '${fieldName}: ${refField.type}' to ${current.name}`,
94
+ analyzer: 'schema-validator',
95
+ category: 'cross-language-schema'
96
+ });
118
97
  }
119
- // Check for extra fields (if not allowed)
120
- if (!this.options.allowAdditionalFields) {
121
- for (const [fieldName, curField] of curFields) {
122
- if (!refFields.has(fieldName)) {
123
- violations.push({
124
- file: current.file,
125
- line: current.line,
126
- severity: 'warning',
127
- message: `Extra field '${fieldName}' in ${current.type} ${current.name}`,
128
- rule: 'extra-field',
129
- violationType: 'extra-field',
130
- schemas: [reference, current],
131
- fieldName,
132
- suggestion: `Remove field '${fieldName}' or add it to the reference schema`,
133
- analyzer: 'schema-validator',
134
- category: 'cross-language-schema'
135
- });
136
- }
137
- }
98
+ return violations;
99
+ }
100
+ /**
101
+ * Check for fields present in the current schema but missing from the reference.
102
+ */
103
+ checkExtraFields(refFields, curFields, reference, current) {
104
+ const violations = [];
105
+ if (this.options.allowAdditionalFields)
106
+ return violations;
107
+ for (const [fieldName] of curFields) {
108
+ if (refFields.has(fieldName))
109
+ continue;
110
+ violations.push({
111
+ file: current.file,
112
+ line: current.line,
113
+ severity: 'warning',
114
+ message: `Extra field '${fieldName}' in ${current.type} ${current.name}`,
115
+ rule: 'extra-field',
116
+ violationType: 'extra-field',
117
+ schemas: [reference, current],
118
+ fieldName,
119
+ suggestion: `Remove field '${fieldName}' or add it to the reference schema`,
120
+ analyzer: 'schema-validator',
121
+ category: 'cross-language-schema'
122
+ });
138
123
  }
139
- // Check field type compatibility
124
+ return violations;
125
+ }
126
+ /**
127
+ * Check type/constraint compatibility for fields present in both schemas.
128
+ */
129
+ checkFieldTypes(refFields, curFields, reference, current) {
130
+ const violations = [];
140
131
  for (const [fieldName, refField] of refFields) {
141
132
  const curField = curFields.get(fieldName);
142
- if (curField) {
143
- const typeViolation = this.compareFieldTypes(fieldName, refField, curField, reference, current);
144
- if (typeViolation)
145
- violations.push(typeViolation);
146
- const constraintViolations = this.compareFieldConstraints(fieldName, refField, curField, reference, current);
147
- violations.push(...constraintViolations);
148
- }
133
+ if (!curField)
134
+ continue;
135
+ const cmp = { fieldName, refField, curField, reference, current };
136
+ const typeViolation = this.compareFieldTypes(cmp);
137
+ if (typeViolation)
138
+ violations.push(typeViolation);
139
+ violations.push(...this.compareFieldConstraints(cmp));
149
140
  }
150
141
  return violations;
151
142
  }
@@ -183,8 +174,8 @@ export class SchemaValidator {
183
174
  checkVersionCompatibility(reference, current) {
184
175
  if (!reference.version || !current.version)
185
176
  return null;
186
- const refVersion = this.parseVersion(reference.version);
187
- const curVersion = this.parseVersion(current.version);
177
+ const refVersion = parseVersion(reference.version);
178
+ const curVersion = parseVersion(current.version);
188
179
  const compatible = this.areVersionsCompatible(refVersion, curVersion);
189
180
  if (!compatible) {
190
181
  return {
@@ -205,9 +196,10 @@ export class SchemaValidator {
205
196
  /**
206
197
  * Compare field types between schemas
207
198
  */
208
- compareFieldTypes(fieldName, refField, curField, refSchema, curSchema) {
209
- const normalizedRefType = this.normalizeType(refField.type, refSchema.language);
210
- const normalizedCurType = this.normalizeType(curField.type, curSchema.language);
199
+ compareFieldTypes(cmp) {
200
+ const { fieldName, refField, curField, reference: refSchema, current: curSchema } = cmp;
201
+ const normalizedRefType = normalizeType(refField.type, refSchema.language);
202
+ const normalizedCurType = normalizeType(curField.type, curSchema.language);
211
203
  if (this.options.strictTypeChecking) {
212
204
  if (normalizedRefType !== normalizedCurType) {
213
205
  return {
@@ -229,7 +221,7 @@ export class SchemaValidator {
229
221
  }
230
222
  else {
231
223
  // Loose type checking - check for compatibility
232
- if (!this.areTypesCompatible(normalizedRefType, normalizedCurType)) {
224
+ if (!areTypesCompatible(normalizedRefType, normalizedCurType)) {
233
225
  return {
234
226
  file: curSchema.file,
235
227
  line: curSchema.line,
@@ -252,7 +244,8 @@ export class SchemaValidator {
252
244
  /**
253
245
  * Compare field constraints
254
246
  */
255
- compareFieldConstraints(fieldName, refField, curField, refSchema, curSchema) {
247
+ compareFieldConstraints(cmp) {
248
+ const { fieldName, refField, curField, reference: refSchema, current: curSchema } = cmp;
256
249
  const violations = [];
257
250
  if (!refField.constraints || !curField.constraints)
258
251
  return violations;
@@ -301,7 +294,7 @@ export class SchemaValidator {
301
294
  const violations = [];
302
295
  for (const field of schema.fields) {
303
296
  // Check for consistent naming convention
304
- if (!this.isConsistentNaming(field.name, schema.language)) {
297
+ if (!isConsistentNaming(field.name, schema.language)) {
305
298
  violations.push({
306
299
  file: schema.file,
307
300
  line: schema.line,
@@ -311,7 +304,7 @@ export class SchemaValidator {
311
304
  violationType: 'field-mismatch',
312
305
  schemas: [schema],
313
306
  fieldName: field.name,
314
- suggestion: `Use ${this.getRecommendedNaming(field.name, schema.language)} naming convention`,
307
+ suggestion: `Use ${getRecommendedNaming(field.name, schema.language)} naming convention`,
315
308
  analyzer: 'schema-validator',
316
309
  category: 'cross-language-schema'
317
310
  });
@@ -319,90 +312,6 @@ export class SchemaValidator {
319
312
  }
320
313
  return violations;
321
314
  }
322
- /**
323
- * Group schemas by name
324
- */
325
- groupSchemasByName(schemas) {
326
- const groups = new Map();
327
- for (const schema of schemas) {
328
- const normalizedName = this.normalizeSchemaName(schema.name);
329
- if (!groups.has(normalizedName)) {
330
- groups.set(normalizedName, []);
331
- }
332
- groups.get(normalizedName).push(schema);
333
- }
334
- return groups;
335
- }
336
- /**
337
- * Normalize schema name for comparison
338
- */
339
- normalizeSchemaName(name) {
340
- return name.toLowerCase()
341
- .replace(/[-_]/g, '')
342
- .replace(/request|response|dto|model/g, '');
343
- }
344
- /**
345
- * Normalize type names across languages
346
- */
347
- normalizeType(type, language) {
348
- const typeMap = {
349
- 'typescript': {
350
- 'string': 'string',
351
- 'number': 'number',
352
- 'boolean': 'boolean',
353
- 'Date': 'datetime',
354
- 'any': 'any'
355
- },
356
- 'go': {
357
- 'string': 'string',
358
- 'int': 'number',
359
- 'int32': 'number',
360
- 'int64': 'number',
361
- 'float32': 'number',
362
- 'float64': 'number',
363
- 'bool': 'boolean',
364
- 'time.Time': 'datetime'
365
- },
366
- 'python': {
367
- 'str': 'string',
368
- 'int': 'number',
369
- 'float': 'number',
370
- 'bool': 'boolean',
371
- 'datetime': 'datetime'
372
- }
373
- };
374
- return typeMap[language]?.[type] || type;
375
- }
376
- /**
377
- * Check if types are compatible across languages
378
- */
379
- areTypesCompatible(type1, type2) {
380
- // Allow some common compatible types
381
- const compatibilityMatrix = {
382
- 'string': ['string'],
383
- 'number': ['number', 'integer', 'float'],
384
- 'boolean': ['boolean', 'bool'],
385
- 'datetime': ['datetime', 'timestamp', 'date'],
386
- 'any': ['any', 'object', 'interface{}']
387
- };
388
- for (const [baseType, compatibleTypes] of Object.entries(compatibilityMatrix)) {
389
- if (compatibleTypes.includes(type1) && compatibleTypes.includes(type2)) {
390
- return true;
391
- }
392
- }
393
- return type1 === type2;
394
- }
395
- /**
396
- * Parse version string
397
- */
398
- parseVersion(version) {
399
- const parts = version.replace(/^v/, '').split('.').map(Number);
400
- return {
401
- major: parts[0] || 0,
402
- minor: parts[1] || 0,
403
- patch: parts[2] || 0
404
- };
405
- }
406
315
  /**
407
316
  * Check if versions are compatible
408
317
  */
@@ -418,111 +327,241 @@ export class SchemaValidator {
418
327
  return true;
419
328
  }
420
329
  }
421
- /**
422
- * Check if field name follows language conventions
423
- */
424
- isConsistentNaming(fieldName, language) {
425
- switch (language) {
426
- case 'typescript':
427
- case 'javascript':
428
- return /^[a-z][a-zA-Z0-9]*$/.test(fieldName); // camelCase
429
- case 'go':
430
- return /^[A-Z][a-zA-Z0-9]*$/.test(fieldName); // PascalCase for exported
431
- case 'python':
432
- return /^[a-z][a-z0-9_]*$/.test(fieldName); // snake_case
433
- default:
434
- return true;
330
+ }
331
+ // ---------------------------------------------------------------------------
332
+ // Stateless utilities (pure functions — no validator state)
333
+ // ---------------------------------------------------------------------------
334
+ /**
335
+ * Group schemas by name
336
+ */
337
+ function groupSchemasByName(schemas) {
338
+ const groups = new Map();
339
+ for (const schema of schemas) {
340
+ const normalizedName = normalizeSchemaName(schema.name);
341
+ if (!groups.has(normalizedName)) {
342
+ groups.set(normalizedName, []);
435
343
  }
344
+ groups.get(normalizedName).push(schema);
436
345
  }
437
- /**
438
- * Get recommended naming convention
439
- */
440
- getRecommendedNaming(fieldName, language) {
441
- switch (language) {
442
- case 'typescript':
443
- case 'javascript':
444
- return 'camelCase';
445
- case 'go':
446
- return 'PascalCase';
447
- case 'python':
448
- return 'snake_case';
449
- default:
450
- return 'consistent';
346
+ return groups;
347
+ }
348
+ /**
349
+ * Normalize schema name for comparison
350
+ */
351
+ function normalizeSchemaName(name) {
352
+ return name.toLowerCase()
353
+ .replace(/[-_]/g, '')
354
+ .replace(/request|response|dto|model/g, '');
355
+ }
356
+ /**
357
+ * Normalize type names across languages
358
+ */
359
+ function normalizeType(type, language) {
360
+ const typeMap = {
361
+ 'typescript': {
362
+ 'string': 'string',
363
+ 'number': 'number',
364
+ 'boolean': 'boolean',
365
+ 'Date': 'datetime',
366
+ 'any': 'any'
367
+ },
368
+ 'go': {
369
+ 'string': 'string',
370
+ 'int': 'number',
371
+ 'int32': 'number',
372
+ 'int64': 'number',
373
+ 'float32': 'number',
374
+ 'float64': 'number',
375
+ 'bool': 'boolean',
376
+ 'time.Time': 'datetime'
377
+ },
378
+ 'python': {
379
+ 'str': 'string',
380
+ 'int': 'number',
381
+ 'float': 'number',
382
+ 'bool': 'boolean',
383
+ 'datetime': 'datetime'
384
+ }
385
+ };
386
+ return typeMap[language]?.[type] || type;
387
+ }
388
+ /**
389
+ * Check if types are compatible across languages
390
+ */
391
+ function areTypesCompatible(type1, type2) {
392
+ // Allow some common compatible types
393
+ const compatibilityMatrix = {
394
+ 'string': ['string'],
395
+ 'number': ['number', 'integer', 'float'],
396
+ 'boolean': ['boolean', 'bool'],
397
+ 'datetime': ['datetime', 'timestamp', 'date'],
398
+ 'any': ['any', 'object', 'interface{}']
399
+ };
400
+ for (const [baseType, compatibleTypes] of Object.entries(compatibilityMatrix)) {
401
+ if (compatibleTypes.includes(type1) && compatibleTypes.includes(type2)) {
402
+ return true;
451
403
  }
452
404
  }
453
- // Static methods for extracting schemas from different sources
454
- static extractTypeScriptInterface(entity) {
455
- if (entity.type !== 'interface')
456
- return null;
457
- return {
458
- id: entity.id,
459
- name: entity.name,
460
- type: 'typescript-interface',
461
- language: 'typescript',
462
- file: entity.file,
463
- line: entity.startLine || 0,
464
- fields: entity.parameters?.map(param => ({
465
- name: param.name,
466
- type: param.type || 'any',
467
- required: !param.optional,
468
- description: param.description
469
- })) || []
470
- };
471
- }
472
- static extractGoStruct(entity) {
473
- if (entity.type !== 'struct')
474
- return null;
475
- const fields = entity.metadata?.fields?.map((field) => ({
476
- name: field.name,
477
- type: field.type,
478
- required: field.isExported, // Simplified assumption
479
- description: field.tag
480
- })) || [];
481
- return {
482
- id: entity.id,
483
- name: entity.name,
484
- type: 'go-struct',
485
- language: 'go',
486
- file: entity.file,
487
- line: entity.startLine || 0,
488
- fields
489
- };
490
- }
491
- static extractProtobufMessage(entity) {
492
- // Simplified protobuf extraction
493
- return {
494
- id: entity.id,
495
- name: entity.name,
496
- type: 'protobuf',
497
- language: 'protobuf',
498
- file: entity.file,
499
- line: entity.startLine || 0,
500
- fields: [] // Would parse .proto file in real implementation
501
- };
405
+ return type1 === type2;
406
+ }
407
+ /**
408
+ * Parse version string
409
+ */
410
+ function parseVersion(version) {
411
+ const parts = version.replace(/^v/, '').split('.').map(Number);
412
+ return {
413
+ major: parts[0] || 0,
414
+ minor: parts[1] || 0,
415
+ patch: parts[2] || 0
416
+ };
417
+ }
418
+ /**
419
+ * Check if field name follows language conventions
420
+ */
421
+ function isConsistentNaming(fieldName, language) {
422
+ switch (language) {
423
+ case 'typescript':
424
+ case 'javascript':
425
+ return /^[a-z][a-zA-Z0-9]*$/.test(fieldName); // camelCase
426
+ case 'go':
427
+ return /^[A-Z][a-zA-Z0-9]*$/.test(fieldName); // PascalCase for exported
428
+ case 'python':
429
+ return /^[a-z][a-z0-9_]*$/.test(fieldName); // snake_case
430
+ default:
431
+ return true;
502
432
  }
503
- static extractGraphQLType(entity) {
504
- // Simplified GraphQL extraction
505
- return {
506
- id: entity.id,
507
- name: entity.name,
508
- type: 'graphql',
509
- language: 'graphql',
510
- file: entity.file,
511
- line: entity.startLine || 0,
512
- fields: [] // Would parse .graphql file in real implementation
513
- };
433
+ }
434
+ /**
435
+ * Get recommended naming convention
436
+ */
437
+ function getRecommendedNaming(fieldName, language) {
438
+ switch (language) {
439
+ case 'typescript':
440
+ case 'javascript':
441
+ return 'camelCase';
442
+ case 'go':
443
+ return 'PascalCase';
444
+ case 'python':
445
+ return 'snake_case';
446
+ default:
447
+ return 'consistent';
514
448
  }
515
- static extractJSONSchema(entity) {
516
- // Simplified JSON Schema extraction
517
- return {
518
- id: entity.id,
519
- name: entity.name,
520
- type: 'json-schema',
521
- language: 'json',
522
- file: entity.file,
523
- line: entity.startLine || 0,
524
- fields: [] // Would parse JSON schema in real implementation
525
- };
449
+ }
450
+ // ---------------------------------------------------------------------------
451
+ // Schema extraction (pure functions — no validator state)
452
+ // ---------------------------------------------------------------------------
453
+ /**
454
+ * Extract schema definitions from entities
455
+ * @param entities
456
+ * @returns
457
+ */
458
+ export function extractSchemas(entities) {
459
+ const schemas = [];
460
+ for (const entity of entities) {
461
+ // TypeScript interfaces
462
+ if (entity.language === 'typescript' && entity.type === 'interface') {
463
+ const schema = extractTypeScriptInterface(entity);
464
+ if (schema)
465
+ schemas.push(schema);
466
+ }
467
+ // Go structs
468
+ if (entity.language === 'go' && entity.type === 'struct') {
469
+ const schema = extractGoStruct(entity);
470
+ if (schema)
471
+ schemas.push(schema);
472
+ }
473
+ // Protocol buffer definitions
474
+ if (entity.file.endsWith('.proto')) {
475
+ const schema = extractProtobufMessage(entity);
476
+ if (schema)
477
+ schemas.push(schema);
478
+ }
479
+ // GraphQL types
480
+ if (entity.file.endsWith('.graphql') || entity.file.endsWith('.gql')) {
481
+ const schema = extractGraphQLType(entity);
482
+ if (schema)
483
+ schemas.push(schema);
484
+ }
485
+ // JSON Schema
486
+ if (entity.file.endsWith('.json') && entity.name.toLowerCase().includes('schema')) {
487
+ const schema = extractJSONSchema(entity);
488
+ if (schema)
489
+ schemas.push(schema);
490
+ }
526
491
  }
492
+ return schemas;
493
+ }
494
+ function extractTypeScriptInterface(entity) {
495
+ if (entity.type !== 'interface')
496
+ return null;
497
+ return {
498
+ id: entity.id,
499
+ name: entity.name,
500
+ type: 'typescript-interface',
501
+ language: 'typescript',
502
+ file: entity.file,
503
+ line: entity.startLine || 0,
504
+ fields: entity.parameters?.map(param => ({
505
+ name: param.name,
506
+ type: param.type || 'any',
507
+ required: !param.optional,
508
+ description: param.description
509
+ })) || []
510
+ };
511
+ }
512
+ function extractGoStruct(entity) {
513
+ if (entity.type !== 'struct')
514
+ return null;
515
+ const fields = entity.metadata?.fields?.map((field) => ({
516
+ name: field.name,
517
+ type: field.type,
518
+ required: field.isExported, // Simplified assumption
519
+ description: field.tag
520
+ })) || [];
521
+ return {
522
+ id: entity.id,
523
+ name: entity.name,
524
+ type: 'go-struct',
525
+ language: 'go',
526
+ file: entity.file,
527
+ line: entity.startLine || 0,
528
+ fields
529
+ };
530
+ }
531
+ function extractProtobufMessage(entity) {
532
+ // Simplified protobuf extraction
533
+ return {
534
+ id: entity.id,
535
+ name: entity.name,
536
+ type: 'protobuf',
537
+ language: 'protobuf',
538
+ file: entity.file,
539
+ line: entity.startLine || 0,
540
+ fields: [] // Would parse .proto file in real implementation
541
+ };
542
+ }
543
+ function extractGraphQLType(entity) {
544
+ // Simplified GraphQL extraction
545
+ return {
546
+ id: entity.id,
547
+ name: entity.name,
548
+ type: 'graphql',
549
+ language: 'graphql',
550
+ file: entity.file,
551
+ line: entity.startLine || 0,
552
+ fields: [] // Would parse .graphql file in real implementation
553
+ };
554
+ }
555
+ function extractJSONSchema(entity) {
556
+ // Simplified JSON Schema extraction
557
+ return {
558
+ id: entity.id,
559
+ name: entity.name,
560
+ type: 'json-schema',
561
+ language: 'json',
562
+ file: entity.file,
563
+ line: entity.startLine || 0,
564
+ fields: [] // Would parse JSON schema in real implementation
565
+ };
527
566
  }
528
567
  //# sourceMappingURL=SchemaValidator.js.map