{"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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"}