smartnpm/ts/smartnpm.classes.npmregistry.ts

251 lines
7.3 KiB
TypeScript
Raw Normal View History

2022-04-04 21:21:49 +00:00
import * as plugins from './smartnpm.plugins.js';
import * as paths from './smartnpm.paths.js';
2017-08-14 15:50:48 +00:00
2017-08-15 15:03:21 +00:00
// interfaces
2023-07-25 16:14:51 +00:00
import { type ISearchObject } from './smartnpm.interfaces.js';
2017-08-14 15:50:48 +00:00
2017-08-15 15:03:21 +00:00
// classes
2022-04-04 21:21:49 +00:00
import { NpmPackage } from './smartnpm.classes.npmpackage.js';
2023-07-25 16:14:51 +00:00
import { type ICacheDescriptor, RegistryCache } from './smartnpm.classes.registrycache.js';
2017-08-14 15:50:48 +00:00
2019-09-06 09:12:23 +00:00
export interface INpmRegistryConstructorOptions {
npmRegistryUrl?: string;
}
2017-08-14 15:50:48 +00:00
export class NpmRegistry {
2019-09-06 09:12:23 +00:00
public options: INpmRegistryConstructorOptions;
2021-04-26 08:30:02 +00:00
public registryCache: RegistryCache;
2018-09-01 14:40:42 +00:00
private searchDomain = 'https://api.npms.io/v2/search?q=';
2019-09-06 09:12:23 +00:00
constructor(optionsArg: INpmRegistryConstructorOptions = {}) {
const defaultOptions: INpmRegistryConstructorOptions = {
2020-06-25 20:03:52 +00:00
npmRegistryUrl: 'https://registry.npmjs.org',
2019-09-06 09:12:23 +00:00
};
this.options = {
...defaultOptions,
2020-06-25 20:03:52 +00:00
...optionsArg,
2019-09-06 09:12:23 +00:00
};
2021-04-26 08:30:02 +00:00
this.registryCache = new RegistryCache(this);
2019-09-06 09:12:23 +00:00
}
2020-03-17 00:38:58 +00:00
/**
* gets info about a package
* @param packageName
*/
2019-09-06 11:22:54 +00:00
public async getPackageInfo(packageName: string): Promise<NpmPackage> {
2023-07-25 16:14:51 +00:00
const fullMetadata = await plugins
.packageJson.default(packageName, {
registryUrl: this.options.npmRegistryUrl,
fullMetadata: true,
})
.catch((err) => {
console.log(err);
return null;
});
const versionData = await plugins.packageJson.default(packageName, {
2019-09-06 09:12:23 +00:00
registryUrl: this.options.npmRegistryUrl,
2023-07-25 16:14:51 +00:00
allVersions: true,
2019-09-06 09:12:23 +00:00
});
2023-07-25 16:14:51 +00:00
const npmPackage = await NpmPackage.createFromFullMetadataAndVersionData(
this,
fullMetadata,
versionData as any
);
2019-09-06 11:22:54 +00:00
return npmPackage;
2019-09-06 09:12:23 +00:00
}
2020-03-17 00:38:58 +00:00
/**
* saves a package to disk
* @param packageName
* @param targetDir
*/
public async savePackageToDisk(packageName: string, targetDir: string): Promise<void> {
2021-04-19 12:55:11 +00:00
plugins.smartfile.fs.ensureDirSync(paths.nogitDir);
2020-03-17 00:38:58 +00:00
const npmPackage = await this.getPackageInfo(packageName);
await npmPackage.saveToDisk(targetDir);
}
/**
* gets a file from a package as Smartfile
*/
2023-07-25 16:14:51 +00:00
public async getFileFromPackage(
packageNameArg: string,
filePathArg: string,
optionsArg?: {
distTag?: string;
version?: string;
}
): Promise<plugins.smartfile.Smartfile> {
2021-05-10 16:12:11 +00:00
// lets create a cache descriptor
const cacheDescriptor: ICacheDescriptor = {
registryUrl: this.options.npmRegistryUrl,
packageName: packageNameArg,
filePath: filePathArg,
distTag: optionsArg?.distTag,
2023-07-25 16:14:51 +00:00
version: optionsArg?.version,
2021-05-10 16:12:11 +00:00
};
// lets see if we have something cached
2023-07-25 16:14:51 +00:00
const cachedFile: plugins.smartfile.Smartfile = await this.registryCache.getCachedFile(
cacheDescriptor
);
2021-05-10 16:12:11 +00:00
// lets handle both occasions
2021-04-26 08:30:02 +00:00
if (!cachedFile) {
const npmPackage = await this.getPackageInfo(packageNameArg);
if (!optionsArg?.version && !optionsArg?.distTag) {
2023-07-25 16:14:51 +00:00
const latestAvailable = npmPackage.allDistTags.find(
(packageArg) => packageArg.name === 'latest'
);
if (!latestAvailable) {
optionsArg = {
2023-07-25 16:14:51 +00:00
version: npmPackage.getBestMatchingVersion('*'),
};
}
}
2021-05-10 16:12:11 +00:00
const fileResult = await npmPackage.getFileFromPackage(filePathArg, optionsArg);
2021-06-07 11:59:56 +00:00
if (fileResult) {
this.registryCache.cacheSmartFile(cacheDescriptor, fileResult);
}
2021-04-26 08:30:02 +00:00
return fileResult;
} else {
return cachedFile;
}
2020-03-17 00:38:58 +00:00
}
2023-07-25 16:14:51 +00:00
public async getFilesFromPackage(
packageNameArg: string,
filePath: string,
optionsArg?: {
distTag?: string;
version?: string;
}
): Promise<plugins.smartfile.Smartfile[]> {
2021-05-05 11:56:12 +00:00
const npmPackage = await this.getPackageInfo(packageNameArg);
if (!optionsArg?.version && !optionsArg?.distTag) {
2023-07-25 16:14:51 +00:00
const latestAvailable = npmPackage.allDistTags.find(
(packageDistTagArg) => packageDistTagArg.name === 'latest'
);
if (!latestAvailable) {
optionsArg = {
2023-07-25 16:14:51 +00:00
version: npmPackage.getBestMatchingVersion('*'),
};
}
}
2021-05-05 11:56:12 +00:00
return npmPackage.getFilesFromPackage(filePath, optionsArg);
2021-05-05 10:54:31 +00:00
}
2023-07-25 16:14:51 +00:00
public async getPackageAsSmartfileVirtualDir(
packageNameArg: string
): Promise<plugins.smartfile.VirtualDirectory> {
2021-04-26 08:30:02 +00:00
/**
* TODO: rewrite as memory only
*/
2020-10-02 14:39:46 +00:00
const baseDir = plugins.path.join(paths.nogitDir, packageNameArg.replace('/', '__'));
await plugins.smartfile.fs.ensureDir(baseDir);
await this.savePackageToDisk(packageNameArg, baseDir);
const virtualDir = await plugins.smartfile.VirtualDirectory.fromFsDirPath(baseDir);
await plugins.smartfile.fs.remove(baseDir);
return virtualDir;
}
2020-03-17 00:38:58 +00:00
/**
* searches for a package on npm
* @param searchObjectArg
*/
public async searchOnNpm(searchObjectArg: ISearchObject) {
2019-09-06 09:12:23 +00:00
if (this.options.npmRegistryUrl !== 'https://registry.npmjs.org') {
throw Error(`cannot search registries other than registry.gitlab.com`);
}
2018-09-01 14:40:42 +00:00
let searchString = '';
2019-09-06 09:12:23 +00:00
const addToSearchString = (addStringArg: string) => {
2018-09-01 14:40:42 +00:00
searchString = `${searchString}+${addStringArg}`;
};
2017-08-15 12:20:33 +00:00
2017-08-15 15:03:21 +00:00
// name
2018-09-01 14:40:42 +00:00
if (searchObjectArg.name) {
searchString = `${searchObjectArg.name}`;
}
2017-08-15 15:03:21 +00:00
2017-08-15 12:20:33 +00:00
// metadata
2018-09-01 14:40:42 +00:00
if (searchObjectArg.author) {
addToSearchString(`author:${searchObjectArg.author}`);
}
if (searchObjectArg.maintainer) {
addToSearchString(`maintainer:${searchObjectArg.maintainer}`);
}
if (searchObjectArg.scope) {
addToSearchString(`scope:${searchObjectArg.scope}`);
}
2017-08-15 15:03:21 +00:00
2017-08-15 12:20:33 +00:00
// status
if (searchObjectArg.deprecated) {
if (searchObjectArg.deprecated === true) {
2018-09-01 14:40:42 +00:00
addToSearchString(`is:deprecated`);
2017-08-15 12:20:33 +00:00
} else {
2018-09-01 14:40:42 +00:00
addToSearchString(`not:deprecated`);
2017-08-15 12:20:33 +00:00
}
}
if (searchObjectArg.unstable) {
if (searchObjectArg.unstable === true) {
2018-09-01 14:40:42 +00:00
addToSearchString(`is:unstable`);
2017-08-15 12:20:33 +00:00
} else {
2018-09-01 14:40:42 +00:00
addToSearchString(`not:unstable`);
2017-08-15 12:20:33 +00:00
}
}
if (searchObjectArg.insecure) {
if (searchObjectArg.insecure === true) {
2018-09-01 14:40:42 +00:00
addToSearchString(`is:insecure`);
2017-08-15 12:20:33 +00:00
} else {
2018-09-01 14:40:42 +00:00
addToSearchString(`not:insecure`);
2017-08-15 12:20:33 +00:00
}
}
2017-08-15 15:03:21 +00:00
2017-08-15 12:20:33 +00:00
// search behaviour
2018-09-01 14:40:42 +00:00
if (searchObjectArg.boostExact) {
addToSearchString(`boost-exact:${searchObjectArg.boostExact}`);
}
if (searchObjectArg.scoreEffect) {
addToSearchString(`score-effect:${searchObjectArg.scoreEffect}`);
}
2017-08-15 15:03:21 +00:00
2017-08-15 12:20:33 +00:00
// analytics
2018-09-01 14:40:42 +00:00
if (searchObjectArg.qualityWeight) {
addToSearchString(`author:${searchObjectArg.qualityWeight}`);
}
if (searchObjectArg.popularityWeight) {
addToSearchString(`author:${searchObjectArg.popularityWeight}`);
}
if (searchObjectArg.maintenanceWeight) {
addToSearchString(`author:${searchObjectArg.maintenanceWeight}`);
}
2017-08-15 12:20:33 +00:00
2020-06-25 20:03:52 +00:00
console.log(
`info: Search on npm for ${plugins.consolecolor.coloredString(searchString, 'pink')}`
2018-09-01 14:40:42 +00:00
);
2017-08-15 15:03:21 +00:00
2018-02-14 22:51:08 +00:00
let body: any;
try {
2019-09-06 09:12:23 +00:00
const response = await plugins.smartrequest.getJson(this.searchDomain + searchString, {});
2018-09-01 14:40:42 +00:00
body = response.body;
2018-02-14 22:51:08 +00:00
} catch {
// we do nothing
}
// lets create the packageArray
2019-09-06 09:12:23 +00:00
const packageArray: NpmPackage[] = [];
2018-02-14 22:51:08 +00:00
// if request failed just return it empty
if (!body || typeof body === 'string') {
2018-09-01 14:40:42 +00:00
return packageArray;
2017-09-13 15:33:07 +00:00
}
2018-02-14 22:51:08 +00:00
2019-09-06 11:22:54 +00:00
for (const packageSearchInfoArg of body.results) {
const npmPackage = await this.getPackageInfo(packageSearchInfoArg.package.name);
packageArray.push(npmPackage);
2017-08-15 15:03:21 +00:00
}
2018-09-01 14:40:42 +00:00
return packageArray;
2017-08-14 15:50:48 +00:00
}
}