Skip to content

Commit 41275d6

Browse files
Jibbarthnicolas-grekas
authored andcommitted
[AssetMapper] Allow to define entrypoint in importmap.php
1 parent 4dc1191 commit 41275d6

File tree

4 files changed

+81
-17
lines changed

4 files changed

+81
-17
lines changed

src/PackageJsonSynchronizer.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private function removeObsoletePackageJsonLinks(): bool
104104

105105
foreach (['dependencies' => $jsDependencies, 'devDependencies' => $jsDevDependencies] as $key => $packages) {
106106
foreach ($packages as $name => $version) {
107-
if ('@' !== $name[0] || 0 !== strpos($version, 'file:'.$this->vendorDir.'/') || false === strpos($version, '/assets')) {
107+
if ('@' !== $name[0] || !str_starts_with($version, 'file:'.$this->vendorDir.'/') || !str_contains($version, '/assets')) {
108108
continue;
109109
}
110110
if (file_exists($this->rootDir.'/'.substr($version, 5).'/package.json')) {
@@ -149,20 +149,36 @@ private function resolveImportMapPackages($phpPackage): array
149149
$dependencies = [];
150150

151151
foreach ($packageJson->read()['symfony']['importmap'] ?? [] as $importMapName => $constraintConfig) {
152-
if (\is_array($constraintConfig)) {
153-
$constraint = $constraintConfig['version'] ?? [];
154-
$package = $constraintConfig['package'] ?? $importMapName;
155-
} else {
152+
if (\is_string($constraintConfig)) {
153+
// Matches string constraint, like "^3.0" or "path:%PACKAGE%/script.js"
156154
$constraint = $constraintConfig;
157155
$package = $importMapName;
156+
$entrypoint = false;
157+
} elseif (\is_array($constraintConfig)) {
158+
// Matches array constraint, like {"version":"^3.0"} or {"version":"path:%PACKAGE%/script.js","entrypoint":true}
159+
// Note that non-path assets can't be entrypoint
160+
$constraint = $constraintConfig['version'] ?? '';
161+
$package = $constraintConfig['package'] ?? $importMapName;
162+
$entrypoint = $constraintConfig['entrypoint'] ?? false;
163+
} else {
164+
throw new \InvalidArgumentException(\sprintf('Invalid constraint config for key "%s": "%s" given, array or string expected.', $importMapName, var_export($constraintConfig, true)));
158165
}
159166

160-
if (0 === strpos($constraint, 'path:')) {
167+
// When "$constraintConfig" matches one of the following cases:
168+
// - "entrypoint:%PACKAGE%/script.js"
169+
// - {"version": "entrypoint:%PACKAGE%/script.js"}
170+
if (str_starts_with($constraint, 'entrypoint:')) {
171+
$entrypoint = true;
172+
$constraint = substr_replace($constraint, 'path:', 0, \strlen('entrypoint:'));
173+
}
174+
175+
if (str_starts_with($constraint, 'path:')) {
161176
$path = substr($constraint, 5);
162177
$path = str_replace('%PACKAGE%', \dirname($packageJson->getPath()), $path);
163178

164179
$dependencies[$importMapName] = [
165180
'path' => $path,
181+
'entrypoint' => $entrypoint,
166182
];
167183

168184
continue;
@@ -239,7 +255,7 @@ private function shouldUpdateConstraint(string $existingConstraint, string $cons
239255
}
240256

241257
/**
242-
* @param array<string, array{path?: string, package?: string, version?: string}> $importMapEntries
258+
* @param array<string, array{path?: string, package?: string, version?: string, entrypoint?: bool}> $importMapEntries
243259
*/
244260
private function updateImportMap(array $importMapEntries): void
245261
{
@@ -264,11 +280,15 @@ private function updateImportMap(array $importMapEntries): void
264280
continue;
265281
}
266282

267-
$this->io->writeError(sprintf('Updating package <comment>%s</> from <info>%s</> to <info>%s</>.', $name, $version, $versionConstraint));
283+
$this->io->writeError(\sprintf('Updating package <comment>%s</> from <info>%s</> to <info>%s</>.', $name, $version, $versionConstraint));
268284
}
269285

270286
if (isset($importMapEntry['path'])) {
271287
$arguments = [$name, '--path='.$importMapEntry['path']];
288+
if (isset($importMapEntry['entrypoint']) && true === $importMapEntry['entrypoint']) {
289+
$arguments[] = '--entrypoint';
290+
}
291+
272292
$this->scriptExecutor->execute(
273293
'symfony-cmd',
274294
'importmap:require',
@@ -293,7 +313,7 @@ private function updateImportMap(array $importMapEntries): void
293313
continue;
294314
}
295315

296-
throw new \InvalidArgumentException(sprintf('Invalid importmap entry: "%s".', var_export($importMapEntry, true)));
316+
throw new \InvalidArgumentException(\sprintf('Invalid importmap entry: "%s".', var_export($importMapEntry, true)));
297317
}
298318
}
299319

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"symfony": {
3+
"importmap": {
4+
"@symfony/test": true
5+
}
6+
}
7+
}

tests/Fixtures/packageJson/vendor/symfony/new-package/assets/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
"@hotcake/foo": "^1.9.0",
1515
"@symfony/new-package": {
1616
"version": "path:%PACKAGE%/dist/loader.js"
17+
},
18+
"@symfony/new-package/entry.js": "entrypoint:%PACKAGE%/entry.js",
19+
"@symfony/new-package/entry2.js": {
20+
"version": "path:%PACKAGE%/entry2.js",
21+
"entrypoint": true
1722
}
1823
}
1924
},

tests/PackageJsonSynchronizerTest.php

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,16 @@ public function testSynchronizeAssetMapperNewPackage()
323323
file_put_contents($this->tempDir.'/importmap.php', '<?php return [];');
324324

325325
$fileModulePath = $this->tempDir.'/vendor/symfony/new-package/assets/dist/loader.js';
326-
$this->scriptExecutor->expects($this->exactly(2))
326+
$entrypointPath = $this->tempDir.'/vendor/symfony/new-package/assets/entry.js';
327+
$secondEntrypointPath = $this->tempDir.'/vendor/symfony/new-package/assets/entry2.js';
328+
329+
$this->scriptExecutor->expects($this->exactly(4))
327330
->method('execute')
328331
->withConsecutive(
329332
['symfony-cmd', 'importmap:require', ['@hotcake/foo@^1.9.0']],
330-
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]]
333+
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]],
334+
['symfony-cmd', 'importmap:require', ['@symfony/new-package/entry.js', '--path='.$entrypointPath, '--entrypoint']],
335+
['symfony-cmd', 'importmap:require', ['@symfony/new-package/entry2.js', '--path='.$secondEntrypointPath, '--entrypoint']],
331336
);
332337

333338
$this->synchronizer->synchronize([
@@ -396,14 +401,19 @@ public function testSynchronizeAssetMapperUpgradesPackageIfNeeded()
396401
'version' => '1.8.0',
397402
],
398403
];
399-
file_put_contents($this->tempDir.'/importmap.php', sprintf('<?php return %s;', var_export($importMap, true)));
404+
file_put_contents($this->tempDir.'/importmap.php', \sprintf('<?php return %s;', var_export($importMap, true)));
400405

401406
$fileModulePath = $this->tempDir.'/vendor/symfony/new-package/assets/dist/loader.js';
402-
$this->scriptExecutor->expects($this->exactly(2))
407+
$entrypointPath = $this->tempDir.'/vendor/symfony/new-package/assets/entry.js';
408+
$secondEntrypointPath = $this->tempDir.'/vendor/symfony/new-package/assets/entry2.js';
409+
410+
$this->scriptExecutor->expects($this->exactly(4))
403411
->method('execute')
404412
->withConsecutive(
405413
['symfony-cmd', 'importmap:require', ['@hotcake/foo@^1.9.0']],
406-
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]]
414+
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]],
415+
['symfony-cmd', 'importmap:require', ['@symfony/new-package/entry.js', '--path='.$entrypointPath, '--entrypoint']],
416+
['symfony-cmd', 'importmap:require', ['@symfony/new-package/entry2.js', '--path='.$secondEntrypointPath, '--entrypoint']]
407417
);
408418

409419
$this->synchronizer->synchronize([
@@ -421,14 +431,21 @@ public function testSynchronizeAssetMapperSkipsUpgradeIfAlreadySatisfied()
421431
// constraint in package.json is ^1.9.0
422432
'version' => '1.9.1',
423433
],
434+
'@symfony/new-package/entry2.js' => [
435+
'path' => './vendor/symfony/new-package/assets/entry2.js',
436+
'entrypoint' => true,
437+
],
424438
];
425-
file_put_contents($this->tempDir.'/importmap.php', sprintf('<?php return %s;', var_export($importMap, true)));
439+
file_put_contents($this->tempDir.'/importmap.php', \sprintf('<?php return %s;', var_export($importMap, true)));
426440

427441
$fileModulePath = $this->tempDir.'/vendor/symfony/new-package/assets/dist/loader.js';
428-
$this->scriptExecutor->expects($this->once())
442+
$entrypointPath = $this->tempDir.'/vendor/symfony/new-package/assets/entry.js';
443+
444+
$this->scriptExecutor->expects($this->exactly(2))
429445
->method('execute')
430446
->withConsecutive(
431-
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]]
447+
['symfony-cmd', 'importmap:require', ['@symfony/new-package', '--path='.$fileModulePath]],
448+
['symfony-cmd', 'importmap:require', ['@symfony/new-package/entry.js', '--path='.$entrypointPath, '--entrypoint']],
432449
);
433450

434451
$this->synchronizer->synchronize([
@@ -438,4 +455,19 @@ public function testSynchronizeAssetMapperSkipsUpgradeIfAlreadySatisfied()
438455
],
439456
]);
440457
}
458+
459+
public function testExceptionWhenInvalidImportMapConstraint()
460+
{
461+
file_put_contents($this->tempDir.'/importmap.php', '<?php return [];');
462+
463+
$this->expectException(\InvalidArgumentException::class);
464+
$this->expectExceptionMessage('Invalid constraint config for key "@symfony/test": "true" given, array or string expected.');
465+
466+
$this->synchronizer->synchronize([
467+
[
468+
'name' => 'symfony/importmap-invalid-constraint-package',
469+
'keywords' => ['symfony-ux'],
470+
],
471+
]);
472+
}
441473
}

0 commit comments

Comments
 (0)