@strapi/sdk-plugin
Version:
Simple tools for developing Strapi plugins
1,221 lines (1,183 loc) • 40.3 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const commander = require("commander");
const packUp = require("@strapi/pack-up");
const boxen = require("boxen");
const chalk = require("chalk");
const fs = require("fs");
const path = require("path");
const fs$1 = require("fs/promises");
const os = require("os");
const pkgUp = require("pkg-up");
const yup = require("yup");
const getLatestVersion = require("get-latest-version");
const gitUrlParse = require("git-url-parse");
const path$1 = require("node:path");
const outdent = require("outdent");
const concurrently = require("concurrently");
const fs$2 = require("node:fs/promises");
const nodemon = require("nodemon");
const ora = require("ora");
const ts = require("typescript");
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
function _interopNamespace(e) {
if (e && e.__esModule)
return e;
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
if (e) {
for (const k in e) {
if (k !== "default") {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const boxen__default = /* @__PURE__ */ _interopDefault(boxen);
const chalk__default = /* @__PURE__ */ _interopDefault(chalk);
const fs__default = /* @__PURE__ */ _interopDefault(fs);
const path__default = /* @__PURE__ */ _interopDefault(path);
const fs__default$1 = /* @__PURE__ */ _interopDefault(fs$1);
const os__default = /* @__PURE__ */ _interopDefault(os);
const pkgUp__default = /* @__PURE__ */ _interopDefault(pkgUp);
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
const getLatestVersion__default = /* @__PURE__ */ _interopDefault(getLatestVersion);
const gitUrlParse__default = /* @__PURE__ */ _interopDefault(gitUrlParse);
const path__default$1 = /* @__PURE__ */ _interopDefault(path$1);
const concurrently__default = /* @__PURE__ */ _interopDefault(concurrently);
const fs__default$2 = /* @__PURE__ */ _interopDefault(fs$2);
const nodemon__default = /* @__PURE__ */ _interopDefault(nodemon);
const ora__default = /* @__PURE__ */ _interopDefault(ora);
const ts__default = /* @__PURE__ */ _interopDefault(ts);
function resolveConfig(opts) {
const { cwd, bundles } = opts;
return {
unstable_viteConfig: {
build: {
commonjsOptions: {
include: [/node_modules/, `${cwd}/**/*`],
extensions: [".js", ".jsx", ".cjs"]
}
}
},
bundles,
dist: "./dist",
/**
* ignore the exports map of a plugin, because we're streamlining the
* process and ensuring the server package and admin package are built
* with the correct runtime and their individual tsconfigs
*/
exports: {}
};
}
const runAction = (name, action2) => (ctx, ...args) => {
const { logger } = ctx;
Promise.resolve().then(() => {
return action2(...args, ctx);
}).catch((error) => {
logger.error(error);
process.exit(1);
});
};
const dirContainsStrapiProject = (dir) => {
try {
const packageJsonPath = path__default.default.join(dir, "package.json");
const pkgJSON = JSON.parse(fs__default.default.readFileSync(packageJsonPath, "utf-8"));
return Boolean(
pkgJSON.dependencies?.["@strapi/strapi"] || pkgJSON.devDependencies?.["@strapi/strapi"]
);
} catch (err) {
return false;
}
};
const getPkgManager = (options, isStrapi) => {
if (isStrapi) {
const hasPackageLock = fs__default.default.existsSync(path__default.default.join(process.cwd(), "package-lock.json"));
const hasYarnLock = fs__default.default.existsSync(path__default.default.join(process.cwd(), "yarn.lock"));
const hasPnpmLock = fs__default.default.existsSync(path__default.default.join(process.cwd(), "pnpm-lock.yaml"));
if (hasPackageLock) {
return "npm";
}
if (hasYarnLock) {
return "yarn";
}
if (hasPnpmLock) {
return "pnpm";
}
}
if (options.useNpm === true) {
return "npm";
}
if (options.usePnpm === true) {
return "pnpm";
}
if (options.useYarn === true) {
return "yarn";
}
const userAgent = process.env.npm_config_user_agent || "";
if (userAgent.startsWith("yarn")) {
return "yarn";
}
if (userAgent.startsWith("pnpm")) {
return "pnpm";
}
return "npm";
};
const logInstructions = (pluginName, { language, path: pluginPath }) => {
const maxLength = ` resolve: './src/plugins/${pluginName}'`.length;
const separator = Array(maxLength).fill("─").join("");
const exportInstruction = language === "js" ? "module.exports =" : "export default";
return `
You can now enable your plugin by adding the following in ${chalk__default.default.yellow(
`./config/plugins.${language}`
)}
${separator}
${exportInstruction} {
${chalk__default.default.gray("// ...")}
${chalk__default.default.green(`'${pluginName}'`)}: {
enabled: ${chalk__default.default.yellow(true)},
resolve: '${chalk__default.default.yellow(pluginPath)}'
},
${chalk__default.default.gray("// ...")}
}
${separator}
`;
};
const runInstall = async (packageManager, pluginPath) => {
const { execa: execaPkg } = await import("execa");
const execa = execaPkg({
cwd: pluginPath,
verbose: "full"
});
await execa`${packageManager} install`;
};
const runBuild = async (packageManager, pluginPath) => {
const { execa: execaPkg } = await import("execa");
const execa = execaPkg({
cwd: pluginPath,
verbose: "full"
});
if (packageManager === "npm") {
await execa`${packageManager} run build`;
return;
}
await execa`${packageManager} build`;
};
const packageJsonSchema = yup__namespace.object({
name: yup__namespace.string().required(),
exports: yup__namespace.lazy(
(value) => yup__namespace.object(
typeof value === "object" ? Object.entries(value).reduce((acc, [key, keyValue]) => {
if (typeof keyValue === "object") {
acc[key] = yup__namespace.object({
types: yup__namespace.string().optional(),
source: yup__namespace.string().required(),
module: yup__namespace.string().optional(),
import: yup__namespace.string().required(),
require: yup__namespace.string().required(),
default: yup__namespace.string().required()
}).noUnknown(true);
} else {
acc[key] = yup__namespace.string().required();
}
return acc;
}, {}) : void 0
).optional()
)
});
const loadPkg = async ({ cwd, logger }) => {
const pkgPath = await pkgUp__default.default({ cwd });
if (!pkgPath) {
throw new Error("Could not find a package.json in the current directory");
}
const buffer = await fs__default$1.default.readFile(pkgPath);
const pkg = JSON.parse(buffer.toString());
logger.debug("Loaded package.json:", os__default.default.EOL, pkg);
return pkg;
};
const validatePkg = async ({ pkg }) => {
try {
const validatedPkg = await packageJsonSchema.validate(pkg, {
strict: true
});
return validatedPkg;
} catch (err) {
if (err instanceof yup__namespace.ValidationError) {
switch (err.type) {
case "required":
if (err.path) {
throw new Error(
`'${err.path}' in 'package.json' is required as type '${chalk__default.default.magenta(
yup__namespace.reach(packageJsonSchema, err.path).type
)}'`
);
}
break;
case "noUnknown":
if (err.path && err.params && "unknown" in err.params) {
throw new Error(
`'${err.path}' in 'package.json' contains the unknown key ${chalk__default.default.magenta(
err.params.unknown
)}, for compatability only the following keys are allowed: ${chalk__default.default.magenta(
"['types', 'source', 'import', 'require', 'default']"
)}`
);
}
break;
default:
if (err.path && err.params && "type" in err.params && "value" in err.params) {
throw new Error(
`'${err.path}' in 'package.json' must be of type '${chalk__default.default.magenta(
err.params.type
)}' (recieved '${chalk__default.default.magenta(typeof err.params.value)}')`
);
}
}
}
throw err;
}
};
const action$4 = async ({ ...opts }, _cmd, { logger, cwd }) => {
try {
process.env.NODE_ENV = "production";
const pkg = await loadPkg({ cwd, logger });
const pkgJson = await validatePkg({ pkg });
if (!pkgJson.exports["./strapi-admin"] && !pkgJson.exports["./strapi-server"]) {
throw new Error(
"You need to have either a strapi-admin or strapi-server export in your package.json"
);
}
const bundles = [];
if (pkgJson.exports["./strapi-admin"]) {
const exp = pkgJson.exports["./strapi-admin"];
const bundle = {
source: exp.source,
import: exp.import,
require: exp.require,
runtime: "web"
};
if (exp.types) {
bundle.types = exp.types;
bundle.tsconfig = "./admin/tsconfig.build.json";
}
bundles.push(bundle);
}
if (pkgJson.exports["./strapi-server"]) {
const exp = pkgJson.exports["./strapi-server"];
const bundle = {
source: exp.source,
import: exp.import,
require: exp.require,
runtime: "node"
};
if (exp.types) {
bundle.types = exp.types;
bundle.tsconfig = "./server/tsconfig.build.json";
}
bundles.push(bundle);
}
await packUp.build({
cwd,
configFile: false,
config: resolveConfig({ cwd, bundles }),
...opts
});
} catch (err) {
logger.error(
"There seems to be an unexpected error, try again with --debug for more information \n"
);
if (err instanceof Error && err.stack) {
logger.log(
chalk__default.default.red(
boxen__default.default(err.stack, {
padding: 1,
align: "left"
})
)
);
}
process.exit(1);
}
};
const command$4 = ({ ctx }) => {
return commander.createCommand("build").description("Bundle your strapi plugin for publishing.").option("-d, --debug", "Enable debugging mode with verbose logs", false).option("--silent", "Don't log anything", false).option("--sourcemap", "produce sourcemaps", false).option("--minify", "minify the output", false).action((...args) => runAction("build", action$4)(ctx, ...args));
};
const gitIgnoreFile = {
name: ".gitignore",
contents: outdent.outdent`
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
############################
# OS X
############################
.DS_Store
.AppleDouble
.LSOverride
Icon
.Spotlight-V100
.Trashes
._*
############################
# Linux
############################
*~
############################
# Windows
############################
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
############################
# Packages
############################
*.7z
*.csv
*.dat
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.com
*.class
*.dll
*.exe
*.o
*.seed
*.so
*.swo
*.swp
*.swn
*.swm
*.out
*.pid
############################
# Logs and databases
############################
.tmp
*.log
*.sql
*.sqlite
*.sqlite3
############################
# Misc.
############################
*#
ssl
.idea
nbproject
.tsbuildinfo
.eslintcache
.env
############################
# Strapi
############################
public/uploads/*
!public/uploads/.gitkeep
############################
# Build
############################
dist
build
############################
# Node.js
############################
lib-cov
lcov.info
pids
logs
results
node_modules
.node_history
############################
# Package managers
############################
.yarn/*
!.yarn/cache
!.yarn/unplugged
!.yarn/patches
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
yarn-error.log
############################
# Tests
############################
coverage
`
};
const USE_RC_VERSIONS = ["@strapi/design-system", "@strapi/icons"];
let promptAnswers = [];
const action$3 = async (packagePath, { silent, debug, useNpm, usePnpm, useYarn, install }, { logger, cwd }) => {
try {
promptAnswers = [];
const isStrapiProject = dirContainsStrapiProject(cwd);
const parsedPath = path__default$1.default.parse(packagePath);
const suggestedPackageName = parsedPath.base;
const isPathPackageName = !packagePath.includes("/");
const pluginPath = isStrapiProject && isPathPackageName ? `./src/plugins/${packagePath}` : packagePath;
const template = getPluginTemplate({ suggestedPackageName });
await packUp.init({
path: pluginPath,
cwd,
silent,
debug,
template
});
const packageManager = getPkgManager(
{
useNpm,
usePnpm,
useYarn
},
isStrapiProject
);
if (install) {
await runInstall(packageManager, pluginPath);
await runBuild(packageManager, pluginPath);
}
if (isStrapiProject) {
const pkgName = promptAnswers.find((option) => option.name === "pkgName")?.answer;
const language = promptAnswers.find((option) => option.name === "typescript")?.answer ? "ts" : "js";
if (typeof pkgName === "string" && ["ts", "js"].includes(language)) {
logger.info(logInstructions(pkgName, { language, path: pluginPath }));
}
}
logger.info("Plugin generated successfully.");
} catch (err) {
logger.error(
"There seems to be an unexpected error, try again with --debug for more information \n"
);
if (err instanceof Error && err.stack) {
logger.log(
chalk__default.default.red(
boxen__default.default(err.stack, {
padding: 1,
align: "left"
})
)
);
}
process.exit(1);
}
};
const PACKAGE_NAME_REGEXP = /^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)\/)?[a-z0-9-~][a-z0-9-._~]*$/i;
const getPluginTemplate = ({ suggestedPackageName }) => {
return packUp.defineTemplate(async ({ logger, gitConfig, packagePath }) => {
let repo;
const [packageFolder] = packagePath.split(path__default$1.default.sep).slice(-1);
if (!packagePath?.length || !packageFolder) {
throw new Error("Missing package path");
}
return {
prompts: [
packUp.definePackageOption({
name: "pkgName",
type: "text",
message: "plugin name",
initial: () => suggestedPackageName ?? repo?.name ?? "",
validate(val) {
if (!val || typeof val !== "string") {
return "package name is required";
}
const match = PACKAGE_NAME_REGEXP.exec(val);
if (!match) {
return "invalid package name";
}
return true;
}
}),
packUp.definePackageOption({
name: "displayName",
type: "text",
message: "plugin display name"
}),
packUp.definePackageOption({
name: "description",
type: "text",
message: "plugin description"
}),
packUp.definePackageOption({
name: "authorName",
type: "text",
message: "plugin author name",
initial: gitConfig?.user?.name
}),
packUp.definePackageOption({
name: "authorEmail",
type: "text",
message: "plugin author email",
initial: gitConfig?.user?.email
}),
packUp.definePackageOption({
name: "repo",
type: "text",
message: "git url",
validate(val) {
if (!val) {
return true;
}
try {
const result = gitUrlParse__default.default(val);
repo = { source: result.source, owner: result.owner, name: result.name };
return true;
} catch (err) {
return "invalid git url";
}
}
}),
packUp.definePackageOption({
name: "license",
type: "text",
message: "plugin license",
initial: "MIT",
validate(v) {
if (!v) {
return "license is required";
}
return true;
}
}),
packUp.definePackageOption({
name: "client-code",
type: "confirm",
message: "register with the admin panel?",
initial: true
}),
packUp.definePackageOption({
name: "server-code",
type: "confirm",
message: "register with the server?",
initial: true
}),
packUp.definePackageFeature({
name: "editorconfig",
initial: true,
optional: true
}),
packUp.definePackageFeature({
name: "eslint",
initial: true,
optional: true
}),
packUp.definePackageFeature({
name: "prettier",
initial: true,
optional: true
}),
packUp.definePackageFeature({
name: "typescript",
initial: true,
optional: true
})
],
async getFiles(answers = []) {
const author = [];
const files = [];
const pkgJson = {
version: "0.0.0",
keywords: [],
type: "commonjs",
exports: {
"./package.json": "./package.json"
},
files: ["dist"],
scripts: {
build: "strapi-plugin build",
watch: "strapi-plugin watch",
"watch:link": "strapi-plugin watch:link",
verify: "strapi-plugin verify"
},
dependencies: {},
devDependencies: {
/**
* We set * as a default version, but further down
* we try to resolve each package to their latest
* version, failing that we leave the fallback of *.
*/
"@strapi/strapi": "*",
"@strapi/sdk-plugin": "*",
prettier: "*"
},
peerDependencies: {
"@strapi/strapi": "^5.0.0",
"@strapi/sdk-plugin": "^5.0.0"
},
strapi: {
kind: "plugin"
}
};
if (Array.isArray(answers)) {
for (const ans of answers) {
const { name, answer } = ans;
switch (name) {
case "pkgName": {
pkgJson.name = String(answer);
pkgJson.strapi.name = String(answer);
break;
}
case "description": {
pkgJson.description = String(answer);
pkgJson.strapi.description = String(answer);
break;
}
case "displayName": {
pkgJson.strapi.displayName = String(answer);
break;
}
case "authorName": {
author.push(String(answer));
break;
}
case "authorEmail": {
if (answer) {
author.push(`<${answer}>`);
}
break;
}
case "license": {
pkgJson.license = String(answer);
break;
}
case "client-code": {
if (answer) {
pkgJson.exports["./strapi-admin"] = {
source: "./admin/src/index.js",
import: "./dist/admin/index.mjs",
require: "./dist/admin/index.js",
default: "./dist/admin/index.js"
};
pkgJson.dependencies = {
...pkgJson.dependencies,
"@strapi/design-system": "*",
"@strapi/icons": "*",
"react-intl": "*"
};
pkgJson.devDependencies = {
...pkgJson.devDependencies,
react: "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-router-dom": "^6.0.0",
"styled-components": "^6.0.0"
};
pkgJson.peerDependencies = {
...pkgJson.peerDependencies,
react: "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react-router-dom": "^6.0.0",
"styled-components": "^6.0.0"
};
}
break;
}
case "server-code": {
if (answer) {
pkgJson.exports["./strapi-server"] = {
source: "./server/src/index.js",
import: "./dist/server/index.mjs",
require: "./dist/server/index.js",
default: "./dist/server/index.js"
};
}
break;
}
case "typescript": {
const isTypescript = Boolean(answer);
if (isTypescript) {
if (isRecord(pkgJson.exports["./strapi-admin"])) {
pkgJson.exports["./strapi-admin"].source = "./admin/src/index.ts";
pkgJson.exports["./strapi-admin"] = {
types: "./dist/admin/src/index.d.ts",
...pkgJson.exports["./strapi-admin"]
};
pkgJson.scripts = {
...pkgJson.scripts,
"test:ts:front": "run -T tsc -p admin/tsconfig.json"
};
pkgJson.devDependencies = {
...pkgJson.devDependencies,
"@types/react": "*",
"@types/react-dom": "*"
};
const { adminTsconfigFiles } = await Promise.resolve().then(() => require("./_chunks/typescript-BvlDiJqU.js"));
files.push(
adminTsconfigFiles.tsconfigBuildFile,
adminTsconfigFiles.tsconfigFile
);
}
if (isRecord(pkgJson.exports["./strapi-server"])) {
pkgJson.exports["./strapi-server"].source = "./server/src/index.ts";
pkgJson.exports["./strapi-server"] = {
types: "./dist/server/src/index.d.ts",
...pkgJson.exports["./strapi-server"]
};
pkgJson.scripts = {
...pkgJson.scripts,
"test:ts:back": "run -T tsc -p server/tsconfig.json"
};
const { serverTsconfigFiles } = await Promise.resolve().then(() => require("./_chunks/typescript-BvlDiJqU.js"));
files.push(
serverTsconfigFiles.tsconfigBuildFile,
serverTsconfigFiles.tsconfigFile
);
}
pkgJson.devDependencies = {
...pkgJson.devDependencies,
"@strapi/typescript-utils": "*",
typescript: "*"
};
} else {
if (isRecord(pkgJson.exports["./strapi-admin"])) {
const { adminJsConfigFile } = await Promise.resolve().then(() => require("./_chunks/javascript-c6C6Dqmz.js"));
files.push(adminJsConfigFile);
}
if (isRecord(pkgJson.exports["./strapi-server"])) {
const { serverJsConfigFile } = await Promise.resolve().then(() => require("./_chunks/javascript-c6C6Dqmz.js"));
files.push(serverJsConfigFile);
}
}
if (isRecord(pkgJson.exports["./strapi-admin"])) {
files.push({
name: isTypescript ? "admin/src/pluginId.ts" : "admin/src/pluginId.js",
contents: outdent.outdent`
export const PLUGIN_ID = '${pkgJson.name.replace(/^strapi-plugin-/i, "")}';
`
});
if (isTypescript) {
const { adminTypescriptFiles } = await Promise.resolve().then(() => require("./_chunks/admin-B7F4D6rB.js"));
files.push(...adminTypescriptFiles);
} else {
const { adminJavascriptFiles } = await Promise.resolve().then(() => require("./_chunks/admin-B7F4D6rB.js"));
files.push(...adminJavascriptFiles);
}
}
if (isRecord(pkgJson.exports["./strapi-server"])) {
if (isTypescript) {
const { serverTypescriptFiles } = await Promise.resolve().then(() => require("./_chunks/server-B-SYspSN.js"));
files.push(...serverTypescriptFiles(packageFolder));
} else {
const { serverJavascriptFiles } = await Promise.resolve().then(() => require("./_chunks/server-B-SYspSN.js"));
files.push(...serverJavascriptFiles(packageFolder));
}
}
break;
}
case "eslint": {
if (answer) {
const { eslintIgnoreFile } = await Promise.resolve().then(() => require("./_chunks/eslint-CMT-ywGG.js"));
files.push(eslintIgnoreFile);
}
break;
}
case "prettier": {
if (answer) {
const { prettierFile, prettierIgnoreFile } = await Promise.resolve().then(() => require("./_chunks/prettier-CbJxRiXe.js"));
files.push(prettierFile, prettierIgnoreFile);
}
break;
}
case "editorconfig": {
if (answer) {
const { editorConfigFile } = await Promise.resolve().then(() => require("./_chunks/editorConfig-DS8M6TFK.js"));
files.push(editorConfigFile);
}
break;
}
}
}
}
if (repo) {
pkgJson.repository = {
type: "git",
url: `git+ssh://git@${repo.source}/${repo.owner}/${repo.name}.git`
};
pkgJson.bugs = {
url: `https://${repo.source}/${repo.owner}/${repo.name}/issues`
};
pkgJson.homepage = `https://${repo.source}/${repo.owner}/${repo.name}#readme`;
}
pkgJson.author = author.filter(Boolean).join(" ") ?? void 0;
try {
pkgJson.devDependencies = await resolveLatestVersionOfDeps(pkgJson.devDependencies);
pkgJson.dependencies = await resolveLatestVersionOfDeps(pkgJson.dependencies);
pkgJson.peerDependencies = await resolveLatestVersionOfDeps(pkgJson.peerDependencies);
} catch (err) {
if (err instanceof Error) {
logger.error(err.message);
} else {
logger.error(err);
}
}
files.push({
name: "package.json",
contents: outdent.outdent`
${JSON.stringify(pkgJson, null, 2)}
`
});
files.push({
name: "README.md",
contents: outdent.outdent`
# ${pkgJson.name}
${pkgJson.description ?? ""}
`
});
files.push(gitIgnoreFile);
promptAnswers = answers;
return files;
}
};
});
};
const isRecord = (value) => Boolean(value) && !Array.isArray(value) && typeof value === "object";
const resolveLatestVersionOfDeps = async (deps) => {
const latestDeps = {};
for (const [name, version] of Object.entries(deps)) {
try {
const range = USE_RC_VERSIONS.includes(name) ? "rc" : version;
const latestVersion = await getLatestVersion__default.default(name, { range });
latestDeps[name] = latestVersion ? `^${latestVersion}` : "*";
} catch (err) {
latestDeps[name] = "*";
}
}
return latestDeps;
};
const command$3 = ({ command: commanderCommand, ctx }) => {
commanderCommand.command("init").description("Create a new plugin at a given path").argument("path", "path to the plugin").option("-d, --debug", "Enable debugging mode with verbose logs", false).option("--silent", "Don't log anything", false).option("--use-npm", "Use npm as the plugin package manager").option("--use-yarn", "Use yarn as the plugin package manager").option("--use-pnpm", "Use pnpm as the plugin package manager").option("--no-install", "Do not install dependencies").action((path2, options) => {
return action$3(path2, options, ctx);
});
};
const action$2 = async (_opts, _cmd, { cwd, logger }) => {
try {
const outDir = "./dist";
const extensions = "ts,js,png,svg,gif,jpeg,css";
const folder = path__default$1.default.join(cwd, outDir);
if (!await pathExists(folder)) {
await fs__default$2.default.mkdir(folder);
}
const pkg = await loadPkg({ cwd, logger });
const pkgJson = await validatePkg({ pkg });
logger.info(
outdent.outdent`
Watching ${outDir} for changes to files with extensions: ${extensions}
To use this package in Strapi, in a separate shell run:
cd /path/to/strapi/project
Then run one of the commands below based on the package manager used in that project:
## yarn
${chalk__default.default.greenBright(`yarn dlx yalc add --link ${pkgJson.name} && yarn install`)}
## npm
${chalk__default.default.greenBright(
`npx yalc add ${pkgJson.name} && npx yalc link ${pkgJson.name} && npm install`
)}
`.trimStart()
);
nodemon__default.default({
watch: [outDir],
ext: extensions,
exec: "yalc push --changed"
});
concurrently__default.default(["npm run watch"]);
nodemon__default.default.on("quit", () => {
process.exit();
}).on("restart", (files) => {
logger.info("Found changes in files:", chalk__default.default.magentaBright(files));
logger.info("Pushing new yalc package...");
}).on("crash", () => {
logger.error(
"An error occurred. Make sure yalc is installed globally on your system. Exiting..."
);
process.exit(1);
});
} catch (err) {
logger.error(
"There seems to be an unexpected error, try again with --debug for more information \n"
);
if (err instanceof Error && err.stack) {
logger.log(
chalk__default.default.red(
boxen__default.default(err.stack, {
padding: 1,
align: "left"
})
)
);
}
process.exit(1);
}
};
const pathExists = async (filepath) => {
try {
await fs__default$2.default.access(filepath);
return true;
} catch (error) {
return false;
}
};
const command$2 = ({ command: commanderCommand, ctx }) => {
commanderCommand.command("watch:link").description("Recompiles your plugin automatically on changes and runs yalc push --publish").option("-d, --debug", "Enable debugging mode with verbose logs", false).option("--silent", "Don't log anything", false).action((...args) => runAction("watch:link", action$2)(ctx, ...args));
};
const action$1 = async (opts, _cmd, { cwd, logger }) => {
try {
await packUp.check({
cwd,
...opts
});
} catch (err) {
logger.error(
"There seems to be an unexpected error, try again with --debug for more information \n"
);
if (err instanceof Error && err.stack) {
logger.log(
chalk__default.default.red(
boxen__default.default(err.stack, {
padding: 1,
align: "left"
})
)
);
}
process.exit(1);
}
};
const command$1 = ({ command: commanderCommand, ctx }) => {
commanderCommand.command("verify").description("Verify the output of your plugin before publishing it.").option("-d, --debug", "Enable debugging mode with verbose logs", false).option("--silent", "Don't log anything", false).action((...args) => runAction("verify", action$1)(ctx, ...args));
};
const action = async (opts, _cmd, { cwd, logger }) => {
try {
const pkg = await loadPkg({ cwd, logger });
const pkgJson = await validatePkg({ pkg });
if (!pkgJson.exports["./strapi-admin"] && !pkgJson.exports["./strapi-server"]) {
throw new Error(
"You need to have either a strapi-admin or strapi-server export in your package.json"
);
}
const bundles = [];
if (pkgJson.exports["./strapi-admin"]) {
const exp = pkgJson.exports["./strapi-admin"];
const bundle = {
source: exp.source,
import: exp.import,
require: exp.require,
runtime: "web"
};
if (exp.types) {
bundle.types = exp.types;
bundle.tsconfig = "./admin/tsconfig.build.json";
}
bundles.push(bundle);
}
if (pkgJson.exports["./strapi-server"]) {
const exp = pkgJson.exports["./strapi-server"];
const bundle = {
source: exp.source,
import: exp.import,
require: exp.require,
runtime: "node"
};
if (exp.types) {
bundle.types = exp.types;
bundle.tsconfig = "./server/tsconfig.build.json";
}
bundles.push(bundle);
}
await packUp.watch({
cwd,
configFile: false,
config: resolveConfig({ cwd, bundles }),
...opts
});
} catch (err) {
logger.error(
"There seems to be an unexpected error, try again with --debug for more information \n"
);
if (err instanceof Error && err.stack) {
logger.log(
chalk__default.default.red(
boxen__default.default(err.stack, {
padding: 1,
align: "left"
})
)
);
}
process.exit(1);
}
};
const command = ({ ctx }) => {
return commander.createCommand("watch").description("Watch & compile your strapi plugin for local development.").option("-d, --debug", "Enable debugging mode with verbose logs", false).option("--silent", "Don't log anything", false).action((...args) => runAction("watch", action)(ctx, ...args));
};
const commands = [
command$4,
command$3,
command$2,
command,
command$1
];
const createLogger = (options = {}) => {
const { silent = false, debug = false, timestamp = true } = options;
const state = { errors: 0, warning: 0 };
return {
get warnings() {
return state.warning;
},
get errors() {
return state.errors;
},
debug(...args) {
if (silent || !debug) {
return;
}
console.log(
chalk__default.default.cyan(`[DEBUG]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
...args
);
},
info(...args) {
if (silent) {
return;
}
console.info(
chalk__default.default.blue(`[INFO]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
...args
);
},
log(...args) {
if (silent) {
return;
}
console.info(chalk__default.default.blue(`${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`), ...args);
},
warn(...args) {
state.warning += 1;
if (silent) {
return;
}
console.warn(
chalk__default.default.yellow(`[WARN]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
...args
);
},
error(...args) {
state.errors += 1;
if (silent) {
return;
}
console.error(
chalk__default.default.red(`[ERROR]${timestamp ? ` [${(/* @__PURE__ */ new Date()).toISOString()}]` : ""}`),
...args
);
},
// @ts-expect-error – returning a subpart of ora is fine because the types tell us what is what.
spinner(text) {
if (silent) {
return {
succeed() {
return this;
},
fail() {
return this;
},
start() {
return this;
},
text: ""
};
}
return ora__default.default(text);
}
};
};
const loadTsConfig = ({
cwd,
path: path2,
logger
}) => {
const configPath = ts__default.default.findConfigFile(cwd, ts__default.default.sys.fileExists, path2);
if (!configPath) {
return void 0;
}
const configFile = ts__default.default.readConfigFile(configPath, ts__default.default.sys.readFile);
const parsedConfig = ts__default.default.parseJsonConfigFileContent(configFile.config, ts__default.default.sys, cwd);
logger.debug("Loaded user TS config:", os__default.default.EOL, parsedConfig);
return {
config: parsedConfig,
path: configPath
};
};
const createCLI = async (argv, command2 = new commander.Command()) => {
command2.storeOptionsAsProperties(false).allowUnknownOption(true);
command2.helpOption("-h, --help", "Display help for command");
command2.helpCommand("help [command]", "Display help for command");
command2.version(
// eslint-disable-next-line @typescript-eslint/no-var-requires
require("../package.json").version,
"-v, --version",
"Output the version number"
);
const cwd = process.cwd();
const hasDebug = argv.includes("--debug");
const hasSilent = argv.includes("--silent");
const logger = createLogger({ debug: hasDebug, silent: hasSilent, timestamp: false });
const tsconfig = loadTsConfig({
cwd,
path: "tsconfig.json",
logger
});
const ctx = {
cwd,
logger,
tsconfig
};
commands.forEach((commandFactory) => {
try {
const subCommand = commandFactory({ command: command2, argv, ctx });
if (subCommand) {
command2.addCommand(subCommand);
}
} catch (e) {
logger.error("Failed to load command", e);
}
});
return command2;
};
const runCLI = async (argv = process.argv, command2 = new commander.Command()) => {
const commands2 = await createCLI(argv, command2);
await commands2.parseAsync(argv);
};
exports.createCLI = createCLI;
exports.runCLI = runCLI;
//# sourceMappingURL=cli.js.map
;