Skip to content

Commit b5b7503

Browse files
committed
go types: update core-gen, core-init and go-init to be compatible with the new language specific system
1 parent ebd568c commit b5b7503

3 files changed

Lines changed: 296 additions & 92 deletions

File tree

json_explorer/codegen/core/__init__.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,27 @@
1717
from .templates import TemplateEngine, TemplateError, get_default_template_engine
1818

1919
__all__ = [
20-
# Base classes
20+
# Base generator interface
2121
"CodeGenerator",
2222
"GeneratorError",
2323
"GenerationResult",
24-
# Schema system
24+
"generate_code",
25+
# Schema system - core data structures
2526
"Schema",
2627
"Field",
2728
"FieldType",
2829
"convert_analyzer_output",
2930
"extract_all_schemas",
30-
# Naming utilities
31+
# Naming utilities - language-agnostic
3132
"NameSanitizer",
3233
"NamingCase",
33-
# Configuration
34+
# Configuration system
3435
"GeneratorConfig",
3536
"ConfigManager",
3637
"ConfigError",
3738
"load_config",
38-
# Templates
39+
# Template system
3940
"TemplateEngine",
4041
"TemplateError",
4142
"get_default_template_engine",
42-
# Main function
43-
"generate_code",
4443
]

json_explorer/codegen/core/generator.py

Lines changed: 107 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Base generator interface for all code generation targets.
33
44
Defines the contract that all language generators must implement.
5+
Focuses on schema-level concerns while leaving type mapping to language generators.
56
"""
67

78
from abc import ABC, abstractmethod
@@ -11,135 +12,162 @@
1112

1213
class GeneratorError(Exception):
1314
"""Base exception for code generation errors."""
15+
1416
pass
1517

1618

1719
class CodeGenerator(ABC):
1820
"""Abstract base class for all code generators."""
19-
21+
2022
def __init__(self, config: Optional[Dict[str, Any]] = None):
2123
"""Initialize generator with optional configuration."""
2224
self.config = config or {}
23-
25+
2426
@property
2527
@abstractmethod
2628
def language_name(self) -> str:
2729
"""Return the name of the target language (e.g., 'go', 'python')."""
2830
pass
29-
31+
3032
@property
3133
@abstractmethod
3234
def file_extension(self) -> str:
3335
"""Return the file extension for generated files (e.g., '.go', '.py')."""
3436
pass
35-
37+
3638
@abstractmethod
3739
def generate(self, schemas: Dict[str, Schema], root_schema_name: str) -> str:
3840
"""
3941
Generate code for all schemas.
40-
42+
4143
Args:
4244
schemas: Dictionary mapping schema names to Schema objects
4345
root_schema_name: Name of the main/root schema
44-
46+
4547
Returns:
4648
Generated code as a string
4749
"""
4850
pass
49-
51+
5052
@abstractmethod
5153
def generate_single_schema(self, schema: Schema) -> str:
5254
"""
5355
Generate code for a single schema.
54-
56+
5557
Args:
5658
schema: Schema to generate code for
57-
59+
5860
Returns:
5961
Generated code for this schema only
6062
"""
6163
pass
62-
63-
@abstractmethod
64-
def map_field_type(self, field: Field) -> str:
65-
"""
66-
Map a field to the target language's type system.
67-
68-
Args:
69-
field: Field to get type for
70-
71-
Returns:
72-
Type name in target language
73-
"""
74-
pass
75-
64+
7665
def get_import_statements(self, schemas: Dict[str, Schema]) -> List[str]:
7766
"""
7867
Get any required import statements for the generated code.
79-
68+
8069
Args:
8170
schemas: All schemas being generated
82-
71+
8372
Returns:
8473
List of import statements (can be empty)
8574
"""
8675
return []
87-
76+
8877
def get_package_declaration(self) -> Optional[str]:
8978
"""
9079
Get package/namespace declaration if needed.
91-
80+
9281
Returns:
9382
Package declaration string or None
9483
"""
9584
return None
96-
85+
9786
def validate_schemas(self, schemas: Dict[str, Schema]) -> List[str]:
9887
"""
99-
Validate schemas for this generator and return any warnings.
100-
88+
Validate schemas for basic structural issues.
89+
90+
Language generators should override this to add language-specific validation.
91+
10192
Args:
10293
schemas: Schemas to validate
103-
94+
10495
Returns:
10596
List of warning messages (empty if no issues)
10697
"""
10798
warnings = []
108-
99+
109100
for schema in schemas.values():
101+
# Check for empty schemas
102+
if not schema.fields:
103+
warnings.append(f"Schema '{schema.name}' has no fields")
104+
105+
# Check for schema-level conflicts and unknowns
110106
for field in schema.fields:
111107
if field.type == FieldType.CONFLICT:
108+
conflicting_type_names = (
109+
[t.value for t in field.conflicting_types]
110+
if field.conflicting_types
111+
else ["unknown"]
112+
)
112113
warnings.append(
113-
f"Type conflict in {schema.name}.{field.name}: "
114-
f"{[t.value for t in field.conflicting_types]}"
114+
f"Type conflict in {schema.name}.{field.name}: {conflicting_type_names}"
115115
)
116116
elif field.type == FieldType.UNKNOWN:
117+
warnings.append(f"Unknown type in {schema.name}.{field.name}")
118+
119+
# Check for missing nested schemas
120+
if field.type == FieldType.OBJECT and not field.nested_schema:
117121
warnings.append(
118-
f"Unknown type in {schema.name}.{field.name}"
122+
f"Object field {schema.name}.{field.name} has no nested schema"
119123
)
120-
124+
125+
# Check for array fields with unclear element types
126+
if field.type == FieldType.ARRAY:
127+
if not field.array_element_type and not field.array_element_schema:
128+
warnings.append(
129+
f"Array field {schema.name}.{field.name} has no element type information"
130+
)
131+
121132
return warnings
122-
133+
123134
def format_code(self, code: str) -> str:
124135
"""
125136
Apply language-specific formatting to generated code.
126-
137+
127138
Args:
128139
code: Raw generated code
129-
140+
130141
Returns:
131142
Formatted code
132143
"""
133-
return code # Default: no formatting
144+
# Basic cleanup - remove excessive blank lines
145+
lines = code.split("\n")
146+
formatted_lines = []
147+
blank_count = 0
148+
149+
for line in lines:
150+
stripped = line.rstrip()
151+
if not stripped:
152+
blank_count += 1
153+
if blank_count <= 2: # Allow max 2 consecutive blank lines
154+
formatted_lines.append("")
155+
else:
156+
blank_count = 0
157+
formatted_lines.append(stripped)
158+
159+
return "\n".join(formatted_lines)
134160

135161

136162
class GenerationResult:
137163
"""Container for generation results and metadata."""
138-
139-
def __init__(self, code: str, warnings: List[str] = None, metadata: Dict[str, Any] = None):
164+
165+
def __init__(
166+
self, code: str, warnings: List[str] = None, metadata: Dict[str, Any] = None
167+
):
140168
"""
141169
Initialize generation result.
142-
170+
143171
Args:
144172
code: Generated code
145173
warnings: Any warnings from generation
@@ -149,52 +177,70 @@ def __init__(self, code: str, warnings: List[str] = None, metadata: Dict[str, An
149177
self.warnings = warnings or []
150178
self.metadata = metadata or {}
151179
self.success = True
152-
180+
153181
@classmethod
154-
def error(cls, message: str, exception: Exception = None) -> 'GenerationResult':
182+
def error(cls, message: str, exception: Exception = None) -> "GenerationResult":
155183
"""Create a failed generation result."""
156184
result = cls(code="")
157185
result.success = False
158186
result.error_message = message
159187
result.exception = exception
160188
return result
161189

190+
def add_warning(self, warning: str):
191+
"""Add a warning to the result."""
192+
self.warnings.append(warning)
193+
194+
def add_metadata(self, key: str, value: Any):
195+
"""Add metadata to the result."""
196+
self.metadata[key] = value
197+
162198

163-
def generate_code(generator: CodeGenerator, schemas: Dict[str, Schema],
164-
root_schema_name: str) -> GenerationResult:
199+
def generate_code(
200+
generator: CodeGenerator, schemas: Dict[str, Schema], root_schema_name: str
201+
) -> GenerationResult:
165202
"""
166203
Generate code using the specified generator with error handling.
167-
204+
168205
Args:
169206
generator: Code generator instance
170207
schemas: Schemas to generate code for
171208
root_schema_name: Name of the root schema
172-
209+
173210
Returns:
174211
GenerationResult with code, warnings, and metadata
175212
"""
176213
try:
177-
# Validate schemas
214+
# Validate schemas at the base level
178215
warnings = generator.validate_schemas(schemas)
179-
216+
180217
# Generate code
181218
code = generator.generate(schemas, root_schema_name)
182-
219+
183220
# Format code
184221
formatted_code = generator.format_code(code)
185-
222+
186223
# Create metadata
187224
metadata = {
188225
"language": generator.language_name,
189226
"file_extension": generator.file_extension,
190227
"schema_count": len(schemas),
191-
"root_schema": root_schema_name
228+
"root_schema": root_schema_name,
229+
"has_conflicts": any(
230+
field.type == FieldType.CONFLICT
231+
for schema in schemas.values()
232+
for field in schema.fields
233+
),
234+
"has_unknowns": any(
235+
field.type == FieldType.UNKNOWN
236+
for schema in schemas.values()
237+
for field in schema.fields
238+
),
192239
}
193-
194-
return GenerationResult(formatted_code, warnings, metadata)
195-
240+
241+
result = GenerationResult(formatted_code, warnings, metadata)
242+
243+
return result
244+
196245
except Exception as e:
197-
return GenerationResult.error(
198-
f"Code generation failed: {str(e)}",
199-
exception=e
200-
)
246+
return GenerationResult.error(f"Code generation failed: {str(e)}", exception=e)

0 commit comments

Comments
 (0)