diff --git a/package-lock.json b/package-lock.json index 46127d6..b4e7301 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12783,10 +12783,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" diff --git a/src/application/project/sdk/phpSdk.ts b/src/application/project/sdk/phpSdk.ts index c6b4b02..bdd7638 100644 --- a/src/application/project/sdk/phpSdk.ts +++ b/src/application/project/sdk/phpSdk.ts @@ -44,6 +44,14 @@ export enum PhpEnvVar { APP_ID = 'CROCT_APP_ID', } +/** + * An optional Croct integration installed when a companion library is already present. + */ +type Integration = { + detect: string, + install: string, +}; + /** * Base SDK for PHP projects. * @@ -54,6 +62,13 @@ export enum PhpEnvVar { export abstract class PhpSdk implements Sdk { private static readonly PHPSTAN_EXTENSION = 'vendor/croct/plug-php/extension.neon'; + private static readonly INTEGRATIONS: readonly Integration[] = [ + { + detect: 'storyblok/php-content-api-client', + install: 'croct/plug-storyblok', + }, + ]; + protected readonly projectDirectory: WorkingDirectory; protected readonly packageManager: PackageManager; @@ -95,6 +110,8 @@ export abstract class PhpSdk implements Sdk { const plan = await this.getInstallationPlan(installation); + const dependencies = [...plan.dependencies, ...await this.getIntegrationDependencies()]; + const configuration: ProjectConfiguration = { ...plan.configuration, paths: { @@ -126,7 +143,7 @@ export abstract class PhpSdk implements Sdk { }); try { - await this.packageManager.addDependencies(plan.dependencies, {logger: logger}); + await this.packageManager.addDependencies(dependencies, {logger: logger}); notifier.confirm('Dependencies installed'); } catch (error) { @@ -294,6 +311,22 @@ export abstract class PhpSdk implements Sdk { }); } + /** + * Resolves the optional integration dependencies enabled by libraries already in the project. + * + * Merged into the installation plan automatically; subclasses without transparent + * auto-decoration override this to opt out. + */ + protected async getIntegrationDependencies(): Promise { + const detected = await Promise.all( + PhpSdk.INTEGRATIONS.map(integration => this.packageManager.hasDependency(integration.detect)), + ); + + return PhpSdk.INTEGRATIONS + .filter((_, index) => detected[index]) + .map(integration => integration.install); + } + protected abstract getInstallationPlan(installation: Installation): Promise; protected abstract generateSlotExampleFiles(slot: Slot, installation: Installation): Promise; diff --git a/src/application/project/sdk/plugPhpSdk.ts b/src/application/project/sdk/plugPhpSdk.ts index b710177..65033f4 100644 --- a/src/application/project/sdk/plugPhpSdk.ts +++ b/src/application/project/sdk/plugPhpSdk.ts @@ -24,6 +24,14 @@ export class PlugPhpSdk extends PhpSdk { }); } + protected getIntegrationDependencies(): Promise { + /* + * Framework-agnostic PHP has no transparent auto-decoration, so optional integrations are + * left for the developer to wire manually. + */ + return Promise.resolve([]); + } + protected async generateSlotExampleFiles(slot: Slot, installation: Installation): Promise { const paths = await this.getPaths(installation.configuration);