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: plugins.packageJson.FullMetadata, 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; public scope: string = null; public version: string = null; public allVersions: PackageVersion[]; public allDistTags: PackageDisttag[]; public description: string = null; public keywords: string[] = 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: any = null; public dist: { integrity: string; shasum: string; tarball: string; }; public score: { final: number; detail: { quality: number; popularity: number; maintenance: number; }; } = null; public searchScore: number = null; public npmRegistryRef: NpmRegistry; constructor(npmRegistryArg: NpmRegistry) { this.npmRegistryRef = npmRegistryArg; } /** * saves the package to disk */ public async saveToDisk(targetDir: string) { const smartarchiveInstance = new plugins.smartarchive.SmartArchive(); await smartarchiveInstance.extractArchiveFromUrlToFs(this.dist.tarball, 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 { const done = plugins.smartpromise.defer(); const smartarchiveInstance = new plugins.smartarchive.SmartArchive(); let tarballUrl = 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; if (optionsArg.distTag) { const targetDistTag = this.allDistTags.find((distTag) => { return distTag.name === optionsArg.distTag; }); if (targetDistTag) { targetVersionString = targetDistTag.targetVersion; } } else { targetVersionString = optionsArg.version; } // 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; } const fileObservable = await smartarchiveInstance.extractArchiveFromUrlToObservable(tarballUrl); const wantedFilePath = plugins.path.join('package', filePath); const allMatchingFiles: plugins.smartfile.Smartfile[] = []; const subscription = fileObservable.subscribe( (fileArg) => { // returnOnFirstArg requires exact match if (returnOnFirstArg && fileArg.path === wantedFilePath) { // lets resolve with the wanted file done.resolve([fileArg]); subscription.unsubscribe(); } else if (!returnOnFirstArg && fileArg.path.startsWith(wantedFilePath)) { allMatchingFiles.push(fileArg); } }, (err) => { console.log(err); }, () => { done.resolve(allMatchingFiles); subscription.unsubscribe(); } ); return done.promise; } /** * 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 { // 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; } }