UNPKG

@pixso/create-plugin

Version:

plugin template

325 lines (293 loc) 8.6 kB
#!/usr/bin/env node const fs = require("fs"); const path = require("path"); const prompts = require("prompts"); const fse = require("fs-extra"); const { blue, green, yellow, cyan, magenta, red, reset } = require("kolorist"); const argv = require("minimist")(process.argv.slice(2), { string: ["_"], boolean: ["help", "host", "force"], alias: { h: "help", t: "template" } }); if (argv.help) { console.log(` Usage: npx @pixso/create-plugin <project-name> [options] Options: -t, --template <name> Specify framework variant (e.g., vue, vue-ts, react, react-ts, preact, preact-ts, svelte, svelte-ts) --host Enable host script support (Only for private deployment clients/hwdc) --force Overwrite target directory if it exists -h, --help Display this help message `); process.exit(0); } const cwd = process.cwd(); const FRAMEWORKS = [ { name: "vue", display: "Vue", color: green, variants: [ { name: "vue-ts", display: "TypeScript", color: blue, }, { name: "vue", display: "JavaScript", color: yellow, }, ], }, { name: "react", display: "React", color: cyan, variants: [ { name: "react-ts", display: "TypeScript", color: blue, }, { name: "react", display: "JavaScript", color: yellow, }, ], }, { name: "preact", display: "Preact", color: magenta, variants: [ { name: "preact-ts", display: "TypeScript", color: blue, }, { name: "preact", display: "JavaScript", color: yellow, }, ], }, { name: "svelte", display: "Svelte", color: red, variants: [ { name: "svelte-ts", display: "TypeScript", color: blue, }, { name: "svelte", display: "JavaScript", color: yellow, }, ], }, ]; const TEMPLATES = FRAMEWORKS.map( (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name] ).reduce((a, b) => a.concat(b), []); function isEmpty(path) { return fs.readdirSync(path).length === 0; } function isValidPackageName(projectName) { return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( projectName ); } function toValidPackageName(projectName) { return projectName .trim() .toLowerCase() .replace(/\s+/g, "-") .replace(/^[._]/, "") .replace(/[^a-z\d\-~]+/g, "-"); } function pkgFromUserAgent(userAgent) { if (!userAgent) return undefined; const pkgSpec = userAgent.split(" ")[0]; const pkgSpecArr = pkgSpec.split("/"); return { name: pkgSpecArr[0], version: pkgSpecArr[1], }; } async function init() { let targetDir = argv._[0]; let argTemplate = argv.template || argv.t; const defaultProjectName = !targetDir ? "pixso-plugin-project" : targetDir; let result; try { result = await prompts( [ { type: targetDir ? null : "text", name: "projectName", message: "Project name:", initial: defaultProjectName, onState: (state) => (targetDir = state.value.trim() || defaultProjectName), }, { type: () => argv.force || !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : "confirm", name: "overwrite", message: () => (targetDir === "." ? "Current directory" : `Target directory "${targetDir}"`) + ` is not empty. Remove existing files and continue?`, }, { type: (_, { overwrite } = {}) => { if (overwrite === false) { throw new Error(red("✖") + " Operation cancelled"); } return null; }, name: "overwriteChecker", }, { type: () => (isValidPackageName(targetDir) ? null : "text"), name: "packageName", message: "Package name:", initial: () => toValidPackageName(targetDir), validate: (dir) => isValidPackageName(dir) || "Invalid package.json name", }, { type: argTemplate && TEMPLATES.includes(argTemplate) ? null : "select", name: "framework", message: typeof argTemplate === "string" && !TEMPLATES.includes(argTemplate) ? reset( `"${argTemplate}" isn't a valid template. Please choose from below: ` ) : reset("Select a framework:"), initial: 0, choices: FRAMEWORKS.map((framework) => { const frameworkColor = framework.color; return { title: frameworkColor(framework.display || framework.name), value: framework, }; }), }, { type: (framework) => framework && framework.variants ? "select" : null, name: "variant", message: reset("Select a variant:"), choices: (framework) => framework.variants.map((variant) => { const variantColor = variant.color; return { title: variantColor(variant.display || variant.name), value: variant.name, }; }), }, ], { onCancel: () => { throw new Error(red("✖") + " Operation cancelled"); }, } ); } catch (cancelled) { console.log(cancelled.message); return; } const overwrite = argv.force || result.overwrite; const { packageName, variant } = result; const containsHostScript = argv.host || false; const root = path.join(cwd, targetDir); if (overwrite) { fse.emptyDirSync(root); } else if (!fs.existsSync(root)) { fs.mkdirSync(root); } argTemplate = variant || argTemplate; const templateDir = path.join(__dirname, `template-${argTemplate}`); fse.copySync(templateDir, root); const pkg = require(path.join(root, "package.json")); pkg.name = packageName || targetDir; if (containsHostScript) { // Update manifest.json to include host entry const manifest = require(path.join(root, "manifest.json")); manifest.main = { sandbox: manifest.main, host: "dist/host.js", }; fs.writeFileSync( path.join(root, "manifest.json"), JSON.stringify(manifest, null, 2) ); // Dynamically generate host script file const hostExt = argTemplate.endsWith("-ts") ? "ts" : "js"; const hostContent = [ "/**", " * Host script - Only available for private deployment clients.", " * For more information: https://pixso.cn/developer/en/", " */", `hostApi.onMounted(() => {`, ` console.log("Host script has been mounted");`, `});`, "", ].join("\n"); fs.writeFileSync(path.join(root, `host.${hostExt}`), hostContent); // Generate plugin.config to enable host compilation const pluginConfigContent = hostExt === "ts" ? [ "import { defineConfig } from '@pixso/plugin-cli';", "", "export default defineConfig({", " host: './host.ts',", "});", "", ].join("\n") : [ "const { defineConfig } = require('@pixso/plugin-cli');", "", "module.exports = defineConfig({", " host: './host.js',", "});", "", ].join("\n"); fs.writeFileSync( path.join(root, `plugin.config.${hostExt}`), pluginConfigContent ); } fs.writeFileSync( path.join(root, "package.json"), JSON.stringify(pkg, null, 2) ); const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent); const pkgManager = pkgInfo ? pkgInfo.name : "npm"; console.log(`\nDone. Now run:\n`); if (root !== cwd) { console.log(` cd ${path.relative(cwd, root)}`); } switch (pkgManager) { case "yarn": console.log(" yarn"); console.log(" yarn dev"); break; default: console.log(` ${pkgManager} install`); console.log(` ${pkgManager} run dev`); break; } } init();