8000 [AssetMapper] Allowing simple, relative "path" values in importmap.php · symfony/symfony@a17396c · GitHub
[go: up one dir, main page]

Skip to content

Commit a17396c

Browse files
committed
[AssetMapper] Allowing simple, relative "path" values in importmap.php
1 parent 89be5a4 commit a17396c

File tree

5 files changed

+121
-12
lines changed

5 files changed

+121
-12
lines changed

src/Symfony/Component/AssetMapper/ImportMap/ImportMapConfigReader.php

+5
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,9 @@ public function writeEntries(ImportMapEntries $entries): void
107107
108108
EOF);
109109
}
110+
111+
public function getRootDirectory(): string
112+
{
113+
return dirname($this->importMapConfigPath);
114+
}
110115
}

src/Symfony/Component/AssetMapper/ImportMap/ImportMapEntry.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
final class ImportMapEntry
2020
{
2121
public function __construct(
22+
public readonly string $importName,
2223
/**
23-
* The logical path to this asset if local or downloaded.
24+
* The path to the asset if local or downloaded.
2425
*/
25-
public readonly string $importName,
2626
public readonly ?string $path = null,
2727
public readonly ?string $url = null,
2828
public readonly bool $isDownloaded = false,

src/Symfony/Component/AssetMapper/ImportMap/ImportMapManager.php

+31-10
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public function downloadMissingPackages(): array
108108
$downloadedPackages = [];
109109

110110
foreach ($entries as $entry) {
111-
if (!$entry->isDownloaded || $this->assetMapper->getAsset($entry->path)) {
111+
if (!$entry->isDownloaded || $this->findAsset($entry->path)) {
112112
continue;
113113
}
114114

@@ -230,7 +230,7 @@ public function getRawImportMapData(): array
230230
$rawImportMapData = [];
231231
foreach ($allEntries as $entry) {
232232
if ($entry->path) {
233-
$asset = $this->assetMapper->getAsset($entry->path);
233+
$asset = $this->findAsset($entry->path);
234234

235235
if (!$asset) {
236236
if ($entry->isDownloaded) {
@@ -330,11 +330,14 @@ private function requirePackages(array $packagesToRequire, ImportMapEntries $imp
330330
}
331331

332332
$path = $requireOptions->path;
333-
if (is_file($path)) {
334-
$path = $this->assetMapper->getAssetFromSourcePath($path)?->logicalPath;
335-
if (null === $path) {
336-
throw new \LogicException(sprintf('The path "%s" of the package "%s" cannot be found in any asset map paths.', $requireOptions->path, $requireOptions->packageName));
337-
}
333+
if (!$this->findAsset($path)) {
334+
throw new \LogicException(sprintf('The path "%s" of the package "%s" cannot be found: either pass the logical name of the asset or a relative path starting with "./".', $requireOptions->path, $requireOptions->packageName));
335+
}
336+
6D4E 337+
// convert absolute paths to relative if possible
338+
$rootImportMapDir = $this->importMapConfigReader->getRootDirectory();
339+
if (str_starts_with($path, $rootImportMapDir)) {
340+
$path = './'.substr($path, \strlen($rootImportMapDir) + 1);
338341
}
339342

340343
$newEntry = new ImportMapEntry(
@@ -384,7 +387,7 @@ private function cleanupPackageFiles(ImportMapEntry $entry): void
384387
return;
385388
}
386389

387-
$asset = $this->assetMapper->getAsset($entry->path);
390+
$asset = $this->findAsset($entry->path);
388391

389392
if (!$asset) {
390393
throw new \LogicException(sprintf('The path "%s" of the package "%s" cannot be found in any as 9E7A set map paths.', $entry->path, $entry->importName));
@@ -418,7 +421,7 @@ private function addImplicitEntries(ImportMapEntry $entry, array $currentImportE
418421
return $currentImportEntries;
419422
}
420423

421-
if (!$asset = $this->assetMapper->getAsset($entry->path)) {
424+
if (!$asset = $this->findAsset($entry->path)) {
422425
// should only be possible at this point for root importmap.php entries
423426
throw new \InvalidArgumentException(sprintf('The asset "%s" mentioned in "importmap.php" cannot be found in any asset map paths.', $entry->path));
424427
}
@@ -498,7 +501,7 @@ private function findEagerEntrypointImports(string $entryName): array
498501
throw new \InvalidArgumentException(sprintf('The entrypoint "%s" is a remote package and cannot be used as an entrypoint.', $entryName));
499502
}
500503

501-
$asset = $this->assetMapper->getAsset($rootImportEntries->get($entryName)->path);
504+
$asset = $this->findAsset($rootImportEntries->get($entryName)->path);
502505
if (!$asset) {
503506
throw new \InvalidArgumentException(sprintf('The path "%s" of the entrypoint "%s" mentioned in "importmap.php" cannot be found in any asset map paths.', $rootImportEntries->get($entryName)->path, $entryName));
504507
}
@@ -529,4 +532,22 @@ private static function getImportMapTypeFromFilename(string $path): ImportMapTyp
529532
{
530533
return str_ends_with($path, '.css F438 ') ? ImportMapType::CSS : ImportMapType::JS;
531534
}
535+
536+
/**
537+
* Finds the MappedAsset allowing for a "logical path", relative or absolute filesystem path.
538+
*/
539+
private function findAsset(string $path): ?MappedAsset
540+
{
541+
if (str_starts_with($path, '/')) {
542+
return $this->assetMapper->getAssetFromSourcePath($path);
543+
}
544+
545+
if (str_starts_with($path, '.')) {
546+
$path = $this->importMapConfigReader->getRootDirectory().'/'.$path;
547+
548+
return $this->assetMapper->getAssetFromSourcePath($path);
549+
}
550+
551+
return $this->assetMapper->getAsset($path);
552+
}
532553
}

src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapConfigReaderTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,10 @@ public function testGetEntriesAndWriteEntries()
102102

103103
$this->assertSame($originalImportMapData, $newImportMapData);
104104
}
105+
106+
public function testGetRootDirectory()
107+
{
108+
$configReader = new ImportMapConfigReader(__DIR__.'/../fixtures/importmap.php');
109+
$this->assertSame(__DIR__.'/../fixtures', $configReader->getRootDirectory());
110+
}
105111
}

src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapManagerTest.php

+77
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public function testGetRawImportMapData(array $importMapEntries, array $mappedAs
6565
$manager = $this->createImportMapManager();
6666
$this->mockImportMap($importMapEntries);
6767
$this->mockAssetMapper($mappedAssets);
68+
$this->configReader->expects($this->any())
69+
->method('getRootDirectory')
70+
->willReturn('/fake/root');
6871

6972
$this->assertEquals($expectedData, $manager->getRawImportMapData());
7073
}
@@ -304,6 +307,51 @@ public function getRawImportMapDataTests(): iterable
304307
],
305308
],
306309
];
310+
311+
yield 'it handles a relative path file' => [
312+
[
313+
new ImportMapEntry(
314+
'app',
315+
path: './assets/app.js',
316+
),
317+
],
318+
[
319+
// key is the mocked "source" path - /fake/root is the
320+
// mocked root directory
321+
'/fake/root/assets/app.js' => new MappedAsset(
322+
'app.js',
323+
publicPath: '/assets/app.js',
324+
),
325+
],
326+
[
327+
'app' => [
328+
'path' => '/assets/app.js',
329+
'type' => 'js',
330+
],
331+
],
332+
];
333+
334+
yield 'it handles an absolute path file' => [
335+
[
336+
new ImportMapEntry(
337+
'app',
338+
path: '/some/path/assets/app.js',
339+
),
340+
],
341+
[
342+
// key is the mocked "source" path
343+
'/some/path/assets/app.js' => new MappedAsset(
344+
'app.js',
345+
publicPath: '/assets/app.js',
346+
),
347+
],
348+
[
349+
'app' => [
350+
'path' => '/assets/app.js',
351+
'type' => 'js',
352+
],
353+
],
354+
];
307355
}
308356

309357
public function testGetRawImportDataUsesCacheFile()
@@ -1139,6 +1187,35 @@ private function mockAssetMapper(array $mappedAssets): void
11391187
return null;
11401188
})
11411189
;
1190+
1191+
$this->assetMapper->expects($this->any())
1192+
->method('getAssetFromSourcePath')
1193+
->willReturnCallback(function (string $sourcePath) use ($mappedAssets) {
1194+
// collapse ../ in paths and ./ in paths to mimic the realpath AssetMapper uses
1195+
$parts = explode('/', $sourcePath);
1196+
$newParts = [];
1197+
foreach ($parts as $part) {
1198+
if ('..' === $part) {
1199+
array_pop($newParts);
1200+
1201+
continue;
1202+
}
1203+
1204+
if ('.' !== $part) {
1205+
$newParts[] = $part;
1206+
}
1207+
}
1208+
$sourcePath = implode('/', $newParts);
1209+
1210+
foreach ($mappedAssets as $assetSourcePath => $asset) {
1211+
if ($assetSourcePath === $sourcePath) {
1212+
return $asset;
1213+
}
1214+
}
1215+
1216+
return null;
1217+
})
1218+
;
11421219
}
11431220

11441221
private function writeFile(string $filename, string $content): void

0 commit comments

Comments
 (0)
0