code-auditor-mcp 3.4.12 → 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.
- package/CHANGELOG.md +46 -1
- package/dist/analyzers/__verify_self_probe.d.ts +2 -0
- package/dist/analyzers/__verify_self_probe.d.ts.map +1 -0
- package/dist/analyzers/__verify_self_probe.js +5 -0
- package/dist/analyzers/__verify_self_probe.js.map +1 -0
- package/dist/analyzers/analyzerUtils.d.ts +34 -1
- package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.js +61 -22
- package/dist/analyzers/analyzerUtils.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +18 -23
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.js +198 -186
- package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +78 -55
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js +244 -243
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts +27 -37
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js +314 -275
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +17 -46
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +620 -523
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
- package/dist/analyzers/documentationAnalyzer.d.ts +7 -2
- package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/documentationAnalyzer.js +259 -198
- package/dist/analyzers/documentationAnalyzer.js.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.js +57 -50
- package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
- package/dist/analyzers/orm/adapterRegistry.d.ts +10 -0
- package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -1
- package/dist/analyzers/orm/adapterRegistry.js +10 -0
- package/dist/analyzers/orm/adapterRegistry.js.map +1 -1
- package/dist/analyzers/orm/drizzleAdapter.d.ts +22 -0
- package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -1
- package/dist/analyzers/orm/drizzleAdapter.js +42 -44
- package/dist/analyzers/orm/drizzleAdapter.js.map +1 -1
- package/dist/analyzers/orm/prismaAdapter.d.ts +30 -0
- package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -1
- package/dist/analyzers/orm/prismaAdapter.js +30 -0
- package/dist/analyzers/orm/prismaAdapter.js.map +1 -1
- package/dist/analyzers/provenance.d.ts +62 -2
- package/dist/analyzers/provenance.d.ts.map +1 -1
- package/dist/analyzers/provenance.js +443 -349
- package/dist/analyzers/provenance.js.map +1 -1
- package/dist/analyzers/reactAnalyzer.d.ts +11 -0
- package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +188 -125
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.d.ts +110 -1
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +1714 -124
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/ruleTiming.d.ts +54 -0
- package/dist/analyzers/ruleTiming.d.ts.map +1 -0
- package/dist/analyzers/ruleTiming.js +71 -0
- package/dist/analyzers/ruleTiming.js.map +1 -0
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +13 -0
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +362 -283
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +26 -68
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +430 -391
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +17 -202
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +1073 -1121
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -49
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +414 -340
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +48 -5
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +262 -134
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +23 -214
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +139 -1521
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +78 -79
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +613 -480
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts +307 -0
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/codeAnalysis.js +965 -0
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -0
- package/dist/analyzers/universal/schema/config.d.ts +31 -0
- package/dist/analyzers/universal/schema/config.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/config.js +57 -0
- package/dist/analyzers/universal/schema/config.js.map +1 -0
- package/dist/analyzers/universal/schema/discovery.d.ts +167 -0
- package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/discovery.js +616 -0
- package/dist/analyzers/universal/schema/discovery.js.map +1 -0
- package/dist/analyzers/universal/schema/jsonSchema.d.ts +27 -0
- package/dist/analyzers/universal/schema/jsonSchema.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/jsonSchema.js +368 -0
- package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -0
- package/dist/analyzers/universal/schema/migrations.d.ts +90 -0
- package/dist/analyzers/universal/schema/migrations.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/migrations.js +238 -0
- package/dist/analyzers/universal/schema/migrations.js.map +1 -0
- package/dist/analyzers/universal/schema/types.d.ts +131 -0
- package/dist/analyzers/universal/schema/types.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/types.js +10 -0
- package/dist/analyzers/universal/schema/types.js.map +1 -0
- package/dist/analyzers/universal/schema/violations.d.ts +44 -0
- package/dist/analyzers/universal/schema/violations.d.ts.map +1 -0
- package/dist/analyzers/universal/schema/violations.js +54 -0
- package/dist/analyzers/universal/schema/violations.js.map +1 -0
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +89 -13
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.js +315 -40
- package/dist/cli.js.map +1 -1
- package/dist/config/configLoader.d.ts.map +1 -1
- package/dist/config/configLoader.js +9 -7
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/defaults.d.ts +12 -3
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +15 -5
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts +75 -0
- package/dist/config/effectiveConfig.d.ts.map +1 -0
- package/dist/config/effectiveConfig.js +213 -0
- package/dist/config/effectiveConfig.js.map +1 -0
- package/dist/config/pathProfiles.d.ts +7 -4
- package/dist/config/pathProfiles.d.ts.map +1 -1
- package/dist/config/pathProfiles.js +8 -10
- package/dist/config/pathProfiles.js.map +1 -1
- package/dist/config/thresholdRationales.d.ts +45 -0
- package/dist/config/thresholdRationales.d.ts.map +1 -0
- package/dist/config/thresholdRationales.js +67 -0
- package/dist/config/thresholdRationales.js.map +1 -0
- package/dist/conventions/conventionMiner.d.ts.map +1 -1
- package/dist/conventions/conventionMiner.js +6 -2
- package/dist/conventions/conventionMiner.js.map +1 -1
- package/dist/enforcement/diffGate.d.ts +55 -0
- package/dist/enforcement/diffGate.d.ts.map +1 -0
- package/dist/enforcement/diffGate.js +136 -0
- package/dist/enforcement/diffGate.js.map +1 -0
- package/dist/enforcement/gate.d.ts +36 -0
- package/dist/enforcement/gate.d.ts.map +1 -0
- package/dist/enforcement/gate.js +72 -0
- package/dist/enforcement/gate.js.map +1 -0
- package/dist/enforcement/suppressions.d.ts +41 -0
- package/dist/enforcement/suppressions.d.ts.map +1 -0
- package/dist/enforcement/suppressions.js +170 -0
- package/dist/enforcement/suppressions.js.map +1 -0
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +4 -1
- package/dist/fingerprint.js.map +1 -1
- package/dist/invariants/ruleEngine.d.ts +3 -4
- package/dist/invariants/ruleEngine.d.ts.map +1 -1
- package/dist/invariants/ruleEngine.js +2 -2
- package/dist/invariants/ruleEngine.js.map +1 -1
- package/dist/languages/LanguageOrchestrator.d.ts +14 -0
- package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.js +93 -55
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/LanguageRegistry.d.ts +8 -0
- package/dist/languages/LanguageRegistry.d.ts.map +1 -1
- package/dist/languages/LanguageRegistry.js +8 -0
- package/dist/languages/LanguageRegistry.js.map +1 -1
- package/dist/languages/RuntimeManager.d.ts +82 -60
- package/dist/languages/RuntimeManager.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.js +404 -349
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/UniversalAnalyzer.d.ts +51 -6
- package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
- package/dist/languages/UniversalAnalyzer.js +127 -88
- package/dist/languages/UniversalAnalyzer.js.map +1 -1
- package/dist/languages/adapterBridge.d.ts +36 -0
- package/dist/languages/adapterBridge.d.ts.map +1 -1
- package/dist/languages/adapterBridge.js +89 -35
- package/dist/languages/adapterBridge.js.map +1 -1
- package/dist/languages/go/GoAdapter.d.ts +66 -23
- package/dist/languages/go/GoAdapter.d.ts.map +1 -1
- package/dist/languages/go/GoAdapter.js +553 -474
- package/dist/languages/go/GoAdapter.js.map +1 -1
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +33 -4
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +101 -66
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
- package/dist/languages/tree-sitter/converter.d.ts +18 -0
- package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
- package/dist/languages/tree-sitter/converter.js +18 -0
- package/dist/languages/tree-sitter/converter.js.map +1 -1
- package/dist/languages/tree-sitter/parser.d.ts +39 -2
- package/dist/languages/tree-sitter/parser.d.ts.map +1 -1
- package/dist/languages/tree-sitter/parser.js +93 -12
- package/dist/languages/tree-sitter/parser.js.map +1 -1
- package/dist/languages/types.d.ts +67 -2
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +253 -72
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +1419 -923
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/pipeline.d.ts +13 -5
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +381 -200
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +3 -8
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +149 -94
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/presets/presets.d.ts +54 -0
- package/dist/presets/presets.d.ts.map +1 -0
- package/dist/presets/presets.js +181 -0
- package/dist/presets/presets.js.map +1 -0
- package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.js +0 -2
- package/dist/reporting/sarifReportGenerator.js.map +1 -1
- package/dist/ruleAliases.d.ts +67 -0
- package/dist/ruleAliases.d.ts.map +1 -0
- package/dist/ruleAliases.js +79 -0
- package/dist/ruleAliases.js.map +1 -0
- package/dist/styles/cssAstExtractor.d.ts.map +1 -1
- package/dist/styles/cssAstExtractor.js +78 -18
- package/dist/styles/cssAstExtractor.js.map +1 -1
- package/dist/styles/styleIndexer.js +10 -1
- package/dist/styles/styleIndexer.js.map +1 -1
- package/dist/styles/tailwindConfigLoader.d.ts +8 -6
- package/dist/styles/tailwindConfigLoader.d.ts.map +1 -1
- package/dist/styles/tailwindConfigLoader.js +61 -15
- package/dist/styles/tailwindConfigLoader.js.map +1 -1
- package/dist/styles/tailwindUtilityExpander.d.ts.map +1 -1
- package/dist/styles/tailwindUtilityExpander.js +13 -1
- package/dist/styles/tailwindUtilityExpander.js.map +1 -1
- package/dist/types.d.ts +181 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -3
- package/plugin/hooks/hooks.json +1 -1
- package/plugin/scripts/hook-audit.sh +25 -7
- 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 =
|
|
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
|
-
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
violations.push(
|
|
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 =
|
|
187
|
-
const curVersion =
|
|
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(
|
|
209
|
-
const
|
|
210
|
-
const
|
|
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 (!
|
|
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(
|
|
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 (!
|
|
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 ${
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|