@wagq/wa-cli 0.6.53 → 0.6.55
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/config/command.js +180 -0
- package/config/lib.js +18 -0
- package/config/ssl/cert.pem +21 -0
- package/config/ssl/key.pem +28 -0
- package/lib/batchUpdate/getUpdateLibs.js +18 -0
- package/lib/batchUpdate/index.js +20 -0
- package/lib/changesetDoc/index.js +55 -0
- package/lib/checkBranch/index.js +23 -0
- package/lib/clear/index.js +35 -0
- package/lib/clone/index.js +23 -0
- package/lib/daml/async.js +112 -0
- package/lib/daml/asyncByApp.js +317 -0
- package/lib/exe/index.js +12 -0
- package/lib/generateIcon/prettier.js +11 -0
- package/lib/generateIcon/synchoronousSvgConfig.js +26 -0
- package/lib/generateIcon/tsx.js +87 -0
- package/lib/init/after.js +83 -0
- package/lib/init/check.js +21 -0
- package/lib/init/index.js +102 -0
- package/lib/locale/xlsx2Config.js +36 -0
- package/lib/server/index.js +56 -0
- package/lib/skill/index.js +35 -0
- package/lib/update/index.js +50 -0
- package/lib/vsSetting/index.js +43 -0
- package/package.json +1 -1
- package/utils/cwd.js +5 -0
- package/utils/log.js +32 -0
- package/utils/packages.js +20 -0
- package/utils/string2data.js +7 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const Prompt = require("inquirer");
|
|
3
|
+
const log = require("../../utils/log");
|
|
4
|
+
const prettier = require("prettier")
|
|
5
|
+
|
|
6
|
+
function string2Data (str) {
|
|
7
|
+
try {
|
|
8
|
+
return new Function('return ' + str)();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
return str;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const catalogue = "pages";
|
|
15
|
+
|
|
16
|
+
const initQuestions = () => [
|
|
17
|
+
{
|
|
18
|
+
type: "list",
|
|
19
|
+
name: "ignore",
|
|
20
|
+
message: "git是否忽略当前目录",
|
|
21
|
+
choices: [true, false],
|
|
22
|
+
default: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
type: "list",
|
|
26
|
+
name: "prettier",
|
|
27
|
+
message: "是否使用prettier格式化代码",
|
|
28
|
+
choices: [true, false],
|
|
29
|
+
default: true,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const handleIgnore = async (ignore, catalogue) => {
|
|
34
|
+
try {
|
|
35
|
+
if (ignore) {
|
|
36
|
+
const ignoreExist = await fs.existsSync(`${process.cwd()}/.gitignore`);
|
|
37
|
+
if (!ignoreExist) {
|
|
38
|
+
await fs.writeFileSync(`.gitignore`, `${catalogue}`, {
|
|
39
|
+
cwd: process.cwd(),
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
const hasCatalogue = await fs
|
|
43
|
+
.readFileSync(`${process.cwd()}/.gitignore`)
|
|
44
|
+
.toString()
|
|
45
|
+
.includes(catalogue);
|
|
46
|
+
if (!hasCatalogue) {
|
|
47
|
+
await fs.appendFileSync(
|
|
48
|
+
`${process.cwd()}/.gitignore`,
|
|
49
|
+
`\n${catalogue}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return Promise.resolve();
|
|
56
|
+
} finally {
|
|
57
|
+
return Promise.resolve();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const getList = async (origin, appId, branchid, token) => {
|
|
62
|
+
try {
|
|
63
|
+
const request = () =>
|
|
64
|
+
fetch(`${origin}/api/assembler/page/list`, {
|
|
65
|
+
headers: {
|
|
66
|
+
accept: "application/json, text/plain, */*",
|
|
67
|
+
"accept-language":
|
|
68
|
+
"zh,ja;q=0.9,zh-CN;q=0.8,en;q=0.7,ko;q=0.6,vi;q=0.5,zh-TW;q=0.4",
|
|
69
|
+
"access-token": token,
|
|
70
|
+
appid: appId,
|
|
71
|
+
branchid: branchid,
|
|
72
|
+
"cache-control": "no-cache",
|
|
73
|
+
"content-type": "application/json",
|
|
74
|
+
pragma: "no-cache",
|
|
75
|
+
"sec-ch-ua":
|
|
76
|
+
'"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"',
|
|
77
|
+
"sec-ch-ua-mobile": "?0",
|
|
78
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
79
|
+
"sec-fetch-dest": "empty",
|
|
80
|
+
"sec-fetch-mode": "cors",
|
|
81
|
+
"sec-fetch-site": "same-origin",
|
|
82
|
+
},
|
|
83
|
+
body: `{"current":1,"size":1000,"name":"","path":"","type":"","appId":${appId}}`,
|
|
84
|
+
method: "POST",
|
|
85
|
+
});
|
|
86
|
+
const res = await request().then((res) => res.json());
|
|
87
|
+
|
|
88
|
+
const lists = res.data.records.map((i) => {
|
|
89
|
+
return {
|
|
90
|
+
id: i.id,
|
|
91
|
+
name: `${i.name}(${i.path.replace(/\//g, "_")})`,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return lists || [];
|
|
96
|
+
} catch (err) {
|
|
97
|
+
log.error(
|
|
98
|
+
`请求页面列表失败,请检查参数是否正确, origin:${origin}, appId: ${appId}, branchid: ${branchid}, token: ${token}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const getDaml = async ({
|
|
104
|
+
lists,
|
|
105
|
+
origin,
|
|
106
|
+
appId,
|
|
107
|
+
branchid,
|
|
108
|
+
token,
|
|
109
|
+
basePath,
|
|
110
|
+
prettier,
|
|
111
|
+
}) => {
|
|
112
|
+
try {
|
|
113
|
+
lists.forEach(async ({ name, id }) => {
|
|
114
|
+
const request = () =>
|
|
115
|
+
fetch(`${origin}/api/assembler/page/getPageDaml`, {
|
|
116
|
+
headers: {
|
|
117
|
+
accept: "application/json, text/plain, */*",
|
|
118
|
+
"accept-language":
|
|
119
|
+
"zh,ja;q=0.9,zh-CN;q=0.8,en;q=0.7,ko;q=0.6,vi;q=0.5,zh-TW;q=0.4",
|
|
120
|
+
"access-token": token,
|
|
121
|
+
appid: appId,
|
|
122
|
+
branchid: branchid,
|
|
123
|
+
"cache-control": "no-cache",
|
|
124
|
+
"content-type": "application/json",
|
|
125
|
+
pragma: "no-cache",
|
|
126
|
+
"sec-ch-ua":
|
|
127
|
+
'"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"',
|
|
128
|
+
"sec-ch-ua-mobile": "?0",
|
|
129
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
130
|
+
"sec-fetch-dest": "empty",
|
|
131
|
+
"sec-fetch-mode": "cors",
|
|
132
|
+
"sec-fetch-site": "same-origin",
|
|
133
|
+
cookie: "_tea_utm_cache_1229=undefined",
|
|
134
|
+
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
135
|
+
},
|
|
136
|
+
body: `{\"pageId\":\"${id}\",\"appId\":\"${appId}\"}`,
|
|
137
|
+
method: "POST",
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
log.loading(`正在同步${name}的逻辑器与变量值`);
|
|
141
|
+
request()
|
|
142
|
+
.then((res) => res.json())
|
|
143
|
+
.then(async (res) => {
|
|
144
|
+
const daml = JSON.parse(res.data.daml);
|
|
145
|
+
await generateLogic(basePath, daml, name, prettier);
|
|
146
|
+
await generateVariable(basePath, daml, name);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
} catch (err) {
|
|
150
|
+
log.error(err);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const addJsDoc = (content, name, fileName) => {
|
|
155
|
+
const hasFileJsDoc = content.includes("@file");
|
|
156
|
+
// 添加标识
|
|
157
|
+
return hasFileJsDoc
|
|
158
|
+
? content
|
|
159
|
+
: `/** @file ${name}(逻辑名称:${fileName}) */
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @type {import("../../../../sass").CustomAction}
|
|
164
|
+
*/
|
|
165
|
+
${content}`;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const formatContent = async (content, filepath) => {
|
|
169
|
+
try {
|
|
170
|
+
const config = await prettier.resolveConfig("path/to/file", {
|
|
171
|
+
useCache: false,
|
|
172
|
+
});
|
|
173
|
+
content = await prettier.format(content, {
|
|
174
|
+
...config,
|
|
175
|
+
semi: false,
|
|
176
|
+
filepath,
|
|
177
|
+
});
|
|
178
|
+
return content;
|
|
179
|
+
} catch (err) {
|
|
180
|
+
return content;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const generateLogic = async (dirName, daml, name, prettier) => {
|
|
185
|
+
try {
|
|
186
|
+
log.loading(`正在同步${name}的逻辑器`);
|
|
187
|
+
const logicDir = `${dirName}/${name}/logic`;
|
|
188
|
+
// 创建逻辑器文件夹
|
|
189
|
+
await fs.mkdirSync(
|
|
190
|
+
`${logicDir}`,
|
|
191
|
+
{ recursive: true },
|
|
192
|
+
{
|
|
193
|
+
cwd: process.cwd(),
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
const pages = daml.app.subapps[0]?.actions?.actionList || [];
|
|
197
|
+
pages.forEach(async ({ content, name: fileName }) => {
|
|
198
|
+
const filePath = `${logicDir}/${fileName}.js`;
|
|
199
|
+
if (prettier) {
|
|
200
|
+
// 添加标识
|
|
201
|
+
content = addJsDoc(content, name, fileName);
|
|
202
|
+
// 格式化
|
|
203
|
+
content = await formatContent(content, filePath);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fs.writeFileSync(filePath, content, {
|
|
207
|
+
cwd: process.cwd(),
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
log.info(`同步${name}的逻辑器成功`);
|
|
211
|
+
} catch (err) {
|
|
212
|
+
log.loading(`同步${name}的逻辑器失败:${err}`);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const generateVariable = async (dirName, daml, name) => {
|
|
217
|
+
try {
|
|
218
|
+
log.loading(`正在同步${name}的变量值`);
|
|
219
|
+
const variableDir = `${dirName}/${name}/variable`;
|
|
220
|
+
// 创建变量文件夹
|
|
221
|
+
await fs.mkdirSync(
|
|
222
|
+
`${variableDir}`,
|
|
223
|
+
{ recursive: true },
|
|
224
|
+
{
|
|
225
|
+
cwd: process.cwd(),
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const variables = daml.app.subapps[0].dataSource.dataList || [];
|
|
230
|
+
|
|
231
|
+
variables.forEach(({ key, value: variableValue }) => {
|
|
232
|
+
fs.writeFileSync(
|
|
233
|
+
`${variableDir}/${key}.json`,
|
|
234
|
+
JSON.stringify(
|
|
235
|
+
variableValue,
|
|
236
|
+
(key, value) => {
|
|
237
|
+
if (typeof value === "string") {
|
|
238
|
+
return string2Data(value);
|
|
239
|
+
}
|
|
240
|
+
return value;
|
|
241
|
+
},
|
|
242
|
+
2
|
|
243
|
+
),
|
|
244
|
+
{
|
|
245
|
+
cwd: process.cwd(),
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
log.info(`同步${name}的变量值成功`);
|
|
250
|
+
} catch (err) {
|
|
251
|
+
log.loading(`同步${name}的变量失败:${err}`);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const checkDamlrc = async () => {
|
|
256
|
+
const exist = await fs.existsSync(`${process.cwd()}/.damlrc.json`);
|
|
257
|
+
if (!exist) {
|
|
258
|
+
log.loading(`
|
|
259
|
+
检测到.damlrc文件不存在,
|
|
260
|
+
正在为你创建所需文件,
|
|
261
|
+
`);
|
|
262
|
+
await fs.writeFileSync(
|
|
263
|
+
`${process.cwd()}/.damlrc.json`,
|
|
264
|
+
`
|
|
265
|
+
[
|
|
266
|
+
{
|
|
267
|
+
"appName": "应用名称",
|
|
268
|
+
"origin": "低代码域名",
|
|
269
|
+
"appId": "应用id",
|
|
270
|
+
"branchid": "应用分支id",
|
|
271
|
+
"token": "你的token"
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
`
|
|
275
|
+
);
|
|
276
|
+
log.error("文件创建成功,请打开.damlrc.json补充你的信息后再次执行命令");
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const main = async () => {
|
|
282
|
+
await checkDamlrc();
|
|
283
|
+
const settings = require(`${process.cwd()}/.damlrc.json`) || [];
|
|
284
|
+
const { ignore, prettier } = await Prompt.default.prompt(initQuestions());
|
|
285
|
+
settings.forEach(async ({ appName, origin, token, appId, branchid }) => {
|
|
286
|
+
const basePath = `${appName}/${catalogue}`;
|
|
287
|
+
const exist = await fs.existsSync(basePath);
|
|
288
|
+
|
|
289
|
+
if (!exist) {
|
|
290
|
+
log.info(`当前目录${basePath}不存在,开始创建${basePath}文件夹`);
|
|
291
|
+
const hasTopDir = await fs.existsSync(appName);
|
|
292
|
+
if (!hasTopDir) {
|
|
293
|
+
await fs.mkdirSync(String(appName), undefined, {
|
|
294
|
+
cwd: process.cwd(),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
await fs.mkdirSync(String(basePath), undefined, {
|
|
298
|
+
cwd: process.cwd(),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
await handleIgnore(ignore, basePath);
|
|
303
|
+
const lists = await getList(origin, appId, branchid, token);
|
|
304
|
+
log.info(`请求${appName}页面列表成功,条数为${lists.length}`);
|
|
305
|
+
await getDaml({
|
|
306
|
+
lists,
|
|
307
|
+
origin,
|
|
308
|
+
appId,
|
|
309
|
+
branchid,
|
|
310
|
+
token,
|
|
311
|
+
basePath,
|
|
312
|
+
prettier,
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
module.exports = main;
|
package/lib/exe/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const { spawn } = require("child_process");
|
|
2
|
+
|
|
3
|
+
const web2exe = (name, path, icon) => {
|
|
4
|
+
const binStr = `npx nativefier --name ${name} ${icon ? ` --icon ${icon}` : ""} ${path}`;
|
|
5
|
+
spawn(binStr, {
|
|
6
|
+
cwd: process.cwd(),
|
|
7
|
+
stdio: "inherit",
|
|
8
|
+
shell: true,
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = web2exe;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const prettier = require('prettier')
|
|
2
|
+
|
|
3
|
+
const format = async (content) => {
|
|
4
|
+
const prettierConfig = await prettier.resolveConfig(process.cwd())
|
|
5
|
+
|
|
6
|
+
const result = await prettier.format(content, { ...prettierConfig, parser: 'typescript' })
|
|
7
|
+
|
|
8
|
+
return result
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = format
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file synchoronousSvgConfig
|
|
3
|
+
* @description 读取svgConfig并生成config配置文件到packages\cartech-library\packages\icon\src\svgConfig
|
|
4
|
+
* */
|
|
5
|
+
const fs = require('fs')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const svgson = require('svgson')
|
|
8
|
+
const format = require('./prettier.js')
|
|
9
|
+
|
|
10
|
+
const synchoronousSvgConfig = async (fileName, content, isMultiple, configPath) => {
|
|
11
|
+
const config = svgson.parseSync(content)
|
|
12
|
+
const filePath = path.join(configPath, `/${fileName}.ts`)
|
|
13
|
+
if (isMultiple) {
|
|
14
|
+
config.isMultiple = true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const fileContent = await format(`
|
|
18
|
+
const ${fileName} = ${JSON.stringify(config)}
|
|
19
|
+
|
|
20
|
+
export default ${fileName}
|
|
21
|
+
`)
|
|
22
|
+
|
|
23
|
+
fs.writeFileSync(filePath, fileContent)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = synchoronousSvgConfig
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { promisify } = require("util");
|
|
5
|
+
const format = require("./prettier.js");
|
|
6
|
+
const synchoronousSvgConfig = require("./synchoronousSvgConfig.js");
|
|
7
|
+
|
|
8
|
+
const generateIcon2Tsx = async (svgPath) => {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const iconDir = path.join(cwd, svgPath);
|
|
11
|
+
const indexPath = path.join(iconDir, "../index.ts");
|
|
12
|
+
const reactIconDir = path.join(iconDir, "../icons");
|
|
13
|
+
const configPath = path.join(iconDir, "../svgConfig");
|
|
14
|
+
// 线框风格
|
|
15
|
+
const outlineIconDir = path.join(iconDir, "/outline");
|
|
16
|
+
// 实底风格
|
|
17
|
+
const fillIconDir = path.join(iconDir, "/fill");
|
|
18
|
+
// 多色风格
|
|
19
|
+
const twoToneIconDir = path.join(iconDir, "/multipleTone");
|
|
20
|
+
let indexContent = "";
|
|
21
|
+
|
|
22
|
+
execSync(`npx rimraf ${reactIconDir}`, {
|
|
23
|
+
stdio: "inherit",
|
|
24
|
+
cwd: cwd,
|
|
25
|
+
shell: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const createDir = async (path) => {
|
|
29
|
+
try {
|
|
30
|
+
await promisify(fs.access)(path);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
await promisify(fs.mkdir)(path);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
await createDir(reactIconDir);
|
|
37
|
+
await createDir(configPath);
|
|
38
|
+
await createDir(outlineIconDir);
|
|
39
|
+
await createDir(outlineIconDir);
|
|
40
|
+
await createDir(fillIconDir);
|
|
41
|
+
|
|
42
|
+
const outlineFiles = fs.readdirSync(outlineIconDir);
|
|
43
|
+
const fillFiles = fs.readdirSync(fillIconDir);
|
|
44
|
+
const twoToneFiles = fs.readdirSync(twoToneIconDir);
|
|
45
|
+
|
|
46
|
+
const createTsx = async (files, dirName) => {
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
const fileName = file?.replace(".svg", "");
|
|
49
|
+
// synchronousDoc(dirName, fileName)
|
|
50
|
+
const svgFilePath = path.join(iconDir, `../svgs/${dirName}/${file}`);
|
|
51
|
+
const fileContent = fs.readFileSync(svgFilePath, {
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
});
|
|
54
|
+
const isMultiple = dirName === "multipleTone";
|
|
55
|
+
synchoronousSvgConfig(fileName, fileContent, isMultiple, configPath);
|
|
56
|
+
|
|
57
|
+
indexContent += `;export { default as ${fileName} } from './icons/${fileName}'`;
|
|
58
|
+
|
|
59
|
+
const reactContent = `
|
|
60
|
+
import IconBase from '../components/IconBase'
|
|
61
|
+
import icon from '../svgConfig/${fileName}'
|
|
62
|
+
import { IconProps } from '@/types'
|
|
63
|
+
|
|
64
|
+
const ${fileName} = (props: IconProps) => {
|
|
65
|
+
|
|
66
|
+
return <IconBase { ...props } icon={icon} />
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default ${fileName}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const content = await format(reactContent);
|
|
73
|
+
const tsxFilePath = `${reactIconDir}/${fileName}.tsx`;
|
|
74
|
+
|
|
75
|
+
fs.writeFileSync(tsxFilePath, content);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fs.writeFileSync(indexPath, await format(indexContent));
|
|
79
|
+
};
|
|
80
|
+
createTsx(outlineFiles, "outline");
|
|
81
|
+
createTsx(fillFiles, "fill");
|
|
82
|
+
createTsx(twoToneFiles, "multipleTone");
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
generateIcon2Tsx,
|
|
87
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const log = require("../../utils/log");
|
|
4
|
+
const { execSync } = require("child_process");
|
|
5
|
+
const ora = require("ora");
|
|
6
|
+
const { libQuestions, libBin } = require("../../config/lib");
|
|
7
|
+
const Prompt = require("inquirer");
|
|
8
|
+
|
|
9
|
+
const cmdPath = process.cwd();
|
|
10
|
+
|
|
11
|
+
const changeProjectInfo = async (packageName) => {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const packagePath = path.join(`${cwd}/${packageName}`, "package.json");
|
|
14
|
+
const packageContent = fs.readFileSync(packagePath, "utf-8");
|
|
15
|
+
const packageInfo = JSON.parse(packageContent);
|
|
16
|
+
packageInfo.name = packageName;
|
|
17
|
+
const readmePath = path.join(`${cwd}/${packageName}`, "README.md");
|
|
18
|
+
const readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
19
|
+
const newReadmeContent = readmeContent.replace("<%= project %>", packageName);
|
|
20
|
+
|
|
21
|
+
await fs.writeFileSync(
|
|
22
|
+
packagePath,
|
|
23
|
+
JSON.stringify(packageInfo, null, " ") + "\n"
|
|
24
|
+
);
|
|
25
|
+
await fs.writeFileSync(readmePath, newReadmeContent);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const initGit = async (packageName) => {
|
|
29
|
+
const execConfig = { cwd: `${cmdPath}/${packageName}` };
|
|
30
|
+
await execSync("git init -b main", execConfig);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const initHusky = (packageName) => {
|
|
34
|
+
const execConfig = { cwd: `${cmdPath}/${packageName}` };
|
|
35
|
+
log.info("初始化Husky中...");
|
|
36
|
+
try {
|
|
37
|
+
execSync("npx --no-install husky install", {
|
|
38
|
+
cwd: `${cmdPath}/${packageName}`,
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
log.error("Husky 命令安装失败: \n" + error);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
execSync('echo "npx lint-staged" > .husky/pre-commit', execConfig);
|
|
45
|
+
execSync(
|
|
46
|
+
'echo "npx --no -- commitlint --edit ${1}" > .husky/commit-msg',
|
|
47
|
+
execConfig
|
|
48
|
+
);
|
|
49
|
+
log.info(`Husky 初始化完成, 可打开${packageName}查看`);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
log.error("Husky 命令写入失败: \n" + error);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const firstCommit = async (packageName) => {
|
|
56
|
+
const execConfig = { cwd: `${cmdPath}/${packageName}` };
|
|
57
|
+
await execSync("git init", execConfig);
|
|
58
|
+
await execSync("git add .", execConfig);
|
|
59
|
+
await execSync(`git commit -m "feat: 初始化项目" --no-verify`, execConfig);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const installLibrary = async (packageName) => {
|
|
63
|
+
const { selectMode } = await Prompt.default.prompt(libQuestions());
|
|
64
|
+
const bin = libBin[selectMode];
|
|
65
|
+
const process = ora("安装依赖中...");
|
|
66
|
+
process.start();
|
|
67
|
+
process.color = "green";
|
|
68
|
+
await execSync(bin, {
|
|
69
|
+
cwd: `${cmdPath}/${packageName}`,
|
|
70
|
+
});
|
|
71
|
+
process.succeed("依赖安装完成");
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const after = async (name) => {
|
|
75
|
+
const packageName = name;
|
|
76
|
+
changeProjectInfo(name);
|
|
77
|
+
await initGit(packageName);
|
|
78
|
+
await installLibrary(packageName);
|
|
79
|
+
await initHusky(packageName);
|
|
80
|
+
await firstCommit(packageName);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
module.exports = after;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const glob = require("glob");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const update = require("../update");
|
|
4
|
+
|
|
5
|
+
const check = async (name) => {
|
|
6
|
+
let hasProject = false;
|
|
7
|
+
const files = await glob.sync("*", { dot: true });
|
|
8
|
+
|
|
9
|
+
hasProject = files.some((f) => {
|
|
10
|
+
return f === name;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
await update();
|
|
14
|
+
|
|
15
|
+
if (!hasProject) {
|
|
16
|
+
return Promise.resolve();
|
|
17
|
+
}
|
|
18
|
+
return Promise.reject("项目已存在,创建失败");
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
module.exports = check;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const Prompt = require("inquirer");
|
|
2
|
+
|
|
3
|
+
const clone = require("../clone/index.js");
|
|
4
|
+
const check = require("./check.js");
|
|
5
|
+
const log = require("../../utils/log.js");
|
|
6
|
+
const after = require("./after.js");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const viteBin = "npm create vite@latest";
|
|
10
|
+
const uniAppBin = "npm create unibest";
|
|
11
|
+
const rnAppBin = "npx create-expo-app --template";
|
|
12
|
+
|
|
13
|
+
const urls = {
|
|
14
|
+
vue单页面后台: { remote: "sdmu-gaoqi/vite-vue" },
|
|
15
|
+
vue多页面项目: { remote: "sdmu-gaoqi/vite-vue-multiple" },
|
|
16
|
+
React: { key: "react" },
|
|
17
|
+
vite: { bin: viteBin },
|
|
18
|
+
"uniapp(unibest)": { bin: uniAppBin },
|
|
19
|
+
"vscode插件-vue版": { remote: "sdmu-gaoqi/vscode-plugin#vue" },
|
|
20
|
+
"vscode插件-react版": { remote: "sdmu-gaoqi/vscode-plugin#react" },
|
|
21
|
+
umi: { bin: "npx create-umi@latest" },
|
|
22
|
+
"react-native": { bin: rnAppBin },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const reactRepoMap = {
|
|
26
|
+
SPA: {
|
|
27
|
+
remote: "direct:https://gitee.com/wa_6/template-vite-react.git#template",
|
|
28
|
+
},
|
|
29
|
+
微前端基座: {
|
|
30
|
+
remote: "direct:https://gitee.com/GQ-og/templat-qk-main.git#template",
|
|
31
|
+
},
|
|
32
|
+
微前端子应用: {
|
|
33
|
+
remote: "direct:https://gitee.com/GQ-og/template-qk-module.git#template",
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const modeOptions = Object.keys(urls);
|
|
38
|
+
|
|
39
|
+
const initQuestions = () => [
|
|
40
|
+
{
|
|
41
|
+
type: "list",
|
|
42
|
+
name: "selectMode",
|
|
43
|
+
message: `请选择模板`,
|
|
44
|
+
choices: modeOptions,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const nameOptions = () => [
|
|
49
|
+
{
|
|
50
|
+
type: "input",
|
|
51
|
+
name: "libraryName",
|
|
52
|
+
message: `请输入项目名`,
|
|
53
|
+
},
|
|
54
|
+
]; // 项目nam
|
|
55
|
+
|
|
56
|
+
const reactOptions = [
|
|
57
|
+
{
|
|
58
|
+
type: "list",
|
|
59
|
+
name: "reactMode",
|
|
60
|
+
message: `请选择分支`,
|
|
61
|
+
choices: Object.keys(reactRepoMap),
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const init = async () => {
|
|
66
|
+
try {
|
|
67
|
+
const { selectMode } = await Prompt.default.prompt(initQuestions());
|
|
68
|
+
const { remote, bin, key } = urls?.[selectMode];
|
|
69
|
+
let repoRemote = remote;
|
|
70
|
+
const isReact = key === "react";
|
|
71
|
+
const needName = !!remote || isReact;
|
|
72
|
+
const cloneOptions = {};
|
|
73
|
+
|
|
74
|
+
if (isReact) {
|
|
75
|
+
const { reactMode } = await Prompt.default.prompt(reactOptions);
|
|
76
|
+
repoRemote = reactRepoMap[reactMode].remote;
|
|
77
|
+
cloneOptions.clone = true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (needName) {
|
|
81
|
+
const { libraryName } = await Prompt.default.prompt(nameOptions());
|
|
82
|
+
if (!repoRemote) {
|
|
83
|
+
log.error("仓库正在建设中,请先选择其他模板");
|
|
84
|
+
}
|
|
85
|
+
await check(libraryName);
|
|
86
|
+
await clone(repoRemote, libraryName, cloneOptions);
|
|
87
|
+
await after(libraryName, selectMode);
|
|
88
|
+
} else {
|
|
89
|
+
const info = `准备从${selectMode}创建`;
|
|
90
|
+
log.info(info);
|
|
91
|
+
execSync(bin, {
|
|
92
|
+
stdio: "inherit",
|
|
93
|
+
cwd: process.cwd(),
|
|
94
|
+
shell: true,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
log.error(error);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
module.exports = init;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const xlsx = require("xlsx");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
|
|
4
|
+
const xlsx2Config = async (path, name, ext) => {
|
|
5
|
+
try {
|
|
6
|
+
const file = xlsx.readFile(`${path}/${name}`);
|
|
7
|
+
const sheetNames = file.SheetNames; // 返回 ['sheet1', 'sheet2']
|
|
8
|
+
const l10n = {};
|
|
9
|
+
for (const sheetName of sheetNames) {
|
|
10
|
+
const jsonData = xlsx.utils.sheet_to_json(file.Sheets[sheetName]);
|
|
11
|
+
const fields = Object.keys(jsonData[0]);
|
|
12
|
+
jsonData.forEach((word) => {
|
|
13
|
+
// 0 是 key
|
|
14
|
+
for (let index = 1; index < fields.length; index++) {
|
|
15
|
+
const field = fields[index];
|
|
16
|
+
if (!l10n[field]) {
|
|
17
|
+
l10n[field] = {};
|
|
18
|
+
}
|
|
19
|
+
l10n[field][word.key] =
|
|
20
|
+
String(word[field || "zh-CN"] || word.key) || "";
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
Object.keys(l10n).forEach((key) => {
|
|
25
|
+
const content = JSON.stringify(l10n[key], null, 2);
|
|
26
|
+
const str = `export default ${content}\n`;
|
|
27
|
+
const writePath = `${path}/${key}.${ext}`;
|
|
28
|
+
fs.writeFileSync(writePath, ext === "json" ? content : str, "utf8");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.log(err, "文件转换失败");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
module.exports = xlsx2Config;
|