import * as plugins from './smartnpm.plugins.js'; import { NpmRegistry } from './smartnpm.classes.npmregistry.js'; import { PackageDisttag } from './smartnpm.classes.packagedisttag.js'; import { PackageVersion, type IVersionData } from './smartnpm.classes.packageversion.js'; export class NpmPackage { public static async createFromFullMetadataAndVersionData( npmRegistryArg: NpmRegistry, fullMetadataArg: Record, versionsDataArg: { name: string; 'dist-tags': { [key: string]: string }; versions: { [key: string]: IVersionData }; } ) { const npmPackage = new NpmPackage(npmRegistryArg); Object.assign(npmPackage, fullMetadataArg); npmPackage.allVersions = []; npmPackage.allDistTags = []; for (const versionArg of Object.keys(versionsDataArg.versions)) { const packageVersion = PackageVersion.createFromVersionData( versionsDataArg.versions[versionArg] ); npmPackage.allVersions.push(packageVersion); } for (const distTagArg of Object.keys(versionsDataArg['dist-tags'])) { const packageDistTag = new PackageDisttag( distTagArg, versionsDataArg['dist-tags'][distTagArg] ); npmPackage.allDistTags.push(packageDistTag); } return npmPackage; } // INSTANCE public name: string | null = null; public scope: string | null = null; public version: string | null = null; public allVersions: PackageVersion[] = []; public allDistTags: PackageDisttag[] = []; public description: string | null = null; public keywords: string[] | null = null; public date!: string; public license!: string; public links!: { npm: string; homepage: string; repository: string; bugs: string; }; public author!: { name: 'Lossless GmbH'; }; public publisher!: { username: 'gitzone'; email: 'npm@git.zone'; }; public maintainers: unknown = null; public dist!: { integrity: string; shasum: string; tarball: string; }; public score: { final: number; detail: { quality: number; popularity: number; maintenance: number; }; } | null = null; public searchScore: number | null = null; public npmRegistryRef: NpmRegistry; constructor(npmRegistryArg: NpmRegistry) { this.npmRegistryRef = npmRegistryArg; } /** * saves the package to disk */ public async saveToDisk(targetDir: string) { await plugins.smartarchive.SmartArchive.create().url(this.dist.tarball).extract(targetDir); } /** * saves the complete package to cache */ public async saveToCache() {} /** * get files from package */ public async getFilesFromPackage( filePath: string, optionsArg: { distTag?: string; version?: string; } = {}, returnOnFirstArg = false ): Promise { let tarballUrl: string | undefined = this.dist?.tarball; if (optionsArg?.version || optionsArg?.distTag) { if (optionsArg.distTag && optionsArg.version) { throw new Error('Please either specify version OR disttag, not both.'); } let targetVersionString: string | undefined; if (optionsArg.distTag) { const targetDistTag = this.allDistTags.find((distTag) => { return distTag.name === optionsArg.distTag; }); if (targetDistTag) { targetVersionString = targetDistTag.targetVersion; } } else { targetVersionString = optionsArg.version; } if (!targetVersionString) { return null; } // lets find the best matching release const bestMatchingVersion = this.getBestMatchingVersion(targetVersionString); if (!bestMatchingVersion) { return null; } tarballUrl = this.allVersions.find( (packageVersion) => packageVersion.version === bestMatchingVersion )?.dist.tarball; } if (!tarballUrl) { return null; } const wantedFilePath = plugins.path.join('package', filePath); const allFiles = await plugins.smartarchive.SmartArchive.create().url(tarballUrl).toSmartFiles(); const allMatchingFiles = allFiles.filter((fileArg) => { if (returnOnFirstArg) { return fileArg.path === wantedFilePath; } return fileArg.path.startsWith(wantedFilePath); }); return returnOnFirstArg ? allMatchingFiles.slice(0, 1) : allMatchingFiles; } /** * get files from package */ public async getFileFromPackage( filePath: string, optionsArg?: { distTag?: string; version?: string; } ): Promise { const result = await this.getFilesFromPackage(filePath, optionsArg, true); return result?.[0] || null; } /** * updates the package with information from the registry */ update() {} /** */ public getBestMatchingVersion(versionArg: string): string | null { // lets find the best matching release const targetVersion = plugins.smartversion.SmartVersion.fromFuzzyString(versionArg); const versionStrings = this.allVersions.map((packageVersion) => packageVersion.version); const bestMatchingVersion = targetVersion.getBestMatch(versionStrings); if (!bestMatchingVersion) { return null; } return bestMatchingVersion; } }