studiocms
Version:
Astro Native CMS for AstroDB. Built from the ground up by the Astro community.
105 lines (89 loc) • 3.88 kB
text/typescript
import { askToContinue, spinner } from '@withstudiocms/effect/clack';
import { Effect, genLogger } from '../../effect.js';
import { CliContext } from '../utils/context.js';
import { type PluginInfo, StudioCMSScopes } from './index.js';
import { fetchPackageJson, parsePluginName } from './npm-utils.js';
export class ValidatePlugins extends Effect.Service<ValidatePlugins>()('ValidatePlugins', {
effect: genLogger('studiocms/cli/add/validatePlugins/ValidatePlugins.effect')(function* () {
const run = (names: string[]) =>
genLogger('studiocms/cli/add/validatePlugins/ValidatePlugins.effect.run')(function* () {
const { chalk } = yield* CliContext;
const spin = yield* spinner();
yield* spin.start('Resolving packages...');
const entries: PluginInfo[] = [];
for (const plugin of names) {
const parsed = yield* parsePluginName(plugin);
if (!parsed)
throw new Error(`${chalk.bold(plugin)} does not appear to be a valid package name!`);
const { scope, name, tag } = parsed;
// biome-ignore lint/suspicious/noExplicitAny: this is a valid use case for explicit any
let pkgJson: any = {};
let pkgType: 'first-party' | 'third-party';
if (scope && !StudioCMSScopes.includes(scope)) {
pkgType = 'third-party';
} else {
const firstPartyPkgCheck = yield* fetchPackageJson(scope, name, tag);
if (firstPartyPkgCheck instanceof Error) {
if (firstPartyPkgCheck.message) {
yield* spin.message(chalk.yellow(firstPartyPkgCheck.message));
}
yield* spin.message(
chalk.yellow(`${chalk.bold(plugin)} is not an official StudioCMS package.`)
);
if (!(yield* askToContinue())) {
throw new Error(
`No problem! Find our official plugins at ${chalk.magenta('https://docs.studiocms.dev')}`
);
}
yield* spin.start('Resolving with third party packages...');
pkgType = 'third-party';
} else {
pkgType = 'first-party';
// biome-ignore lint/suspicious/noExplicitAny: this is a valid use case for explicit any
pkgJson = firstPartyPkgCheck as any;
}
}
if (pkgType === 'third-party') {
const thirdPartyPkgCheck = yield* fetchPackageJson(scope, name, tag);
if (thirdPartyPkgCheck instanceof Error) {
if (thirdPartyPkgCheck.message) {
yield* spin.message(chalk.yellow(thirdPartyPkgCheck.message));
}
throw new Error(`Unable to fetch ${chalk.bold(plugin)}. Does the package exist?`);
}
// biome-ignore lint/suspicious/noExplicitAny: this is a valid use case for explicit any
pkgJson = thirdPartyPkgCheck as any;
}
const resolvedScope = pkgType === 'first-party' ? '@studiocms' : scope;
const packageName = `${resolvedScope ? `${resolvedScope}/` : ''}${name}`;
const pluginName = packageName;
const dependencies: PluginInfo['dependencies'] = [[pkgJson.name, `^${pkgJson.version}`]];
if (pkgJson.peerDependencies) {
const meta = pkgJson.peerDependenciesMeta || {};
for (const peer in pkgJson.peerDependencies) {
const optional = meta[peer]?.optional || false;
const isStudioCMS = peer === 'studiocms';
if (!optional && !isStudioCMS) {
dependencies.push([peer, pkgJson.peerDependencies[peer]]);
}
}
}
const keywords = Array.isArray(pkgJson.keywords) ? pkgJson.keywords : [];
if (!keywords.includes('studiocms-plugin')) {
throw new Error(
`${chalk.bold(plugin)} doesn't appear to be an StudioCMS Plugin. Find our official plugins at ${chalk.magenta('https://docs.studiocms.dev')}`
);
}
entries.push({
id: plugin,
packageName,
dependencies,
pluginName,
});
}
yield* spin.stop('Packages Resolved.');
return entries;
});
return { run };
}),
}) {}