neo-cmp-cli 1.6.2-beta.6 → 1.6.3
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/package.json +1 -1
- package/src/module/inspect.js +5 -4
- package/src/neo/neoService.js +28 -28
- package/src/oss/publish2oss.js +25 -24
- package/src/template/antd-custom-cmp-template/package.json +1 -1
- package/src/template/echarts-custom-cmp-template/package.json +1 -1
- package/src/template/empty-custom-cmp-template/package.json +1 -1
- package/src/template/neo-custom-cmp-template/package.json +1 -1
- package/src/template/react-custom-cmp-template/package.json +1 -1
- package/src/template/react-ts-custom-cmp-template/package.json +1 -1
- package/src/template/vue2-custom-cmp-template/package.json +1 -1
- package/src/utils/cmpUtils/createCmpByZip.js +16 -15
- package/src/utils/cmpUtils/deleteCmp.js +6 -5
- package/src/utils/cmpUtils/pullCmp.js +10 -10
- package/src/utils/cmpUtils/pushCmp.js +23 -23
- package/src/utils/common.js +62 -3
- package/src/utils/projectUtils/openProject.js +5 -3
- package/test/demo3.js +1 -1
- package/test/deprecate-versions.js +1 -1
package/package.json
CHANGED
package/src/module/inspect.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const { getCurWebpackConfig } = require('akfun'); // 用于获取当前webpack配置的方法
|
|
5
5
|
const curConfig = require('../config/index');
|
|
6
6
|
const { consoleTag } = require('../utils/neoParams'); // 输出标记
|
|
7
|
+
const { errorLog, successLog } = require('../utils/common');
|
|
7
8
|
|
|
8
9
|
// 根据当前配置文件内容创建指定名称的文件
|
|
9
10
|
const createConfigJs = function (fileName, fileCont) {
|
|
@@ -24,17 +25,17 @@ module.exports = (type) => {
|
|
|
24
25
|
if (type === 'dev') {
|
|
25
26
|
const devConfig = getCurWebpackConfig(type, curConfig);
|
|
26
27
|
createConfigJs('current-neo-dev-config.js', devConfig);
|
|
27
|
-
|
|
28
|
+
successLog(`当前配置数据已输出至 current-neo-dev-config.js中。`, spinner);
|
|
28
29
|
} else if (type === 'lib') {
|
|
29
30
|
const libraryConfig = getCurWebpackConfig(type, curConfig);
|
|
30
31
|
createConfigJs('current-neo-build2lib-config.js', libraryConfig);
|
|
31
|
-
|
|
32
|
+
successLog(`当前配置数据已输出至 current-neo-build2lib-config.js中。`, spinner);
|
|
32
33
|
} else if (type === 'build') {
|
|
33
34
|
const prodConfig = getCurWebpackConfig(type, curConfig);
|
|
34
35
|
// 默认输出生产环境的配置文件
|
|
35
36
|
createConfigJs('current-neo-build-config.js', prodConfig);
|
|
36
|
-
|
|
37
|
+
successLog(`当前配置数据已输出至 current-neo-build-config.js。`, spinner);
|
|
37
38
|
} else {
|
|
38
|
-
|
|
39
|
+
errorLog(`type 不能为空。`, spinner);
|
|
39
40
|
}
|
|
40
41
|
};
|
package/src/neo/neoService.js
CHANGED
|
@@ -6,7 +6,7 @@ const ora = require('ora');
|
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
const { resolve } = require('akfun');
|
|
8
8
|
const updatePublishLog = require('../utils/projectUtils/updatePublishLog');
|
|
9
|
-
const { getFramework } = require('../utils/common');
|
|
9
|
+
const { getFramework, errorLog, successLog } = require('../utils/common');
|
|
10
10
|
|
|
11
11
|
// NeoCRM 平台默认 API 配置
|
|
12
12
|
const NeoCrmAPI = {
|
|
@@ -123,7 +123,7 @@ class NeoService {
|
|
|
123
123
|
const spinner = ora('获取 token...').start();
|
|
124
124
|
// 检查缓存是否有效
|
|
125
125
|
if (!this.isTokenExpired()) {
|
|
126
|
-
|
|
126
|
+
successLog('使用缓存的 token。', spinner);
|
|
127
127
|
return this.tokenCache.token;
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -147,7 +147,7 @@ class NeoService {
|
|
|
147
147
|
const { access_token, expires_in } = response.data || {};
|
|
148
148
|
|
|
149
149
|
if (!access_token) {
|
|
150
|
-
|
|
150
|
+
errorLog('获取 token 失败(授权配置错误):响应中未包含 access_token,' + JSON.stringify(response.data), spinner);
|
|
151
151
|
process.exit(1);
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -161,12 +161,12 @@ class NeoService {
|
|
|
161
161
|
spinner.stop();
|
|
162
162
|
return access_token;
|
|
163
163
|
} catch (error) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
errorLog('获取 token 失败', spinner);
|
|
165
|
+
errorLog(`\n获取 token 失败: ${error.message}`);
|
|
166
|
+
errorLog(`\ntoken 授权地址: ${tokenUrl}`);
|
|
167
|
+
errorLog(`\ntoken 请求参数: ${formData}`);
|
|
168
168
|
if (error.response) {
|
|
169
|
-
|
|
169
|
+
errorLog(`响应数据: ${JSON.stringify(error.response.data)}`);
|
|
170
170
|
}
|
|
171
171
|
process.exit(1);
|
|
172
172
|
}
|
|
@@ -197,10 +197,10 @@ class NeoService {
|
|
|
197
197
|
const spinner = ora('token 已过期,正在刷新...').start();
|
|
198
198
|
try {
|
|
199
199
|
const token = await this.refreshToken();
|
|
200
|
-
|
|
200
|
+
successLog('token 刷新成功。', spinner);
|
|
201
201
|
return token;
|
|
202
202
|
} catch (error) {
|
|
203
|
-
|
|
203
|
+
errorLog('token 刷新失败。', spinner);
|
|
204
204
|
throw error;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
@@ -334,10 +334,10 @@ class NeoService {
|
|
|
334
334
|
} else if (resultData && typeof resultData === 'object' && resultData.url) {
|
|
335
335
|
fileUrl = resultData.url;
|
|
336
336
|
}
|
|
337
|
-
|
|
337
|
+
successLog(`文件上传成功: ${fileName} -> ${fileUrl}`, spinner);
|
|
338
338
|
return fileUrl;
|
|
339
339
|
} catch (error) {
|
|
340
|
-
|
|
340
|
+
errorLog(`上传文件失败: ${error.message}, 文件路径: ${filePath}`, spinner);
|
|
341
341
|
|
|
342
342
|
// 输出详细的错误信息
|
|
343
343
|
if (error.response) {
|
|
@@ -346,11 +346,11 @@ class NeoService {
|
|
|
346
346
|
const responseData = error.response.data;
|
|
347
347
|
const requestUrl = error.config?.url || this.uploadAPI();
|
|
348
348
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
349
|
+
errorLog(`\n========== 上传请求详情 ==========`);
|
|
350
|
+
errorLog(`请求 URL: ${requestUrl}`);
|
|
351
|
+
errorLog(`HTTP 状态码: ${status} ${statusText}`);
|
|
352
|
+
errorLog(`响应数据: ${JSON.stringify(responseData)}`);
|
|
353
|
+
errorLog(`==================================\n`);
|
|
354
354
|
|
|
355
355
|
if (status === 404) {
|
|
356
356
|
throw new Error(
|
|
@@ -360,7 +360,7 @@ class NeoService {
|
|
|
360
360
|
);
|
|
361
361
|
}
|
|
362
362
|
} else if (error.request) {
|
|
363
|
-
|
|
363
|
+
errorLog('请求已发送但未收到响应,请检查网络连接或代理配置。');
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
throw error;
|
|
@@ -375,11 +375,11 @@ class NeoService {
|
|
|
375
375
|
*/
|
|
376
376
|
async publish2oss(cmpType, fileExtensions = ['.js', '.css', '.zip']) {
|
|
377
377
|
if (!cmpType) {
|
|
378
|
-
|
|
378
|
+
errorLog(`自定义组件名称不能为空: ${cmpType}`);
|
|
379
379
|
return;
|
|
380
380
|
}
|
|
381
381
|
if (!fs.existsSync(this.assetsRoot)) {
|
|
382
|
-
|
|
382
|
+
errorLog(`未找到自定义组件资源目录: ${this.assetsRoot}`);
|
|
383
383
|
return;
|
|
384
384
|
}
|
|
385
385
|
|
|
@@ -419,7 +419,7 @@ class NeoService {
|
|
|
419
419
|
curCmpInfo.asset = fileUrl;
|
|
420
420
|
}
|
|
421
421
|
} catch (error) {
|
|
422
|
-
|
|
422
|
+
errorLog(`文件上传失败(${file}):\n`);
|
|
423
423
|
process.exit(1);
|
|
424
424
|
}
|
|
425
425
|
}
|
|
@@ -468,11 +468,11 @@ class NeoService {
|
|
|
468
468
|
spinner.clear();
|
|
469
469
|
spinner.stop();
|
|
470
470
|
} catch (error) {
|
|
471
|
-
|
|
471
|
+
errorLog('更新组件失败。', spinner);
|
|
472
472
|
if (error.message) {
|
|
473
|
-
|
|
473
|
+
errorLog(`更新组件失败: ${error.message}`);
|
|
474
474
|
} else {
|
|
475
|
-
|
|
475
|
+
errorLog(`响应数据: ${JSON.stringify(error)}`);
|
|
476
476
|
}
|
|
477
477
|
process.exit(1);
|
|
478
478
|
}
|
|
@@ -518,9 +518,9 @@ class NeoService {
|
|
|
518
518
|
this.updateCustomCmpList(response.data.data || []);
|
|
519
519
|
} catch (error) {
|
|
520
520
|
if (error.message) {
|
|
521
|
-
|
|
521
|
+
errorLog(`获取自定义组件列表失败: ${error.message}`);
|
|
522
522
|
} else {
|
|
523
|
-
|
|
523
|
+
errorLog(`响应数据: ${JSON.stringify(error)}`);
|
|
524
524
|
}
|
|
525
525
|
process.exit(1);
|
|
526
526
|
}
|
|
@@ -624,9 +624,9 @@ class NeoService {
|
|
|
624
624
|
|
|
625
625
|
return response.data;
|
|
626
626
|
} catch (error) {
|
|
627
|
-
|
|
627
|
+
errorLog(`请求失败 [${method} ${api}]: ${error.message}`);
|
|
628
628
|
if (error.response) {
|
|
629
|
-
|
|
629
|
+
errorLog(`响应数据: ${JSON.stringify(error.response.data)}`);
|
|
630
630
|
}
|
|
631
631
|
throw error;
|
|
632
632
|
}
|
package/src/oss/publish2oss.js
CHANGED
|
@@ -6,6 +6,7 @@ const ora = require('ora');
|
|
|
6
6
|
const { catchCurPackageJson } = require('../utils/pathUtils');
|
|
7
7
|
const getConfigObj = require('../utils/getConfigObj');
|
|
8
8
|
const updatePublishLog = require('../utils/projectUtils/updatePublishLog');
|
|
9
|
+
const { errorLog, warningLog, successLog } = require('../utils/common');
|
|
9
10
|
|
|
10
11
|
// 获取当前项目的package文件
|
|
11
12
|
const currentPackageJsonDir = catchCurPackageJson();
|
|
@@ -185,7 +186,7 @@ async function uploadSingleFile(bosClient, filePath, objectKey, ossType, ossConf
|
|
|
185
186
|
// 上传文件
|
|
186
187
|
const result = await bosClient.upload(objectKey, filePath);
|
|
187
188
|
const ossPath = getFilePath(ossType, ossConfig.bucket, objectKey);
|
|
188
|
-
|
|
189
|
+
successLog(`文件上传成功: ${fileName} -> ${ossPath}`, spinner);
|
|
189
190
|
|
|
190
191
|
return {
|
|
191
192
|
success: true,
|
|
@@ -197,17 +198,17 @@ async function uploadSingleFile(bosClient, filePath, objectKey, ossType, ossConf
|
|
|
197
198
|
resultMsg: result
|
|
198
199
|
};
|
|
199
200
|
} catch (error) {
|
|
200
|
-
|
|
201
|
+
errorLog(`文件上传失败: ${fileName}`, spinner);
|
|
201
202
|
|
|
202
203
|
// 输出详细的错误信息
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
errorLog(`\n========== 上传文件详情 ==========`);
|
|
205
|
+
errorLog(`文件路径: ${filePath}`);
|
|
206
|
+
errorLog(`OSS 对象键: ${objectKey}`);
|
|
207
|
+
errorLog(`错误信息: ${error.message}`);
|
|
207
208
|
if (error.stack) {
|
|
208
|
-
|
|
209
|
+
errorLog(`错误堆栈: ${error.stack}`);
|
|
209
210
|
}
|
|
210
|
-
|
|
211
|
+
errorLog(`==================================\n`);
|
|
211
212
|
|
|
212
213
|
return {
|
|
213
214
|
success: false,
|
|
@@ -231,44 +232,44 @@ async function uploadSingleFile(bosClient, filePath, objectKey, ossType, ossConf
|
|
|
231
232
|
const publish2oss = async (ossType, ossConfig, assetsRoot, fileExtensions = ['.js', '.css']) => {
|
|
232
233
|
// 参数验证
|
|
233
234
|
if (ossType !== 'baidu' && ossType !== 'ali') {
|
|
234
|
-
|
|
235
|
+
errorLog(`不支持的oss类型: ${ossType}`);
|
|
235
236
|
return;
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
if (!ossConfig) {
|
|
239
|
-
|
|
240
|
+
errorLog('ossConfig 不能为空');
|
|
240
241
|
return;
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
if (!assetsRoot) {
|
|
244
|
-
|
|
245
|
+
errorLog('assetsRoot 不能为空');
|
|
245
246
|
return;
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
// 检查目录是否存在
|
|
249
250
|
if (!fs.existsSync(assetsRoot)) {
|
|
250
|
-
|
|
251
|
+
errorLog(`assetsRoot 不存在: ${assetsRoot}`);
|
|
251
252
|
return;
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
// 检查目录是否为目录
|
|
255
256
|
const assetsRootStat = fs.statSync(assetsRoot);
|
|
256
257
|
if (!assetsRootStat.isDirectory()) {
|
|
257
|
-
|
|
258
|
+
errorLog(`assetsRoot 不是目录: ${assetsRoot}`);
|
|
258
259
|
return;
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
// 创建 OSS 客户端
|
|
262
263
|
const bosClient = getBosClient(ossType, ossConfig);
|
|
263
264
|
if (!bosClient) {
|
|
264
|
-
|
|
265
|
+
errorLog(`无法创建 OSS 客户端,请检查 ossType 和 ossConfig 配置`);
|
|
265
266
|
return;
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
// 读取构建目录下的所有文件
|
|
269
270
|
const files = fs.readdirSync(assetsRoot);
|
|
270
271
|
if (files.length === 0) {
|
|
271
|
-
|
|
272
|
+
warningLog(`构建目录为空: ${assetsRoot}`);
|
|
272
273
|
return;
|
|
273
274
|
}
|
|
274
275
|
|
|
@@ -286,7 +287,7 @@ const publish2oss = async (ossType, ossConfig, assetsRoot, fileExtensions = ['.j
|
|
|
286
287
|
const fileInfo = path.parse(filePath);
|
|
287
288
|
return fileExtensions.includes(fileInfo.ext);
|
|
288
289
|
} catch (error) {
|
|
289
|
-
|
|
290
|
+
warningLog(`无法读取文件状态: ${filePath} - ${error.message}`);
|
|
290
291
|
return false;
|
|
291
292
|
}
|
|
292
293
|
});
|
|
@@ -296,7 +297,7 @@ const publish2oss = async (ossType, ossConfig, assetsRoot, fileExtensions = ['.j
|
|
|
296
297
|
return;
|
|
297
298
|
}
|
|
298
299
|
|
|
299
|
-
|
|
300
|
+
successLog(`找到 ${filesToUpload.length} 个文件需要上传`, spinner);
|
|
300
301
|
|
|
301
302
|
// 并行上传所有指定类型的文件
|
|
302
303
|
const uploadPromises = filesToUpload.map(async (file) => {
|
|
@@ -320,7 +321,7 @@ const publish2oss = async (ossType, ossConfig, assetsRoot, fileExtensions = ['.j
|
|
|
320
321
|
// 更新发布日志
|
|
321
322
|
updatePublishLog(widgetFilesMap);
|
|
322
323
|
} else {
|
|
323
|
-
|
|
324
|
+
warningLog('未生成有效的文件上传结果');
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
// 统计上传结果
|
|
@@ -328,18 +329,18 @@ const publish2oss = async (ossType, ossConfig, assetsRoot, fileExtensions = ['.j
|
|
|
328
329
|
const failCount = validResults.filter((r) => r && !r.success).length;
|
|
329
330
|
|
|
330
331
|
if (failCount > 0) {
|
|
331
|
-
|
|
332
|
+
warningLog(`\n上传完成:成功 ${succeedCount} 个,失败 ${failCount} 个`);
|
|
332
333
|
} else {
|
|
333
334
|
console.info(`\n✅ 所有文件上传成功!共 ${succeedCount} 个文件`);
|
|
334
335
|
}
|
|
335
336
|
} catch (error) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
337
|
+
errorLog('批量上传文件异常', spinner);
|
|
338
|
+
errorLog('\n========== 批量上传异常 ==========');
|
|
339
|
+
errorLog(`错误信息: ${error.message}`);
|
|
339
340
|
if (error.stack) {
|
|
340
|
-
|
|
341
|
+
errorLog(`错误堆栈: ${error.stack}`);
|
|
341
342
|
}
|
|
342
|
-
|
|
343
|
+
errorLog('==================================\n');
|
|
343
344
|
throw error;
|
|
344
345
|
}
|
|
345
346
|
};
|
|
@@ -7,6 +7,7 @@ const _ = require('lodash');
|
|
|
7
7
|
const { consoleTag } = require('../neoParams'); // 输出标记
|
|
8
8
|
const hasCmpTypeByDir = require('./hasCmpTypeByDir');
|
|
9
9
|
const hasNeoProject = require('../projectUtils/hasNeoProject');
|
|
10
|
+
const { errorLog, warningLog, successLog, parseTsConfigWithTypeScript } = require('../common');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* 检查对象键名是否需要加引号
|
|
@@ -117,14 +118,14 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
117
118
|
const finalCmpName = cmpName;
|
|
118
119
|
|
|
119
120
|
if (!hasNeoProject()) {
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
errorLog(
|
|
122
|
+
`当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo createProject)。`
|
|
122
123
|
);
|
|
123
124
|
process.exit(1);
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
if (hasCmpTypeByDir(finalCmpName)) {
|
|
127
|
-
|
|
128
|
+
errorLog(`当前项目已经存在${finalCmpName}自定义组件。`);
|
|
128
129
|
process.exit(1);
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -156,7 +157,7 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
156
157
|
maxBodyLength: Infinity
|
|
157
158
|
});
|
|
158
159
|
} catch (axiosError) {
|
|
159
|
-
|
|
160
|
+
errorLog(`下载文件失败: ${axiosError.message}`, spinner);
|
|
160
161
|
throw axiosError;
|
|
161
162
|
}
|
|
162
163
|
|
|
@@ -180,7 +181,7 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
180
181
|
|
|
181
182
|
await fs.writeFile(zipFilePath, buffer);
|
|
182
183
|
} catch (writeError) {
|
|
183
|
-
|
|
184
|
+
errorLog(`读取组件源码文件失败: ${writeError.message}`, spinner);
|
|
184
185
|
throw writeError;
|
|
185
186
|
}
|
|
186
187
|
|
|
@@ -196,7 +197,7 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
196
197
|
const cmpSourcePath = path.join(extractPath, componentBaseDir, finalCmpName);
|
|
197
198
|
|
|
198
199
|
if (!fs.existsSync(cmpSourcePath)) {
|
|
199
|
-
|
|
200
|
+
errorLog(`解压后的 zip 包中未找到 ${finalCmpName} 组件源码目录。`, spinner);
|
|
200
201
|
// 只删除解压目录,保留 zip 源文件
|
|
201
202
|
await fs.remove(extractPath);
|
|
202
203
|
return false;
|
|
@@ -210,7 +211,7 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
210
211
|
try {
|
|
211
212
|
await fs.copy(cmpSourcePath, targetComponentsDir);
|
|
212
213
|
} catch (err) {
|
|
213
|
-
|
|
214
|
+
errorLog(`自定义组件模板下载失败:${err.message || err}`, spinner);
|
|
214
215
|
// 只删除解压目录,保留 zip 源文件
|
|
215
216
|
await fs.remove(extractPath);
|
|
216
217
|
return false;
|
|
@@ -271,13 +272,13 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
271
272
|
);
|
|
272
273
|
const newDeps = Object.keys(newPackageJsonDeps);
|
|
273
274
|
if (newDeps.length > 0) {
|
|
274
|
-
|
|
275
|
-
|
|
275
|
+
warningLog(
|
|
276
|
+
`检测到 package.json 中新增了 ${
|
|
276
277
|
newDeps.length
|
|
277
278
|
} 个依赖包:${newDeps.join(', ')}`
|
|
278
279
|
);
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
warningLog(
|
|
281
|
+
`为确保组件正常运行,请执行以下命令安装依赖:npm install 或 yarn install`
|
|
281
282
|
);
|
|
282
283
|
}
|
|
283
284
|
// 合并 package.json:将源文件的配置合并到目标文件中
|
|
@@ -344,10 +345,10 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
344
345
|
} else if (fileName === 'tsconfig.json') {
|
|
345
346
|
// 处理 tsconfig.json 文件(当目标文件已存在时)
|
|
346
347
|
try {
|
|
347
|
-
const sourceTsconfigJson =
|
|
348
|
+
const sourceTsconfigJson = parseTsConfigWithTypeScript(sourcePath);
|
|
348
349
|
// 先判断 targetPath 是否存在,如果存在则合并,否则直接写入
|
|
349
350
|
if (await fs.pathExists(targetPath)) {
|
|
350
|
-
const targetTsconfigJson =
|
|
351
|
+
const targetTsconfigJson = parseTsConfigWithTypeScript(targetPath);
|
|
351
352
|
// 合并配置:源配置合并到目标配置(目标配置优先级更高)
|
|
352
353
|
const mergedTsconfigJson = _.merge({}, sourceTsconfigJson, targetTsconfigJson);
|
|
353
354
|
// 使用 writeJson 写入,确保 JSON 格式正确(所有键名都会被正确序列化)
|
|
@@ -374,11 +375,11 @@ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/c
|
|
|
374
375
|
|
|
375
376
|
// 清理解压目录,保留 zip 源文件
|
|
376
377
|
await fs.remove(extractPath);
|
|
377
|
-
|
|
378
|
+
successLog(`已成功从 zip 包解析自定义组件(${finalCmpName})!`, spinner);
|
|
378
379
|
|
|
379
380
|
return true;
|
|
380
381
|
} catch (error) {
|
|
381
|
-
|
|
382
|
+
errorLog(`从 zip 包创建自定义组件失败(${finalCmpName}):${error.message || error}`, spinner);
|
|
382
383
|
// 清理解压目录,保留 zip 源文件
|
|
383
384
|
const extractPath = path.join(tempDir, finalCmpName);
|
|
384
385
|
if (await fs.pathExists(extractPath)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const ora = require('ora');
|
|
2
2
|
const NeoService = require('../../neo/neoService');
|
|
3
|
+
const { errorLog, successLog } = require('../common');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 从 NeoCRM 删除自定义组件
|
|
@@ -14,7 +15,7 @@ const NeoService = require('../../neo/neoService');
|
|
|
14
15
|
*/
|
|
15
16
|
const deleteCmp = async (cmpType, authConfig, _neoService) => {
|
|
16
17
|
if (!authConfig) {
|
|
17
|
-
|
|
18
|
+
errorLog('未找到 NeoCRM 平台授权配置(neo.config.js / authConfig)。');
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -38,23 +39,23 @@ const deleteCmp = async (cmpType, authConfig, _neoService) => {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
if (cmpList.length === 0) {
|
|
41
|
-
|
|
42
|
+
errorLog('删除失败,当前租户暂无任何自定义组件。', spinner);
|
|
42
43
|
process.exit(1);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
// 获取自定义组件信息
|
|
46
47
|
cmpInfo = neoService.getCmpInfoByCmpType(cmpType);
|
|
47
48
|
if (!cmpInfo) {
|
|
48
|
-
|
|
49
|
+
errorLog(`删除失败,当前租户不存在${cmpType}自定义组件。`, spinner);
|
|
49
50
|
process.exit(1);
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// 调用删除 API
|
|
53
54
|
spinner.info(`正在删除${cmpType}自定义组件...`);
|
|
54
55
|
await neoService.deleteCmp(cmpType);
|
|
55
|
-
|
|
56
|
+
successLog(`已成功删除${cmpType}自定义组件!\n`, spinner);
|
|
56
57
|
} catch (error) {
|
|
57
|
-
|
|
58
|
+
errorLog(`删除自定义组件失败: ${error.message}`, spinner);
|
|
58
59
|
process.exit(1);
|
|
59
60
|
}
|
|
60
61
|
};
|
|
@@ -3,7 +3,7 @@ const { catchCurPackageJson } = require('../pathUtils');
|
|
|
3
3
|
const getConfigObj = require('../getConfigObj');
|
|
4
4
|
const ora = require('ora');
|
|
5
5
|
const NeoService = require('../../neo/neoService');
|
|
6
|
-
const { getFramework } = require('../common');
|
|
6
|
+
const { getFramework, errorLog, successLog } = require('../common');
|
|
7
7
|
const getCmpTypeByDir = require('./getCmpTypeByDir.js');
|
|
8
8
|
const createCmpByZip = require('./createCmpByZip.js');
|
|
9
9
|
|
|
@@ -27,13 +27,13 @@ const framework = getFramework(currentPackageJson.framework);
|
|
|
27
27
|
*/
|
|
28
28
|
const pullCmp = async (cmpType, authConfig, _neoService) => {
|
|
29
29
|
if (!authConfig) {
|
|
30
|
-
|
|
30
|
+
errorLog('未找到 NeoCRM 平台授权配置(neo.config.js / authConfig)。');
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const cmpTypes = getCmpTypeByDir(); // 获取当前项目目录中已存在的自定义组件类型
|
|
35
35
|
if (cmpTypes.indexOf(cmpType) > -1) {
|
|
36
|
-
|
|
36
|
+
errorLog(`当前项目目录中已存在${cmpType}自定义组件。(./src/components 目录下)`);
|
|
37
37
|
process.exit(1);
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -60,26 +60,26 @@ const pullCmp = async (cmpType, authConfig, _neoService) => {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (cmpList.length === 0) {
|
|
63
|
-
|
|
63
|
+
errorLog('拉取失败,当前租户暂无任何自定义组件。', spinner);
|
|
64
64
|
process.exit(1);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// 获取自定义组件信息
|
|
68
68
|
cmpInfo = neoService.getCmpInfoByCmpType(cmpType);
|
|
69
69
|
if (!cmpInfo) {
|
|
70
|
-
|
|
70
|
+
errorLog(`拉取失败,当前租户不存在${cmpType}自定义组件。`, spinner);
|
|
71
71
|
process.exit(1);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// 判断拉取的组件和当前项目是否为同一技术栈
|
|
75
75
|
if (cmpInfo.framework !== framework) {
|
|
76
|
-
|
|
76
|
+
errorLog(`拉取失败,${cmpType}自定义组件与当前项目技术栈不一致。`, spinner);
|
|
77
77
|
process.exit(1);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// 获取当前源码
|
|
81
81
|
if (!cmpInfo.codeLib) {
|
|
82
|
-
|
|
82
|
+
errorLog(`拉取失败,${cmpType}自定义组件未记录对应的源码文件。`, spinner);
|
|
83
83
|
process.exit(1);
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -89,13 +89,13 @@ const pullCmp = async (cmpType, authConfig, _neoService) => {
|
|
|
89
89
|
// 将zip 包里面的自定义组件源码解析到 src/components 目录下
|
|
90
90
|
const cmpResult = await createCmpByZip(codeLib, cmpType, './src/components');
|
|
91
91
|
if (!cmpResult) {
|
|
92
|
-
|
|
92
|
+
errorLog(`拉取失败,${cmpType}自定义组件源码解析失败,请检查源码文件是否正确。`, spinner);
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
successLog(`已成功拉取${cmpType}自定义组件!\n`, spinner);
|
|
97
97
|
} catch (error) {
|
|
98
|
-
|
|
98
|
+
errorLog(`拉取自定义组件失败: ${error.message}`, spinner);
|
|
99
99
|
throw error;
|
|
100
100
|
}
|
|
101
101
|
};
|
|
@@ -5,7 +5,7 @@ const { catchCurPackageJson } = require('../pathUtils');
|
|
|
5
5
|
const getConfigObj = require('../getConfigObj');
|
|
6
6
|
const ora = require('ora');
|
|
7
7
|
const NeoService = require('../../neo/neoService');
|
|
8
|
-
const { getFramework } = require('../common');
|
|
8
|
+
const { getFramework, errorLog, successLog } = require('../common');
|
|
9
9
|
const createCmpProjectZip = require('../projectUtils/createCmpProjectZip');
|
|
10
10
|
|
|
11
11
|
// 获取当前项目的package文件
|
|
@@ -20,14 +20,14 @@ const currentPackageJson = getConfigObj(currentPackageJsonDir);
|
|
|
20
20
|
*/
|
|
21
21
|
const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
22
22
|
if (!cmpInfo || !cmpInfo.cmpType) {
|
|
23
|
-
|
|
23
|
+
errorLog('自定义组件信息或组件名称不能为空');
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const { cmpType } = cmpInfo;
|
|
28
28
|
|
|
29
29
|
if (!assetsRoot || !fs.existsSync(assetsRoot)) {
|
|
30
|
-
|
|
30
|
+
errorLog(`未找到自定义组件目录: ${assetsRoot}`);
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
const widgetName = _.camelCase(cmpType);
|
|
@@ -53,11 +53,11 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
|
53
53
|
// 获取导出的模型类(可能是 default 导出或命名导出)
|
|
54
54
|
// const CatchCustomCmpModelClass = modelModule.default || modelModule;
|
|
55
55
|
} else {
|
|
56
|
-
|
|
56
|
+
errorLog(`未找到自定义组件模型文件,请检查以下路径是否存在:${modelFile}`);
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
59
|
if (!globalThis.window || !globalThis.window.NEOEditorCustomModels) {
|
|
60
|
-
|
|
60
|
+
errorLog(
|
|
61
61
|
`模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `
|
|
62
62
|
);
|
|
63
63
|
return null;
|
|
@@ -65,14 +65,14 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
|
65
65
|
|
|
66
66
|
const ModelClass = globalThis.window.NEOEditorCustomModels[cmpType];
|
|
67
67
|
if (!ModelClass) {
|
|
68
|
-
|
|
68
|
+
errorLog(`未找到自定义组件模型类(${cmpType}),模型文件地址: ${modelFile} `);
|
|
69
69
|
return null;
|
|
70
70
|
}
|
|
71
71
|
// 实例化模型类
|
|
72
72
|
const modelInstance = new ModelClass();
|
|
73
73
|
|
|
74
74
|
if (!modelInstance) {
|
|
75
|
-
|
|
75
|
+
errorLog(`未找到自定义组件模型信息(${cmpType}),模型文件地址: ${modelFile} `);
|
|
76
76
|
return null;
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -104,8 +104,8 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
|
|
|
104
104
|
console.log(`自定义组件模型信息(${cmpType}):`, curCmpInfo);
|
|
105
105
|
return curCmpInfo;
|
|
106
106
|
} catch (error) {
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
errorLog(`自定义组件模型文件解析失败 (${modelFile || '未知路径'}): ${error.message}`);
|
|
108
|
+
errorLog(error.stack);
|
|
109
109
|
return null;
|
|
110
110
|
} finally {
|
|
111
111
|
// 恢复原始的 window 对象(如果之前存在)
|
|
@@ -132,7 +132,7 @@ const pushCmp = async (config, cmpType) => {
|
|
|
132
132
|
const { auth: credentials } = config;
|
|
133
133
|
|
|
134
134
|
if (!credentials) {
|
|
135
|
-
|
|
135
|
+
errorLog('未找到 NeoCRM 平台授权配置(neo.config.js / neoConfig)');
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -150,12 +150,12 @@ const pushCmp = async (config, cmpType) => {
|
|
|
150
150
|
try {
|
|
151
151
|
zipPath = createCmpProjectZip(cmpType, process.cwd(), config.assetsRoot);
|
|
152
152
|
if (!zipPath) {
|
|
153
|
-
|
|
153
|
+
errorLog('[1/4] 源码文件打包失败,未返回 zip 文件路径。', spinner);
|
|
154
154
|
} else {
|
|
155
|
-
|
|
155
|
+
successLog(`[1/4] 源码文件打包完成: ${path.basename(zipPath)}。`, spinner);
|
|
156
156
|
}
|
|
157
157
|
} catch (error) {
|
|
158
|
-
|
|
158
|
+
errorLog(`[1/4] 源码文件打包失败。`, spinner);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// 步骤 3: 上传构建后资源文件
|
|
@@ -164,12 +164,12 @@ const pushCmp = async (config, cmpType) => {
|
|
|
164
164
|
try {
|
|
165
165
|
cmpInfo = await neoService.publish2oss(cmpType);
|
|
166
166
|
if (!cmpInfo || !cmpInfo.cmpType) {
|
|
167
|
-
|
|
167
|
+
errorLog('[2/4] 上传构建产物失败,未获取到组件信息。', spinner);
|
|
168
168
|
} else {
|
|
169
|
-
|
|
169
|
+
successLog(`[2/4] 构建产物上传完成。`, spinner);
|
|
170
170
|
}
|
|
171
171
|
} catch (error) {
|
|
172
|
-
|
|
172
|
+
errorLog(`[2/4] 构建产物上传失败。`, spinner);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// 步骤 4: 构建组件数据
|
|
@@ -178,21 +178,21 @@ const pushCmp = async (config, cmpType) => {
|
|
|
178
178
|
try {
|
|
179
179
|
componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
|
|
180
180
|
if (!componentInfo) {
|
|
181
|
-
|
|
181
|
+
errorLog(`[3/4] 未获取到自定义组件模型信息(${cmpType})。`, spinner);
|
|
182
182
|
} else {
|
|
183
|
-
|
|
183
|
+
successLog(`[3/4] 组件数据构建完成。`, spinner);
|
|
184
184
|
}
|
|
185
185
|
} catch (error) {
|
|
186
|
-
|
|
186
|
+
errorLog(`[3/4] 组件数据构建失败: ${error.message}`, spinner);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// 步骤 5: 保存组件信息
|
|
190
190
|
spinner.start(`[4/4] 保存组件信息到 NeoCRM 平台...`);
|
|
191
191
|
try {
|
|
192
192
|
await neoService.updateCustomComponent(componentInfo);
|
|
193
|
-
|
|
193
|
+
successLog(`[4/4] 组件信息保存成功`, spinner);
|
|
194
194
|
} catch (error) {
|
|
195
|
-
|
|
195
|
+
errorLog(`[4/4] 组件信息保存失败`, spinner);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// 最终成功提示
|
|
@@ -203,11 +203,11 @@ const pushCmp = async (config, cmpType) => {
|
|
|
203
203
|
try {
|
|
204
204
|
// ora 的 spinner 对象可能没有 isSpinning 属性,使用 try-catch 安全访问
|
|
205
205
|
if (spinner && spinner.isSpinning) {
|
|
206
|
-
|
|
206
|
+
errorLog(`❌ 自定义组件发布失败: ${error.message}`, spinner);
|
|
207
207
|
}
|
|
208
208
|
} catch {
|
|
209
209
|
// 如果访问失败或 spinner 已停止,直接输出错误信息
|
|
210
|
-
|
|
210
|
+
errorLog(`\n❌ 自定义组件发布失败: ${error.message}`);
|
|
211
211
|
}
|
|
212
212
|
throw error;
|
|
213
213
|
}
|
package/src/utils/common.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const ts = require('typescript');
|
|
1
3
|
const { consoleTag } = require('./neoParams');
|
|
4
|
+
|
|
2
5
|
/**
|
|
3
6
|
* 获取技术栈标识
|
|
4
7
|
* 目的:兼容用户非标准写法
|
|
@@ -27,10 +30,10 @@ function getFramework(_framework) {
|
|
|
27
30
|
case 'vue3.0':
|
|
28
31
|
case 'vue 3.0':
|
|
29
32
|
curFramework = 3;
|
|
30
|
-
|
|
33
|
+
errorLog('暂不支持 vue3.0 技术栈。');
|
|
31
34
|
break;
|
|
32
35
|
case 'react-js':
|
|
33
|
-
|
|
36
|
+
errorLog('暂不支持 react-js 技术栈。');
|
|
34
37
|
curFramework = 0;
|
|
35
38
|
break;
|
|
36
39
|
case 'react':
|
|
@@ -43,6 +46,62 @@ function getFramework(_framework) {
|
|
|
43
46
|
return curFramework;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
// 输出红色字体的错误日志
|
|
50
|
+
function errorLog(message, spinner) {
|
|
51
|
+
const errorMessage = `${consoleTag} ${chalk.red(message)}`;
|
|
52
|
+
if (spinner) {
|
|
53
|
+
spinner.fail(errorMessage);
|
|
54
|
+
} else {
|
|
55
|
+
console.error(errorMessage);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 输出黄色字体的警告日志
|
|
60
|
+
function warningLog(message) {
|
|
61
|
+
const warningMessage = `${consoleTag} ${chalk.yellow(message)}`;
|
|
62
|
+
if (spinner) {
|
|
63
|
+
spinner.warn(warningMessage);
|
|
64
|
+
} else {
|
|
65
|
+
console.warn(warningMessage);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 输出绿色字体的成功日志
|
|
70
|
+
function successLog(message) {
|
|
71
|
+
const successMessage = `${consoleTag} ${chalk.green(message)}`;
|
|
72
|
+
if (spinner) {
|
|
73
|
+
spinner.succeed(successMessage);
|
|
74
|
+
} else {
|
|
75
|
+
console.log(successMessage);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 使用 TypeScript 官方 API 解析 tsconfig.json(推荐)
|
|
81
|
+
* 需要安装: npm install typescript --save-dev
|
|
82
|
+
* 优点: 官方支持,能正确处理 extends、注释等所有特性
|
|
83
|
+
*/
|
|
84
|
+
function parseTsConfigWithTypeScript(configPath) {
|
|
85
|
+
try {
|
|
86
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
87
|
+
|
|
88
|
+
if (configFile.error) {
|
|
89
|
+
throw new Error(`解析 tsconfig.json 失败: ${configFile.error.messageText}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return configFile.config;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error.code === 'MODULE_NOT_FOUND') {
|
|
95
|
+
throw new Error('请先安装 typescript: npm install typescript --save-dev');
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
46
101
|
module.exports = {
|
|
47
|
-
getFramework
|
|
102
|
+
getFramework,
|
|
103
|
+
errorLog,
|
|
104
|
+
warningLog,
|
|
105
|
+
successLog,
|
|
106
|
+
parseTsConfigWithTypeScript
|
|
48
107
|
};
|
|
@@ -2,6 +2,7 @@ const path = require('path');
|
|
|
2
2
|
const { exec } = require('child_process');
|
|
3
3
|
const ora = require('ora');
|
|
4
4
|
const { consoleTag } = require('../neoParams');
|
|
5
|
+
const { errorLog } = require('../common');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* 打开自定义组件项目
|
|
@@ -46,7 +47,7 @@ module.exports = function (editorType, targetPath) {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
if (commands.length === 0) {
|
|
49
|
-
|
|
50
|
+
errorLog(`不支持的操作系统: ${process.platform}`);
|
|
50
51
|
process.exit(1);
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -55,8 +56,9 @@ module.exports = function (editorType, targetPath) {
|
|
|
55
56
|
// 尝试执行命令列表中的第一个可用命令
|
|
56
57
|
const tryCommand = (index) => {
|
|
57
58
|
if (index >= commands.length) {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
errorLog(
|
|
60
|
+
`无法打开编辑器,已尝试所有可用方式。\n 请确保已安装 Cursor 或 Visual Studio Code 并将其添加到系统 PATH 中。`,
|
|
61
|
+
spinner
|
|
60
62
|
);
|
|
61
63
|
process.exit(1);
|
|
62
64
|
}
|
package/test/demo3.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
|
|
3
3
|
// 所有需要废弃的版本(1.6.2 之前的所有版本)
|
|
4
|
-
const versionsToDeprecate = ["1.6.2-beta.
|
|
4
|
+
const versionsToDeprecate = ["1.6.2-beta.5"];
|
|
5
5
|
|
|
6
6
|
const packageName = 'neo-cmp-cli';
|
|
7
7
|
const deprecateMessage = '此版本为开发中版本(存在 bug),请升级到最新版本。';
|