Skip to content

Commit

Permalink
Better testing and importing
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvanassche committed Aug 9, 2023
1 parent 658940e commit 0440e11
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 35 deletions.
6 changes: 4 additions & 2 deletions src/Actions/ConnectReferencesAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ public function execute(TransformedCollection $collection): ReferenceMap
return;
}

$metadata['references'][] = $reference;
$typeReference->connect($referenceMap->get($reference));
$transformed = $referenceMap->get($reference);

$metadata['references'][] = $transformed;
$typeReference->connect($transformed);
}, [TypeReference::class]);

foreach ($collection as $transformed) {
Expand Down
7 changes: 2 additions & 5 deletions src/Actions/ResolveModuleImportsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public function __construct(

public function execute(
Location $location,
ReferenceMap $referenceMap,
): ImportsCollection {
$collection = new ImportsCollection();

Expand All @@ -32,9 +31,7 @@ public function execute(
);

foreach ($location->transformed as $transformedItem) {
foreach ($transformedItem->references as $reference) {
$referencedTransformed = $referenceMap->get($reference);

foreach ($transformedItem->references as $referencedTransformed) {
if ($referencedTransformed->location === $location->segments) {
continue;
}
Expand Down Expand Up @@ -80,7 +77,7 @@ protected function resolveImportedName(
}

if (! in_array("{$name}Import", $usedNamesInScope)) {
return "{$name}Alt";
return "{$name}Import";
}

$counter = 2;
Expand Down
10 changes: 8 additions & 2 deletions src/Actions/ResolveRelativePathAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ public function execute(array $from, array $to): ?string
$relativeSegments[] = '..';
}

$hasSuffixedSegments = false;

for ($i = $commonDepth; $i < count($to); $i++) {
$relativeSegments[] = $to[$i];

$hasSuffixedSegments = true;
}

return implode('/', $relativeSegments);
}
$relativePath = implode('/', $relativeSegments);

return $hasSuffixedSegments ? $relativePath : $relativePath.'/';
}
}
10 changes: 8 additions & 2 deletions src/Collections/ImportsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,15 @@ public function getIterator(): Traversable
*/
public function getTypeScriptNodes(): array
{
return array_map(
return array_values(array_map(
fn (ImportLocation $import) => $import->toTypeScriptNode(),
$this->imports,
);
));
}

/** @return array<ImportLocation> */
public function toArray(): array
{
return array_values($this->imports);
}
}
7 changes: 1 addition & 6 deletions src/Support/ImportLocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ public function toTypeScriptNode(): ?TypeScriptImport
return null;
}

$names = array_unique(array_map(
fn (ImportName $name) => (string) $name,
$this->importNames,
));

return new TypeScriptImport($this->relativePath, $names);
return new TypeScriptImport($this->relativePath, $this->importNames);
}
}
17 changes: 17 additions & 0 deletions src/Support/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Spatie\TypeScriptTransformer\Support;

use Spatie\TypeScriptTransformer\References\Reference;
use Spatie\TypeScriptTransformer\Transformed\Transformed;

class Location
Expand All @@ -15,4 +16,20 @@ public function __construct(
public array $transformed,
) {
}

public function getTransformedByReference(Reference $reference): ?Transformed
{
foreach ($this->transformed as $transformed) {
if ($transformed->reference->getKey() === $reference->getKey()) {
return $transformed;
}
}

return null;
}

public function hasReference(Reference $reference): bool
{
return $this->getTransformedByReference($reference) !== null;
}
}
3 changes: 1 addition & 2 deletions src/Transformed/Transformed.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Transformed

/**
* @param array<string> $location
* @param array<Reference> $references
* @param array<Transformed> $references
*/
public function __construct(
public TypeScriptNode $typeScriptNode,
Expand All @@ -26,7 +26,6 @@ public function __construct(
) {
}


public function getName(): ?string
{
if (isset($this->name)) {
Expand Down
15 changes: 4 additions & 11 deletions src/Writers/ModuleWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@
namespace Spatie\TypeScriptTransformer\Writers;

use Spatie\TypeScriptTransformer\Actions\ResolveModuleImportsAction;
use Spatie\TypeScriptTransformer\Actions\ResolveRelativePathAction;
use Spatie\TypeScriptTransformer\Actions\SplitTransformedPerLocationAction;
use Spatie\TypeScriptTransformer\Collections\ReferenceMap;
use Spatie\TypeScriptTransformer\References\Reference;
use Spatie\TypeScriptTransformer\Support\ImportName;
use Spatie\TypeScriptTransformer\Support\Location;
use Spatie\TypeScriptTransformer\Support\TransformedCollection;
use Spatie\TypeScriptTransformer\Support\WriteableFile;
use Spatie\TypeScriptTransformer\Support\WritingContext;
use Spatie\TypeScriptTransformer\Transformed\Transformed;
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptImport;

class ModuleWriter implements Writer
{
Expand Down Expand Up @@ -43,15 +39,12 @@ protected function writeLocation(
Location $location,
ReferenceMap $referenceMap,
): WriteableFile {
$imports = $this->resolveModuleImportsAction->execute(
$location,
$referenceMap,
);
$imports = $this->resolveModuleImportsAction->execute($location);

$output = '';

$writingContext = new WritingContext(function (Reference $reference) use ($referenceMap, $imports) {
if($name = $imports->getAliasOrNameForReference($reference)){
$writingContext = new WritingContext(function (Reference $reference) use ($location, $referenceMap, $imports) {
if ($name = $imports->getAliasOrNameForReference($reference)) {
return $name;
}

Expand All @@ -63,7 +56,7 @@ protected function writeLocation(
$output .= $import->write($writingContext);
}

if($imports->isEmpty() === false){
if ($imports->isEmpty() === false) {
$output .= PHP_EOL;
}

Expand Down
120 changes: 120 additions & 0 deletions tests/Actions/ResolveModuleImportsActionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

use Spatie\TypeScriptTransformer\Actions\ResolveModuleImportsAction;
use Spatie\TypeScriptTransformer\Support\ImportLocation;
use Spatie\TypeScriptTransformer\Support\ImportName;
use Spatie\TypeScriptTransformer\Support\Location;
use Spatie\TypeScriptTransformer\Tests\Factories\TransformedFactory;
use Spatie\TypeScriptTransformer\TypeScript\TypeReference;
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptImport;
use Spatie\TypeScriptTransformer\TypeScript\TypeScriptString;

beforeEach(function () {
$this->action = new ResolveModuleImportsAction();
});

it('wont resolve imports when types are in the same module', function () {
$location = new Location([], [
$reference = TransformedFactory::alias('A', new TypeScriptString())->build(),
TransformedFactory::alias('B', new TypeReference($reference->reference), references: [
$reference,
])->build(),
]);

expect($this->action->execute($location)->isEmpty())->toBe(true);
});

it('will import a type from another module', function () {
$nestedReference = TransformedFactory::alias('Nested', new TypeScriptString(), location: ['parent', 'level', 'nested'])->build();
$parentReference = TransformedFactory::alias('Parent', new TypeScriptString(), location: ['parent'])->build();
$deeperParent = TransformedFactory::alias('DeeperParent', new TypeScriptString(), location: ['parent', 'deeper'])->build();
$rootReference = TransformedFactory::alias('Root', new TypeScriptString(), location: [])->build();

$location = new Location(['parent', 'level'], [
TransformedFactory::alias('Type', new TypeScriptString(), references: [
$nestedReference,
$parentReference,
$deeperParent,
$rootReference,
])->build(),
]);

$imports = $this->action->execute($location);

expect($imports->toArray())
->toHaveCount(4)
->each->toBeInstanceOf(ImportLocation::class);

expect($imports->getTypeScriptNodes())->toEqual([
new TypeScriptImport('nested', [new ImportName('Nested', $nestedReference->reference)]),
new TypeScriptImport('../', [new ImportName('Parent', $parentReference->reference)]),
new TypeScriptImport('../deeper', [new ImportName('DeeperParent', $deeperParent->reference)]),
new TypeScriptImport('../../', [new ImportName('Root', $rootReference->reference)]),
]);
});

it('wont import the same type twice', function () {
$nestedReference = TransformedFactory::alias('Nested', new TypeScriptString(), location: ['nested'])->build();

$location = new Location([], [
TransformedFactory::alias('TypeA', new TypeScriptString(), references: [
$nestedReference,
])->build(),
TransformedFactory::alias('TypeB', new TypeScriptString(), references: [
$nestedReference,
])->build(),
]);

$imports = $this->action->execute($location);

expect($imports->toArray())
->toHaveCount(1)
->each->toBeInstanceOf(ImportLocation::class);

expect($imports->getTypeScriptNodes())->toEqual([
new TypeScriptImport('nested', [new ImportName('Nested', $nestedReference->reference)]),
]);
});

it('will alias a reference if it is already in the module', function (){
$nestedCollection = TransformedFactory::alias('Collection', new TypeScriptString(), location: ['nested'])->build();

$location = new Location([], [
TransformedFactory::alias('Collection', new TypeScriptString(), references: [
$nestedCollection,
])->build(),
]);

$imports = $this->action->execute($location);

expect($imports->toArray())
->toHaveCount(1)
->each->toBeInstanceOf(ImportLocation::class);

expect($imports->getTypeScriptNodes())->toEqual([
new TypeScriptImport('nested', [new ImportName('Collection', $nestedCollection->reference, 'CollectionImport')]),
]);
});

it('will alias a reference if it is already in the module and already aliased by another import', function (){
$nestedCollection = TransformedFactory::alias('Collection', new TypeScriptString(), location: ['nested'])->build();
$otherNestedCollection = TransformedFactory::alias('Collection', new TypeScriptString(), location: ['otherNested'])->build();

$location = new Location([], [
TransformedFactory::alias('Collection', new TypeScriptString(), references: [
$nestedCollection,
$otherNestedCollection,
])->build(),
]);

$imports = $this->action->execute($location);

expect($imports->toArray())
->toHaveCount(2)
->each->toBeInstanceOf(ImportLocation::class);

expect($imports->getTypeScriptNodes())->toEqual([
new TypeScriptImport('nested', [new ImportName('Collection', $nestedCollection->reference, 'CollectionImport')]),
new TypeScriptImport('otherNested', [new ImportName('Collection', $otherNestedCollection->reference, 'CollectionImport2')]),
]);
});
5 changes: 5 additions & 0 deletions tests/Actions/ResolveRelativePathActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
['a', 'b', 'c', 'd'],
['a', 'b', 'e', 'd'],
'../../e/d'
],
[
['a', 'b'],
['a'],
'../'
]
]
);
9 changes: 8 additions & 1 deletion tests/Factories/TransformedFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@ public static function alias(
?Reference $reference = null,
?array $location = null,
bool $export = true,
?array $references = null,
): TransformedFactory {
$reference = $reference ?? new CustomReference(
'factory_alias',
($location !== null ? implode('.', $location) : '').Str::slug($name)
);

return new self(
typeScriptNode: new TypeScriptAlias(new TypeScriptIdentifier($name), $typeScriptNode),
reference: $reference ?? new CustomReference('factory_alias', Str::slug($name)),
reference: $reference,
location: $location,
export: $export,
references: $references
);
}

Expand Down
39 changes: 35 additions & 4 deletions tests/Writers/ModuleWriterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@
expect($files[0])
->path->toBe($this->path.'/index.ts')
->contents->toBe(<<<TypeScript
import { A } from './nested';
import { B } from './nested/subNested';
import { A } from 'nested';
import { B } from 'nested/subNested';
export type C = {
a: A
Expand Down Expand Up @@ -158,7 +158,7 @@
expect($files[0])
->path->toBe($this->path.'/index.ts')
->contents->toBe(<<<TypeScript
import { A, B } from './nested';
import { A, B } from 'nested';
export type C = {
a: A
Expand Down Expand Up @@ -197,9 +197,40 @@
expect($files[1])
->path->toBe($this->path.'/nested/index.ts')
->contents->toBe(<<<'TypeScript'
import { A } from './..';
import { A } from '../';
export type B = A;

TypeScript);
});

it('can automatically alias imported types', function () {
$reference = new CustomReference('test', 'A');

$transformedCollection = new TransformedCollection([
TransformedFactory::alias('A', new TypeScriptString(), reference: $reference)->build(),
TransformedFactory::alias('A', new TypeReference($reference), location: ['nested'])->build(),
]);

$files = $this->writer->output(
$transformedCollection,
(new ConnectReferencesAction())->execute($transformedCollection),
);

expect($files)
->toHaveCount(2)
->each->toBeInstanceOf(WriteableFile::class);

expect($files[0])
->path->toBe($this->path.'/index.ts')
->contents->toBe('export type A = string;'.PHP_EOL);

expect($files[1])
->path->toBe($this->path.'/nested/index.ts')
->contents->toBe(<<<'TypeScript'
import { A as AImport } from '../';
export type A = AImport;

TypeScript);
});

0 comments on commit 0440e11

Please sign in to comment.