@knotx/cli 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +154 -79
- package/dist/index.mjs +155 -80
- package/package.json +5 -6
- package/templates/README.md.template +5 -5
- package/templates/playground/index.html.template +1 -2
- package/templates/playground/main.jsx.template +1 -8
- package/templates/playground/main.react.template +1 -2
- package/templates/playground/tsconfig.json.template +3 -2
- package/templates/plugin.jsx.template +3 -3
- package/templates/vite.config.ts.template +9 -9
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const node_child_process = require('node:child_process');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
const process = require('node:process');
|
|
7
|
+
const node_util = require('node:util');
|
|
7
8
|
const chalk = require('chalk');
|
|
8
9
|
const commander = require('commander');
|
|
9
10
|
const fs = require('fs-extra');
|
|
@@ -58,6 +59,11 @@ var __async = (__this, __arguments, generator) => {
|
|
|
58
59
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
59
60
|
});
|
|
60
61
|
};
|
|
62
|
+
process__default.on("uncaughtException", (error) => {
|
|
63
|
+
console.error(chalk__default.red("\u274C \u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:"));
|
|
64
|
+
console.error(chalk__default.red(error.stack || error.toString()));
|
|
65
|
+
process__default.exit(1);
|
|
66
|
+
});
|
|
61
67
|
const templatesDir = path__default.resolve(__dirname, "..", "templates");
|
|
62
68
|
const program = new commander.Command();
|
|
63
69
|
program.name("knotx").description("Knotx CLI - \u521B\u5EFA\u548C\u7BA1\u7406Knotx\u63D2\u4EF6").version("0.0.1");
|
|
@@ -67,33 +73,43 @@ program.command("create-plugin").description("\u521B\u5EFA\u4E00\u4E2A\u65B0\u76
|
|
|
67
73
|
{
|
|
68
74
|
type: "input",
|
|
69
75
|
name: "pluginName",
|
|
70
|
-
message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u540D\u79F0 (\u4F8B\u5982: my-plugin):",
|
|
76
|
+
message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u540D\u79F0 (\u4F8B\u5982: @knotx/plugins-my-plugin):",
|
|
71
77
|
validate: (input) => {
|
|
72
78
|
if (!input)
|
|
73
79
|
return "\u63D2\u4EF6\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
74
|
-
if (!/^[a-z0-9-]+$/.test(input))
|
|
75
|
-
return "\u63D2\u4EF6\u540D\u79F0\
|
|
80
|
+
if (!/^(?:@[a-z0-9-]+\/)?[a-z0-9-]+$/.test(input))
|
|
81
|
+
return "\u63D2\u4EF6\u540D\u79F0\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5E94\u8BE5\u662F\u6709\u6548\u7684npm\u5305\u540D";
|
|
76
82
|
return true;
|
|
77
|
-
}
|
|
83
|
+
},
|
|
84
|
+
default: "@knotx/plugins-"
|
|
78
85
|
},
|
|
79
86
|
{
|
|
80
87
|
type: "list",
|
|
81
88
|
name: "environment",
|
|
82
89
|
message: "\u8BF7\u9009\u62E9\u63D2\u4EF6\u8FD0\u884C\u73AF\u5883:",
|
|
83
|
-
choices: ["
|
|
90
|
+
choices: ["react", "jsx"]
|
|
84
91
|
}
|
|
85
92
|
]);
|
|
86
93
|
const { pluginName, environment } = answers;
|
|
87
|
-
const
|
|
88
|
-
|
|
94
|
+
const dirName = pluginName.split("/").pop();
|
|
95
|
+
let currentDir;
|
|
96
|
+
try {
|
|
97
|
+
currentDir = process__default.cwd();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(chalk__default.red(`\u274C \u9519\u8BEF: \u65E0\u6CD5\u83B7\u53D6\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${error}`));
|
|
100
|
+
console.log(chalk__default.yellow("\u5C1D\u8BD5\u4F7F\u7528\u5907\u7528\u65B9\u6CD5\u83B7\u53D6\u76EE\u5F55..."));
|
|
101
|
+
currentDir = path__default.resolve(__dirname, "..");
|
|
102
|
+
console.log(chalk__default.green(`\u2705 \u4F7F\u7528\u5907\u7528\u76EE\u5F55: ${currentDir}`));
|
|
103
|
+
}
|
|
104
|
+
const targetDir = safeResolvePath(currentDir, dirName);
|
|
89
105
|
if (fs__default.existsSync(targetDir)) {
|
|
90
|
-
console.log(chalk__default.red(`\u274C \u9519\u8BEF: \u76EE\u5F55 ${
|
|
106
|
+
console.log(chalk__default.red(`\u274C \u9519\u8BEF: \u76EE\u5F55 ${dirName} \u5DF2\u5B58\u5728`));
|
|
91
107
|
return;
|
|
92
108
|
}
|
|
93
109
|
let spinner = ora__default("\u{1F4C2} \u521B\u5EFA\u63D2\u4EF6\u76EE\u5F55...").start();
|
|
94
110
|
try {
|
|
95
|
-
yield
|
|
96
|
-
yield
|
|
111
|
+
yield safeEnsureDir(targetDir);
|
|
112
|
+
yield safeEnsureDir(safeResolvePath(targetDir, "src"));
|
|
97
113
|
spinner.succeed("\u{1F4C2} \u63D2\u4EF6\u76EE\u5F55\u521B\u5EFA\u6210\u529F");
|
|
98
114
|
spinner = ora__default("\u{1F50D} \u83B7\u53D6 @knotx \u5305\u7684\u6700\u65B0\u7248\u672C...").start();
|
|
99
115
|
const knotxVersions = yield getKnotxPackageVersions();
|
|
@@ -122,13 +138,19 @@ program.command("create-plugin").description("\u521B\u5EFA\u4E00\u4E2A\u65B0\u76
|
|
|
122
138
|
console.warn(chalk__default.yellow(` \u53EF\u80FD\u7684\u539F\u56E0: ${error.message}`));
|
|
123
139
|
}
|
|
124
140
|
console.log(chalk__default.green(`
|
|
125
|
-
\u2705 \u63D2\u4EF6 ${chalk__default.bold(
|
|
141
|
+
\u2705 \u63D2\u4EF6 ${chalk__default.bold(pluginName)} \u521B\u5EFA\u6210\u529F\uFF01`));
|
|
126
142
|
console.log(`
|
|
127
143
|
\u{1F4C1} \u63D2\u4EF6\u76EE\u5F55: ${chalk__default.cyan(targetDir)}`);
|
|
128
144
|
console.log(`
|
|
129
145
|
\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u4EE5\u5B89\u88C5\u4F9D\u8D56\u5E76\u5F00\u59CB\u5F00\u53D1:
|
|
130
146
|
`);
|
|
131
|
-
|
|
147
|
+
let cdCommand;
|
|
148
|
+
try {
|
|
149
|
+
cdCommand = `cd ${path__default.relative(process__default.cwd(), targetDir)}`;
|
|
150
|
+
} catch (e) {
|
|
151
|
+
cdCommand = `cd ${targetDir}`;
|
|
152
|
+
}
|
|
153
|
+
console.log(chalk__default.cyan(` ${cdCommand}`));
|
|
132
154
|
console.log(chalk__default.cyan(" pnpm install"));
|
|
133
155
|
console.log(chalk__default.cyan(" pnpm build"));
|
|
134
156
|
console.log(chalk__default.cyan(" pnpm dev # \u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\uFF0C\u8FD0\u884C playground"));
|
|
@@ -158,15 +180,23 @@ function getKnotxPackageVersions() {
|
|
|
158
180
|
"@knotx/plugins-base-render"
|
|
159
181
|
];
|
|
160
182
|
const npmRegistry = "https://registry.npmjs.org";
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
183
|
+
const execAsync = node_util.promisify(node_child_process.exec);
|
|
184
|
+
const results = yield Promise.all(
|
|
185
|
+
packages.map((pkg) => __async(this, null, function* () {
|
|
186
|
+
try {
|
|
187
|
+
const cmd = `npm view ${pkg} version --registry=${npmRegistry} --timeout=10000`;
|
|
188
|
+
const { stdout } = yield execAsync(cmd, { timeout: 1e4 });
|
|
189
|
+
const version = stdout.trim();
|
|
190
|
+
return { pkg, version: `^${version}`, success: true };
|
|
191
|
+
} catch (e) {
|
|
192
|
+
console.warn(chalk__default.yellow(`\u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6 ${pkg} \u7684\u6700\u65B0\u7248\u672C\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u7248\u672C`));
|
|
193
|
+
return { pkg, version: "latest", success: false };
|
|
194
|
+
}
|
|
195
|
+
}))
|
|
196
|
+
);
|
|
197
|
+
results.forEach(({ pkg, version }) => {
|
|
198
|
+
knotxVersions[pkg] = version;
|
|
199
|
+
});
|
|
170
200
|
return knotxVersions;
|
|
171
201
|
} catch (e) {
|
|
172
202
|
console.warn(chalk__default.yellow("\u26A0\uFE0F \u83B7\u53D6 @knotx \u5305\u7248\u672C\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u7248\u672C"));
|
|
@@ -176,7 +206,9 @@ function getKnotxPackageVersions() {
|
|
|
176
206
|
"@knotx/jsx": "latest",
|
|
177
207
|
"@knotx/build-config": "latest",
|
|
178
208
|
"@knotx/eslint-config": "latest",
|
|
179
|
-
"@knotx/typescript-config": "latest"
|
|
209
|
+
"@knotx/typescript-config": "latest",
|
|
210
|
+
"@knotx/react": "latest",
|
|
211
|
+
"@knotx/plugins-base-render": "latest"
|
|
180
212
|
};
|
|
181
213
|
}
|
|
182
214
|
});
|
|
@@ -184,10 +216,10 @@ function getKnotxPackageVersions() {
|
|
|
184
216
|
function createPackageJson(targetDir, pluginName, environment, knotxVersions) {
|
|
185
217
|
return __async(this, null, function* () {
|
|
186
218
|
const packageJson = {
|
|
187
|
-
name:
|
|
219
|
+
name: pluginName,
|
|
188
220
|
type: "module",
|
|
189
221
|
version: "0.0.1",
|
|
190
|
-
description: `${capitalize(pluginName)} Plugin for Knotx`,
|
|
222
|
+
description: `${capitalize(pluginName.split("/").pop() || pluginName)} Plugin for Knotx`,
|
|
191
223
|
license: "MIT",
|
|
192
224
|
publishConfig: {
|
|
193
225
|
access: "public"
|
|
@@ -231,13 +263,15 @@ function createPackageJson(targetDir, pluginName, environment, knotxVersions) {
|
|
|
231
263
|
"vitest": "^3.0.0"
|
|
232
264
|
}
|
|
233
265
|
};
|
|
234
|
-
if (environment === "jsx")
|
|
235
|
-
packageJson.peerDependencies.react = "^17";
|
|
236
|
-
packageJson.peerDependencies["react-dom"] = "^17";
|
|
237
|
-
packageJson.devDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
266
|
+
if (environment === "jsx") {
|
|
238
267
|
packageJson.devDependencies["@knotx/plugins-base-render"] = knotxVersions["@knotx/plugins-base-render"];
|
|
239
|
-
|
|
268
|
+
} else if (environment === "react") {
|
|
269
|
+
packageJson.peerDependencies.react = ">=17";
|
|
270
|
+
packageJson.peerDependencies["react-dom"] = ">=17";
|
|
271
|
+
packageJson.peerDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
272
|
+
packageJson.devDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
240
273
|
packageJson.devDependencies["@vitejs/plugin-react"] = "^4.3.4";
|
|
274
|
+
packageJson.devDependencies.react = "^17";
|
|
241
275
|
packageJson.devDependencies["react-dom"] = "^17";
|
|
242
276
|
packageJson.devDependencies["@types/react"] = "^17";
|
|
243
277
|
packageJson.devDependencies["@types/react-dom"] = "^17";
|
|
@@ -300,12 +334,12 @@ function sortObjectAlphabetically(obj) {
|
|
|
300
334
|
function createConfigFiles(targetDir) {
|
|
301
335
|
return __async(this, null, function* () {
|
|
302
336
|
try {
|
|
303
|
-
const tsconfigTemplate = yield fs__default.readFile(
|
|
304
|
-
const buildConfigTemplate = yield fs__default.readFile(
|
|
305
|
-
const eslintConfigTemplate = yield fs__default.readFile(
|
|
306
|
-
yield fs__default.writeFile(
|
|
307
|
-
yield fs__default.writeFile(
|
|
308
|
-
yield fs__default.writeFile(
|
|
337
|
+
const tsconfigTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "tsconfig.json.template"), "utf-8");
|
|
338
|
+
const buildConfigTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "build.config.ts.template"), "utf-8");
|
|
339
|
+
const eslintConfigTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "eslint.config.js.template"), "utf-8");
|
|
340
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "tsconfig.json"), tsconfigTemplate);
|
|
341
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "build.config.ts"), buildConfigTemplate);
|
|
342
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "eslint.config.js"), eslintConfigTemplate);
|
|
309
343
|
} catch (error) {
|
|
310
344
|
console.error("\u65E0\u6CD5\u8BFB\u53D6\u6A21\u677F\u6587\u4EF6:", error);
|
|
311
345
|
const tsconfig = {
|
|
@@ -318,15 +352,15 @@ function createConfigFiles(targetDir) {
|
|
|
318
352
|
}
|
|
319
353
|
};
|
|
320
354
|
yield fs__default.writeFile(
|
|
321
|
-
|
|
355
|
+
safeResolvePath(targetDir, "tsconfig.json"),
|
|
322
356
|
JSON.stringify(tsconfig, null, 2)
|
|
323
357
|
);
|
|
324
358
|
yield fs__default.writeFile(
|
|
325
|
-
|
|
359
|
+
safeResolvePath(targetDir, "build.config.ts"),
|
|
326
360
|
'import { defineBuildConfig } from "@knotx/build-config";\n\nexport default defineBuildConfig();'
|
|
327
361
|
);
|
|
328
362
|
yield fs__default.writeFile(
|
|
329
|
-
|
|
363
|
+
safeResolvePath(targetDir, "eslint.config.js"),
|
|
330
364
|
"export { default } from '@knotx/eslint-config';"
|
|
331
365
|
);
|
|
332
366
|
}
|
|
@@ -335,46 +369,49 @@ function createConfigFiles(targetDir) {
|
|
|
335
369
|
function createSourceFiles(targetDir, pluginName, environment) {
|
|
336
370
|
return __async(this, null, function* () {
|
|
337
371
|
try {
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
-
|
|
372
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
373
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
374
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
375
|
+
const indexTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "index.ts.template"), "utf-8");
|
|
376
|
+
const indexContent = indexTemplate.replace(/\{\{pluginName\}\}/g, camelCaseName);
|
|
377
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "src", "index.ts"), indexContent);
|
|
341
378
|
let templatePath;
|
|
342
379
|
if (environment === "jsx") {
|
|
343
|
-
templatePath =
|
|
380
|
+
templatePath = safeResolvePath(templatesDir, "plugin.jsx.template");
|
|
344
381
|
} else {
|
|
345
|
-
templatePath =
|
|
382
|
+
templatePath = safeResolvePath(templatesDir, "plugin.jsx.template");
|
|
346
383
|
}
|
|
347
384
|
const pluginTemplate = yield fs__default.readFile(templatePath, "utf-8");
|
|
348
|
-
const pluginContent = pluginTemplate.replace(/\{\{
|
|
349
|
-
const fileName = `${
|
|
350
|
-
yield fs__default.writeFile(
|
|
351
|
-
yield createPlayground(targetDir,
|
|
385
|
+
const pluginContent = pluginTemplate.replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName);
|
|
386
|
+
const fileName = `${camelCaseName}.tsx`;
|
|
387
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "src", fileName), pluginContent);
|
|
388
|
+
yield createPlayground(targetDir, pluginNameWithoutScope, camelCaseName, pascalCaseName, environment);
|
|
352
389
|
} catch (error) {
|
|
353
390
|
console.error("\u65E0\u6CD5\u8BFB\u53D6\u6A21\u677F\u6587\u4EF6:", error);
|
|
354
391
|
}
|
|
355
392
|
});
|
|
356
393
|
}
|
|
357
|
-
function createPlayground(targetDir, pluginName, environment) {
|
|
394
|
+
function createPlayground(targetDir, pluginName, camelCaseName, pascalCaseName, environment) {
|
|
358
395
|
return __async(this, null, function* () {
|
|
359
|
-
const playgroundDir =
|
|
360
|
-
yield
|
|
396
|
+
const playgroundDir = safeResolvePath(targetDir, "playground");
|
|
397
|
+
yield safeEnsureDir(playgroundDir);
|
|
361
398
|
try {
|
|
362
|
-
const viteConfigTemplate = yield fs__default.readFile(
|
|
363
|
-
const htmlTemplate = yield fs__default.readFile(
|
|
364
|
-
const tsConfigTemplate = yield fs__default.readFile(
|
|
399
|
+
const viteConfigTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "vite.config.ts.template"), "utf-8");
|
|
400
|
+
const htmlTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "playground/index.html.template"), "utf-8");
|
|
401
|
+
const tsConfigTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "playground/tsconfig.json.template"), "utf-8");
|
|
365
402
|
const isReact = environment === "react";
|
|
366
403
|
const mainTemplate = yield fs__default.readFile(
|
|
367
|
-
|
|
404
|
+
safeResolvePath(templatesDir, `playground/main.${isReact ? "react" : "jsx"}.template`),
|
|
368
405
|
"utf-8"
|
|
369
406
|
);
|
|
370
407
|
const fileExtension = isReact ? "tsx" : "ts";
|
|
371
408
|
const viteConfigContent = viteConfigTemplate.replace(new RegExp("\\{\\{#if isReact\\}\\}(.*?)\\{\\{\\/if\\}\\}", "gs"), isReact ? "$1" : "");
|
|
372
|
-
const htmlContent = htmlTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{
|
|
373
|
-
const mainContent = mainTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{capitalizedPluginName\}\}/g,
|
|
374
|
-
yield fs__default.writeFile(
|
|
375
|
-
yield fs__default.writeFile(
|
|
376
|
-
yield fs__default.writeFile(
|
|
377
|
-
yield fs__default.writeFile(
|
|
409
|
+
const htmlContent = htmlTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{pluginNameWithoutScope\}\}/g, pluginName).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName).replace(/\{\{fileExtension\}\}/g, fileExtension);
|
|
410
|
+
const mainContent = mainTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName);
|
|
411
|
+
yield fs__default.writeFile(safeResolvePath(playgroundDir, "vite.config.ts"), viteConfigContent);
|
|
412
|
+
yield fs__default.writeFile(safeResolvePath(playgroundDir, "index.html"), htmlContent);
|
|
413
|
+
yield fs__default.writeFile(safeResolvePath(playgroundDir, `main.${fileExtension}`), mainContent);
|
|
414
|
+
yield fs__default.writeFile(safeResolvePath(playgroundDir, "tsconfig.json"), tsConfigTemplate);
|
|
378
415
|
} catch (error) {
|
|
379
416
|
console.error("\u8BFB\u53D6 playground \u6A21\u677F\u6587\u4EF6\u5931\u8D25:", error);
|
|
380
417
|
}
|
|
@@ -383,50 +420,84 @@ function createPlayground(targetDir, pluginName, environment) {
|
|
|
383
420
|
function createReadme(targetDir, pluginName) {
|
|
384
421
|
return __async(this, null, function* () {
|
|
385
422
|
try {
|
|
386
|
-
const readmeTemplate = yield fs__default.readFile(
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
|
|
423
|
+
const readmeTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, "README.md.template"), "utf-8");
|
|
424
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
425
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
426
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
427
|
+
const description = `${pascalCaseName} Plugin for Knotx`;
|
|
428
|
+
const readmeContent = readmeTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{pluginNameWithoutScope\}\}/g, pluginNameWithoutScope).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName).replace(/\{\{description\}\}/g, description);
|
|
429
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "README.md"), readmeContent);
|
|
390
430
|
} catch (error) {
|
|
391
431
|
console.error("\u65E0\u6CD5\u8BFB\u53D6 README \u6A21\u677F\u6587\u4EF6:", error);
|
|
392
|
-
const
|
|
432
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
433
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
434
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
435
|
+
const readmeContent = `# ${pluginName}
|
|
393
436
|
|
|
394
|
-
${
|
|
437
|
+
${pascalCaseName} Plugin for Knotx
|
|
395
438
|
|
|
396
439
|
## \u5B89\u88C5
|
|
397
440
|
|
|
398
441
|
\`\`\`bash
|
|
399
|
-
npm install
|
|
442
|
+
npm install ${pluginName}
|
|
400
443
|
# \u6216\u8005
|
|
401
|
-
yarn add
|
|
444
|
+
yarn add ${pluginName}
|
|
402
445
|
# \u6216\u8005
|
|
403
|
-
pnpm add
|
|
446
|
+
pnpm add ${pluginName}
|
|
404
447
|
\`\`\`
|
|
405
448
|
|
|
406
449
|
## \u4F7F\u7528\u65B9\u6CD5
|
|
407
450
|
|
|
408
451
|
\`\`\`typescript
|
|
409
|
-
import { ${
|
|
452
|
+
import { ${camelCaseName} } from '${pluginName}';
|
|
410
453
|
|
|
411
454
|
// \u5728\u60A8\u7684Knotx\u5E94\u7528\u4E2D\u4F7F\u7528\u63D2\u4EF6
|
|
412
|
-
app.use(${
|
|
455
|
+
app.use(${camelCaseName});
|
|
413
456
|
\`\`\`
|
|
414
457
|
|
|
415
458
|
## \u8BB8\u53EF\u8BC1
|
|
416
459
|
|
|
417
460
|
MIT`;
|
|
418
|
-
yield fs__default.writeFile(
|
|
461
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, "README.md"), readmeContent);
|
|
419
462
|
}
|
|
420
463
|
});
|
|
421
464
|
}
|
|
422
465
|
function capitalize(str) {
|
|
423
466
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
424
467
|
}
|
|
468
|
+
function toCamelCase(str) {
|
|
469
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
470
|
+
}
|
|
471
|
+
function toPascalCase(str) {
|
|
472
|
+
return capitalize(toCamelCase(str));
|
|
473
|
+
}
|
|
474
|
+
function safeResolvePath(basePath, ...paths) {
|
|
475
|
+
try {
|
|
476
|
+
return path__default.resolve(basePath, ...paths);
|
|
477
|
+
} catch (error) {
|
|
478
|
+
console.warn(chalk__default.yellow(`\u26A0\uFE0F \u8DEF\u5F84\u89E3\u6790\u5931\u8D25: ${error}`));
|
|
479
|
+
return paths.reduce((result, part) => `${result}/${part}`, basePath);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function safeEnsureDir(dirPath) {
|
|
483
|
+
return __async(this, null, function* () {
|
|
484
|
+
try {
|
|
485
|
+
yield fs__default.ensureDir(dirPath);
|
|
486
|
+
} catch (e) {
|
|
487
|
+
console.warn(chalk__default.yellow(`\u26A0\uFE0F \u521B\u5EFA\u76EE\u5F55 ${dirPath} \u5931\u8D25\uFF0C\u5C1D\u8BD5\u4F7F\u7528\u5907\u7528\u65B9\u6CD5`));
|
|
488
|
+
try {
|
|
489
|
+
fs__default.mkdirSync(dirPath, { recursive: true });
|
|
490
|
+
} catch (syncError) {
|
|
491
|
+
throw new Error(`\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55 ${dirPath}: ${syncError}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
425
496
|
function createGitignore(targetDir) {
|
|
426
497
|
return __async(this, null, function* () {
|
|
427
498
|
try {
|
|
428
|
-
const gitignoreTemplate = yield fs__default.readFile(
|
|
429
|
-
yield fs__default.writeFile(
|
|
499
|
+
const gitignoreTemplate = yield fs__default.readFile(safeResolvePath(templatesDir, ".gitignore.template"), "utf-8");
|
|
500
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, ".gitignore"), gitignoreTemplate);
|
|
430
501
|
} catch (error) {
|
|
431
502
|
console.error("\u65E0\u6CD5\u8BFB\u53D6 .gitignore \u6A21\u677F\u6587\u4EF6:", error);
|
|
432
503
|
const gitignoreContent = `# \u4F9D\u8D56\u76EE\u5F55
|
|
@@ -456,15 +527,16 @@ pnpm-debug.log*
|
|
|
456
527
|
# \u6D4B\u8BD5\u8986\u76D6\u7387
|
|
457
528
|
coverage
|
|
458
529
|
`;
|
|
459
|
-
yield fs__default.writeFile(
|
|
530
|
+
yield fs__default.writeFile(safeResolvePath(targetDir, ".gitignore"), gitignoreContent);
|
|
460
531
|
}
|
|
461
532
|
});
|
|
462
533
|
}
|
|
463
534
|
function initGitRepo(targetDir) {
|
|
464
535
|
try {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
536
|
+
if (!fs__default.existsSync(targetDir)) {
|
|
537
|
+
throw new Error(`\u76EE\u5F55 ${targetDir} \u4E0D\u5B58\u5728`);
|
|
538
|
+
}
|
|
539
|
+
const gitOptions = {
|
|
468
540
|
cwd: targetDir,
|
|
469
541
|
stdio: "ignore",
|
|
470
542
|
env: __spreadProps(__spreadValues({}, process__default.env), {
|
|
@@ -473,7 +545,10 @@ function initGitRepo(targetDir) {
|
|
|
473
545
|
GIT_COMMITTER_NAME: "Knotx CLI",
|
|
474
546
|
GIT_COMMITTER_EMAIL: "knotx-cli@noreply.github.com"
|
|
475
547
|
})
|
|
476
|
-
}
|
|
548
|
+
};
|
|
549
|
+
node_child_process.execSync("git init", gitOptions);
|
|
550
|
+
node_child_process.execSync("git add .", gitOptions);
|
|
551
|
+
node_child_process.execSync('git commit -m "Initial commit with Knotx plugin template"', gitOptions);
|
|
477
552
|
return true;
|
|
478
553
|
} catch (error) {
|
|
479
554
|
if (error instanceof Error) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
2
|
+
import { exec, execSync } from 'node:child_process';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import process from 'node:process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
5
6
|
import chalk from 'chalk';
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import fs from 'fs-extra';
|
|
@@ -47,6 +48,11 @@ var __async = (__this, __arguments, generator) => {
|
|
|
47
48
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
48
49
|
});
|
|
49
50
|
};
|
|
51
|
+
process.on("uncaughtException", (error) => {
|
|
52
|
+
console.error(chalk.red("\u274C \u53D1\u751F\u672A\u6355\u83B7\u7684\u9519\u8BEF:"));
|
|
53
|
+
console.error(chalk.red(error.stack || error.toString()));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
50
56
|
const templatesDir = path.resolve(__dirname, "..", "templates");
|
|
51
57
|
const program = new Command();
|
|
52
58
|
program.name("knotx").description("Knotx CLI - \u521B\u5EFA\u548C\u7BA1\u7406Knotx\u63D2\u4EF6").version("0.0.1");
|
|
@@ -56,33 +62,43 @@ program.command("create-plugin").description("\u521B\u5EFA\u4E00\u4E2A\u65B0\u76
|
|
|
56
62
|
{
|
|
57
63
|
type: "input",
|
|
58
64
|
name: "pluginName",
|
|
59
|
-
message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u540D\u79F0 (\u4F8B\u5982: my-plugin):",
|
|
65
|
+
message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u540D\u79F0 (\u4F8B\u5982: @knotx/plugins-my-plugin):",
|
|
60
66
|
validate: (input) => {
|
|
61
67
|
if (!input)
|
|
62
68
|
return "\u63D2\u4EF6\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
63
|
-
if (!/^[a-z0-9-]+$/.test(input))
|
|
64
|
-
return "\u63D2\u4EF6\u540D\u79F0\
|
|
69
|
+
if (!/^(?:@[a-z0-9-]+\/)?[a-z0-9-]+$/.test(input))
|
|
70
|
+
return "\u63D2\u4EF6\u540D\u79F0\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5E94\u8BE5\u662F\u6709\u6548\u7684npm\u5305\u540D";
|
|
65
71
|
return true;
|
|
66
|
-
}
|
|
72
|
+
},
|
|
73
|
+
default: "@knotx/plugins-"
|
|
67
74
|
},
|
|
68
75
|
{
|
|
69
76
|
type: "list",
|
|
70
77
|
name: "environment",
|
|
71
78
|
message: "\u8BF7\u9009\u62E9\u63D2\u4EF6\u8FD0\u884C\u73AF\u5883:",
|
|
72
|
-
choices: ["
|
|
79
|
+
choices: ["react", "jsx"]
|
|
73
80
|
}
|
|
74
81
|
]);
|
|
75
82
|
const { pluginName, environment } = answers;
|
|
76
|
-
const
|
|
77
|
-
|
|
83
|
+
const dirName = pluginName.split("/").pop();
|
|
84
|
+
let currentDir;
|
|
85
|
+
try {
|
|
86
|
+
currentDir = process.cwd();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.log(chalk.red(`\u274C \u9519\u8BEF: \u65E0\u6CD5\u83B7\u53D6\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${error}`));
|
|
89
|
+
console.log(chalk.yellow("\u5C1D\u8BD5\u4F7F\u7528\u5907\u7528\u65B9\u6CD5\u83B7\u53D6\u76EE\u5F55..."));
|
|
90
|
+
currentDir = path.resolve(__dirname, "..");
|
|
91
|
+
console.log(chalk.green(`\u2705 \u4F7F\u7528\u5907\u7528\u76EE\u5F55: ${currentDir}`));
|
|
92
|
+
}
|
|
93
|
+
const targetDir = safeResolvePath(currentDir, dirName);
|
|
78
94
|
if (fs.existsSync(targetDir)) {
|
|
79
|
-
console.log(chalk.red(`\u274C \u9519\u8BEF: \u76EE\u5F55 ${
|
|
95
|
+
console.log(chalk.red(`\u274C \u9519\u8BEF: \u76EE\u5F55 ${dirName} \u5DF2\u5B58\u5728`));
|
|
80
96
|
return;
|
|
81
97
|
}
|
|
82
98
|
let spinner = ora("\u{1F4C2} \u521B\u5EFA\u63D2\u4EF6\u76EE\u5F55...").start();
|
|
83
99
|
try {
|
|
84
|
-
yield
|
|
85
|
-
yield
|
|
100
|
+
yield safeEnsureDir(targetDir);
|
|
101
|
+
yield safeEnsureDir(safeResolvePath(targetDir, "src"));
|
|
86
102
|
spinner.succeed("\u{1F4C2} \u63D2\u4EF6\u76EE\u5F55\u521B\u5EFA\u6210\u529F");
|
|
87
103
|
spinner = ora("\u{1F50D} \u83B7\u53D6 @knotx \u5305\u7684\u6700\u65B0\u7248\u672C...").start();
|
|
88
104
|
const knotxVersions = yield getKnotxPackageVersions();
|
|
@@ -111,13 +127,19 @@ program.command("create-plugin").description("\u521B\u5EFA\u4E00\u4E2A\u65B0\u76
|
|
|
111
127
|
console.warn(chalk.yellow(` \u53EF\u80FD\u7684\u539F\u56E0: ${error.message}`));
|
|
112
128
|
}
|
|
113
129
|
console.log(chalk.green(`
|
|
114
|
-
\u2705 \u63D2\u4EF6 ${chalk.bold(
|
|
130
|
+
\u2705 \u63D2\u4EF6 ${chalk.bold(pluginName)} \u521B\u5EFA\u6210\u529F\uFF01`));
|
|
115
131
|
console.log(`
|
|
116
132
|
\u{1F4C1} \u63D2\u4EF6\u76EE\u5F55: ${chalk.cyan(targetDir)}`);
|
|
117
133
|
console.log(`
|
|
118
134
|
\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u4EE5\u5B89\u88C5\u4F9D\u8D56\u5E76\u5F00\u59CB\u5F00\u53D1:
|
|
119
135
|
`);
|
|
120
|
-
|
|
136
|
+
let cdCommand;
|
|
137
|
+
try {
|
|
138
|
+
cdCommand = `cd ${path.relative(process.cwd(), targetDir)}`;
|
|
139
|
+
} catch (e) {
|
|
140
|
+
cdCommand = `cd ${targetDir}`;
|
|
141
|
+
}
|
|
142
|
+
console.log(chalk.cyan(` ${cdCommand}`));
|
|
121
143
|
console.log(chalk.cyan(" pnpm install"));
|
|
122
144
|
console.log(chalk.cyan(" pnpm build"));
|
|
123
145
|
console.log(chalk.cyan(" pnpm dev # \u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\uFF0C\u8FD0\u884C playground"));
|
|
@@ -147,15 +169,23 @@ function getKnotxPackageVersions() {
|
|
|
147
169
|
"@knotx/plugins-base-render"
|
|
148
170
|
];
|
|
149
171
|
const npmRegistry = "https://registry.npmjs.org";
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
172
|
+
const execAsync = promisify(exec);
|
|
173
|
+
const results = yield Promise.all(
|
|
174
|
+
packages.map((pkg) => __async(this, null, function* () {
|
|
175
|
+
try {
|
|
176
|
+
const cmd = `npm view ${pkg} version --registry=${npmRegistry} --timeout=10000`;
|
|
177
|
+
const { stdout } = yield execAsync(cmd, { timeout: 1e4 });
|
|
178
|
+
const version = stdout.trim();
|
|
179
|
+
return { pkg, version: `^${version}`, success: true };
|
|
180
|
+
} catch (e) {
|
|
181
|
+
console.warn(chalk.yellow(`\u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6 ${pkg} \u7684\u6700\u65B0\u7248\u672C\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u7248\u672C`));
|
|
182
|
+
return { pkg, version: "latest", success: false };
|
|
183
|
+
}
|
|
184
|
+
}))
|
|
185
|
+
);
|
|
186
|
+
results.forEach(({ pkg, version }) => {
|
|
187
|
+
knotxVersions[pkg] = version;
|
|
188
|
+
});
|
|
159
189
|
return knotxVersions;
|
|
160
190
|
} catch (e) {
|
|
161
191
|
console.warn(chalk.yellow("\u26A0\uFE0F \u83B7\u53D6 @knotx \u5305\u7248\u672C\u5931\u8D25\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u7248\u672C"));
|
|
@@ -165,7 +195,9 @@ function getKnotxPackageVersions() {
|
|
|
165
195
|
"@knotx/jsx": "latest",
|
|
166
196
|
"@knotx/build-config": "latest",
|
|
167
197
|
"@knotx/eslint-config": "latest",
|
|
168
|
-
"@knotx/typescript-config": "latest"
|
|
198
|
+
"@knotx/typescript-config": "latest",
|
|
199
|
+
"@knotx/react": "latest",
|
|
200
|
+
"@knotx/plugins-base-render": "latest"
|
|
169
201
|
};
|
|
170
202
|
}
|
|
171
203
|
});
|
|
@@ -173,10 +205,10 @@ function getKnotxPackageVersions() {
|
|
|
173
205
|
function createPackageJson(targetDir, pluginName, environment, knotxVersions) {
|
|
174
206
|
return __async(this, null, function* () {
|
|
175
207
|
const packageJson = {
|
|
176
|
-
name:
|
|
208
|
+
name: pluginName,
|
|
177
209
|
type: "module",
|
|
178
210
|
version: "0.0.1",
|
|
179
|
-
description: `${capitalize(pluginName)} Plugin for Knotx`,
|
|
211
|
+
description: `${capitalize(pluginName.split("/").pop() || pluginName)} Plugin for Knotx`,
|
|
180
212
|
license: "MIT",
|
|
181
213
|
publishConfig: {
|
|
182
214
|
access: "public"
|
|
@@ -220,13 +252,15 @@ function createPackageJson(targetDir, pluginName, environment, knotxVersions) {
|
|
|
220
252
|
"vitest": "^3.0.0"
|
|
221
253
|
}
|
|
222
254
|
};
|
|
223
|
-
if (environment === "jsx")
|
|
224
|
-
packageJson.peerDependencies.react = "^17";
|
|
225
|
-
packageJson.peerDependencies["react-dom"] = "^17";
|
|
226
|
-
packageJson.devDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
255
|
+
if (environment === "jsx") {
|
|
227
256
|
packageJson.devDependencies["@knotx/plugins-base-render"] = knotxVersions["@knotx/plugins-base-render"];
|
|
228
|
-
|
|
257
|
+
} else if (environment === "react") {
|
|
258
|
+
packageJson.peerDependencies.react = ">=17";
|
|
259
|
+
packageJson.peerDependencies["react-dom"] = ">=17";
|
|
260
|
+
packageJson.peerDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
261
|
+
packageJson.devDependencies["@knotx/react"] = knotxVersions["@knotx/react"];
|
|
229
262
|
packageJson.devDependencies["@vitejs/plugin-react"] = "^4.3.4";
|
|
263
|
+
packageJson.devDependencies.react = "^17";
|
|
230
264
|
packageJson.devDependencies["react-dom"] = "^17";
|
|
231
265
|
packageJson.devDependencies["@types/react"] = "^17";
|
|
232
266
|
packageJson.devDependencies["@types/react-dom"] = "^17";
|
|
@@ -289,12 +323,12 @@ function sortObjectAlphabetically(obj) {
|
|
|
289
323
|
function createConfigFiles(targetDir) {
|
|
290
324
|
return __async(this, null, function* () {
|
|
291
325
|
try {
|
|
292
|
-
const tsconfigTemplate = yield fs.readFile(
|
|
293
|
-
const buildConfigTemplate = yield fs.readFile(
|
|
294
|
-
const eslintConfigTemplate = yield fs.readFile(
|
|
295
|
-
yield fs.writeFile(
|
|
296
|
-
yield fs.writeFile(
|
|
297
|
-
yield fs.writeFile(
|
|
326
|
+
const tsconfigTemplate = yield fs.readFile(safeResolvePath(templatesDir, "tsconfig.json.template"), "utf-8");
|
|
327
|
+
const buildConfigTemplate = yield fs.readFile(safeResolvePath(templatesDir, "build.config.ts.template"), "utf-8");
|
|
328
|
+
const eslintConfigTemplate = yield fs.readFile(safeResolvePath(templatesDir, "eslint.config.js.template"), "utf-8");
|
|
329
|
+
yield fs.writeFile(safeResolvePath(targetDir, "tsconfig.json"), tsconfigTemplate);
|
|
330
|
+
yield fs.writeFile(safeResolvePath(targetDir, "build.config.ts"), buildConfigTemplate);
|
|
331
|
+
yield fs.writeFile(safeResolvePath(targetDir, "eslint.config.js"), eslintConfigTemplate);
|
|
298
332
|
} catch (error) {
|
|
299
333
|
console.error("\u65E0\u6CD5\u8BFB\u53D6\u6A21\u677F\u6587\u4EF6:", error);
|
|
300
334
|
const tsconfig = {
|
|
@@ -307,15 +341,15 @@ function createConfigFiles(targetDir) {
|
|
|
307
341
|
}
|
|
308
342
|
};
|
|
309
343
|
yield fs.writeFile(
|
|
310
|
-
|
|
344
|
+
safeResolvePath(targetDir, "tsconfig.json"),
|
|
311
345
|
JSON.stringify(tsconfig, null, 2)
|
|
312
346
|
);
|
|
313
347
|
yield fs.writeFile(
|
|
314
|
-
|
|
348
|
+
safeResolvePath(targetDir, "build.config.ts"),
|
|
315
349
|
'import { defineBuildConfig } from "@knotx/build-config";\n\nexport default defineBuildConfig();'
|
|
316
350
|
);
|
|
317
351
|
yield fs.writeFile(
|
|
318
|
-
|
|
352
|
+
safeResolvePath(targetDir, "eslint.config.js"),
|
|
319
353
|
"export { default } from '@knotx/eslint-config';"
|
|
320
354
|
);
|
|
321
355
|
}
|
|
@@ -324,46 +358,49 @@ function createConfigFiles(targetDir) {
|
|
|
324
358
|
function createSourceFiles(targetDir, pluginName, environment) {
|
|
325
359
|
return __async(this, null, function* () {
|
|
326
360
|
try {
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
361
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
362
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
363
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
364
|
+
const indexTemplate = yield fs.readFile(safeResolvePath(templatesDir, "index.ts.template"), "utf-8");
|
|
365
|
+
const indexContent = indexTemplate.replace(/\{\{pluginName\}\}/g, camelCaseName);
|
|
366
|
+
yield fs.writeFile(safeResolvePath(targetDir, "src", "index.ts"), indexContent);
|
|
330
367
|
let templatePath;
|
|
331
368
|
if (environment === "jsx") {
|
|
332
|
-
templatePath =
|
|
369
|
+
templatePath = safeResolvePath(templatesDir, "plugin.jsx.template");
|
|
333
370
|
} else {
|
|
334
|
-
templatePath =
|
|
371
|
+
templatePath = safeResolvePath(templatesDir, "plugin.jsx.template");
|
|
335
372
|
}
|
|
336
373
|
const pluginTemplate = yield fs.readFile(templatePath, "utf-8");
|
|
337
|
-
const pluginContent = pluginTemplate.replace(/\{\{
|
|
338
|
-
const fileName = `${
|
|
339
|
-
yield fs.writeFile(
|
|
340
|
-
yield createPlayground(targetDir,
|
|
374
|
+
const pluginContent = pluginTemplate.replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName);
|
|
375
|
+
const fileName = `${camelCaseName}.tsx`;
|
|
376
|
+
yield fs.writeFile(safeResolvePath(targetDir, "src", fileName), pluginContent);
|
|
377
|
+
yield createPlayground(targetDir, pluginNameWithoutScope, camelCaseName, pascalCaseName, environment);
|
|
341
378
|
} catch (error) {
|
|
342
379
|
console.error("\u65E0\u6CD5\u8BFB\u53D6\u6A21\u677F\u6587\u4EF6:", error);
|
|
343
380
|
}
|
|
344
381
|
});
|
|
345
382
|
}
|
|
346
|
-
function createPlayground(targetDir, pluginName, environment) {
|
|
383
|
+
function createPlayground(targetDir, pluginName, camelCaseName, pascalCaseName, environment) {
|
|
347
384
|
return __async(this, null, function* () {
|
|
348
|
-
const playgroundDir =
|
|
349
|
-
yield
|
|
385
|
+
const playgroundDir = safeResolvePath(targetDir, "playground");
|
|
386
|
+
yield safeEnsureDir(playgroundDir);
|
|
350
387
|
try {
|
|
351
|
-
const viteConfigTemplate = yield fs.readFile(
|
|
352
|
-
const htmlTemplate = yield fs.readFile(
|
|
353
|
-
const tsConfigTemplate = yield fs.readFile(
|
|
388
|
+
const viteConfigTemplate = yield fs.readFile(safeResolvePath(templatesDir, "vite.config.ts.template"), "utf-8");
|
|
389
|
+
const htmlTemplate = yield fs.readFile(safeResolvePath(templatesDir, "playground/index.html.template"), "utf-8");
|
|
390
|
+
const tsConfigTemplate = yield fs.readFile(safeResolvePath(templatesDir, "playground/tsconfig.json.template"), "utf-8");
|
|
354
391
|
const isReact = environment === "react";
|
|
355
392
|
const mainTemplate = yield fs.readFile(
|
|
356
|
-
|
|
393
|
+
safeResolvePath(templatesDir, `playground/main.${isReact ? "react" : "jsx"}.template`),
|
|
357
394
|
"utf-8"
|
|
358
395
|
);
|
|
359
396
|
const fileExtension = isReact ? "tsx" : "ts";
|
|
360
397
|
const viteConfigContent = viteConfigTemplate.replace(new RegExp("\\{\\{#if isReact\\}\\}(.*?)\\{\\{\\/if\\}\\}", "gs"), isReact ? "$1" : "");
|
|
361
|
-
const htmlContent = htmlTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{
|
|
362
|
-
const mainContent = mainTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{capitalizedPluginName\}\}/g,
|
|
363
|
-
yield fs.writeFile(
|
|
364
|
-
yield fs.writeFile(
|
|
365
|
-
yield fs.writeFile(
|
|
366
|
-
yield fs.writeFile(
|
|
398
|
+
const htmlContent = htmlTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{pluginNameWithoutScope\}\}/g, pluginName).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName).replace(/\{\{fileExtension\}\}/g, fileExtension);
|
|
399
|
+
const mainContent = mainTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName);
|
|
400
|
+
yield fs.writeFile(safeResolvePath(playgroundDir, "vite.config.ts"), viteConfigContent);
|
|
401
|
+
yield fs.writeFile(safeResolvePath(playgroundDir, "index.html"), htmlContent);
|
|
402
|
+
yield fs.writeFile(safeResolvePath(playgroundDir, `main.${fileExtension}`), mainContent);
|
|
403
|
+
yield fs.writeFile(safeResolvePath(playgroundDir, "tsconfig.json"), tsConfigTemplate);
|
|
367
404
|
} catch (error) {
|
|
368
405
|
console.error("\u8BFB\u53D6 playground \u6A21\u677F\u6587\u4EF6\u5931\u8D25:", error);
|
|
369
406
|
}
|
|
@@ -372,50 +409,84 @@ function createPlayground(targetDir, pluginName, environment) {
|
|
|
372
409
|
function createReadme(targetDir, pluginName) {
|
|
373
410
|
return __async(this, null, function* () {
|
|
374
411
|
try {
|
|
375
|
-
const readmeTemplate = yield fs.readFile(
|
|
376
|
-
const
|
|
377
|
-
const
|
|
378
|
-
|
|
412
|
+
const readmeTemplate = yield fs.readFile(safeResolvePath(templatesDir, "README.md.template"), "utf-8");
|
|
413
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
414
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
415
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
416
|
+
const description = `${pascalCaseName} Plugin for Knotx`;
|
|
417
|
+
const readmeContent = readmeTemplate.replace(/\{\{pluginName\}\}/g, pluginName).replace(/\{\{pluginNameWithoutScope\}\}/g, pluginNameWithoutScope).replace(/\{\{camelCaseName\}\}/g, camelCaseName).replace(/\{\{capitalizedPluginName\}\}/g, pascalCaseName).replace(/\{\{description\}\}/g, description);
|
|
418
|
+
yield fs.writeFile(safeResolvePath(targetDir, "README.md"), readmeContent);
|
|
379
419
|
} catch (error) {
|
|
380
420
|
console.error("\u65E0\u6CD5\u8BFB\u53D6 README \u6A21\u677F\u6587\u4EF6:", error);
|
|
381
|
-
const
|
|
421
|
+
const pluginNameWithoutScope = pluginName.split("/").pop() || pluginName;
|
|
422
|
+
const camelCaseName = toCamelCase(pluginNameWithoutScope);
|
|
423
|
+
const pascalCaseName = toPascalCase(pluginNameWithoutScope);
|
|
424
|
+
const readmeContent = `# ${pluginName}
|
|
382
425
|
|
|
383
|
-
${
|
|
426
|
+
${pascalCaseName} Plugin for Knotx
|
|
384
427
|
|
|
385
428
|
## \u5B89\u88C5
|
|
386
429
|
|
|
387
430
|
\`\`\`bash
|
|
388
|
-
npm install
|
|
431
|
+
npm install ${pluginName}
|
|
389
432
|
# \u6216\u8005
|
|
390
|
-
yarn add
|
|
433
|
+
yarn add ${pluginName}
|
|
391
434
|
# \u6216\u8005
|
|
392
|
-
pnpm add
|
|
435
|
+
pnpm add ${pluginName}
|
|
393
436
|
\`\`\`
|
|
394
437
|
|
|
395
438
|
## \u4F7F\u7528\u65B9\u6CD5
|
|
396
439
|
|
|
397
440
|
\`\`\`typescript
|
|
398
|
-
import { ${
|
|
441
|
+
import { ${camelCaseName} } from '${pluginName}';
|
|
399
442
|
|
|
400
443
|
// \u5728\u60A8\u7684Knotx\u5E94\u7528\u4E2D\u4F7F\u7528\u63D2\u4EF6
|
|
401
|
-
app.use(${
|
|
444
|
+
app.use(${camelCaseName});
|
|
402
445
|
\`\`\`
|
|
403
446
|
|
|
404
447
|
## \u8BB8\u53EF\u8BC1
|
|
405
448
|
|
|
406
449
|
MIT`;
|
|
407
|
-
yield fs.writeFile(
|
|
450
|
+
yield fs.writeFile(safeResolvePath(targetDir, "README.md"), readmeContent);
|
|
408
451
|
}
|
|
409
452
|
});
|
|
410
453
|
}
|
|
411
454
|
function capitalize(str) {
|
|
412
455
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
413
456
|
}
|
|
457
|
+
function toCamelCase(str) {
|
|
458
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
459
|
+
}
|
|
460
|
+
function toPascalCase(str) {
|
|
461
|
+
return capitalize(toCamelCase(str));
|
|
462
|
+
}
|
|
463
|
+
function safeResolvePath(basePath, ...paths) {
|
|
464
|
+
try {
|
|
465
|
+
return path.resolve(basePath, ...paths);
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.warn(chalk.yellow(`\u26A0\uFE0F \u8DEF\u5F84\u89E3\u6790\u5931\u8D25: ${error}`));
|
|
468
|
+
return paths.reduce((result, part) => `${result}/${part}`, basePath);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function safeEnsureDir(dirPath) {
|
|
472
|
+
return __async(this, null, function* () {
|
|
473
|
+
try {
|
|
474
|
+
yield fs.ensureDir(dirPath);
|
|
475
|
+
} catch (e) {
|
|
476
|
+
console.warn(chalk.yellow(`\u26A0\uFE0F \u521B\u5EFA\u76EE\u5F55 ${dirPath} \u5931\u8D25\uFF0C\u5C1D\u8BD5\u4F7F\u7528\u5907\u7528\u65B9\u6CD5`));
|
|
477
|
+
try {
|
|
478
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
479
|
+
} catch (syncError) {
|
|
480
|
+
throw new Error(`\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55 ${dirPath}: ${syncError}`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
}
|
|
414
485
|
function createGitignore(targetDir) {
|
|
415
486
|
return __async(this, null, function* () {
|
|
416
487
|
try {
|
|
417
|
-
const gitignoreTemplate = yield fs.readFile(
|
|
418
|
-
yield fs.writeFile(
|
|
488
|
+
const gitignoreTemplate = yield fs.readFile(safeResolvePath(templatesDir, ".gitignore.template"), "utf-8");
|
|
489
|
+
yield fs.writeFile(safeResolvePath(targetDir, ".gitignore"), gitignoreTemplate);
|
|
419
490
|
} catch (error) {
|
|
420
491
|
console.error("\u65E0\u6CD5\u8BFB\u53D6 .gitignore \u6A21\u677F\u6587\u4EF6:", error);
|
|
421
492
|
const gitignoreContent = `# \u4F9D\u8D56\u76EE\u5F55
|
|
@@ -445,15 +516,16 @@ pnpm-debug.log*
|
|
|
445
516
|
# \u6D4B\u8BD5\u8986\u76D6\u7387
|
|
446
517
|
coverage
|
|
447
518
|
`;
|
|
448
|
-
yield fs.writeFile(
|
|
519
|
+
yield fs.writeFile(safeResolvePath(targetDir, ".gitignore"), gitignoreContent);
|
|
449
520
|
}
|
|
450
521
|
});
|
|
451
522
|
}
|
|
452
523
|
function initGitRepo(targetDir) {
|
|
453
524
|
try {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
525
|
+
if (!fs.existsSync(targetDir)) {
|
|
526
|
+
throw new Error(`\u76EE\u5F55 ${targetDir} \u4E0D\u5B58\u5728`);
|
|
527
|
+
}
|
|
528
|
+
const gitOptions = {
|
|
457
529
|
cwd: targetDir,
|
|
458
530
|
stdio: "ignore",
|
|
459
531
|
env: __spreadProps(__spreadValues({}, process.env), {
|
|
@@ -462,7 +534,10 @@ function initGitRepo(targetDir) {
|
|
|
462
534
|
GIT_COMMITTER_NAME: "Knotx CLI",
|
|
463
535
|
GIT_COMMITTER_EMAIL: "knotx-cli@noreply.github.com"
|
|
464
536
|
})
|
|
465
|
-
}
|
|
537
|
+
};
|
|
538
|
+
execSync("git init", gitOptions);
|
|
539
|
+
execSync("git add .", gitOptions);
|
|
540
|
+
execSync('git commit -m "Initial commit with Knotx plugin template"', gitOptions);
|
|
466
541
|
return true;
|
|
467
542
|
} catch (error) {
|
|
468
543
|
if (error instanceof Error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knotx/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "CLI tool for Knotx",
|
|
5
5
|
"author": "boenfu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"directory": "packages/cli"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
|
-
"access": "public"
|
|
15
|
-
"registry": "https://registry.npmjs.org/"
|
|
14
|
+
"access": "public"
|
|
16
15
|
},
|
|
17
16
|
"exports": {
|
|
18
17
|
".": {
|
|
@@ -41,9 +40,9 @@
|
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@types/fs-extra": "^11.0.4",
|
|
43
42
|
"@types/inquirer": "^9.0.7",
|
|
44
|
-
"@knotx/build-config": "0.0.
|
|
45
|
-
"@knotx/eslint-config": "0.0.
|
|
46
|
-
"@knotx/typescript-config": "0.0.
|
|
43
|
+
"@knotx/build-config": "0.0.5",
|
|
44
|
+
"@knotx/eslint-config": "0.0.5",
|
|
45
|
+
"@knotx/typescript-config": "0.0.5"
|
|
47
46
|
},
|
|
48
47
|
"scripts": {
|
|
49
48
|
"build": "unbuild --failOnWarn=false",
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# {{pluginName}}
|
|
2
2
|
|
|
3
3
|
{{description}}
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install
|
|
8
|
+
npm install {{pluginName}}
|
|
9
9
|
# 或者
|
|
10
|
-
yarn add
|
|
10
|
+
yarn add {{pluginName}}
|
|
11
11
|
# 或者
|
|
12
|
-
pnpm add
|
|
12
|
+
pnpm add {{pluginName}}
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## 使用方法
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
import { {{capitalizedPluginName}} } from '
|
|
18
|
+
import { {{capitalizedPluginName}} } from '{{pluginName}}'
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## 许可证
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
<title>{{capitalizedPluginName}} Plugin Playground</title>
|
|
7
7
|
<style>
|
|
8
8
|
body {
|
|
9
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
10
9
|
margin: 0;
|
|
11
10
|
padding: 20px;
|
|
12
11
|
background-color: #f7f7f7;
|
|
@@ -29,7 +28,7 @@
|
|
|
29
28
|
<body>
|
|
30
29
|
<div class="container">
|
|
31
30
|
<h1>{{capitalizedPluginName}} Plugin Demo</h1>
|
|
32
|
-
<p>这是 {{
|
|
31
|
+
<p>这是 {{pluginNameWithoutScope}} 插件的演示页面。您可以在这里测试插件的功能。</p>
|
|
33
32
|
|
|
34
33
|
<div id="app">
|
|
35
34
|
<!-- 插件内容将在这里展示 -->
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { {{capitalizedPluginName}} } from '../src'
|
|
2
2
|
|
|
3
3
|
// 在这里初始化和使用您的插件
|
|
4
|
-
const plugin = new {{capitalizedPluginName}}()
|
|
5
|
-
plugin.init()
|
|
6
|
-
|
|
7
|
-
// 更新演示区域
|
|
8
|
-
const appElement = document.getElementById('app')
|
|
9
|
-
if (appElement) {
|
|
10
|
-
appElement.innerHTML += '<p>插件已初始化,请查看控制台输出</p>'
|
|
11
|
-
}
|
|
4
|
+
const plugin = new {{capitalizedPluginName}}();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BaseRender } from '@knotx/plugins-base-render'
|
|
2
1
|
import { Knotx } from '@knotx/react'
|
|
3
2
|
import { StrictMode } from 'react'
|
|
4
3
|
import ReactDOM from 'react-dom'
|
|
@@ -31,7 +30,7 @@ function App() {
|
|
|
31
30
|
style={{ height: 480, boxShadow: '0 0 2px #333', borderRadius: 4 }}
|
|
32
31
|
nodes={nodes}
|
|
33
32
|
edges={edges}
|
|
34
|
-
plugins={[
|
|
33
|
+
plugins={[{{capitalizedPluginName}}]}
|
|
35
34
|
/>
|
|
36
35
|
)
|
|
37
36
|
}
|
|
@@ -3,14 +3,14 @@ import type { NodeData } from '@knotx/core'
|
|
|
3
3
|
import { BasePlugin } from '@knotx/core'
|
|
4
4
|
import { inject, OnInit } from '@knotx/decorators'
|
|
5
5
|
|
|
6
|
-
export class {{capitalizedPluginName}} extends BasePlugin<'{{
|
|
7
|
-
name = '{{
|
|
6
|
+
export class {{capitalizedPluginName}} extends BasePlugin<'{{camelCaseName}}'> {
|
|
7
|
+
name = '{{camelCaseName}}' as const
|
|
8
8
|
|
|
9
9
|
@inject.nodes()
|
|
10
10
|
nodes!: NodeData[]
|
|
11
11
|
|
|
12
12
|
@OnInit
|
|
13
13
|
init() {
|
|
14
|
-
console.log('{{capitalizedPluginName}} 插件已加载'
|
|
14
|
+
console.log('{{capitalizedPluginName}} 插件已加载')
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -3,16 +3,16 @@ import { defineConfig } from 'vite'
|
|
|
3
3
|
|
|
4
4
|
export default defineConfig({
|
|
5
5
|
plugins: [{{#if isReact}}react({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
]],
|
|
6
|
+
babel: {
|
|
7
|
+
plugins: [[
|
|
8
|
+
'@babel/plugin-proposal-decorators',
|
|
9
|
+
{
|
|
10
|
+
version: '2023-11',
|
|
11
|
+
decoratorsBeforeExport: true,
|
|
14
12
|
},
|
|
15
|
-
|
|
13
|
+
]],
|
|
14
|
+
},
|
|
15
|
+
}){{/if}}],
|
|
16
16
|
server: {
|
|
17
17
|
port: 5173,
|
|
18
18
|
},
|