Parse and validate AT Protocol Lexicons with DTO generation for Laravel
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix generator imports and support for standalone object types

+77 -24
+38 -2
src/Generator/ClassGenerator.php
··· 88 88 // Get class components 89 89 $namespace = $this->extensions->filter('filter:class:namespace', $this->naming->nsidToNamespace($nsid), $document); 90 90 $className = $this->extensions->filter('filter:class:className', $this->naming->toClassName($document->id->getName()), $document); 91 - $useStatements = $this->extensions->filter('filter:class:useStatements', $this->collectUseStatements($recordDef, $namespace), $document, $recordDef); 91 + $useStatements = $this->extensions->filter('filter:class:useStatements', $this->collectUseStatements($recordDef, $namespace, $className), $document, $recordDef); 92 92 $properties = $this->extensions->filter('filter:class:properties', $this->generateProperties($recordDef), $document, $recordDef); 93 93 $constructor = $this->extensions->filter('filter:class:constructor', $this->generateConstructor($recordDef), $document, $recordDef); 94 94 $methods = $this->extensions->filter('filter:class:methods', $this->generateMethods($document), $document); ··· 213 213 * @param array<string, mixed> $definition 214 214 * @return array<string> 215 215 */ 216 - protected function collectUseStatements(array $definition, string $currentNamespace = ''): array 216 + protected function collectUseStatements(array $definition, string $currentNamespace = '', string $currentClassName = ''): array 217 217 { 218 218 $uses = ['SocialDept\\Schema\\Data\\Data']; 219 219 $properties = $definition['properties'] ?? []; 220 + $hasUnions = false; 221 + $localRefs = []; 220 222 221 223 foreach ($properties as $propDef) { 222 224 $propUses = $this->typeMapper->getUseStatements($propDef); 223 225 $uses = array_merge($uses, $propUses); 224 226 227 + // Check if this property uses unions 228 + if (isset($propDef['type']) && $propDef['type'] === 'union') { 229 + $hasUnions = true; 230 + } 231 + 232 + // Collect local references for import 233 + if (isset($propDef['type']) && $propDef['type'] === 'ref' && isset($propDef['ref'])) { 234 + $ref = $propDef['ref']; 235 + if (str_starts_with($ref, '#')) { 236 + $localRefs[] = ltrim($ref, '#'); 237 + } 238 + } 239 + 225 240 // Handle array items 226 241 if (isset($propDef['items'])) { 227 242 $itemUses = $this->typeMapper->getUseStatements($propDef['items']); 228 243 $uses = array_merge($uses, $itemUses); 244 + 245 + // Check for local refs in array items 246 + if (isset($propDef['items']['type']) && $propDef['items']['type'] === 'ref' && isset($propDef['items']['ref'])) { 247 + $ref = $propDef['items']['ref']; 248 + if (str_starts_with($ref, '#')) { 249 + $localRefs[] = ltrim($ref, '#'); 250 + } 251 + } 229 252 } 253 + } 254 + 255 + // Add local ref imports from nested namespace 256 + if (!empty($localRefs) && $currentNamespace && $currentClassName) { 257 + foreach ($localRefs as $localRef) { 258 + $refClassName = $this->naming->toClassName($localRef); 259 + $uses[] = $currentNamespace . '\\' . $currentClassName . '\\' . $refClassName; 260 + } 261 + } 262 + 263 + // Add UnionHelper if unions are used 264 + if ($hasUnions) { 265 + $uses[] = 'SocialDept\\Schema\\Support\\UnionHelper'; 230 266 } 231 267 232 268 // Remove duplicates and sort
+8 -1
src/Generator/DTOGenerator.php
··· 136 136 { 137 137 $generatedFiles = []; 138 138 139 - // Generate main class if it's a record 139 + // Generate main class if it's a record or object 140 + $mainDef = $document->getMainDefinition(); 141 + $mainType = $mainDef['type'] ?? null; 142 + 140 143 if ($document->isRecord()) { 144 + $file = $this->generateRecordClass($document, $options); 145 + $generatedFiles[] = $file; 146 + } elseif ($mainType === 'object') { 147 + // Generate for standalone object types (like strongRef) 141 148 $file = $this->generateRecordClass($document, $options); 142 149 $generatedFiles[] = $file; 143 150 }
+4 -4
src/Generator/MethodGenerator.php
··· 290 290 $variantsArray = '['.implode(', ', $variantClasses).']'; 291 291 292 292 if ($isRequired) { 293 - return "\\SocialDept\\Schema\\Support\\UnionHelper::resolveClosedUnion(\$data['{$name}'], {$variantsArray})"; 293 + return "UnionHelper::resolveClosedUnion(\$data['{$name}'], {$variantsArray})"; 294 294 } 295 295 296 - return "isset(\$data['{$name}']) ? \\SocialDept\\Schema\\Support\\UnionHelper::resolveClosedUnion(\$data['{$name}'], {$variantsArray}) : null"; 296 + return "isset(\$data['{$name}']) ? UnionHelper::resolveClosedUnion(\$data['{$name}'], {$variantsArray}) : null"; 297 297 } 298 298 299 299 // Open unions - validate $type presence using UnionHelper 300 300 if (! $isClosed) { 301 301 if ($isRequired) { 302 - return "\\SocialDept\\Schema\\Support\\UnionHelper::validateOpenUnion(\$data['{$name}'])"; 302 + return "UnionHelper::validateOpenUnion(\$data['{$name}'])"; 303 303 } 304 304 305 - return "isset(\$data['{$name}']) ? \\SocialDept\\Schema\\Support\\UnionHelper::validateOpenUnion(\$data['{$name}']) : null"; 305 + return "isset(\$data['{$name}']) ? UnionHelper::validateOpenUnion(\$data['{$name}']) : null"; 306 306 } 307 307 308 308 // Fallback for unions with only local refs
+27 -17
src/Generator/TypeMapper.php
··· 206 206 } 207 207 208 208 // Handle NSID fragments (e.g., com.atproto.label.defs#selfLabels) 209 - // Extract just the NSID part for class resolution 209 + // Convert fragment to class name 210 210 if (str_contains($ref, '#')) { 211 - $ref = explode('#', $ref)[0]; 211 + [$baseNsid, $fragment] = explode('#', $ref, 2); 212 + return $this->naming->toClassName($fragment); 212 213 } 213 214 214 215 // Convert NSID reference to fully qualified class name ··· 256 257 // Build union type with all variants 257 258 $types = []; 258 259 foreach ($externalRefs as $ref) { 259 - // Handle NSID fragments - extract just the NSID part 260 + // Handle NSID fragments - convert fragment to class name 260 261 if (str_contains($ref, '#')) { 261 - $ref = explode('#', $ref)[0]; 262 + [$baseNsid, $fragment] = explode('#', $ref, 2); 263 + $types[] = $this->naming->toClassName($fragment); 264 + } else { 265 + // Convert to fully qualified class name, then extract short name 266 + $fqcn = $this->naming->nsidToClassName($ref); 267 + $parts = explode('\\', $fqcn); 268 + $types[] = end($parts); 262 269 } 263 - 264 - // Convert to fully qualified class name, then extract short name 265 - $fqcn = $this->naming->nsidToClassName($ref); 266 - $parts = explode('\\', $fqcn); 267 - $types[] = end($parts); 268 270 } 269 271 270 272 // Return union type (e.g., "Theme|ThemeV2" or just "Theme" for single ref) ··· 298 300 continue; 299 301 } 300 302 301 - // Handle NSID fragments - extract just the NSID part 303 + // Handle NSID fragments - convert fragment to class name 302 304 if (str_contains($ref, '#')) { 303 - $ref = explode('#', $ref)[0]; 305 + [$baseNsid, $fragment] = explode('#', $ref, 2); 306 + $types[] = $this->naming->toClassName($fragment); 307 + continue; 304 308 } 305 309 306 310 // Convert to fully qualified class name, then extract short name ··· 412 416 return []; 413 417 } 414 418 415 - // Handle NSID fragments - extract just the NSID part 419 + // Handle NSID fragments - convert fragment to class name 416 420 if (str_contains($ref, '#')) { 417 - $ref = explode('#', $ref)[0]; 421 + [$baseNsid, $fragment] = explode('#', $ref, 2); 422 + $namespace = $this->naming->nsidToNamespace($baseNsid); 423 + $className = $this->naming->toClassName($fragment); 424 + return [$namespace . '\\' . $className]; 418 425 } 419 426 420 427 return [$this->naming->nsidToClassName($ref)]; ··· 436 443 continue; 437 444 } 438 445 439 - // Handle NSID fragments - extract just the NSID part 446 + // Handle NSID fragments - convert fragment to class name 440 447 if (str_contains($ref, '#')) { 441 - $ref = explode('#', $ref)[0]; 448 + [$baseNsid, $fragment] = explode('#', $ref, 2); 449 + $namespace = $this->naming->nsidToNamespace($baseNsid); 450 + $className = $this->naming->toClassName($fragment); 451 + $classes[] = $namespace . '\\' . $className; 452 + } else { 453 + $classes[] = $this->naming->nsidToClassName($ref); 442 454 } 443 - 444 - $classes[] = $this->naming->nsidToClassName($ref); 445 455 } 446 456 447 457 return $classes;