peezy-cli
Version:
Production-ready CLI for scaffolding modern applications with curated full-stack templates, intelligent migrations, and enterprise security.
310 lines (290 loc) • 8.79 kB
JavaScript
/**
* Plugin Utilities v1.0
*
* Utility functions and helpers for plugin development
*/
import { readFile, writeFile, mkdir, copyFile, access } from "node:fs/promises";
import { dirname } from "node:path";
import { log } from "../../utils/logger.js";
/**
* Create plugin utilities instance
*/
export function createPluginUtils(projectPath, dependencies, packageJsonUpdates) {
return {
fs: {
async readFile(path) {
return readFile(path, "utf8");
},
async writeFile(path, content) {
await mkdir(dirname(path), { recursive: true });
await writeFile(path, content, "utf8");
},
async exists(path) {
try {
await access(path);
return true;
}
catch {
return false;
}
},
async mkdir(path) {
await mkdir(path, { recursive: true });
},
async copy(src, dest) {
await mkdir(dirname(dest), { recursive: true });
await copyFile(src, dest);
},
},
template: {
render(template, data) {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] ?? match;
});
},
replaceTokens(content, tokens) {
let result = content;
for (const [token, value] of Object.entries(tokens)) {
const regex = new RegExp(`\\$\\{${token}\\}`, "g");
result = result.replace(regex, value);
}
return result;
},
},
package: {
addDependency(name, version, dev = false) {
const depString = version ? `${name}@${version}` : name;
if (dev) {
dependencies.development.push(depString);
}
else {
dependencies.production.push(depString);
}
},
removeDependency(name) {
dependencies.production = dependencies.production.filter((dep) => !dep.startsWith(name));
dependencies.development = dependencies.development.filter((dep) => !dep.startsWith(name));
},
updatePackageJson(updates) {
Object.assign(packageJsonUpdates, updates);
},
},
git: {
async isRepo() {
try {
const { execSync } = await import("node:child_process");
execSync("git rev-parse --git-dir", {
cwd: projectPath,
stdio: "ignore",
});
return true;
}
catch {
return false;
}
},
async init() {
const { execSync } = await import("node:child_process");
execSync("git init", { cwd: projectPath });
},
async add(files) {
const { execSync } = await import("node:child_process");
execSync(`git add ${files.join(" ")}`, { cwd: projectPath });
},
async commit(message) {
const { execSync } = await import("node:child_process");
execSync(`git commit -m "${message}"`, { cwd: projectPath });
},
},
};
}
/**
* Create plugin logger instance
*/
export function createPluginLogger(pluginName) {
const prefix = `[${pluginName}]`;
return {
info(message, ...args) {
log.info(`${prefix} ${message}`, ...args);
},
warn(message, ...args) {
log.warn(`${prefix} ${message}`, ...args);
},
error(message, ...args) {
log.err(`${prefix} ${message}`, ...args);
},
debug(message, ...args) {
log.debug(`${prefix} ${message}`, ...args);
},
success(message, ...args) {
log.ok(`${prefix} ${message}`, ...args);
},
};
}
/**
* Validate plugin configuration
*/
export function validatePluginConfig(config) {
const errors = [];
if (!config || typeof config !== "object") {
errors.push("Plugin config must be an object");
return { valid: false, errors };
}
if (!config.plugins || typeof config.plugins !== "object") {
errors.push("Plugin config must have a plugins object");
}
return { valid: errors.length === 0, errors };
}
/**
* Create a basic plugin template
*/
export function createPluginTemplate(name, description) {
return `/**
* ${name} Plugin
* ${description}
*/
import type { Plugin, PluginManifest, PluginHooks } from '@peezy/plugin-api';
export default class ${name.replace(/[^a-zA-Z0-9]/g, "")}Plugin implements Plugin {
manifest: PluginManifest = {
name: '${name}',
version: '1.0.0',
description: '${description}',
author: 'Your Name',
minCliVersion: '^1.0.0',
homepage: 'https://github.com/your-username/${name}',
keywords: ['peezy', 'plugin'],
license: 'MIT'
};
hooks: PluginHooks = {
async beforeScaffold(context) {
context.logger.info('Running before scaffold hook');
},
async afterScaffold(context) {
context.logger.info('Running after scaffold hook');
},
async configValidation(config) {
return {
valid: true,
errors: [],
warnings: []
};
}
};
async initialize(): Promise<void> {
// Plugin initialization logic
}
async dispose(): Promise<void> {
// Plugin cleanup logic
}
}
`;
}
/**
* Plugin development helpers
*/
export const PluginDev = {
/**
* Create a new plugin project structure
*/
async createPluginProject(name, description, targetDir) {
const utils = createPluginUtils(targetDir, { production: [], development: [] }, {});
// Create package.json
const packageJson = {
name,
version: "1.0.0",
description,
main: "dist/index.js",
types: "dist/index.d.ts",
scripts: {
build: "tsc",
dev: "tsc --watch",
test: "jest",
prepublishOnly: "npm run build",
},
peerDependencies: {
"@peezy/plugin-api": "^1.0.0",
},
devDependencies: {
"@peezy/plugin-api": "^1.0.0",
"@types/node": "^20.0.0",
typescript: "^5.0.0",
jest: "^29.0.0",
"@types/jest": "^29.0.0",
},
keywords: ["peezy", "plugin"],
license: "MIT",
};
await utils.fs.writeFile(`${targetDir}/package.json`, JSON.stringify(packageJson, null, 2));
// Create TypeScript config
const tsConfig = {
compilerOptions: {
target: "ES2022",
module: "ESNext",
moduleResolution: "bundler",
declaration: true,
outDir: "dist",
rootDir: "src",
strict: true,
esModuleInterop: true,
skipLibCheck: true,
forceConsistentCasingInFileNames: true,
},
include: ["src/**/*"],
exclude: ["node_modules", "dist", "**/*.test.ts"],
};
await utils.fs.writeFile(`${targetDir}/tsconfig.json`, JSON.stringify(tsConfig, null, 2));
// Create plugin source
await utils.fs.mkdir(`${targetDir}/src`);
await utils.fs.writeFile(`${targetDir}/src/index.ts`, createPluginTemplate(name, description));
// Create README
const readme = `# ${name}
${description}
## Installation
\`\`\`bash
npm install ${name}
\`\`\`
## Usage
Add to your \`.peezy/plugins.json\`:
\`\`\`json
{
"plugins": {
"${name}": {
"enabled": true
}
}
}
\`\`\`
## Configuration
This plugin supports the following configuration options:
\`\`\`json
{
"plugins": {
"${name}": {
"enabled": true,
"config": {
// Plugin-specific configuration
}
}
}
}
\`\`\`
## Development
\`\`\`bash
npm run dev # Watch mode
npm run build # Build for production
npm test # Run tests
\`\`\`
## License
MIT
`;
await utils.fs.writeFile(`${targetDir}/README.md`, readme);
// Create .gitignore
const gitignore = `node_modules/
dist/
*.log
.DS_Store
`;
await utils.fs.writeFile(`${targetDir}/.gitignore`, gitignore);
},
};
//# sourceMappingURL=utils.js.map