Skip to content

Commit 297fa32

Browse files
committed
Add comments
1 parent 0b5350a commit 297fa32

File tree

1 file changed

+30
-9
lines changed

1 file changed

+30
-9
lines changed

src/TypeScriptifyModel.php

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,13 @@ private function mapNativeCastToTypeScriptType(string $attribute): string {
185185
/**
186186
* Map a database column type to a TypeScript type.
187187
*
188-
* @param \Illuminate\Support\Stringable $columnType
188+
* @param string $columnType
189189
*
190190
* @return string
191191
*/
192-
private function mapDatabaseTypeToTypeScriptType(Stringable $columnType): string {
192+
private function mapDatabaseTypeToTypeScriptType(string $columnType): string {
193+
$columnType = Str::of($columnType);
194+
193195
return match (true) {
194196
$columnType->startsWith('bit') => 'number',
195197
$columnType->startsWith('int') => 'number',
@@ -280,8 +282,6 @@ private function convertForeignKeyToFullyQualifiedModelName(string $attribute):
280282
* @return string
281283
*/
282284
private function getTypeScriptType(stdClass $columnSchema): string {
283-
$columnType = Str::of($columnSchema->Type);
284-
285285
if ($this->isAttributeRelation($columnSchema->Field)) {
286286
$fullyQualifiedRelatedModelName = $this->convertForeignKeyToFullyQualifiedModelName($columnSchema->Field);
287287

@@ -294,6 +294,8 @@ private function getTypeScriptType(stdClass $columnSchema): string {
294294
// We generate new interfaces for any relational attributes.
295295
// That means we can recursively instantiate the current class to generate
296296
// as many interface definitions for relational attributes as we need.
297+
// We pass our existing convertedModelsMap instance here to prevent this class
298+
// mapping models we've already mapped in this current class instance.
297299
$mappedType = (new self($fullyQualifiedRelatedModelName, $this->convertedModelsMap))->generate();
298300
}
299301
} else {
@@ -302,7 +304,7 @@ private function getTypeScriptType(stdClass $columnSchema): string {
302304
// simply map the database type to a TypeScript type.
303305
$mappedType = $this->isAttributeNativelyCasted($columnSchema->Field)
304306
? $this->mapNativeCastToTypeScriptType($columnSchema->Field)
305-
: $this->mapDatabaseTypeToTypeScriptType($columnType);
307+
: $this->mapDatabaseTypeToTypeScriptType($columnSchema->Type);
306308
}
307309

308310
// We can't do much with an unknown type.
@@ -347,7 +349,11 @@ public function includeHidden(bool $includeHidden): self {
347349
public function generate(): string {
348350
$tableColumns = collect(DB::select(DB::raw('SHOW COLUMNS FROM ' . $this->model->getTable())));
349351

350-
$interfaceName = Str::of($this->fullyQualifiedModelName)->afterLast('\\')->toString();
352+
$interfaceName = Str::afterLast($this->fullyQualifiedModelName, '\\');
353+
354+
// At this point, we haven't technically generated the full TypeScript interface definition
355+
// for the target model. However, if the current model was to reference itself (which is valid),
356+
// without doing this here, it would cause an infinite loop.
351357
$this->convertedModelsMap[$this->fullyQualifiedModelName] = $interfaceName;
352358

353359
// The output buffer always needs to start with the first `interface X {` line.
@@ -361,24 +367,38 @@ public function generate(): string {
361367
$relationName = $this->convertForeignKeyToPredictedRelationName($columnSchema->Field);
362368
$generatedTypeScriptType = Str::of($this->getTypeScriptType($columnSchema));
363369

364-
$isRelationNewInterfaceDefinition = $generatedTypeScriptType->startsWith('interface ');
370+
// We know we've just generated a new interface if the generated TypeScript type
371+
// starts with 'interface '. If it doesn't, we'll be referring to a TypeScript type
372+
// that's been previously generated.
373+
$isRelationInterfaceDefinition = $generatedTypeScriptType->startsWith('interface ');
365374

366-
if ($isRelationNewInterfaceDefinition) {
375+
if ($isRelationInterfaceDefinition) {
376+
// interface User { => User
367377
$generatedInterfaceName = $generatedTypeScriptType
368378
->after('interface ')
369379
->before(' {');
370380

371381
$fullyQualifiedRelatedModelName = $this->convertForeignKeyToFullyQualifiedModelName($columnSchema->Field);
382+
// We've just generated a new interface, we'll want to make sure our class doesn't attempt to
383+
// generate it again by adding it to our convertedModelsMap.
372384
$this->convertedModelsMap[$fullyQualifiedRelatedModelName] = $generatedInterfaceName->toString();
373385

386+
// Columns aren't always required. To make sure we're not losing other type metadata,
387+
// we'll append everything after the end of the interface definition onto the new
388+
// interface name we've generated.
374389
$generatedType = $generatedInterfaceName->append($generatedTypeScriptType->afterLast('}'));
375390
} else {
391+
// If we don't have a new relation interface definition, we'll have the interface name definition,
392+
// retrieved from the convertedModelsMap (as well as any type metadata). We can use that value directly.
376393
$generatedType = $generatedTypeScriptType;
377394
}
378395

396+
// Append the relation to the interface we're generating.
379397
$outputBuffer->push(sprintf(' %s: %s;', $relationName, $generatedType));
380398

381-
if ($isRelationNewInterfaceDefinition) {
399+
// If we've generated a new interface, we'll want to append it above the current
400+
// interface we're in the process of generating.
401+
if ($isRelationInterfaceDefinition) {
382402
// Add an empty line so related interfaces aren't directly after each other.
383403
$outputBuffer->prepend('');
384404

@@ -395,6 +415,7 @@ public function generate(): string {
395415
->each(fn ($str) => $outputBuffer->prepend($str));
396416
}
397417
} else {
418+
// Append the column name, and the TypeScript type to the interface we're generating.
398419
$outputBuffer->push(sprintf(' %s: %s;', $columnSchema->Field, $this->getTypeScriptType($columnSchema)));
399420
}
400421
});

0 commit comments

Comments
 (0)