@directus/extensions-sdk
Version:
A toolkit to develop extensions to extend Directus
132 lines (129 loc) • 5.65 kB
JavaScript
import { BUNDLE_EXTENSION_TYPES, EXTENSION_LANGUAGES, EXTENSION_PKG_KEY, EXTENSION_TYPES, HYBRID_EXTENSION_TYPES, } from '@directus/extensions';
import { isIn } from '@directus/utils';
import chalk from 'chalk';
import { execa } from 'execa';
import fse from 'fs-extra';
import ora from 'ora';
import path from 'path';
import { LAST_BREAKING_RELEASE } from '../../constants/last-breaking.js';
import getPackageManager from '../utils/get-package-manager.js';
import { isLanguage, languageToShort } from '../utils/languages.js';
import { log } from '../utils/logger.js';
import copyTemplate from './helpers/copy-template.js';
import getExtensionDevDeps from './helpers/get-extension-dev-deps.js';
export default async function create(type, name, options) {
const install = options.install ?? true;
const targetDir = name.substring(name.lastIndexOf('/') + 1);
const targetPath = path.resolve(targetDir);
if (!isIn(type, EXTENSION_TYPES)) {
log(`Extension type ${chalk.bold(type)} is not supported. Available extension types: ${EXTENSION_TYPES.map((t) => chalk.bold.magenta(t)).join(', ')}.`, 'error');
process.exit(1);
}
if (targetDir.length === 0) {
log(`Extension name can not be empty.`, 'error');
process.exit(1);
}
if (await fse.pathExists(targetPath)) {
const info = await fse.stat(targetPath);
if (!info.isDirectory()) {
log(`Destination ${chalk.bold(targetDir)} already exists and is not a directory.`, 'error');
process.exit(1);
}
const files = await fse.readdir(targetPath);
if (files.length > 0) {
log(`Destination ${chalk.bold(targetDir)} already exists and is not empty.`, 'error');
process.exit(1);
}
}
if (isIn(type, BUNDLE_EXTENSION_TYPES)) {
await createBundleExtension({ type, name, targetDir, targetPath, install });
}
else {
const language = options.language ?? 'javascript';
await createExtension({ type, name, targetDir, targetPath, language, install });
}
}
async function createBundleExtension({ type, name, targetDir, targetPath, install, }) {
const spinner = ora(chalk.bold('Scaffolding Directus extension...')).start();
await fse.ensureDir(targetPath);
await copyTemplate(type, targetPath);
const host = `^${LAST_BREAKING_RELEASE}`;
const options = { type, path: { app: 'dist/app.js', api: 'dist/api.js' }, entries: [], host };
const packageManifest = getPackageManifest(name, options, await getExtensionDevDeps(type));
await fse.writeJSON(path.join(targetPath, 'package.json'), packageManifest, { spaces: '\t' });
const packageManager = getPackageManager();
if (install) {
await execa(packageManager, ['install'], { cwd: targetPath });
}
spinner.succeed(chalk.bold('Done'));
log(getDoneMessage(type, targetDir, targetPath, packageManager, install));
}
async function createExtension({ type, name, targetDir, targetPath, language, install, }) {
if (!isLanguage(language)) {
log(`Language ${chalk.bold(language)} is not supported. Available languages: ${EXTENSION_LANGUAGES.map((t) => chalk.bold.magenta(t)).join(', ')}.`, 'error');
process.exit(1);
}
const spinner = ora(chalk.bold('Scaffolding Directus extension...')).start();
await fse.ensureDir(targetPath);
await copyTemplate(type, targetPath, 'src', language);
const host = `^${LAST_BREAKING_RELEASE}`;
const options = isIn(type, HYBRID_EXTENSION_TYPES)
? {
type,
path: { app: 'dist/app.js', api: 'dist/api.js' },
source: { app: `src/app.${languageToShort(language)}`, api: `src/api.${languageToShort(language)}` },
host,
}
: {
type,
path: 'dist/index.js',
source: `src/index.${languageToShort(language)}`,
host,
};
const packageManifest = getPackageManifest(name, options, await getExtensionDevDeps(type, language));
await fse.writeJSON(path.join(targetPath, 'package.json'), packageManifest, { spaces: '\t' });
const packageManager = getPackageManager();
if (install) {
await execa(packageManager, ['install'], { cwd: targetPath });
}
spinner.succeed(chalk.bold('Done'));
log(getDoneMessage(type, targetDir, targetPath, packageManager, install));
}
function getPackageManifest(name, options, deps) {
const packageManifest = {
name: name,
description: 'Please enter a description for your extension',
icon: 'extension',
version: '1.0.0',
keywords: ['directus', 'directus-extension', `directus-extension-${options.type}`],
type: 'module',
files: ['dist'],
[EXTENSION_PKG_KEY]: options,
scripts: {
build: 'directus-extension build',
dev: 'directus-extension build -w --no-minify',
link: 'directus-extension link',
},
devDependencies: deps,
};
if (options.type === 'bundle') {
packageManifest['scripts']['add'] = 'directus-extension add';
}
return packageManifest;
}
function getDoneMessage(type, targetDir, targetPath, packageManager, install) {
let message = `
Your ${type} extension has been created at ${chalk.green(targetPath)}
To start developing, run:
${chalk.blue('cd')} ${targetDir}`;
if (!install) {
message += `
${chalk.blue(`${packageManager}`)} install`;
}
message += `
${chalk.blue(`${packageManager} run`)} dev
To build for production, run:
${chalk.blue(`${packageManager} run`)} build
`;
return message;
}