diff --git a/src/License/Generator.php b/src/License/Generator.php index 45c99aa..f35c182 100644 --- a/src/License/Generator.php +++ b/src/License/Generator.php @@ -20,14 +20,29 @@ use Symfony\Component\Filesystem\Filesystem; +/** + * Generates LICENSE files from composer.json metadata. + * + * This class orchestrates the license generation workflow: + * 1. Reads metadata from composer.json via Reader + * 2. Resolves the license identifier to a template filename + * 3. Loads the license template content + * 4. Resolves placeholders with metadata (year, author, project, organization) + * 5. Writes the resulting LICENSE file to the target path + * + * Generation is skipped if a LICENSE file already exists or if the + * license is not supported. + */ final readonly class Generator implements GeneratorInterface { /** - * @param Reader $reader - * @param Resolver $resolver - * @param TemplateLoader $templateLoader - * @param PlaceholderResolver $placeholderResolver - * @param Filesystem $filesystem + * Creates a new Generator instance. + * + * @param Reader $reader The reader for extracting metadata from composer.json + * @param Resolver $resolver The resolver for mapping license identifiers to templates + * @param TemplateLoader $templateLoader The loader for reading template files + * @param PlaceholderResolver $placeholderResolver The resolver for template placeholders + * @param Filesystem $filesystem The filesystem component for file operations */ public function __construct( private Reader $reader, @@ -38,9 +53,11 @@ public function __construct( ) {} /** - * @param string $targetPath + * Generates a LICENSE file at the specified path. + * + * @param string $targetPath The full path where the LICENSE file should be written * - * @return string|null + * @return string|null The generated license content, or null if generation failed */ public function generate(string $targetPath): ?string { @@ -84,7 +101,9 @@ public function generate(string $targetPath): ?string } /** - * @return bool + * Checks whether a supported license is present in composer.json. + * + * @return bool True if a supported license is defined, false otherwise */ public function hasLicense(): bool { diff --git a/src/License/GeneratorInterface.php b/src/License/GeneratorInterface.php index 21425e1..c55f5ff 100644 --- a/src/License/GeneratorInterface.php +++ b/src/License/GeneratorInterface.php @@ -18,17 +18,31 @@ namespace FastForward\DevTools\License; +/** + * Generates LICENSE files from composer.json metadata. + * + * This interface defines the contract for generating license files + * by reading composer.json and producing appropriate license content. + */ interface GeneratorInterface { /** - * @param string $targetPath + * Generates a LICENSE file at the specified path. * - * @return string|null + * Reads the license from composer.json, validates it's supported, + * loads the appropriate template, resolves placeholders, and writes + * the LICENSE file to the target path. + * + * @param string $targetPath The full path where the LICENSE file should be written + * + * @return string|null The generated license content, or null if generation failed */ public function generate(string $targetPath): ?string; /** - * @return bool + * Checks whether a supported license is present in composer.json. + * + * @return bool True if a supported license is defined, false otherwise */ public function hasLicense(): bool; } diff --git a/src/License/PlaceholderResolver.php b/src/License/PlaceholderResolver.php index d28de3d..0a7090e 100644 --- a/src/License/PlaceholderResolver.php +++ b/src/License/PlaceholderResolver.php @@ -20,11 +20,31 @@ use function Safe\preg_replace; +/** + * Resolves placeholders in license templates with metadata values. + * + * This class replaces placeholders like {{ year }}, {{ author }}, {{ project }}, + * {{ organization }}, and {{ copyright_holder }} with values from metadata. + * Unresolved placeholders are removed and excess newlines are normalized. + */ final class PlaceholderResolver implements PlaceholderResolverInterface { /** - * @param array{year?: int, organization?: string, author?: string, project?: string} $metadata - * @param string $template + * Resolves placeholders in a license template with the provided metadata. + * + * Supported placeholders: + * - {{ year }} - The copyright year (defaults to current year) + * - {{ organization }} - The organization or vendor name + * - {{ author }} - The primary author name or email + * - {{ project }} - The project/package name + * - {{ copyright_holder }} - Organization or author (organization takes precedence) + * + * Unmatched placeholders are removed, and consecutive blank lines are normalized. + * + * @param string $template The license template content with placeholders + * @param array{year?: int, organization?: string, author?: string, project?: string} $metadata The metadata values to use for replacement + * + * @return string The template with all resolved placeholders */ public function resolve(string $template, array $metadata): string { diff --git a/src/License/PlaceholderResolverInterface.php b/src/License/PlaceholderResolverInterface.php index 564e90b..2e3723d 100644 --- a/src/License/PlaceholderResolverInterface.php +++ b/src/License/PlaceholderResolverInterface.php @@ -18,11 +18,21 @@ namespace FastForward\DevTools\License; +/** + * Resolves placeholders in license templates with metadata values. + * + * This interface defines the contract for replacing template placeholders + * such as [year], [author], [project] with actual values. + */ interface PlaceholderResolverInterface { /** - * @param string $template - * @param array{year?: int, organization?: string, author?: string, project?: string} $metadata + * Resolves placeholders in a license template with the provided metadata. + * + * @param string $template The license template content with placeholders + * @param array{year?: int, organization?: string, author?: string, project?: string} $metadata The metadata values to use for replacement + * + * @return string The template with all resolved placeholders */ public function resolve(string $template, array $metadata): string; } diff --git a/src/License/Reader.php b/src/License/Reader.php index 871d3b8..5cf3166 100644 --- a/src/License/Reader.php +++ b/src/License/Reader.php @@ -23,12 +23,23 @@ use function Safe\json_decode; +/** + * Reads composer.json and exposes metadata for license generation. + * + * This class parses a composer.json file via SplFileObject and provides + * methods to extract license information, package name, authors, vendor, + * and the current year for copyright notices. + */ final readonly class Reader implements ReaderInterface { private array $data; /** + * Creates a new Reader instance. + * * @param SplFileObject $source The source file to read from, typically composer.json + * + * @throws JsonException if the JSON content is invalid */ public function __construct(SplFileObject $source) { @@ -36,9 +47,11 @@ public function __construct(SplFileObject $source) } /** - * @param SplFileObject $source The source file to read from, typically composer.json + * Reads and parses the JSON content from the source file. + * + * @param SplFileObject $source The source file to read from * - * @return array + * @return array The parsed JSON data as an associative array * * @throws JsonException if the JSON is invalid */ @@ -50,7 +63,13 @@ private function readData(SplFileObject $source): array } /** - * @return string|null + * Retrieves the license identifier from composer.json. + * + * If the license is a single string, returns it directly. + * If it's an array with one element, extracts that element. + * Returns null if no license is set or if multiple licenses are specified. + * + * @return string|null the license string, or null if not set or unsupported */ public function getLicense(): ?string { @@ -64,7 +83,9 @@ public function getLicense(): ?string } /** - * @return string + * Retrieves the package name from composer.json. + * + * @return string the full package name (vendor/package), or empty string if not set */ public function getPackageName(): string { @@ -72,7 +93,12 @@ public function getPackageName(): string } /** - * @return array + * Retrieves the list of authors from composer.json. + * + * Each author is normalized to include name, email, homepage, and role fields. + * Returns an empty array if no authors are defined. + * + * @return array */ public function getAuthors(): array { @@ -94,7 +120,12 @@ public function getAuthors(): array } /** - * @return string|null + * Extracts the vendor name from the package name. + * + * The package name is expected in vendor/package format. + * Returns null if no package name is set or if the package has no vendor prefix. + * + * @return string|null the vendor name, or null if package has no vendor prefix */ public function getVendor(): ?string { @@ -114,7 +145,9 @@ public function getVendor(): ?string } /** - * @return int + * Returns the current year for copyright notices. + * + * @return int the current year as an integer */ public function getYear(): int { @@ -122,9 +155,14 @@ public function getYear(): int } /** - * @param array $license + * Extracts a single license from an array of licenses. + * + * Returns the first license if exactly one element exists. + * Returns null if the array is empty or contains multiple licenses. + * + * @param array $license The license array to extract from * - * @return string|null + * @return string|null a single license string, or null if extraction is not possible */ private function extractLicense(array $license): ?string { diff --git a/src/License/ReaderInterface.php b/src/License/ReaderInterface.php index 06be9f1..36a4db9 100644 --- a/src/License/ReaderInterface.php +++ b/src/License/ReaderInterface.php @@ -18,30 +18,46 @@ namespace FastForward\DevTools\License; +/** + * Reads and exposes metadata from composer.json for license generation. + * + * This interface provides access to license information, package name, + * authors, vendor, and year data extracted from a project's composer.json. + */ interface ReaderInterface { /** - * @return string|null + * Retrieves the license identifier from composer.json. + * + * @return string|null the license string, or null if not set or unsupported */ public function getLicense(): ?string; /** - * @return string + * Retrieves the package name from composer.json. + * + * @return string the full package name (vendor/package) */ public function getPackageName(): string; /** + * Retrieves the list of authors from composer.json. + * * @return array */ public function getAuthors(): array; /** - * @return string|null + * Extracts the vendor name from the package name. + * + * @return string|null the vendor name, or null if package has no vendor prefix */ public function getVendor(): ?string; /** - * @return int + * Returns the current year for copyright notices. + * + * @return int the current year as an integer */ public function getYear(): int; } diff --git a/src/License/Resolver.php b/src/License/Resolver.php index 3de3ab1..a13567f 100644 --- a/src/License/Resolver.php +++ b/src/License/Resolver.php @@ -18,6 +18,12 @@ namespace FastForward\DevTools\License; +/** + * Resolves license identifiers to their corresponding template filenames. + * + * This class maintains a mapping of supported open-source licenses to their + * template files and provides methods to check support and resolve licenses. + */ final class Resolver implements ResolverInterface { private const array SUPPORTED_LICENSES = [ @@ -38,9 +44,13 @@ final class Resolver implements ResolverInterface ]; /** - * @param string $license + * Checks whether the given license identifier is supported. + * + * The check is case-insensitive and handles common license variants. * - * @return bool + * @param string $license The license identifier to check + * + * @return bool True if the license is supported, false otherwise */ public function isSupported(string $license): bool { @@ -48,9 +58,11 @@ public function isSupported(string $license): bool } /** - * @param string $license + * Resolves a license identifier to its template filename. + * + * @param string $license The license identifier to resolve * - * @return string|null + * @return string|null The template filename if supported, or null if not */ public function resolve(string $license): ?string { @@ -64,9 +76,11 @@ public function resolve(string $license): ?string } /** - * @param string $license + * Normalizes the license identifier for comparison. + * + * @param string $license The license identifier to normalize * - * @return string + * @return string The normalized license string */ private function normalize(string $license): string { diff --git a/src/License/ResolverInterface.php b/src/License/ResolverInterface.php index 3e018a1..8de9d21 100644 --- a/src/License/ResolverInterface.php +++ b/src/License/ResolverInterface.php @@ -18,19 +18,29 @@ namespace FastForward\DevTools\License; +/** + * Resolves license identifiers to their corresponding template filenames. + * + * This interface checks whether a given license is supported and maps it + * to the appropriate license template file for content generation. + */ interface ResolverInterface { /** - * @param string $license + * Checks whether the given license identifier is supported. * - * @return bool + * @param string $license The license identifier to check (e.g., "MIT", "Apache-2.0") + * + * @return bool True if the license is supported, false otherwise */ public function isSupported(string $license): bool; /** - * @param string $license + * Resolves a license identifier to its template filename. + * + * @param string $license The license identifier to resolve * - * @return string|null + * @return string|null The template filename if supported, or null if not */ public function resolve(string $license): ?string; } diff --git a/src/License/TemplateLoader.php b/src/License/TemplateLoader.php index 6c72881..e123238 100644 --- a/src/License/TemplateLoader.php +++ b/src/License/TemplateLoader.php @@ -22,12 +22,20 @@ use function Safe\file_get_contents; +/** + * Loads license template files from the filesystem. + * + * This class reads license template files from a configured templates directory. + * The default directory is the packaged resources/licenses folder. + */ final readonly class TemplateLoader implements TemplateLoaderInterface { private string $templatesPath; /** - * @param string|null $templatesPath + * Creates a new TemplateLoader instance. + * + * @param string|null $templatesPath Optional custom path to the templates directory */ public function __construct(?string $templatesPath = null) { @@ -35,11 +43,13 @@ public function __construct(?string $templatesPath = null) } /** - * @param string $templateFilename + * Loads a license template file by its filename. + * + * @param string $templateFilename The filename of the template to load (e.g., "mit.txt") * - * @return string + * @return string The template content * - * @throws RuntimeException + * @throws RuntimeException if the template file is not found */ public function load(string $templateFilename): string { diff --git a/src/License/TemplateLoaderInterface.php b/src/License/TemplateLoaderInterface.php index 4b8f797..ec18d09 100644 --- a/src/License/TemplateLoaderInterface.php +++ b/src/License/TemplateLoaderInterface.php @@ -18,12 +18,22 @@ namespace FastForward\DevTools\License; +/** + * Loads license template files from the filesystem. + * + * This interface defines the contract for reading license template content + * based on a template filename provided by the resolver. + */ interface TemplateLoaderInterface { /** - * @param string $templateFilename + * Loads a license template file by its filename. + * + * @param string $templateFilename The filename of the template to load + * + * @return string The template content * - * @return string + * @throws RuntimeException if the template file is not found */ public function load(string $templateFilename): string; }