{"version":3,"file":"packagist.mjs","names":[],"sources":["../../src/registries/packagist.ts"],"sourcesContent":["import type { Client } from \"../core/client.ts\";\nimport type { Dependency, Maintainer, Package, URLBuilder, Version } from \"../core/types.ts\";\nimport { Registry } from \"../core/registry.ts\";\nimport { NotFoundError, InvalidPURLError, rethrowFetchError } from \"../core/errors.ts\";\nimport { combineLicenses } from \"../core/license.ts\";\nimport { normalizeRepositoryURL } from \"../core/repository.ts\";\nimport { buildPURL } from \"../core/purl.ts\";\n\n/** Packagist API response for a single package. */\ninterface PackagistPackageResponse {\n  package: {\n    name: string;\n    description: string;\n    repository?: string;\n    keywords?: string[];\n    versions: Record<string, PackagistVersion>;\n  };\n}\n\ninterface PackagistAuthor {\n  readonly name?: string;\n  readonly email?: string;\n  readonly homepage?: string;\n  readonly role?: string;\n}\n\n/** Packagist version data. */\ninterface PackagistVersion {\n  name: string;\n  version: string;\n  license?: string | string[];\n  keywords?: string[];\n  authors?: readonly PackagistAuthor[];\n  require?: Record<string, string>;\n  \"require-dev\"?: Record<string, string>;\n  source?: {\n    type?: string;\n    url?: string;\n    reference?: string;\n  };\n  dist?: {\n    type?: string;\n    url?: string;\n    reference?: string;\n    shasum?: string;\n  };\n  time?: string;\n}\n\n/** Packagist registry client. */\nexport class PackagistRegistry extends Registry {\n  constructor(baseURL: string, client: Client) {\n    super();\n    this.baseURL = baseURL;\n    this.client = client;\n  }\n\n  readonly baseURL: string;\n  readonly client: Client;\n\n  ecosystem(): string {\n    return \"composer\";\n  }\n\n  async fetchPackage(name: string, signal?: AbortSignal): Promise<Package> {\n    const [vendor, pkg] = this.parseName(name);\n    const url = `${this.baseURL}/packages/${vendor}/${pkg}.json`;\n\n    try {\n      const data = await this.client.getJSON<PackagistPackageResponse>(url, signal);\n      const packageData = data.package;\n\n      // Find latest version\n      const versions = Object.keys(packageData.versions);\n      const latestVersion = this.findLatestVersion(versions);\n\n      // Get license from latest version\n      const latestVersionData = packageData.versions[latestVersion];\n      const licenses = this.extractLicenses(latestVersionData.license);\n\n      return {\n        name: packageData.name,\n        description: packageData.description || \"\",\n        homepage: \"\",\n        documentation: \"\",\n        repository: normalizeRepositoryURL(\n          packageData.repository ? packageData.repository : (latestVersionData.source?.url ?? \"\"),\n        ),\n        licenses,\n        keywords: packageData.keywords ?? [],\n        namespace: vendor,\n        latestVersion,\n        metadata: {},\n      };\n    } catch (error) {\n      rethrowFetchError(error, this.ecosystem(), name);\n    }\n  }\n\n  async fetchVersions(name: string, signal?: AbortSignal): Promise<Version[]> {\n    const [vendor, pkg] = this.parseName(name);\n    const url = `${this.baseURL}/packages/${vendor}/${pkg}.json`;\n\n    try {\n      const data = await this.client.getJSON<PackagistPackageResponse>(url, signal);\n      const versions: Version[] = [];\n\n      for (const [versionStr, versionData] of Object.entries(data.package.versions)) {\n        const licenses = this.extractLicenses(versionData.license);\n        const publishedAt = versionData.time ? new Date(versionData.time) : null;\n\n        versions.push({\n          number: versionStr,\n          publishedAt,\n          licenses,\n          integrity: versionData.dist?.shasum ? `sha1-${versionData.dist.shasum}` : \"\",\n          status: \"\",\n          metadata: {},\n        });\n      }\n\n      return versions;\n    } catch (error) {\n      rethrowFetchError(error, this.ecosystem(), name);\n    }\n  }\n\n  async fetchDependencies(\n    name: string,\n    version: string,\n    signal?: AbortSignal,\n  ): Promise<Dependency[]> {\n    const [vendor, pkg] = this.parseName(name);\n    const url = `${this.baseURL}/packages/${vendor}/${pkg}.json`;\n\n    try {\n      const data = await this.client.getJSON<PackagistPackageResponse>(url, signal);\n      const versionData = data.package.versions[version];\n\n      if (!versionData) {\n        throw new NotFoundError(\"composer\", name, version);\n      }\n\n      const dependencies: Dependency[] = [];\n\n      // Runtime dependencies\n      if (versionData.require) {\n        for (const [depName, requirements] of Object.entries(versionData.require)) {\n          if (!this.shouldSkipDependency(depName)) {\n            dependencies.push({\n              name: depName,\n              requirements,\n              scope: \"runtime\",\n              optional: false,\n            });\n          }\n        }\n      }\n\n      // Development dependencies\n      if (versionData[\"require-dev\"]) {\n        for (const [depName, requirements] of Object.entries(versionData[\"require-dev\"])) {\n          if (!this.shouldSkipDependency(depName)) {\n            dependencies.push({\n              name: depName,\n              requirements,\n              scope: \"development\",\n              optional: false,\n            });\n          }\n        }\n      }\n\n      return dependencies;\n    } catch (error) {\n      rethrowFetchError(error, this.ecosystem(), name, version);\n    }\n  }\n\n  async fetchMaintainers(name: string, signal?: AbortSignal): Promise<Maintainer[]> {\n    const [vendor, pkg] = this.parseName(name);\n    const url = `${this.baseURL}/packages/${vendor}/${pkg}.json`;\n\n    try {\n      const data = await this.client.getJSON<PackagistPackageResponse>(url, signal);\n      return this.collectMaintainers(Object.values(data.package.versions));\n    } catch (error) {\n      rethrowFetchError(error, this.ecosystem(), name);\n    }\n  }\n\n  urls(): URLBuilder {\n    return {\n      registry: (name: string, version?: string) => {\n        const [vendor, pkg] = this.parseName(name);\n        const base = `https://packagist.org/packages/${vendor}/${pkg}`;\n        return version ? `${base}#${version}` : base;\n      },\n      download: (name: string, version: string) => {\n        const [vendor, pkg] = this.parseName(name);\n        return `https://repo.packagist.org/p/${vendor}/${pkg}/${version}.json`;\n      },\n      documentation: (name: string, _version?: string) => {\n        const [vendor, pkg] = this.parseName(name);\n        return `https://packagist.org/packages/${vendor}/${pkg}`;\n      },\n      readme: (name: string, _version?: string) => {\n        const [vendor, pkg] = this.parseName(name);\n        return `https://packagist.org/packages/${vendor}/${pkg}`;\n      },\n      purl: (name: string, version?: string) => {\n        const [vendor, pkg] = this.parseName(name);\n        return buildPURL({ type: \"composer\", namespace: vendor, name: pkg, version });\n      },\n    };\n  }\n\n  private collectMaintainers(\n    versions: readonly Readonly<Pick<PackagistVersion, \"authors\">>[],\n  ): Maintainer[] {\n    const maintainers: Maintainer[] = [];\n    const seen = new Set<string>();\n\n    for (const version of versions) {\n      for (const author of version.authors ?? []) {\n        const key = `${author.name}:${author.email}`;\n        if (seen.has(key)) continue;\n        seen.add(key);\n        maintainers.push(this.toMaintainer(author));\n      }\n    }\n\n    return maintainers;\n  }\n\n  private toMaintainer(author: Readonly<PackagistAuthor>): Maintainer {\n    return {\n      uuid: \"\",\n      login: author.email ? author.email.split(\"@\")[0] : \"\",\n      name: author.name || \"\",\n      email: author.email || \"\",\n      url: author.homepage || \"\",\n      role: author.role || \"\",\n    };\n  }\n\n  private parseName(name: string): [string, string] {\n    const parts = name.split(\"/\");\n    if (parts.length !== 2 || !parts[0] || !parts[1]) {\n      throw new InvalidPURLError(\n        `pkg:composer/${name}`,\n        'invalid Composer package name, expected \"vendor/package\" format',\n      );\n    }\n    return [parts[0]!, parts[1]!];\n  }\n\n  private findLatestVersion(versions: readonly string[]): string {\n    // Filter out dev versions\n    const stable = versions.filter((v) => !v.startsWith(\"dev-\") && !v.endsWith(\"-dev\"));\n    if (stable.length === 0) {\n      return versions[0] || \"\";\n    }\n\n    // Sort by semantic versioning (simplified)\n    return (\n      stable.sort((a, b) => {\n        // Remove 'v' prefix if present\n        const aClean = a.replace(/^v/, \"\");\n        const bClean = b.replace(/^v/, \"\");\n\n        // Try numeric comparison for simple versions\n        const aParts = aClean.split(\".\").map((p) => Number.parseInt(p, 10));\n        const bParts = bClean.split(\".\").map((p) => Number.parseInt(p, 10));\n\n        for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n          const aPart = aParts[i] ?? 0;\n          const bPart = bParts[i] ?? 0;\n          if (aPart !== bPart) {\n            return bPart - aPart;\n          }\n        }\n\n        return 0;\n      })[0] ||\n      versions[0] ||\n      \"\"\n    );\n  }\n\n  private extractLicenses(raw: string | readonly string[] | undefined): string {\n    if (!raw) return \"\";\n\n    const licenses = Array.isArray(raw) ? raw : [raw];\n    return combineLicenses(licenses);\n  }\n\n  private shouldSkipDependency(name: string): boolean {\n    return name === \"php\" || name.startsWith(\"ext-\");\n  }\n}\n"],"mappings":"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"}