@opentapd/tplugin-cli 0.49.0 → 0.50.0
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/cli.js +5 -0
- package/lib/modules.js +224 -0
- package/package.json +2 -2
package/cli.js
CHANGED
|
@@ -94,6 +94,11 @@ program.command('resources')
|
|
|
94
94
|
.description('添加扩展模块模板')
|
|
95
95
|
.action(actionRunner(() => require('./lib/resources')()));
|
|
96
96
|
|
|
97
|
+
// modules 添加新的开放能力扩展
|
|
98
|
+
program.command('modules')
|
|
99
|
+
.description('添加开放能力扩展demo')
|
|
100
|
+
.action(actionRunner(() => require('./lib/modules')()));
|
|
101
|
+
|
|
97
102
|
if (tpluginConf.tapd.pluginEnv !== 'cloud') {
|
|
98
103
|
// workspace 创建个人专属开发项目
|
|
99
104
|
program.command('workspace')
|
package/lib/modules.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2021 Tencent Inc. All rights reserved.
|
|
3
|
+
* Author: raferzeng@tencent.com
|
|
4
|
+
*
|
|
5
|
+
* The implementation of CLI: resources
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const fs = require('fs-extra');
|
|
10
|
+
const yaml = require('js-yaml');
|
|
11
|
+
const spinner = require('../util/spinner');
|
|
12
|
+
const tapdsdk = require('../util/tapd');
|
|
13
|
+
const inquirer = require('inquirer');
|
|
14
|
+
const checkPluginYaml = require('../util/checkPluginYaml');
|
|
15
|
+
const _ = require('lodash');
|
|
16
|
+
const rimraf = require('rimraf');
|
|
17
|
+
const { exec } = require('child_process');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { downloadAndUnzip } = require('../util/tools');
|
|
20
|
+
const tpluginConf = require('../config');
|
|
21
|
+
const util = require('util');
|
|
22
|
+
const execPromised = util.promisify(exec);
|
|
23
|
+
const asyncExec = async (...args) => {
|
|
24
|
+
const { stdout, stderr } = await execPromised(...args);
|
|
25
|
+
if (stderr) {
|
|
26
|
+
throw new Error(stderr);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return stdout;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// modules命令实现
|
|
33
|
+
module.exports = async () => {
|
|
34
|
+
// 检查plugin.yaml 文件
|
|
35
|
+
checkPluginYaml();
|
|
36
|
+
|
|
37
|
+
const yamlPath = `${process.cwd()}/plugin.yaml`;
|
|
38
|
+
|
|
39
|
+
// 选择要添加的 开放能力扩展
|
|
40
|
+
const moduleExt = await getModuleExt();
|
|
41
|
+
|
|
42
|
+
const docObj = yaml.load(fs.readFileSync(yamlPath, 'utf8')); // 现在的配置
|
|
43
|
+
try {
|
|
44
|
+
// 合并并过滤重复配置
|
|
45
|
+
const pluginConfigs = filterPluginConfigs(docObj, moduleExt);
|
|
46
|
+
|
|
47
|
+
// plugin.yaml中写入扩展点配置
|
|
48
|
+
docObj.app = pluginConfigs;
|
|
49
|
+
fs.writeFileSync(yamlPath, yaml.dump(docObj));
|
|
50
|
+
spinner.succeed('plugin.yaml写入成功');
|
|
51
|
+
} catch (err) {
|
|
52
|
+
spinner.fail(`plugin.yaml写入失败. Err : ${err}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 拉取并添加开放能力扩展模版文件
|
|
56
|
+
await createModuleExtFromZip(moduleExt);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* getModuleExt() 加载并选择添加的开放能力扩展配置
|
|
61
|
+
* @returns {Object}
|
|
62
|
+
*/
|
|
63
|
+
async function getModuleExt() {
|
|
64
|
+
spinner.start('加载开放能力...');
|
|
65
|
+
// 加载开放能力
|
|
66
|
+
try {
|
|
67
|
+
const moduleExtOpts = await getModuleExtOpts();
|
|
68
|
+
|
|
69
|
+
if (!moduleExtOpts.length) {
|
|
70
|
+
spinner.fail(chalk.red('加载开放能力失败'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
spinner.stop();
|
|
75
|
+
const moduleExtList = moduleExtOpts.map((item) => {
|
|
76
|
+
const { key , name } = item;
|
|
77
|
+
return {
|
|
78
|
+
name: `${key} (${name})`,
|
|
79
|
+
value: item,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const required = function (value) {
|
|
84
|
+
return value.length ? true : '请按空格键选择开放能力';
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// 选择需要添加的开放能力
|
|
88
|
+
return await inquirer.prompt([{
|
|
89
|
+
type: 'checkbox',
|
|
90
|
+
name: 'extensions',
|
|
91
|
+
message: '请选择要扩展的开放能力:',
|
|
92
|
+
choices: moduleExtList,
|
|
93
|
+
loop: false,
|
|
94
|
+
validate: required,
|
|
95
|
+
}]);
|
|
96
|
+
|
|
97
|
+
} catch (err) {
|
|
98
|
+
spinner.fail(chalk.red(`加载开放能力失败 ${err}`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* getEntranceOpts() 加载开放能力扩展
|
|
105
|
+
*/
|
|
106
|
+
async function getModuleExtOpts() {
|
|
107
|
+
const { data } = await tapdsdk.request({ url: '/open_user_app/module_extensions', method: 'GET' });
|
|
108
|
+
return (data.data || []);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* filterPluginConfigs() 合并并过滤重复配置
|
|
113
|
+
* @param {Object} docObj - 已有配置
|
|
114
|
+
* @param {Object} moduleExt - 新添加的配置
|
|
115
|
+
* @returns {Object[]|boolean}
|
|
116
|
+
*/
|
|
117
|
+
function filterPluginConfigs(docObj, moduleExt) {
|
|
118
|
+
let pluginConfigs = docObj.app || [];
|
|
119
|
+
|
|
120
|
+
// 合并添加的配置信息
|
|
121
|
+
moduleExt.extensions.forEach(exetension => {
|
|
122
|
+
// 防重
|
|
123
|
+
const currentExetension = _.get(pluginConfigs, exetension.path, []);
|
|
124
|
+
// 检查对象的值中是否包含unique_key
|
|
125
|
+
const hasUniqueKey = _.some(currentExetension, (item) => {
|
|
126
|
+
if (exetension?.key !== 'webhook') {
|
|
127
|
+
return item.code === exetension.unique_key;
|
|
128
|
+
} else {
|
|
129
|
+
return item.handler === exetension.unique_key;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if(!hasUniqueKey){
|
|
134
|
+
pluginConfigs = _.mergeWith({}, pluginConfigs, exetension.demo, customizer);
|
|
135
|
+
}else{
|
|
136
|
+
spinner.fail(`该扩展开放能力已经存在 : ${exetension.name}`);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return pluginConfigs;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function customizer(objValue, srcValue) {
|
|
144
|
+
// 如果是数组,则合并数组
|
|
145
|
+
if (_.isArray(objValue)) {
|
|
146
|
+
return objValue.concat(srcValue);
|
|
147
|
+
}
|
|
148
|
+
// 如果不是数组,继续使用默认的 merge 行为
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function createModuleExtDemo(moduleExt) {
|
|
152
|
+
const frame = 'ui-nodejs-vue';
|
|
153
|
+
const demoPath = path.join(process.cwd(), 'demo');
|
|
154
|
+
const basePath = path.join(demoPath, frame);
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
moduleExt.extensions.forEach(exetension => {
|
|
158
|
+
const tmlPath = path.join(demoPath, exetension.demoTmpl);
|
|
159
|
+
exetension.demoTmplFile.forEach(fileDir => {
|
|
160
|
+
const sourceDirPath = path.join(tmlPath, fileDir);
|
|
161
|
+
const currentDirPath = path.join(process.cwd(), fileDir);
|
|
162
|
+
// 复制模板文件到插件仓库目录中
|
|
163
|
+
fs.copySync(`${sourceDirPath}`, currentDirPath);
|
|
164
|
+
});
|
|
165
|
+
spinner.succeed(`扩展开放能力: ${exetension.name} 模板创建成功`);
|
|
166
|
+
});
|
|
167
|
+
fs.copySync(path.join(basePath, 'package.json'), path.join(process.cwd(), 'package.json'));
|
|
168
|
+
fs.copySync(path.join(basePath, 'utils.js'), path.join(process.cwd(), 'utils.js'));
|
|
169
|
+
fs.copySync(path.join(basePath, 'webpack.config.js'), path.join(process.cwd(), 'webpack.config.js'));
|
|
170
|
+
} catch (err) {
|
|
171
|
+
rimraf(demoPath, () => {});
|
|
172
|
+
spinner.fail(`扩展开放能力模板创建失败. Err : ${err}`);
|
|
173
|
+
}
|
|
174
|
+
rimraf(demoPath, () => {});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function createModuleExtFromZip(moduleExt) {
|
|
178
|
+
const repoRes = await getTmpRepoUrl({ code: 'demo' });
|
|
179
|
+
if (!repoRes || !repoRes.status) {
|
|
180
|
+
spinner.fail('获取Demo代码失败.');
|
|
181
|
+
return ;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
spinner.start('开始生成 Demo 代码');
|
|
185
|
+
await downloadAndUnzip(repoRes.data.download_url);
|
|
186
|
+
spinner.start('开始模板定制工作 🔥🔥🔥');
|
|
187
|
+
await demoDecorateJob();
|
|
188
|
+
|
|
189
|
+
spinner.succeed('Demo 代码生成成功');
|
|
190
|
+
rimraf('demo.zip', () => {});
|
|
191
|
+
|
|
192
|
+
createModuleExtDemo(moduleExt);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
*
|
|
197
|
+
* @description 替换demo中的一些特定值,如 @tencent 的包名
|
|
198
|
+
*/
|
|
199
|
+
async function demoDecorateJob() {
|
|
200
|
+
const PLUGIN_ENV = tpluginConf.tapd.pluginEnv;
|
|
201
|
+
|
|
202
|
+
if (
|
|
203
|
+
PLUGIN_ENV !== 'oa'
|
|
204
|
+
) {
|
|
205
|
+
const NPM_SCOPED_NAME = {
|
|
206
|
+
cloud: '@opentapd',
|
|
207
|
+
ex: '@tapd',
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const npmScopedName = NPM_SCOPED_NAME[PLUGIN_ENV];
|
|
211
|
+
|
|
212
|
+
await asyncExec(`node demo/scripts/replace-tencent-in-package-json/sh.js demo/ui-nodejs-vue/package.json ${npmScopedName}`);
|
|
213
|
+
await asyncExec(`node demo/scripts/replace-package-name/sh.js ${path.join(process.env.PWD, `demo/ui-nodejs-vue`)} ${npmScopedName}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* getTmpRepoUrl(): 获取仓库当前代码制品code.zip的临时下载链接
|
|
219
|
+
* @return array data
|
|
220
|
+
*/
|
|
221
|
+
async function getTmpRepoUrl(params) {
|
|
222
|
+
const { data } = await tapdsdk.request({ url: '/open_user_app/get_tmp_repo_url', method: 'POST', params });
|
|
223
|
+
return data;
|
|
224
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentapd/tplugin-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "tplugin-cli",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tplugin-cli": "index.js"
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"node": ">=14.13.0"
|
|
79
79
|
},
|
|
80
80
|
"main": "index.js",
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "0f64809cfd742799f1441b626ad4b85a7cdf8eb4"
|
|
82
82
|
}
|