UNPKG

@strapi/sdk-plugin

Version:

Simple tools for developing Strapi plugins

1,221 lines (1,183 loc) 40.3 kB
"use strict"; 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