Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to `ichava/icon-sets-bootstrap` follow [Keep a Changelog](ht

### Changed

- **This pack requires `ichava/core` and nothing else.** `composer.json` `require` is now `php` and `ichava/core`; `illuminate/support` and `laranail/package-tools` were dropped from it and still arrive through core. The provider extends core's `IconPackServiceProvider` and declares its constants class and component class, so `src/` imports no `laranail/*` namespace; it registers the same name, path, Blade component and icon directory as before. The composer `type` is `ichava-icon-set`, which core's pack discovery reads. The README and `docs/installation.md` no longer restate the `laranail/*` repositories: they link to core's installation guide, the one place that lists them, and no longer say the pack is on Packagist, which no Ichava package is yet. `tests/Unit/CoreOnlyDependencyTest.php` fails if any of it comes back.
- **The upstream sync runs icon-sets-sync `06b17d7`** (icon-sets-sync#88), up from `5fa93a6`, which adds this pack's recipe, the `split-variants` and `exclude` transforms, and the `licence_sha256` pin on the upstream licence text. The `uses:` pin and `toolkit-ref` move together; the reusable workflow's inputs did not change between the two commits, so the caller's `with:` block is untouched.

## [0.1.0] - TBD
Expand Down
13 changes: 1 addition & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,7 @@ Requires [`ichava/core`](https://github.com/ichava/core) `^0.1` on PHP `^8.4.1 |

## Install

`ichava/core` and this pack come from Packagist. The `laranail/*` packages core depends on are not on Packagist yet, so the **application's** `composer.json` names them:

```json
{
"repositories": [
{ "type": "vcs", "url": "https://github.com/laranail/package-tools" },
{ "type": "vcs", "url": "https://github.com/laranail/console" },
{ "type": "vcs", "url": "https://github.com/laranail/enumerator" },
{ "type": "vcs", "url": "https://github.com/laranail/db-tools" }
]
}
```
This pack requires [`ichava/core`](https://github.com/ichava/core) and nothing else. Nothing in the Ichava family is on Packagist yet, so the **application's** `composer.json` first names the repositories: core's [installation guide](https://github.com/ichava/core/blob/main/docs/installation.md#1-point-composer-at-the-repositories) holds the one block that lists them, core's dependencies included, and this pack's line in it is `https://github.com/ichava/icon-sets-bootstrap`.

Then require the pack:

Expand Down
6 changes: 2 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ichava/icon-sets-bootstrap",
"description": "2,078 Bootstrap Icons (v1.13.2) for Laravel 13 on the Ichava icon ecosystem. Artwork MIT, by The Bootstrap Authors.",
"type": "library",
"type": "ichava-icon-set",
"keywords": [
"icons",
"svg",
Expand All @@ -22,9 +22,7 @@
],
"require": {
"php": "^8.4.1 || ^8.5",
"illuminate/support": "^13.0",
"ichava/core": "^0.1",
"laranail/package-tools": "^0.1.0"
"ichava/core": "^0.1"
},
"repositories": [
{
Expand Down
13 changes: 8 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ that do not exist yet, and logging there raises `Log [ichava] not defined`.
Core discovers installed packs at runtime. It has no list of them, so a pack is added by installing
it and removed by removing it.

## It requires `laranail/package-tools` directly

The provider writes `Package` into its own `configurePackage()` signature, so it depends on that
class whatever the dependency graph delivers transitively through core. **Require what you import**
is the rule; a transitive dependency is not a contract.
## It requires `ichava/core` only

`composer.json` requires `php` and `ichava/core`, and nothing under `src/` names a class from any
other `Simtabi\Laranail` namespace. The provider extends core's `IconPackServiceProvider` and declares
its constants class and its component class; core writes the `laranail/package-tools` signature, so
the `laranail/*` packages reach this pack only through core. The composer `type` is
`ichava-icon-set`, which is how core's pack discovery finds it. `tests/Unit/CoreOnlyDependencyTest.php`
fails if any of that changes.

## Upstream

Expand Down
9 changes: 5 additions & 4 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ Core is the engine; this pack is only icons and the provider that registers them

## The repositories block

The `ichava/*` packages are on Packagist, but the `laranail/*` packages core depends on are not yet, so Composer has to be told where to find them.
Composer reads `repositories` only from the root package, which is why the block belongs in the
**application's** `composer.json` and has to name the whole transitive closure rather than just this
pack. Core's [installation guide](https://github.com/ichava/core/blob/main/docs/installation.md) gives the full block.
This pack requires `ichava/core` and nothing else; the `laranail/*` packages are core's dependencies,
not this pack's. Nothing in the Ichava family is on Packagist yet, and Composer reads `repositories`
only from the root package, so the **application's** `composer.json` names core, core's dependencies
and this pack. Core's [installation guide](https://github.com/ichava/core/blob/main/docs/installation.md#1-point-composer-at-the-repositories) holds that block and is the one place that lists
it; this pack's line is `https://github.com/ichava/icon-sets-bootstrap`.

## Require it

Expand Down
27 changes: 6 additions & 21 deletions src/Providers/IconsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,22 @@

namespace Simtabi\Laranail\Ichava\IconSetsBootstrap\Providers;

use Simtabi\Laranail\Package\Tools\Package;
use Simtabi\Laranail\Ichava\Services\IconRegistry;
use Simtabi\Laranail\Ichava\Support\ServiceProvider;
use Simtabi\Laranail\Package\Tools\Exceptions\InvalidPath;
use Simtabi\Laranail\Package\Tools\Exceptions\InvalidPackage;
use Simtabi\Laranail\Ichava\Support\IconPackServiceProvider;
use Simtabi\Laranail\Ichava\IconSetsBootstrap\Constants\IconsConstants;
use Simtabi\Laranail\Ichava\IconSetsBootstrap\View\Components\IconComponent;

/**
* Registers the Bootstrap Icons set with the Ichava registry on boot.
*/
class IconsServiceProvider extends ServiceProvider
class IconsServiceProvider extends IconPackServiceProvider
{
/**
* @throws InvalidPath
* @throws InvalidPackage
*/
public function configurePackage(Package $package): void
protected function constantsClass(): string
{
$package
->setName(IconsConstants::getVendorPackage())
->setPathFrom(source: $this, levelsUp: 2);
return IconsConstants::class;
}

public function bootingPackage(): void
protected function componentClass(): string
{
$this->loadBladeComponent(componentClass: IconComponent::class, packageName: 'icon-sets-bootstrap');

$this->app->make(IconRegistry::class)->fromDirectory(
$this->package->basePath('resources/assets/svg'),
self::class,
);
return IconComponent::class;
}
}
77 changes: 77 additions & 0 deletions tests/Unit/CoreOnlyDependencyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

/*
|--------------------------------------------------------------------------
| A pack depends on ichava/core, and on nothing else
|--------------------------------------------------------------------------
|
| Core alone uses the laranail/* packages. A pack requires `php` and
| `ichava/core`, extends core's IconPackServiceProvider, and names no class
| from any other Simtabi\Laranail namespace, so a laranail change reaches the
| packs through core and nowhere else.
|
| `Simtabi\Laranail\Ichava\` is core's namespace, and this pack's own sits
| under it. `Simtabi\Laranail\Ichava\IconBrowser\` is ichava/icon-browser's,
| which a pack must not depend on either.
|
| Reads the committed composer.json. CI aliases core's main into it for the
| install and restores the file before the tests run.
|
| Pest functions only: a PHPUnit class in the same file would stop being
| collected.
|
*/

/** @return array<string, mixed> */
function coreOnlyComposerJson(): array
{
$composer = json_decode((string) file_get_contents(dirname(__DIR__, 2) . '/composer.json'), true, flags: JSON_THROW_ON_ERROR);

return is_array($composer) ? $composer : [];
}

it('requires php and ichava/core, and nothing else', function (): void {
$require = array_keys(coreOnlyComposerJson()['require'] ?? []);
sort($require);

expect($require)->toBe(['ichava/core', 'php']);
});

it('declares the composer type core discovers packs by', function (): void {
expect(coreOnlyComposerJson()['type'] ?? null)->toBe('ichava-icon-set');
});

it('imports no laranail namespace but ichava/core from src/', function (): void {
$inspected = 0;
$offenders = [];

$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(dirname(__DIR__, 2) . '/src', FilesystemIterator::SKIP_DOTS),
);

foreach ($files as $file) {
if (! $file instanceof SplFileInfo || ! $file->isFile() || $file->getExtension() !== 'php') {
continue;
}

$inspected++;
$source = (string) file_get_contents($file->getPathname());

// Every spelling: a `use` line, a fully qualified name, or a string with
// escaped backslashes.
preg_match_all('/Simtabi\\\\+Laranail\\\\+(\w+)(?:\\\\+(\w+))?/', $source, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
if ($match[1] !== 'Ichava' || ($match[2] ?? '') === 'IconBrowser') {
$offenders[] = $file->getFilename() . ': ' . $match[0];
}
}
}

// Every pack has a provider, a constants class, an enum and a component. A
// walk that stops finding them must fail, not pass over an empty tree.
expect($inspected)->toBeGreaterThanOrEqual(4)
->and($offenders)->toBe([]);
});
Loading