@widget-js/cli 1.0.4 → 1.0.5
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/babel.config.js +20 -0
- package/bin/widget.js +13 -210
- package/jest.config.js +14 -0
- package/lib/createWidget.js +217 -0
- package/package.json +30 -5
- package/tools/cleanup.js +29 -0
- package/tools/packagejson.js +25 -0
- package/tsconfig.json +74 -0
package/babel.config.js
ADDED
package/bin/widget.js
CHANGED
|
@@ -1,217 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {chalk} from "@vue/cli-shared-utils";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import {snakeCase, paramCase} from "change-case";
|
|
6
|
-
import {fileURLToPath} from 'url';
|
|
7
|
-
import shell from 'shelljs';
|
|
8
|
-
import promptChecker from "../lib/promts/promptChecker.js";
|
|
9
|
-
import {exit, exitProcess} from "@vue/cli-shared-utils/lib/exit.js";
|
|
10
|
-
import ejs from "ejs";
|
|
11
|
-
import consola from "consola";
|
|
1
|
+
import {program} from 'commander';
|
|
12
2
|
|
|
3
|
+
import packageJson from '../package.json' assert {type: 'json'};
|
|
4
|
+
import createWidget from "../lib/createWidget.js";
|
|
13
5
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
program
|
|
7
|
+
.version(`@widget-js/cli ${packageJson.version}`)
|
|
8
|
+
.usage('<command> [options]')
|
|
9
|
+
program
|
|
10
|
+
.command('create')
|
|
11
|
+
.description('创建新的组件')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
await createWidget()
|
|
14
|
+
})
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
program.parse(process.argv);
|
|
21
17
|
|
|
22
|
-
let widgetFolder = path.join(process.cwd(), "./src/widgets");
|
|
23
|
-
let devOptions = widgetPackage["devOptions"] ?? {};
|
|
24
|
-
if (devOptions["folder"]) {
|
|
25
|
-
widgetFolder = devOptions["folder"];
|
|
26
|
-
consola.info(`组件路径:${widgetFolder}`);
|
|
27
|
-
} else {
|
|
28
|
-
consola.info(`没有配置devOptions.folder,使用默认路径${widgetFolder}`);
|
|
29
|
-
}
|
|
30
18
|
|
|
31
|
-
if (!fs.existsSync(widgetFolder)) {
|
|
32
|
-
fs.mkdirSync(widgetFolder, {recursive: true});
|
|
33
|
-
}
|
|
34
19
|
|
|
35
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
36
|
-
const __dirname = path.dirname(__filename);
|
|
37
|
-
|
|
38
|
-
Array.prototype.max = function () {
|
|
39
|
-
return Math.max.apply(null, this);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
Array.prototype.min = function () {
|
|
43
|
-
return Math.min.apply(null, this);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const getMiddleValue = (arr) => {
|
|
47
|
-
if (arr.length === 1) {
|
|
48
|
-
return arr[0];
|
|
49
|
-
} else if (arr.length === 2) {
|
|
50
|
-
return arr.max();
|
|
51
|
-
} else {
|
|
52
|
-
const max = arr.max();
|
|
53
|
-
const min = arr.min();
|
|
54
|
-
const sum = arr[0] + arr[1] + arr[2];
|
|
55
|
-
return sum - max - min;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let name = await promptChecker({
|
|
60
|
-
type: "input",
|
|
61
|
-
name: 'name',
|
|
62
|
-
message: chalk.blue("请输入组件名(大驼峰式),如:CountdownClock")
|
|
63
|
-
}, (answer) => {
|
|
64
|
-
const name = answer.name;
|
|
65
|
-
if (name == null || name === '') {
|
|
66
|
-
consola.log(chalk.red('组件名不能为空'));
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
return true;
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
consola.log(chalk.green(name))
|
|
73
|
-
|
|
74
|
-
let title = await promptChecker({
|
|
75
|
-
type: "input",
|
|
76
|
-
name: 'title',
|
|
77
|
-
message: chalk.blue("请输入组件标题,如:倒计时")
|
|
78
|
-
})
|
|
79
|
-
consola.log(chalk.green(title))
|
|
80
|
-
|
|
81
|
-
let answerW = await promptChecker({
|
|
82
|
-
type: "checkbox",
|
|
83
|
-
name: 'w',
|
|
84
|
-
message: chalk.blue("请选择组件宽度,最多选3个,例如选中2,4,6,代表组件最小宽为2,默认宽为4,最大宽为6,单选代表不可拉伸"),
|
|
85
|
-
choices: [1, 2, 3, 4, 5, 6]
|
|
86
|
-
}, (answer) => {
|
|
87
|
-
if (answer.w.length === 0) {
|
|
88
|
-
consola.log(chalk.red('宽度必须选择'));
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (answer.w.length > 3) {
|
|
93
|
-
consola.log(chalk.red('宽度最多选择3个'));
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
return true;
|
|
97
|
-
})
|
|
98
|
-
consola.log(chalk.green(answerW))
|
|
99
|
-
|
|
100
|
-
let answerH = await promptChecker({
|
|
101
|
-
type: "checkbox",
|
|
102
|
-
name: 'h',
|
|
103
|
-
message: chalk.blue("请选择组件高度,最多选3个,例如选中1,2,代表组件最小高为1,默认高为2,最大高为2,单选代表不可拉伸"),
|
|
104
|
-
choices: [1, 2, 3, 4, 5, 6]
|
|
105
|
-
}, (answer) => {
|
|
106
|
-
if (answer.h.length === 0) {
|
|
107
|
-
consola.log(chalk.red('高度必须选择'));
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (answer.h.length > 3) {
|
|
112
|
-
consola.log(chalk.red('高度最多选择3个'));
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
consola.log(chalk.green(answerH))
|
|
119
|
-
|
|
120
|
-
let configurable = await promptChecker({
|
|
121
|
-
type: "confirm",
|
|
122
|
-
name: 'configurable',
|
|
123
|
-
message: chalk.blue("组件是否可配置,例如修改背景颜色,字体大小等")
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
consola.log(chalk.green(configurable))
|
|
127
|
-
|
|
128
|
-
const width = getMiddleValue(answerW);
|
|
129
|
-
const height = getMiddleValue(answerH);
|
|
130
|
-
const minWidth = answerW.min();
|
|
131
|
-
const maxWidth = answerW.max();
|
|
132
|
-
const minHeight = answerH.min();
|
|
133
|
-
const maxHeight = answerH.max();
|
|
134
|
-
const snakeCaseName = snakeCase(name);
|
|
135
|
-
const paramCaseName = paramCase(name);
|
|
136
|
-
const packageName = "com.wisdom.widgets." + snakeCaseName;
|
|
137
|
-
|
|
138
|
-
const widgetDir = path.join(widgetFolder, paramCaseName)
|
|
139
|
-
if (!fs.existsSync(widgetDir)) {
|
|
140
|
-
fs.mkdirSync(widgetDir);
|
|
141
|
-
} else {
|
|
142
|
-
let answer = await inquirer.prompt([{
|
|
143
|
-
type: 'confirm',
|
|
144
|
-
name: 'override',
|
|
145
|
-
message: chalk.red('组件名已存在,是否继续?')
|
|
146
|
-
}])
|
|
147
|
-
if (!answer.override) {
|
|
148
|
-
exitProcess();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const renderOptions = {
|
|
153
|
-
name: name,
|
|
154
|
-
snakeCaseName: snakeCaseName,
|
|
155
|
-
paramCaseName: paramCaseName,
|
|
156
|
-
packageName: packageName,
|
|
157
|
-
title: title,
|
|
158
|
-
configurable: configurable,
|
|
159
|
-
width: width,
|
|
160
|
-
height: height,
|
|
161
|
-
maxWidth: maxWidth,
|
|
162
|
-
minHeight: minHeight,
|
|
163
|
-
maxHeight: maxHeight,
|
|
164
|
-
minWidth: minWidth
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function renderToFile(templateFile, outputFile, renderOptions) {
|
|
168
|
-
const defineTemplatePath = path.join(__dirname, '../template', templateFile)
|
|
169
|
-
let defineTemplate = fs.readFileSync(defineTemplatePath, 'utf8');
|
|
170
|
-
fs.writeFileSync(outputFile, ejs.render(defineTemplate, renderOptions))
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const widgetDefineFile = path.resolve(widgetDir, `${name}.widget.ts`)
|
|
174
|
-
const widgetFile = path.resolve(widgetDir, `${name}Widget.vue`);
|
|
175
|
-
const widgetViewFile = path.resolve(widgetDir, `${name}WidgetView.vue`)
|
|
176
|
-
const widgetRoutesFile = path.resolve(widgetDir, `${name}WidgetRoutes.ts`)
|
|
177
|
-
|
|
178
|
-
renderToFile('WidgetDefine.ejs', widgetDefineFile, renderOptions);
|
|
179
|
-
renderToFile('Widget.ejs', widgetFile, renderOptions);
|
|
180
|
-
renderToFile('WidgetView.ejs', widgetViewFile, renderOptions);
|
|
181
|
-
renderToFile('WidgetRoutes.ejs', widgetRoutesFile, renderOptions);
|
|
182
|
-
if (configurable) {
|
|
183
|
-
const configFile = path.resolve(widgetDir, `${name}ConfigView.vue`)
|
|
184
|
-
renderToFile('WidgetConfig.ejs', configFile, renderOptions);
|
|
185
|
-
}
|
|
186
|
-
if (devOptions["useStorybook"]) {
|
|
187
|
-
const storiesFile = path.resolve(widgetDir, `${name}Widget.stories.ts`)
|
|
188
|
-
renderToFile('stories.ejs', storiesFile, renderOptions);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// 注册路由
|
|
192
|
-
const routeFile = path.join(widgetFolder, 'widget-router.ts');
|
|
193
|
-
let routeContent;
|
|
194
|
-
if (fs.existsSync(routeFile)) {
|
|
195
|
-
routeContent = fs.readFileSync(routeFile, 'utf8');
|
|
196
|
-
} else {
|
|
197
|
-
routeContent = fs.readFileSync(path.join(__dirname, "../template/widget-router.ts"), 'utf8');
|
|
198
|
-
}
|
|
199
|
-
const importRouteStr = `import ${name}WidgetRoutes from "./${paramCaseName}/${name}WidgetRoutes";`
|
|
200
|
-
const routeStr = `...${name}WidgetRoutes,`
|
|
201
|
-
if (!routeContent.includes(importRouteStr)) {
|
|
202
|
-
routeContent = routeContent.replaceAll("//FBI WANING! IMPORT PLACE", `${importRouteStr}\n//FBI WANING! IMPORT PLACE`)
|
|
203
|
-
}
|
|
204
|
-
if (!routeContent.includes(routeStr)) {
|
|
205
|
-
routeContent = routeContent.replaceAll("//FBI WANING! ROUTE PLACE", `${routeStr}\n //FBI WANING! ROUTE PLACE`)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
fs.writeFileSync(routeFile, routeContent)
|
|
209
|
-
|
|
210
|
-
//添加到版本控制
|
|
211
|
-
let gitAdd = `git add ${widgetDir}`;
|
|
212
|
-
consola.info(chalk.grey(gitAdd))
|
|
213
|
-
shell.exec(gitAdd);
|
|
214
|
-
consola.log("=================")
|
|
215
|
-
consola.info(`已创建组件:${widgetDir}`)
|
|
216
|
-
consola.success("Happy coding!")
|
|
217
20
|
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
roots: ['<rootDir>/test'],
|
|
3
|
+
testMatch: [
|
|
4
|
+
'**/__tests__/**/*.+(ts|tsx|js)',
|
|
5
|
+
'**/?(*.)+(spec|test).+(ts|tsx|js)',
|
|
6
|
+
],
|
|
7
|
+
transform: {
|
|
8
|
+
'^.+\\.(ts|tsx)$': ['ts-jest',{
|
|
9
|
+
tsconfig: 'tsconfig.json'
|
|
10
|
+
}],
|
|
11
|
+
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
|
12
|
+
'./config/fileTransformer.js',
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import {exit, exitProcess} from "@vue/cli-shared-utils/lib/exit.js";
|
|
5
|
+
import {fileURLToPath} from "url";
|
|
6
|
+
import promptChecker from "./promts/promptChecker.js";
|
|
7
|
+
import {chalk} from "@vue/cli-shared-utils";
|
|
8
|
+
import {paramCase, snakeCase} from "change-case";
|
|
9
|
+
import inquirer from "inquirer";
|
|
10
|
+
import ejs from "ejs";
|
|
11
|
+
import shell from "shelljs";
|
|
12
|
+
|
|
13
|
+
export default async function createWidget() {
|
|
14
|
+
let widgetJson = path.join(process.cwd(), "widget.json");
|
|
15
|
+
if (!fs.existsSync(widgetJson)) {
|
|
16
|
+
consola.error("没有在根目录找到widget.json文件")
|
|
17
|
+
exit();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let widgetPackage = JSON.parse(fs.readFileSync(widgetJson));
|
|
21
|
+
|
|
22
|
+
let widgetFolder = path.join(process.cwd(), "./src/widgets");
|
|
23
|
+
let devOptions = widgetPackage["devOptions"] ?? {};
|
|
24
|
+
if (devOptions["folder"]) {
|
|
25
|
+
widgetFolder = devOptions["folder"];
|
|
26
|
+
consola.info(`组件路径:${widgetFolder}`);
|
|
27
|
+
} else {
|
|
28
|
+
consola.info(`没有配置devOptions.folder,使用默认路径${widgetFolder}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(widgetFolder)) {
|
|
32
|
+
fs.mkdirSync(widgetFolder, {recursive: true});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
36
|
+
const __dirname = path.dirname(__filename);
|
|
37
|
+
|
|
38
|
+
Array.prototype.max = function () {
|
|
39
|
+
return Math.max.apply(null, this);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Array.prototype.min = function () {
|
|
43
|
+
return Math.min.apply(null, this);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getMiddleValue = (arr) => {
|
|
47
|
+
if (arr.length === 1) {
|
|
48
|
+
return arr[0];
|
|
49
|
+
} else if (arr.length === 2) {
|
|
50
|
+
return arr.max();
|
|
51
|
+
} else {
|
|
52
|
+
const max = arr.max();
|
|
53
|
+
const min = arr.min();
|
|
54
|
+
const sum = arr[0] + arr[1] + arr[2];
|
|
55
|
+
return sum - max - min;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let name = await promptChecker({
|
|
60
|
+
type: "input",
|
|
61
|
+
name: 'name',
|
|
62
|
+
message: chalk.blue("请输入组件名(大驼峰式),如:CountdownClock")
|
|
63
|
+
}, (answer) => {
|
|
64
|
+
const name = answer.name;
|
|
65
|
+
if (name == null || name === '') {
|
|
66
|
+
consola.log(chalk.red('组件名不能为空'));
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
consola.log(chalk.green(name))
|
|
73
|
+
|
|
74
|
+
let title = await promptChecker({
|
|
75
|
+
type: "input",
|
|
76
|
+
name: 'title',
|
|
77
|
+
message: chalk.blue("请输入组件标题,如:倒计时")
|
|
78
|
+
})
|
|
79
|
+
consola.log(chalk.green(title))
|
|
80
|
+
|
|
81
|
+
let answerW = await promptChecker({
|
|
82
|
+
type: "checkbox",
|
|
83
|
+
name: 'w',
|
|
84
|
+
message: chalk.blue("请选择组件宽度,最多选3个,例如选中2,4,6,代表组件最小宽为2,默认宽为4,最大宽为6,单选代表不可拉伸"),
|
|
85
|
+
choices: [1, 2, 3, 4, 5, 6]
|
|
86
|
+
}, (answer) => {
|
|
87
|
+
if (answer.w.length === 0) {
|
|
88
|
+
consola.log(chalk.red('宽度必须选择'));
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (answer.w.length > 3) {
|
|
93
|
+
consola.log(chalk.red('宽度最多选择3个'));
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
})
|
|
98
|
+
consola.log(chalk.green(answerW))
|
|
99
|
+
|
|
100
|
+
let answerH = await promptChecker({
|
|
101
|
+
type: "checkbox",
|
|
102
|
+
name: 'h',
|
|
103
|
+
message: chalk.blue("请选择组件高度,最多选3个,例如选中1,2,代表组件最小高为1,默认高为2,最大高为2,单选代表不可拉伸"),
|
|
104
|
+
choices: [1, 2, 3, 4, 5, 6]
|
|
105
|
+
}, (answer) => {
|
|
106
|
+
if (answer.h.length === 0) {
|
|
107
|
+
consola.log(chalk.red('高度必须选择'));
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (answer.h.length > 3) {
|
|
112
|
+
consola.log(chalk.red('高度最多选择3个'));
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
consola.log(chalk.green(answerH))
|
|
119
|
+
|
|
120
|
+
let configurable = await promptChecker({
|
|
121
|
+
type: "confirm",
|
|
122
|
+
name: 'configurable',
|
|
123
|
+
message: chalk.blue("组件是否可配置,例如修改背景颜色,字体大小等")
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
consola.log(chalk.green(configurable))
|
|
127
|
+
|
|
128
|
+
const width = getMiddleValue(answerW);
|
|
129
|
+
const height = getMiddleValue(answerH);
|
|
130
|
+
const minWidth = answerW.min();
|
|
131
|
+
const maxWidth = answerW.max();
|
|
132
|
+
const minHeight = answerH.min();
|
|
133
|
+
const maxHeight = answerH.max();
|
|
134
|
+
const snakeCaseName = snakeCase(name);
|
|
135
|
+
const paramCaseName = paramCase(name);
|
|
136
|
+
const packageName = "com.wisdom.widgets." + snakeCaseName;
|
|
137
|
+
|
|
138
|
+
const widgetDir = path.join(widgetFolder, paramCaseName)
|
|
139
|
+
if (!fs.existsSync(widgetDir)) {
|
|
140
|
+
fs.mkdirSync(widgetDir);
|
|
141
|
+
} else {
|
|
142
|
+
let answer = await inquirer.prompt([{
|
|
143
|
+
type: 'confirm',
|
|
144
|
+
name: 'override',
|
|
145
|
+
message: chalk.red('组件名已存在,是否继续?')
|
|
146
|
+
}])
|
|
147
|
+
if (!answer.override) {
|
|
148
|
+
exitProcess();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const renderOptions = {
|
|
153
|
+
name: name,
|
|
154
|
+
snakeCaseName: snakeCaseName,
|
|
155
|
+
paramCaseName: paramCaseName,
|
|
156
|
+
packageName: packageName,
|
|
157
|
+
title: title,
|
|
158
|
+
configurable: configurable,
|
|
159
|
+
width: width,
|
|
160
|
+
height: height,
|
|
161
|
+
maxWidth: maxWidth,
|
|
162
|
+
minHeight: minHeight,
|
|
163
|
+
maxHeight: maxHeight,
|
|
164
|
+
minWidth: minWidth
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function renderToFile(templateFile, outputFile, renderOptions) {
|
|
168
|
+
const defineTemplatePath = path.join(__dirname, '../template', templateFile)
|
|
169
|
+
let defineTemplate = fs.readFileSync(defineTemplatePath, 'utf8');
|
|
170
|
+
fs.writeFileSync(outputFile, ejs.render(defineTemplate, renderOptions))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const widgetDefineFile = path.resolve(widgetDir, `${name}.widget.ts`)
|
|
174
|
+
const widgetFile = path.resolve(widgetDir, `${name}Widget.vue`);
|
|
175
|
+
const widgetViewFile = path.resolve(widgetDir, `${name}WidgetView.vue`)
|
|
176
|
+
const widgetRoutesFile = path.resolve(widgetDir, `${name}WidgetRoutes.ts`)
|
|
177
|
+
|
|
178
|
+
renderToFile('WidgetDefine.ejs', widgetDefineFile, renderOptions);
|
|
179
|
+
renderToFile('Widget.ejs', widgetFile, renderOptions);
|
|
180
|
+
renderToFile('WidgetView.ejs', widgetViewFile, renderOptions);
|
|
181
|
+
renderToFile('WidgetRoutes.ejs', widgetRoutesFile, renderOptions);
|
|
182
|
+
if (configurable) {
|
|
183
|
+
const configFile = path.resolve(widgetDir, `${name}ConfigView.vue`)
|
|
184
|
+
renderToFile('WidgetConfig.ejs', configFile, renderOptions);
|
|
185
|
+
}
|
|
186
|
+
if (devOptions["useStorybook"]) {
|
|
187
|
+
const storiesFile = path.resolve(widgetDir, `${name}Widget.stories.ts`)
|
|
188
|
+
renderToFile('stories.ejs', storiesFile, renderOptions);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 注册路由
|
|
192
|
+
const routeFile = path.join(widgetFolder, 'widget-router.ts');
|
|
193
|
+
let routeContent;
|
|
194
|
+
if (fs.existsSync(routeFile)) {
|
|
195
|
+
routeContent = fs.readFileSync(routeFile, 'utf8');
|
|
196
|
+
} else {
|
|
197
|
+
routeContent = fs.readFileSync(path.join(__dirname, "../template/widget-router.ts"), 'utf8');
|
|
198
|
+
}
|
|
199
|
+
const importRouteStr = `import ${name}WidgetRoutes from "./${paramCaseName}/${name}WidgetRoutes";`
|
|
200
|
+
const routeStr = `...${name}WidgetRoutes,`
|
|
201
|
+
if (!routeContent.includes(importRouteStr)) {
|
|
202
|
+
routeContent = routeContent.replaceAll("//FBI WANING! IMPORT PLACE", `${importRouteStr}\n//FBI WANING! IMPORT PLACE`)
|
|
203
|
+
}
|
|
204
|
+
if (!routeContent.includes(routeStr)) {
|
|
205
|
+
routeContent = routeContent.replaceAll("//FBI WANING! ROUTE PLACE", `${routeStr}\n //FBI WANING! ROUTE PLACE`)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
fs.writeFileSync(routeFile, routeContent)
|
|
209
|
+
|
|
210
|
+
//添加到版本控制
|
|
211
|
+
let gitAdd = `git add ${widgetDir}`;
|
|
212
|
+
consola.info(chalk.grey(gitAdd))
|
|
213
|
+
shell.exec(gitAdd);
|
|
214
|
+
consola.log("=================")
|
|
215
|
+
consola.info(`已创建组件:${widgetDir}`)
|
|
216
|
+
consola.success("Happy coding!")
|
|
217
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@widget-js/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"main": "bin/widget.js",
|
|
5
5
|
"author": "Neo Fu",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
7
|
"private": false,
|
|
9
8
|
"bin": {
|
|
10
9
|
"widget": "bin/widget.js"
|
|
11
10
|
},
|
|
11
|
+
"type": "module",
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
@@ -17,14 +17,39 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@vue/cli-shared-utils": "^5.0.8",
|
|
20
|
+
"@widget-js/core": "^0.1.14",
|
|
21
|
+
"chalk": "^5.2.0",
|
|
20
22
|
"change-case": "^4.1.2",
|
|
23
|
+
"commander": "^9.4.1",
|
|
21
24
|
"consola": "^2.15.3",
|
|
22
25
|
"ejs": "^3.1.8",
|
|
23
26
|
"inquirer": "^9.1.4",
|
|
24
|
-
"shelljs": "^0.8.5"
|
|
27
|
+
"shelljs": "^0.8.5",
|
|
28
|
+
"ws": "^8.11.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/inquirer": "latest",
|
|
32
|
+
"@types/ejs": "latest",
|
|
33
|
+
"@types/shelljs": "latest",
|
|
34
|
+
"@types/node": "^18.11.13",
|
|
35
|
+
"@babel/cli": "^7.19.3",
|
|
36
|
+
"@babel/core": "^7.20.2",
|
|
37
|
+
"@babel/node": "^7.20.2",
|
|
38
|
+
"@babel/preset-env": "^7.20.2",
|
|
39
|
+
"webpack": "^5.75.0",
|
|
40
|
+
"webpack-cli": "^5.0.0",
|
|
41
|
+
"ts-jest": "^29.0.3",
|
|
42
|
+
"ts-loader": "^9.4.1",
|
|
43
|
+
"typescript": "^4.9.3",
|
|
44
|
+
"pinst": "^3.0.0",
|
|
45
|
+
"@types/jest": "^29.2.3"
|
|
25
46
|
},
|
|
26
|
-
"devDependencies": {},
|
|
27
47
|
"scripts": {
|
|
28
|
-
"widget": "node ./bin/widget.js"
|
|
48
|
+
"widget": "node ./bin/widget.js",
|
|
49
|
+
"build": "npm run build:esm && npm run build:types && npm run build:cjs && npm run build:umd",
|
|
50
|
+
"build:cjs": "node tools/cleanup cjs && tsc -p config/tsconfig.cjs.json",
|
|
51
|
+
"build:esm": "node tools/cleanup esm && tsc -p config/tsconfig.esm.json",
|
|
52
|
+
"build:umd": "node tools/cleanup umd && webpack --config config/webpack.config.js",
|
|
53
|
+
"build:types": "node tools/cleanup types && tsc -p config/tsconfig.types.json"
|
|
29
54
|
}
|
|
30
55
|
}
|
package/tools/cleanup.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const Path = require('path')
|
|
4
|
+
/* eslint-enable */
|
|
5
|
+
|
|
6
|
+
const deleteFolderRecursive = (path) => {
|
|
7
|
+
if (fs.existsSync(path)) {
|
|
8
|
+
fs.readdirSync(path).forEach((file) => {
|
|
9
|
+
const curPath = Path.join(path, file)
|
|
10
|
+
if (fs.lstatSync(curPath).isDirectory()) {
|
|
11
|
+
deleteFolderRecursive(curPath)
|
|
12
|
+
} else {
|
|
13
|
+
fs.unlinkSync(curPath)
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
fs.rmdirSync(path)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const folder = process.argv.slice(2)[0]
|
|
21
|
+
|
|
22
|
+
if (folder) {
|
|
23
|
+
deleteFolderRecursive(Path.join(__dirname, '../dist', folder))
|
|
24
|
+
} else {
|
|
25
|
+
deleteFolderRecursive(Path.join(__dirname, '../dist/cjs'))
|
|
26
|
+
deleteFolderRecursive(Path.join(__dirname, '../dist/esm'))
|
|
27
|
+
deleteFolderRecursive(Path.join(__dirname, '../dist/umd'))
|
|
28
|
+
deleteFolderRecursive(Path.join(__dirname, '../dist/types'))
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const Path = require('path')
|
|
4
|
+
const fileName = '../package.json'
|
|
5
|
+
const file = require(fileName)
|
|
6
|
+
/* eslint-enable */
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2)
|
|
9
|
+
|
|
10
|
+
for (let i = 0, l = args.length; i < l; i++) {
|
|
11
|
+
if (i % 2 === 0) {
|
|
12
|
+
file[args[i]] = args[i + 1]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fs.writeFile(
|
|
17
|
+
Path.join(__dirname, fileName),
|
|
18
|
+
JSON.stringify(file, null, 2),
|
|
19
|
+
(err) => {
|
|
20
|
+
if (err) {
|
|
21
|
+
return console.log(err)
|
|
22
|
+
}
|
|
23
|
+
console.log('Writing to ' + fileName)
|
|
24
|
+
}
|
|
25
|
+
)
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
|
4
|
+
|
|
5
|
+
/* Basic Options */
|
|
6
|
+
// "incremental": true, /* Enable incremental compilation */
|
|
7
|
+
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
|
8
|
+
// "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
|
9
|
+
// "lib": [], /* Specify library files to be included in the compilation. */
|
|
10
|
+
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
11
|
+
// "checkJs": true, /* Report errors in .js files. */
|
|
12
|
+
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
|
13
|
+
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
14
|
+
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
15
|
+
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
|
16
|
+
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
17
|
+
// "outDir": "./", /* Redirect output structure to the directory. */
|
|
18
|
+
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
19
|
+
// "composite": true, /* Enable project compilation */
|
|
20
|
+
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
21
|
+
// "removeComments": true, /* Do not emit comments to output. */
|
|
22
|
+
// "noEmit": true, /* Do not emit outputs. */
|
|
23
|
+
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
|
24
|
+
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
|
25
|
+
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
|
26
|
+
|
|
27
|
+
/* Strict Type-Checking Options */
|
|
28
|
+
"strict": true /* Enable all strict type-checking options. */,
|
|
29
|
+
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
30
|
+
// "strictNullChecks": true, /* Enable strict null checks. */
|
|
31
|
+
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
|
32
|
+
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
|
33
|
+
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
|
34
|
+
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
|
35
|
+
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
|
36
|
+
|
|
37
|
+
/* Additional Checks */
|
|
38
|
+
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
|
39
|
+
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
40
|
+
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
41
|
+
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
42
|
+
|
|
43
|
+
/* Module Resolution Options */
|
|
44
|
+
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
|
45
|
+
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
|
46
|
+
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
47
|
+
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
48
|
+
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
49
|
+
/* Type declaration files to be included in compilation. */
|
|
50
|
+
// "types": ["element-plus/global"],
|
|
51
|
+
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
|
52
|
+
// "resolveJsonModule": true,
|
|
53
|
+
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
|
54
|
+
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
|
55
|
+
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
56
|
+
|
|
57
|
+
/* Source Map Options */
|
|
58
|
+
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
59
|
+
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
60
|
+
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
61
|
+
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
62
|
+
|
|
63
|
+
/* Experimental Options */
|
|
64
|
+
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
65
|
+
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
66
|
+
|
|
67
|
+
/* Advanced Options */
|
|
68
|
+
|
|
69
|
+
/* Skip type checking of declaration files. */
|
|
70
|
+
"skipLibCheck": true,
|
|
71
|
+
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
|
72
|
+
},
|
|
73
|
+
"include": ["src/**/*"],
|
|
74
|
+
}
|