Skip to main content

provenant/models/
datasource_id.rs

1// SPDX-FileCopyrightText: Provenant contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Datasource identifiers for package parsers.
5//!
6//! Each variant uniquely identifies the type of package data source (file format)
7//! that was parsed. These IDs enable the assembly system to intelligently merge
8//! related package files.
9
10use serde::{Deserialize, Serialize};
11use std::fmt;
12use std::str::FromStr;
13use strum::{EnumCount, EnumIter};
14
15/// Unique identifier for the type of package data source (file format).
16///
17/// Datasource IDs distinguish between different file types within the same ecosystem
18/// (e.g., `NpmPackageJson` vs `NpmPackageLockJson`). The assembly system uses these
19/// IDs to match packages from related files for merging into a single logical package.
20///
21/// # Serialization
22///
23/// Variants serialize as PascalCase in the cache/spill format (e.g., `NpmPackageJson`).
24/// For JSON output, use `as_str()` / `Display` which returns snake_case strings
25/// matching the Python ScanCode Toolkit values (e.g., `npm_package_json`).
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, EnumCount, EnumIter)]
27pub enum DatasourceId {
28    // ── About/README/OS ──
29    AboutFile,
30    Readme,
31    EtcOsRelease,
32
33    // ── Alpine ──
34    AlpineApkArchive,
35    AlpineApkbuild,
36    AlpineInstalledDb,
37
38    // ── Arch Linux ──
39    ArchAurinfo,
40    ArchPkginfo,
41    ArchSrcinfo,
42
43    // ── Android ──
44    AndroidAab,
45    AndroidAarLibrary,
46    AndroidApk,
47    AndroidManifestXml,
48    AndroidSoongMetadata,
49
50    // ── Apache Axis2 ──
51    Axis2Mar,
52    Axis2ModuleXml,
53
54    // ── Autotools ──
55    AutotoolsConfigure,
56
57    // ── Bazel ──
58    BazelBuild,
59    BazelModule,
60
61    // ── Bitbake ──
62    BitbakeRecipe,
63    BitbakeRecipeAppend,
64
65    // ── Bower ──
66    BowerJson,
67
68    // ── Buck ──
69    BuckFile,
70    BuckMetadata,
71
72    // ── Bun ──
73    BunLock,
74    BunLockb,
75
76    // ── Carthage ──
77    CarthageCartfile,
78    CarthageCartfileResolved,
79
80    // ── Cargo/Rust ──
81    CargoLock,
82    CargoToml,
83    RustBinary,
84    WindowsExecutable,
85
86    // ── Chef ──
87    /// Matches Python reference value.
88    ChefCookbookMetadataJson,
89    /// Matches Python reference value.
90    ChefCookbookMetadataRb,
91
92    CitationCff,
93
94    // ── CocoaPods ──
95    CocoapodsPodfile,
96    CocoapodsPodfileLock,
97    CocoapodsPodspec,
98    CocoapodsPodspecJson,
99
100    // ── Conan ──
101    ConanConanDataYml,
102    ConanConanFilePy,
103    ConanConanFileTxt,
104    ConanLock,
105
106    // ── Conda ──
107    /// Matches Python reference value.
108    CondaYaml,
109    CondaMetaJson,
110    CondaMetaYaml,
111
112    // ── Clojure ──
113    ClojureDepsEdn,
114    ClojureProjectClj,
115
116    // ── CPAN/Perl ──
117    CpanDistIni,
118    /// Matches Python reference value.
119    CpanMakefile,
120    CpanManifest,
121    CpanMetaJson,
122    CpanMetaYml,
123
124    // ── CRAN/R ──
125    CranDescription,
126
127    // ── Dart/Flutter ──
128    PubspecLock,
129    PubspecYaml,
130
131    // ── Debian ──
132    DebianControlExtractedDeb,
133    DebianControlInSource,
134    DebianCopyright,
135    DebianCopyrightInSource,
136    DebianCopyrightInPackage,
137    DebianCopyrightStandalone,
138    DebianDeb,
139    /// Matches Python reference value.
140    DebianSourceMetadataTarball,
141    DebianDistrolessInstalledDb,
142    /// Matches Python reference value.
143    DebianInstalledFilesList,
144    DebianInstalledMd5Sums,
145    DebianInstalledStatusDb,
146    DebianMd5SumsInExtractedDeb,
147    /// Matches Python reference value.
148    DebianOriginalSourceTarball,
149    DebianSourceControlDsc,
150
151    // ── Deno ──
152    DenoJson,
153    DenoLock,
154
155    // ── Docker ──
156    Dockerfile,
157
158    // ── Erlang / OTP ──
159    ErlangOtpAppSrc,
160    RebarConfig,
161    RebarLock,
162
163    // ── FreeBSD ──
164    FreebsdCompactManifest,
165
166    // ── Go ──
167    Godeps,
168    GoBinary,
169    GoMod,
170    GoModGraph,
171    GoSum,
172    GoWork,
173
174    // ── Haskell / Hackage ──
175    HackageCabal,
176    HackageCabalProject,
177    HackageStackYaml,
178
179    // ── Gradle ──
180    BuildGradle,
181    GradleLockfile,
182    GradleModule,
183
184    // ── Haxe ──
185    HaxelibJson,
186
187    // ── Helm ──
188    HelmChartLock,
189    HelmChartYaml,
190
191    // ── Hex/Elixir ──
192    HexMixLock,
193
194    // ── Julia ──
195    JuliaProjectToml,
196    JuliaManifestToml,
197
198    // ── Java ──
199    AntIvyXml,
200    JavaEarApplicationXml,
201    JavaEarArchive,
202    JavaJar,
203    JavaJarManifest,
204    JavaOsgiManifest,
205    JavaWarArchive,
206    JavaWarWebXml,
207    JbossSar,
208    JbossServiceXml,
209
210    // ── Maven ──
211    MavenPom,
212    MavenPomProperties,
213    MesonBuild,
214
215    SbtBuildSbt,
216
217    // ── Microsoft ──
218    MicrosoftCabinet,
219    MicrosoftUpdateManifestMum,
220
221    // ── Mobile/Browser ──
222    AppleDmg,
223    ChromeCrx,
224    IosIpa,
225    MozillaXpi,
226
227    // ── Meteor ──
228    MeteorPackage,
229
230    NixDefaultNix,
231    NixFlakeLock,
232    NixFlakeNix,
233
234    // ── npm ──
235    NpmPackageJson,
236    NpmPackageLockJson,
237
238    // ── NuGet ──
239    NugetCsproj,
240    NugetDepsJson,
241    NugetDirectoryBuildProps,
242    NugetDirectoryPackagesProps,
243    NugetNupkg,
244    NugetProjectJson,
245    NugetProjectLockJson,
246    NugetPackagesConfig,
247    NugetPackagesLock,
248    NugetNuspec,
249    NugetVbproj,
250    NugetFsproj,
251
252    // ── OCaml/opam ──
253    OpamFile,
254
255    // ── PHP/Composer ──
256    PhpComposerJson,
257    PhpComposerLock,
258
259    // ── pnpm ──
260    PnpmLockYaml,
261    PnpmWorkspaceYaml,
262
263    // ── Python/PyPI ──
264    Pipfile,
265    PipfileLock,
266    PipRequirements,
267    PixiLock,
268    PixiToml,
269    PypiPipOriginJson,
270    PypiEgg,
271    PypiEggPkginfo,
272    PypiEditableEggPkginfo,
273    PypiInspectDeplock,
274    PypiJson,
275    PypiPoetryLock,
276    PypiPoetryPyprojectToml,
277    PypiSdist,
278    PypiPylockToml,
279    PypiPyprojectToml,
280    PypiSdistPkginfo,
281    PypiSetupCfg,
282    PypiSetupPy,
283    PypiUvLock,
284    PypiWheel,
285    PypiWheelMetadata,
286
287    // ── RPM ──
288    RpmArchive,
289    RpmInstalledDatabaseBdb,
290    RpmInstalledDatabaseNdb,
291    RpmInstalledDatabaseSqlite,
292    RpmMarinerManifest,
293    RpmPackageLicenses,
294    RpmSpecfile,
295    RpmYumdb,
296
297    // ── Ruby/RubyGems ──
298    Gemfile,
299    GemfileExtracted,
300    GemfileLock,
301    GemfileLockExtracted,
302    GemArchive,
303    /// Matches Python reference value.
304    GemArchiveExtracted,
305    Gemspec,
306    GemspecExtracted,
307    GemGemspecInstalledSpecifications,
308
309    // ── Disk Images/Installers ──
310    InstallshieldInstaller,
311    IsoDiskImage,
312    NsisInstaller,
313    SharShellArchive,
314    SquashfsDiskImage,
315
316    // ── Swift ──
317    SwiftPackageManifestJson,
318    SwiftPackageResolved,
319    SwiftPackageShowDependencies,
320
321    PubliccodeYaml,
322
323    // ── vcpkg ──
324    VcpkgJson,
325
326    // ── Yarn ──
327    YarnLock,
328    YarnLockV1,
329    YarnLockV2,
330    YarnPnpCjs,
331
332    // ── Git ──
333    Gitmodules,
334}
335
336impl DatasourceId {
337    /// Returns the string representation of this datasource ID.
338    ///
339    /// This matches the serialized form used in JSON output.
340    pub fn as_str(&self) -> &'static str {
341        match self {
342            // About/README/OS
343            Self::AboutFile => "about_file",
344            Self::Readme => "readme",
345            Self::EtcOsRelease => "etc_os_release",
346
347            // Alpine
348            Self::AlpineApkArchive => "alpine_apk_archive",
349            Self::AlpineApkbuild => "alpine_apkbuild",
350            Self::AlpineInstalledDb => "alpine_installed_db",
351
352            // Arch Linux
353            Self::ArchAurinfo => "arch_aurinfo",
354            Self::ArchPkginfo => "arch_pkginfo",
355            Self::ArchSrcinfo => "arch_srcinfo",
356
357            // Android
358            Self::AndroidAab => "android_aab",
359            Self::AndroidAarLibrary => "android_aar_library",
360            Self::AndroidApk => "android_apk",
361            Self::AndroidManifestXml => "android_manifest_xml",
362            Self::AndroidSoongMetadata => "android_soong_metadata",
363
364            // Apache Axis2
365            Self::Axis2Mar => "axis2_mar",
366            Self::Axis2ModuleXml => "axis2_module_xml",
367
368            // Autotools
369            Self::AutotoolsConfigure => "autotools_configure",
370
371            // Bazel
372            Self::BazelBuild => "bazel_build",
373
374            // Bitbake
375            Self::BitbakeRecipe => "bitbake_recipe",
376            Self::BitbakeRecipeAppend => "bitbake_recipe_append",
377
378            // Bower
379            Self::BowerJson => "bower_json",
380
381            // Buck
382            Self::BuckFile => "buck_file",
383            Self::BuckMetadata => "buck_metadata",
384
385            // Carthage
386            Self::CarthageCartfile => "carthage_cartfile",
387            Self::CarthageCartfileResolved => "carthage_cartfile_resolved",
388
389            // Cargo/Rust
390            Self::CargoLock => "cargo_lock",
391            Self::CargoToml => "cargo_toml",
392            Self::RustBinary => "rust_binary",
393            Self::WindowsExecutable => "windows_executable",
394
395            // Chef
396            Self::ChefCookbookMetadataJson => "chef_cookbook_metadata_json",
397            Self::ChefCookbookMetadataRb => "chef_cookbook_metadata_rb",
398
399            Self::CitationCff => "citation_cff",
400
401            // CocoaPods
402            Self::CocoapodsPodfile => "cocoapods_podfile",
403            Self::CocoapodsPodfileLock => "cocoapods_podfile_lock",
404            Self::CocoapodsPodspec => "cocoapods_podspec",
405            Self::CocoapodsPodspecJson => "cocoapods_podspec_json",
406
407            // Conan
408            Self::ConanConanDataYml => "conan_conandata_yml",
409            Self::ConanConanFilePy => "conan_conanfile_py",
410            Self::ConanConanFileTxt => "conan_conanfile_txt",
411            Self::ConanLock => "conan_lock",
412
413            // Conda
414            Self::CondaYaml => "conda_yaml",
415            Self::CondaMetaJson => "conda_meta_json",
416            Self::CondaMetaYaml => "conda_meta_yaml",
417
418            // Clojure
419            Self::ClojureDepsEdn => "clojure_deps_edn",
420            Self::ClojureProjectClj => "clojure_project_clj",
421
422            // CPAN/Perl
423            Self::CpanDistIni => "cpan_dist_ini",
424            Self::CpanMakefile => "cpan_makefile",
425            Self::CpanManifest => "cpan_manifest",
426            Self::CpanMetaJson => "cpan_meta_json",
427            Self::CpanMetaYml => "cpan_meta_yml",
428
429            // CRAN/R
430            Self::CranDescription => "cran_description",
431
432            // Dart/Flutter
433            Self::PubspecLock => "pubspec_lock",
434            Self::PubspecYaml => "pubspec_yaml",
435
436            // Debian
437            Self::DebianControlExtractedDeb => "debian_control_extracted_deb",
438            Self::DebianControlInSource => "debian_control_in_source",
439            Self::DebianCopyright => "debian_copyright",
440            Self::DebianCopyrightInSource => "debian_copyright_in_source",
441            Self::DebianCopyrightInPackage => "debian_copyright_in_package",
442            Self::DebianCopyrightStandalone => "debian_copyright_standalone",
443            Self::DebianDeb => "debian_deb",
444            Self::DebianSourceMetadataTarball => "debian_source_metadata_tarball",
445            Self::DebianDistrolessInstalledDb => "debian_distroless_installed_db",
446            Self::DebianInstalledFilesList => "debian_installed_files_list",
447            Self::DebianInstalledMd5Sums => "debian_installed_md5sums",
448            Self::DebianInstalledStatusDb => "debian_installed_status_db",
449            Self::DebianMd5SumsInExtractedDeb => "debian_md5sums_in_extracted_deb",
450            Self::DebianOriginalSourceTarball => "debian_original_source_tarball",
451            Self::DebianSourceControlDsc => "debian_source_control_dsc",
452            Self::DenoJson => "deno_json",
453            Self::DenoLock => "deno_lock",
454            Self::Dockerfile => "dockerfile",
455            Self::ErlangOtpAppSrc => "erlang_otp_app_src",
456            Self::RebarConfig => "rebar_config",
457            Self::RebarLock => "rebar_lock",
458            Self::BazelModule => "bazel_module",
459
460            // FreeBSD
461            Self::FreebsdCompactManifest => "freebsd_compact_manifest",
462
463            // Go
464            Self::Godeps => "godeps",
465            Self::GoBinary => "go_binary",
466            Self::GoMod => "go_mod",
467            Self::GoModGraph => "go_mod_graph",
468            Self::GoSum => "go_sum",
469            Self::GoWork => "go_work",
470
471            // Haskell / Hackage
472            Self::HackageCabal => "hackage_cabal",
473            Self::HackageCabalProject => "hackage_cabal_project",
474            Self::HackageStackYaml => "hackage_stack_yaml",
475
476            // Gradle
477            Self::BuildGradle => "build_gradle",
478            Self::GradleLockfile => "gradle_lockfile",
479            Self::GradleModule => "gradle_module",
480
481            // Haxe
482            Self::HaxelibJson => "haxelib_json",
483
484            // Helm
485            Self::HelmChartLock => "helm_chart_lock",
486            Self::HelmChartYaml => "helm_chart_yaml",
487
488            // Hex/Elixir
489            Self::HexMixLock => "hex_mix_lock",
490
491            // Julia
492            Self::JuliaProjectToml => "julia_project_toml",
493            Self::JuliaManifestToml => "julia_manifest_toml",
494
495            // Java
496            Self::AntIvyXml => "ant_ivy_xml",
497            Self::JavaEarApplicationXml => "java_ear_application_xml",
498            Self::JavaEarArchive => "java_ear_archive",
499            Self::JavaJar => "java_jar",
500            Self::JavaJarManifest => "java_jar_manifest",
501            Self::JavaOsgiManifest => "java_osgi_manifest",
502            Self::JavaWarArchive => "java_war_archive",
503            Self::JavaWarWebXml => "java_war_web_xml",
504            Self::JbossSar => "jboss_sar",
505            Self::JbossServiceXml => "jboss_service_xml",
506
507            // Maven
508            Self::MavenPom => "maven_pom",
509            Self::MavenPomProperties => "maven_pom_properties",
510            Self::MesonBuild => "meson_build",
511            Self::SbtBuildSbt => "sbt_build_sbt",
512
513            // Microsoft
514            Self::MicrosoftCabinet => "microsoft_cabinet",
515            Self::MicrosoftUpdateManifestMum => "microsoft_update_manifest_mum",
516
517            // Mobile/Browser
518            Self::AppleDmg => "apple_dmg",
519            Self::ChromeCrx => "chrome_crx",
520            Self::IosIpa => "ios_ipa",
521            Self::MozillaXpi => "mozilla_xpi",
522
523            // Meteor
524            Self::MeteorPackage => "meteor_package",
525
526            Self::NixDefaultNix => "nix_default_nix",
527            Self::NixFlakeLock => "nix_flake_lock",
528            Self::NixFlakeNix => "nix_flake_nix",
529
530            // npm
531            Self::BunLock => "bun_lock",
532            Self::BunLockb => "bun_lockb",
533            Self::NpmPackageJson => "npm_package_json",
534            Self::NpmPackageLockJson => "npm_package_lock_json",
535
536            // NuGet
537            Self::NugetCsproj => "nuget_csproj",
538            Self::NugetDepsJson => "nuget_deps_json",
539            Self::NugetDirectoryBuildProps => "nuget_directory_build_props",
540            Self::NugetDirectoryPackagesProps => "nuget_directory_packages_props",
541            Self::NugetNupkg => "nuget_nupkg",
542            Self::NugetProjectJson => "nuget_project_json",
543            Self::NugetProjectLockJson => "nuget_project_lock_json",
544            Self::NugetPackagesConfig => "nuget_packages_config",
545            Self::NugetPackagesLock => "nuget_packages_lock",
546            Self::NugetNuspec => "nuget_nuspec",
547            Self::NugetVbproj => "nuget_vbproj",
548            Self::NugetFsproj => "nuget_fsproj",
549
550            // OCaml/opam
551            Self::OpamFile => "opam_file",
552
553            // PHP/Composer
554            Self::PhpComposerJson => "php_composer_json",
555            Self::PhpComposerLock => "php_composer_lock",
556
557            // pnpm
558            Self::PnpmLockYaml => "pnpm_lock_yaml",
559            Self::PnpmWorkspaceYaml => "pnpm_workspace_yaml",
560
561            // Python/PyPI
562            Self::Pipfile => "pipfile",
563            Self::PipfileLock => "pipfile_lock",
564            Self::PipRequirements => "pip_requirements",
565            Self::PixiLock => "pixi_lock",
566            Self::PixiToml => "pixi_toml",
567            Self::PypiPipOriginJson => "pypi_pip_origin_json",
568            Self::PypiEgg => "pypi_egg",
569            Self::PypiEggPkginfo => "pypi_egg_pkginfo",
570            Self::PypiEditableEggPkginfo => "pypi_editable_egg_pkginfo",
571            Self::PypiInspectDeplock => "pypi_inspect_deplock",
572            Self::PypiJson => "pypi_json",
573            Self::PypiPoetryLock => "pypi_poetry_lock",
574            Self::PypiPoetryPyprojectToml => "pypi_poetry_pyproject_toml",
575            Self::PypiSdist => "pypi_sdist",
576            Self::PypiPylockToml => "pypi_pylock_toml",
577            Self::PypiPyprojectToml => "pypi_pyproject_toml",
578            Self::PypiSdistPkginfo => "pypi_sdist_pkginfo",
579            Self::PypiSetupCfg => "pypi_setup_cfg",
580            Self::PypiSetupPy => "pypi_setup_py",
581            Self::PypiUvLock => "pypi_uv_lock",
582            Self::PypiWheel => "pypi_wheel",
583            Self::PypiWheelMetadata => "pypi_wheel_metadata",
584
585            // RPM
586            Self::RpmArchive => "rpm_archive",
587            Self::RpmInstalledDatabaseBdb => "rpm_installed_database_bdb",
588            Self::RpmInstalledDatabaseNdb => "rpm_installed_database_ndb",
589            Self::RpmInstalledDatabaseSqlite => "rpm_installed_database_sqlite",
590            Self::RpmMarinerManifest => "rpm_mariner_manifest",
591            Self::RpmPackageLicenses => "rpm_package_licenses",
592            Self::RpmSpecfile => "rpm_specfile",
593            Self::RpmYumdb => "rpm_yumdb",
594
595            // Ruby/RubyGems
596            Self::Gemfile => "gemfile",
597            Self::GemfileExtracted => "gemfile_extracted",
598            Self::GemfileLock => "gemfile_lock",
599            Self::GemfileLockExtracted => "gemfile_lock_extracted",
600            Self::GemArchive => "gem_archive",
601            Self::GemArchiveExtracted => "gem_archive_extracted",
602            Self::Gemspec => "gemspec",
603            Self::GemspecExtracted => "gemspec_extracted",
604            Self::GemGemspecInstalledSpecifications => "gem_gemspec_installed_specifications",
605
606            // Disk Images/Installers
607            Self::InstallshieldInstaller => "installshield_installer",
608            Self::IsoDiskImage => "iso_disk_image",
609            Self::NsisInstaller => "nsis_installer",
610            Self::SharShellArchive => "shar_shell_archive",
611            Self::SquashfsDiskImage => "squashfs_disk_image",
612
613            // Swift
614            Self::SwiftPackageManifestJson => "swift_package_manifest_json",
615            Self::SwiftPackageResolved => "swift_package_resolved",
616            Self::SwiftPackageShowDependencies => "swift_package_show_dependencies",
617
618            Self::PubliccodeYaml => "publiccode_yaml",
619
620            // vcpkg
621            Self::VcpkgJson => "vcpkg_json",
622
623            // Yarn
624            Self::YarnLock => "yarn_lock",
625            Self::YarnLockV1 => "yarn_lock_v1",
626            Self::YarnLockV2 => "yarn_lock_v2",
627            Self::YarnPnpCjs => "yarn_pnp_cjs",
628
629            // Git
630            Self::Gitmodules => "gitmodules",
631        }
632    }
633}
634
635impl AsRef<str> for DatasourceId {
636    fn as_ref(&self) -> &str {
637        self.as_str()
638    }
639}
640
641impl fmt::Display for DatasourceId {
642    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643        f.write_str(self.as_str())
644    }
645}
646
647impl FromStr for DatasourceId {
648    type Err = String;
649
650    fn from_str(s: &str) -> Result<Self, Self::Err> {
651        match s {
652            "nuget_nupsec" => return Ok(DatasourceId::NugetNuspec),
653            "rpm_spefile" => return Ok(DatasourceId::RpmSpecfile),
654            _ => {}
655        }
656        use strum::IntoEnumIterator;
657        Self::iter()
658            .find(|variant| variant.as_str() == s)
659            .ok_or_else(|| format!("unknown datasource id: {}", s))
660    }
661}
662
663#[cfg(test)]
664mod tests {
665    use super::*;
666
667    #[test]
668    fn test_serialization() {
669        let id = DatasourceId::NpmPackageJson;
670        let json = serde_json::to_string(&id).unwrap();
671        assert_eq!(json, r#""NpmPackageJson""#);
672    }
673
674    #[test]
675    fn test_deserialization() {
676        let json = r#""NpmPackageJson""#;
677        let id: DatasourceId = serde_json::from_str(json).unwrap();
678        assert_eq!(id, DatasourceId::NpmPackageJson);
679    }
680
681    #[test]
682    fn test_as_str() {
683        assert_eq!(DatasourceId::NpmPackageJson.as_str(), "npm_package_json");
684        assert_eq!(DatasourceId::CargoLock.as_str(), "cargo_lock");
685        assert_eq!(
686            DatasourceId::PypiPyprojectToml.as_str(),
687            "pypi_pyproject_toml"
688        );
689        assert_eq!(DatasourceId::HackageCabal.as_str(), "hackage_cabal");
690        assert_eq!(DatasourceId::CitationCff.as_str(), "citation_cff");
691        assert_eq!(DatasourceId::PubliccodeYaml.as_str(), "publiccode_yaml");
692        assert_eq!(DatasourceId::YarnPnpCjs.as_str(), "yarn_pnp_cjs");
693    }
694
695    #[test]
696    fn test_display() {
697        assert_eq!(DatasourceId::NpmPackageJson.to_string(), "npm_package_json");
698    }
699
700    #[test]
701    fn test_as_ref() {
702        let id = DatasourceId::NpmPackageJson;
703        let s: &str = id.as_ref();
704        assert_eq!(s, "npm_package_json");
705    }
706
707    #[test]
708    fn test_python_rename_mappings() {
709        // Test the ~12 IDs that changed from our old values to match Python
710        assert_eq!(DatasourceId::BuckFile.as_str(), "buck_file");
711        assert_eq!(DatasourceId::BuckMetadata.as_str(), "buck_metadata");
712        assert_eq!(
713            DatasourceId::ChefCookbookMetadataJson.as_str(),
714            "chef_cookbook_metadata_json"
715        );
716        assert_eq!(
717            DatasourceId::ChefCookbookMetadataRb.as_str(),
718            "chef_cookbook_metadata_rb"
719        );
720        assert_eq!(DatasourceId::CondaYaml.as_str(), "conda_yaml");
721        assert_eq!(DatasourceId::CpanMakefile.as_str(), "cpan_makefile");
722        assert_eq!(
723            DatasourceId::DebianInstalledFilesList.as_str(),
724            "debian_installed_files_list"
725        );
726        assert_eq!(
727            DatasourceId::DebianOriginalSourceTarball.as_str(),
728            "debian_original_source_tarball"
729        );
730        assert_eq!(
731            DatasourceId::DebianSourceMetadataTarball.as_str(),
732            "debian_source_metadata_tarball"
733        );
734        assert_eq!(
735            DatasourceId::GemArchiveExtracted.as_str(),
736            "gem_archive_extracted"
737        );
738        // Corrected from typos in Python reference
739        assert_eq!(DatasourceId::NugetNuspec.as_str(), "nuget_nuspec");
740        assert_eq!(DatasourceId::RpmSpecfile.as_str(), "rpm_specfile");
741    }
742
743    #[test]
744    fn test_canonical_serialization() {
745        let nuget_json = serde_json::to_string(&DatasourceId::NugetNuspec).unwrap();
746        assert_eq!(nuget_json, r#""NugetNuspec""#);
747
748        let rpm_json = serde_json::to_string(&DatasourceId::RpmSpecfile).unwrap();
749        assert_eq!(rpm_json, r#""RpmSpecfile""#);
750    }
751
752    #[test]
753    fn test_legacy_typo_aliases() {
754        assert_eq!(
755            DatasourceId::from_str("nuget_nupsec").unwrap(),
756            DatasourceId::NugetNuspec
757        );
758        assert_eq!(
759            DatasourceId::from_str("rpm_spefile").unwrap(),
760            DatasourceId::RpmSpecfile
761        );
762    }
763}