cloudcc-cli 2.1.8 → 2.2.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/README.md CHANGED
@@ -1,3 +1,20 @@
1
+ # ReleaseV2.2.0
2
+ #### Release Date: 2025-11-24
3
+ #### Release Scope: Full
4
+ #### Release Content
5
+ * Optimization
6
+ * Update the packaging and parsing of Vue files
7
+ * Add upload dependency tree to custom component
8
+
9
+
10
+
11
+ # ReleaseV2.1.9
12
+ #### Release Date: 2025-9-1
13
+ #### Release Scope: Full
14
+ #### Release Content
15
+ * Optimization
16
+ * getBaseUrl change orgId.
17
+
1
18
  # ReleaseV2.1.8
2
19
  #### Release Date: 2025-7-30
3
20
  #### Release Scope: Full
package/bin/cc.js CHANGED
@@ -4,6 +4,13 @@ const chalk = require("chalk")
4
4
  let argvs = process.argv.splice(2);
5
5
 
6
6
  let action = argvs[0]
7
+ // 处理版本查询命令
8
+ if (action === '-version' || action === '-v' || action === '--version' || action === '--v') {
9
+ const version = require("../src/version/index")
10
+ version('get', argvs);
11
+ return;
12
+ }
13
+
7
14
  if (!action) {
8
15
  console.log()
9
16
  console.log(chalk.yellow("Please see the help documentation"));
@@ -43,6 +50,8 @@ cc.object = require("../src/object/index")
43
50
  cc.recordType = require("../src/recordType/index")
44
51
 
45
52
  cc.config = require("../src/config/index")
53
+
54
+ cc.version = require("../src/version/index")
46
55
  try {
47
56
  cc[argvs[1]](argvs[0], argvs);
48
57
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudcc-cli",
3
- "version": "2.1.8",
3
+ "version": "2.2.0",
4
4
  "description": "cloudcc-cli",
5
5
  "keywords": [
6
6
  "cloudcc",
@@ -20,6 +20,8 @@
20
20
  "package-jar": "mvn clean && mvn package"
21
21
  },
22
22
  "dependencies": {
23
+ "@babel/parser": "^7.28.5",
24
+ "@babel/traverse": "^7.28.5",
23
25
  "axios": "^0.21.4",
24
26
  "boxen": "^4.0.0",
25
27
  "chalk": "^2.4.2",
@@ -29,7 +29,6 @@ data() {
29
29
  .cc-container {
30
30
  text-align: center;
31
31
  padding: 8px;
32
- background: goldenrod;
33
32
  }
34
33
  </style>`
35
34
 
@@ -38,7 +38,6 @@ data() {
38
38
  .cc-container {
39
39
  text-align: center;
40
40
  padding: 8px;
41
- background: goldenrod;
42
41
  }
43
42
  </style>`
44
43
 
@@ -7,6 +7,7 @@ const { readCache, writeCache } = require("../../utils/cache")
7
7
  const { checkUpdate } = require("../../utils/checkVersion")
8
8
  const BaseUrl = "https://developer.apis.cloudcc.cn"
9
9
  const { getPackageJson } = require("../../utils/config.js")
10
+ const { parseVueDataFunction, collectDependenciesWithTree } = require("../../utils/utils.js")
10
11
 
11
12
 
12
13
  class Builder {
@@ -86,16 +87,10 @@ class Builder {
86
87
  console.log(chalk.yellow("Warning: The scoped attribute is missing in style, which may cause global style pollution. It is recommended to fix it。"));
87
88
  console.log()
88
89
  }
89
- vueData = vueData.split(/data\s*\(\s*\)/)[1].split(/isLock\s*:/)[0] + "isLock:false,};}";
90
- vueData = "function data()" + vueData;
91
- let data = {}
92
- try {
93
- data = eval(`(${vueData})`)()
94
- }
95
- catch (e) {
96
- console.log()
97
- console.log(chalk.red("Error: The data function cannot contain reference variables."));
98
- console.log()
90
+
91
+ // 提取 data() 函数的返回对象
92
+ let data = parseVueDataFunction(vueContent);
93
+ if (!data) {
99
94
  return null;
100
95
  }
101
96
  if (!data.propObj) {
@@ -189,7 +184,50 @@ class Builder {
189
184
  belongOrgFlag = this.options.pluginConfig.belongOrgFlag
190
185
  }
191
186
  vueData = JSON.stringify(data);
192
- return { compName, component, vueContent, vueData, bizType, compDesc, category, loadModel, belongOrgFlag }
187
+
188
+ // 收集所有依赖文件
189
+ const baseDir = path.join(process.cwd(), 'plugins');
190
+ const entryFile = path.join(baseDir, buildFileName);
191
+ const allDependencies = collectDependenciesWithTree(entryFile, baseDir);
192
+
193
+ // 收集根目录下的配置文件
194
+ const rootDir = process.cwd();
195
+ const configFiles = ['package.json', 'cloudcc-cli.config.js'];
196
+
197
+ for (const configFile of configFiles) {
198
+ const configPath = path.join(rootDir, configFile);
199
+ if (fs.existsSync(configPath)) {
200
+ try {
201
+ const content = fs.readFileSync(configPath, 'utf8');
202
+ allDependencies[configFile] = content;
203
+ } catch (err) {
204
+ console.log(chalk.yellow(`Warning: Cannot read ${configFile}:`, err.message));
205
+ }
206
+ }
207
+ }
208
+
209
+ // 输出依赖信息到文件
210
+ try {
211
+ const outputPath = path.join(process.cwd(), 'dependencies-output.json');
212
+ fs.writeFileSync(outputPath, JSON.stringify(allDependencies, null, 2), 'utf8');
213
+ console.log(chalk.green(`Dependencies collected and saved to: ${outputPath}`));
214
+ console.log(chalk.cyan(`Total files: ${Object.keys(allDependencies).length}`));
215
+ } catch (err) {
216
+ console.log(chalk.yellow('Warning: Failed to write dependencies output file:', err.message));
217
+ }
218
+
219
+ return {
220
+ compName,
221
+ component,
222
+ vueContent,
223
+ vueData,
224
+ bizType,
225
+ compDesc,
226
+ category,
227
+ loadModel,
228
+ belongOrgFlag,
229
+ dependencies: allDependencies
230
+ }
193
231
  };
194
232
 
195
233
  initPluginFile(buildFileName, component, plginTemp) {
@@ -258,13 +296,15 @@ class Builder {
258
296
  "compLabel": obj.compName,
259
297
  "compUniName": obj.component,
260
298
  "compContentJs": jsContent,
261
- "compContentVue": obj.vueContent,
299
+ "compContentVue": JSON.stringify(obj.dependencies || {}),
300
+ // "compContentVue": obj.vueContent,
262
301
  "vueData": obj.vueData,
263
302
  "bizType": obj.bizType,
264
303
  "compDesc": obj.compDesc,
265
304
  "category": obj.category,
266
305
  "loadModel": obj.loadModel,
267
- "belongOrgFlag": obj.belongOrgFlag
306
+ "belongOrgFlag": obj.belongOrgFlag,
307
+ "dependencies": JSON.stringify(obj.dependencies || {})
268
308
  }
269
309
 
270
310
  let devSvcDispatch = this.options.devConsoleConfig.devSvcDispatch || '/devconsole'
@@ -275,7 +315,8 @@ class Builder {
275
315
  console.error(chalk.green(`Success!`));
276
316
  console.log();
277
317
  } else {
278
- console.error(chalk.red(`Publish Plugin Fail: ${JSON.stringify(res)}`));
318
+ console.log("res", res);
319
+ console.error(chalk.red(`Fail: ${res.returnInfo}`));
279
320
  console.log();
280
321
  }
281
322
  return res;
@@ -0,0 +1,10 @@
1
+ const chalk = require("chalk")
2
+ const pkg = require("../../package.json")
3
+
4
+ function get() {
5
+ console.log()
6
+ console.log(chalk.green(`cloudcc-cli version: ${pkg.version}`));
7
+ console.log()
8
+ }
9
+
10
+ module.exports = get;
@@ -0,0 +1,8 @@
1
+ const cc = {}
2
+ cc.get = require("./get")
3
+
4
+ function Version(action, argvs) {
5
+ cc[action](argvs)
6
+ }
7
+
8
+ module.exports = Version;
package/template/Appvue CHANGED
@@ -5,21 +5,21 @@
5
5
  </template>
6
6
 
7
7
  <script>
8
- export default {
9
- name: "App",
10
- };
8
+ export default {
9
+ name: "App",
10
+ };
11
11
  </script>
12
12
 
13
13
  <style lang="scss" scoped>
14
- html body {
15
- padding: 0;
16
- margin: 0;
17
- height: 100vh;
18
- width: 100%;
19
- }
20
- .cc-container {
21
- text-align: center;
22
- padding: 8px;
23
- background: goldenrod;
24
- }
14
+ html body {
15
+ padding: 0;
16
+ margin: 0;
17
+ height: 100vh;
18
+ width: 100%;
19
+ }
20
+
21
+ .cc-container {
22
+ text-align: center;
23
+ padding: 8px;
24
+ }
25
25
  </style>
@@ -1 +1 @@
1
- module.exports = { "use": "dev", "dev": { "username": "xxx", "secretKey": "xxx" } }
1
+ module.exports = { "use": "dev", "dev": { "safetyMark": "xxx", "CloudCCDev": "xxx" } }
package/template/indexvue CHANGED
@@ -25,6 +25,5 @@ export default {
25
25
  .cc - container {
26
26
  text - align: center;
27
27
  padding: 8px;
28
- background: goldenrod;
29
28
  }
30
29
  </style>
@@ -23,7 +23,6 @@ function checkNpmVersion() {
23
23
  });
24
24
 
25
25
  onlineVersionNum = Number(onlineVersion.replace(/\./g, ""));
26
-
27
26
  console.log('\n');
28
27
  console.log(chalk.bold.cyan(' CloudCC CLI Version\n'));
29
28
  console.log(' ' + chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
@@ -70,7 +69,6 @@ async function checkUpdate(path = process.cwd()) {
70
69
  const cacheKey = 'version_check';
71
70
  const now = Date.now();
72
71
  const oneHour = 60 * 60 * 1000;
73
-
74
72
  if (cache[cacheKey] &&
75
73
  cache[cacheKey].timestamp &&
76
74
  (now - cache[cacheKey].timestamp) < oneHour) {
package/utils/config.js CHANGED
@@ -58,8 +58,7 @@ async function getPackageJson3(projectPath = process.cwd()) {
58
58
  */
59
59
  async function getPackageJsonCache(projectPath = process.cwd()) {
60
60
  let config = require(path.join(projectPath, "cloudcc-cli.config.js"));
61
- const cacheData = readCache()[config[config.use].safetyMark || config[config.use].secretKey];
62
-
61
+ const cacheData = readCache(projectPath)[config[config.use].safetyMark || config[config.use].secretKey];
63
62
  if (cacheData && cacheData.timestamp) {
64
63
  const oneHour = 60 * 60 * 1000; // 1小时的毫秒数
65
64
  const currentTime = Date.now();
package/utils/utils.js CHANGED
@@ -24,7 +24,7 @@ async function getBaseUrl(config) {
24
24
  if (config.baseUrl) {
25
25
  config.apiSvc = config.baseUrl + (config.apiSvcPrefix || "/apisvc")
26
26
  config.setupSvc = config.baseUrl + (config.setupSvcPrefix || "/setup")
27
- } else {
27
+ } else if (config.orgId) {
28
28
  let u = "https://developer.apis.cloudcc.cn/oauth/apidomain?scope=cloudccCRM&orgId=" + config.orgId
29
29
  let res = await axios({
30
30
  url: u,
@@ -165,5 +165,408 @@ function decryptCloudCCDevInfo(encryptedData) {
165
165
  */
166
166
  const javaContentRegular = /\/\/\s*@SOURCE_CONTENT_START\r?\n([\s\S]*?)\r?\n\s*\/\/\s*@SOURCE_CONTENT_END/
167
167
 
168
+ // 用于 AST 解析
169
+ let babelParser, babelTraverse;
170
+ try {
171
+ babelParser = require('@babel/parser');
172
+ babelTraverse = require('@babel/traverse').default;
173
+ } catch (e) {
174
+ // 如果没有安装 babel 依赖,将在使用时提示安装
175
+ babelParser = null;
176
+ babelTraverse = null;
177
+ }
178
+
179
+ /**
180
+ * 使用 AST 解析 Vue 文件中的 data() 函数
181
+ * @param {string} vueContent - Vue 文件内容
182
+ * @returns {Object|null} 解析出的 data 对象,失败返回 null
183
+ */
184
+ function parseVueDataFunction(vueContent) {
185
+ // if (!babelParser || !babelTraverse) {
186
+ // console.log()
187
+ // console.log(chalk.yellow("Warning: @babel/parser and @babel/traverse are not installed. Please run:"));
188
+ // console.log(chalk.cyan("npm install --save @babel/parser @babel/traverse"));
189
+ // console.log()
190
+ // console.log(chalk.yellow("Falling back to regex parsing..."));
191
+ // return parseVueDataFunctionWithRegex(vueContent);
192
+ // }
193
+
194
+ try {
195
+ // 提取 <script> 标签中的内容
196
+ const scriptMatch = vueContent.match(/<script[^>]*>([\s\S]*?)<\/script>/);
197
+ if (!scriptMatch) {
198
+ console.log()
199
+ console.log(chalk.red("Error: Cannot find <script> tag in the vue file."));
200
+ console.log()
201
+ return null;
202
+ }
203
+
204
+ const scriptContent = scriptMatch[1];
205
+
206
+ // 使用 Babel 解析 JavaScript 代码
207
+ const ast = babelParser.parse(scriptContent, {
208
+ sourceType: 'module',
209
+ plugins: ['jsx', 'typescript']
210
+ });
211
+
212
+ let dataObject = null;
213
+
214
+ // 遍历 AST,查找 data() 方法
215
+ babelTraverse(ast, {
216
+ ObjectMethod(path) {
217
+ // 查找名为 data 的方法
218
+ if (path.node.key.name === 'data' && path.node.params.length === 0) {
219
+ // 查找 return 语句
220
+ path.traverse({
221
+ ReturnStatement(returnPath) {
222
+ if (returnPath.node.argument && returnPath.node.argument.type === 'ObjectExpression') {
223
+ // 将 AST 对象表达式转换为实际的 JavaScript 对象
224
+ dataObject = astToObject(returnPath.node.argument);
225
+ returnPath.stop();
226
+ }
227
+ }
228
+ });
229
+ path.stop();
230
+ }
231
+ },
232
+ // 也处理 data: function() {} 的形式
233
+ ObjectProperty(path) {
234
+ if (path.node.key.name === 'data' &&
235
+ (path.node.value.type === 'FunctionExpression' || path.node.value.type === 'ArrowFunctionExpression')) {
236
+ // 查找 return 语句
237
+ path.traverse({
238
+ ReturnStatement(returnPath) {
239
+ if (returnPath.node.argument && returnPath.node.argument.type === 'ObjectExpression') {
240
+ dataObject = astToObject(returnPath.node.argument);
241
+ returnPath.stop();
242
+ }
243
+ }
244
+ });
245
+ path.stop();
246
+ }
247
+ }
248
+ });
249
+
250
+ if (!dataObject) {
251
+ console.log()
252
+ console.log(chalk.red("Error: Cannot find data() function or its return statement in the vue file."));
253
+ console.log()
254
+ return null;
255
+ }
256
+
257
+ return dataObject;
258
+
259
+ } catch (e) {
260
+ console.log()
261
+ console.log(chalk.red("Error: Failed to parse vue file with AST."));
262
+ console.log(chalk.red("Details: " + e.message));
263
+ console.log()
264
+ return null;
265
+ }
266
+ }
267
+
268
+ /**
269
+ * 将 Babel AST 对象表达式转换为 JavaScript 对象
270
+ * @param {Object} node - AST 节点
271
+ * @returns {Object} JavaScript 对象
272
+ */
273
+ function astToObject(node) {
274
+ if (node.type === 'ObjectExpression') {
275
+ const obj = {};
276
+ for (const prop of node.properties) {
277
+ if (prop.type === 'ObjectProperty') {
278
+ const key = prop.key.name || prop.key.value;
279
+ obj[key] = astToValue(prop.value);
280
+ } else if (prop.type === 'SpreadElement') {
281
+ // 处理展开运算符 {...obj}
282
+ console.log(chalk.yellow("Warning: Spread operator is not fully supported in data object."));
283
+ }
284
+ }
285
+ return obj;
286
+ }
287
+ return astToValue(node);
288
+ }
289
+
290
+ /**
291
+ * 将 AST 值节点转换为 JavaScript 值
292
+ * @param {Object} node - AST 节点
293
+ * @returns {*} JavaScript 值
294
+ */
295
+ function astToValue(node) {
296
+ switch (node.type) {
297
+ case 'StringLiteral':
298
+ return node.value;
299
+ case 'NumericLiteral':
300
+ return node.value;
301
+ case 'BooleanLiteral':
302
+ return node.value;
303
+ case 'NullLiteral':
304
+ return null;
305
+ case 'ObjectExpression':
306
+ return astToObject(node);
307
+ case 'ArrayExpression':
308
+ return node.elements.map(el => astToValue(el));
309
+ case 'UnaryExpression':
310
+ // 处理负数等
311
+ if (node.operator === '-' && node.argument.type === 'NumericLiteral') {
312
+ return -node.argument.value;
313
+ }
314
+ return undefined;
315
+ default:
316
+ // 对于无法静态解析的值(如函数、变量引用等),返回 undefined
317
+ return undefined;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * 降级方案:使用正则表达式解析 Vue data() 函数
323
+ * @param {string} vueContent - Vue 文件内容
324
+ * @returns {Object|null} 解析出的 data 对象,失败返回 null
325
+ */
326
+ function parseVueDataFunctionWithRegex(vueContent) {
327
+ try {
328
+ // 匹配 data() 函数,找到开始位置
329
+ const dataStartMatch = vueContent.match(/data\s*\(\s*\)\s*\{[\s\S]*?return\s*\{/);
330
+ if (!dataStartMatch) {
331
+ console.log()
332
+ console.log(chalk.red("Error: Cannot find data() function or its return statement in the vue file."));
333
+ console.log()
334
+ return null;
335
+ }
336
+
337
+ // 从 return { 后面开始提取,需要匹配嵌套的大括号
338
+ let startIndex = dataStartMatch.index + dataStartMatch[0].length;
339
+ let braceCount = 1;
340
+ let endIndex = startIndex;
341
+
342
+ // 逐字符扫描,匹配嵌套的大括号
343
+ while (endIndex < vueContent.length && braceCount > 0) {
344
+ const char = vueContent[endIndex];
345
+ if (char === '{') {
346
+ braceCount++;
347
+ } else if (char === '}') {
348
+ braceCount--;
349
+ }
350
+ endIndex++;
351
+ }
352
+
353
+ if (braceCount !== 0) {
354
+ console.log()
355
+ console.log(chalk.red("Error: Cannot parse data() function, unmatched braces."));
356
+ console.log()
357
+ return null;
358
+ }
359
+
360
+ // 提取返回对象的内容(不包括最外层的大括号)
361
+ const dataObjectContent = vueContent.substring(startIndex, endIndex - 1);
362
+
363
+ // 使用 Function 构造器在独立作用域中执行
364
+ const evalCode = `return {${dataObjectContent}};`;
365
+ const dataFunc = new Function(evalCode);
366
+ return dataFunc();
367
+
368
+ } catch (e) {
369
+ console.log()
370
+ console.log(chalk.red("Error: Failed to parse data function with regex."));
371
+ console.log(chalk.red("Details: " + e.message));
372
+ console.log()
373
+ return null;
374
+ }
375
+ }
376
+
377
+
378
+ /**
379
+ * 解析 JS 代码中的依赖(import/require)
380
+ * @param {string} jsContent - JS 代码内容
381
+ * @returns {Array<string>} 依赖路径数组
382
+ */
383
+ function parseJsDependencies(jsContent) {
384
+ const dependencies = [];
385
+
386
+ // 匹配 ES6 import
387
+ const importRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
388
+ let match;
389
+ while ((match = importRegex.exec(jsContent)) !== null) {
390
+ dependencies.push(match[1]);
391
+ }
392
+
393
+ // 匹配 require
394
+ const requireRegex = /require\s*\(['"]([^'"]+)['"]\)/g;
395
+ while ((match = requireRegex.exec(jsContent)) !== null) {
396
+ dependencies.push(match[1]);
397
+ }
398
+
399
+ return dependencies;
400
+ }
401
+
402
+ /**
403
+ * 解析 CSS 中的依赖(@import)
404
+ * @param {string} cssContent - CSS 代码内容
405
+ * @returns {Array<string>} 依赖路径数组
406
+ */
407
+ function parseCssDependencies(cssContent) {
408
+ const dependencies = [];
409
+
410
+ // 匹配 @import
411
+ const importRegex = /@import\s+['"]([^'"]+)['"]/g;
412
+ let match;
413
+ while ((match = importRegex.exec(cssContent)) !== null) {
414
+ dependencies.push(match[1]);
415
+ }
416
+
417
+ return dependencies;
418
+ }
419
+
420
+ /**
421
+ * 解析文件中的依赖(import/require)
422
+ * @param {string} fileContent - 文件内容
423
+ * @param {string} fileType - 文件类型 ('vue', 'js', 'css')
424
+ * @returns {Array<string>} 依赖路径数组
425
+ */
426
+ function parseDependencies(fileContent, fileType) {
427
+ const dependencies = [];
428
+
429
+ if (fileType === 'vue') {
430
+ // 提取 <script> 部分
431
+ const scriptMatch = fileContent.match(/<script[^>]*>([\s\S]*?)<\/script>/);
432
+ if (scriptMatch) {
433
+ dependencies.push(...parseJsDependencies(scriptMatch[1]));
434
+ }
435
+
436
+ // 提取 <style> 中的 @import
437
+ const styleMatches = fileContent.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/g);
438
+ for (const match of styleMatches) {
439
+ dependencies.push(...parseCssDependencies(match[1]));
440
+ }
441
+ } else if (fileType === 'js') {
442
+ dependencies.push(...parseJsDependencies(fileContent));
443
+ } else if (fileType === 'css') {
444
+ dependencies.push(...parseCssDependencies(fileContent));
445
+ }
446
+
447
+ return dependencies;
448
+ }
449
+
450
+ /**
451
+ * 解析依赖路径(处理相对路径、扩展名等)
452
+ * @param {string} depPath - 依赖路径
453
+ * @param {string} currentFile - 当前文件的绝对路径
454
+ * @param {string} baseDir - 基础目录
455
+ * @returns {string|null} 解析后的绝对路径,未找到返回 null
456
+ */
457
+ function resolveDependencyPath(depPath, currentFile, baseDir) {
458
+ const fs = require('fs');
459
+ const path = require('path');
460
+
461
+ const currentDir = path.dirname(currentFile);
462
+ const possibleExtensions = ['', '.vue', '.js', '.jsx', '.ts', '.tsx', '.css', '.scss', '.sass', '.less'];
463
+
464
+ // 尝试不同的扩展名
465
+ for (const ext of possibleExtensions) {
466
+ const fullPath = path.resolve(currentDir, depPath + ext);
467
+ if (fs.existsSync(fullPath)) {
468
+ const stat = fs.statSync(fullPath);
469
+ if (stat.isFile()) {
470
+ return fullPath;
471
+ }
472
+ }
473
+ }
474
+
475
+ // 如果是目录,尝试 index 文件
476
+ const dirPath = path.resolve(currentDir, depPath);
477
+ if (fs.existsSync(dirPath)) {
478
+ const stat = fs.statSync(dirPath);
479
+ if (stat.isDirectory()) {
480
+ for (const ext of ['.vue', '.js', '.jsx', '.ts', '.tsx']) {
481
+ const indexPath = path.join(dirPath, 'index' + ext);
482
+ if (fs.existsSync(indexPath)) {
483
+ return indexPath;
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ return null;
490
+ }
491
+
492
+ /**
493
+ * 递归收集所有依赖文件
494
+ * @param {string} entryFile - 入口文件路径(绝对路径或相对于 baseDir)
495
+ * @param {string} baseDir - 基础目录
496
+ * @param {Set} visited - 已访问的文件集合(用于避免循环依赖)
497
+ * @returns {Object} { files: { relativePath: fileContent }, tree: dependencyTree }
498
+ */
499
+ function collectDependencies(entryFile, baseDir, visited = new Set()) {
500
+ const fs = require('fs');
501
+ const path = require('path');
502
+ const dependencies = {};
503
+
504
+ // 规范化路径
505
+ const normalizedPath = path.isAbsolute(entryFile) ? entryFile : path.resolve(baseDir, entryFile);
506
+
507
+ // 避免循环依赖
508
+ if (visited.has(normalizedPath)) {
509
+ return dependencies;
510
+ }
511
+ visited.add(normalizedPath);
512
+
513
+ // 读取文件内容
514
+ let fileContent;
515
+ try {
516
+ fileContent = fs.readFileSync(normalizedPath, 'utf8');
517
+ } catch (error) {
518
+ console.log(chalk.yellow(`Warning: Cannot read file ${normalizedPath}`));
519
+ return dependencies;
520
+ }
521
+
522
+ // 保存当前文件(使用相对路径作为键)
523
+ const relativePath = path.relative(baseDir, normalizedPath);
524
+ dependencies[relativePath] = fileContent;
525
+
526
+ // 确定文件类型
527
+ const ext = path.extname(normalizedPath).slice(1);
528
+ const fileType = ext === 'vue' ? 'vue' :
529
+ (['css', 'scss', 'sass', 'less'].includes(ext)) ? 'css' : 'js';
530
+
531
+ // 解析依赖
532
+ const deps = parseDependencies(fileContent, fileType);
533
+
534
+ // 递归处理每个依赖
535
+ for (const dep of deps) {
536
+ // 只处理相对路径(跳过 node_modules 和绝对路径的包)
537
+ if (dep.startsWith('.') || dep.startsWith('/')) {
538
+ const depPath = resolveDependencyPath(dep, normalizedPath, baseDir);
539
+ if (depPath) {
540
+ const subDeps = collectDependencies(depPath, baseDir, visited);
541
+ Object.assign(dependencies, subDeps);
542
+ } else {
543
+ console.log(chalk.yellow(`Warning: Cannot resolve dependency "${dep}" from ${relativePath}`));
544
+ }
545
+ }
546
+ }
547
+
548
+ return dependencies;
549
+ }
550
+
551
+ /**
552
+ * 收集依赖文件
553
+ * @param {string} entryFile - 入口文件路径
554
+ * @param {string} baseDir - 基础目录
555
+ * @returns {Object} { [relativePath]: fileContent }
556
+ */
557
+ function collectDependenciesWithTree(entryFile, baseDir) {
558
+ return collectDependencies(entryFile, baseDir);
559
+ }
168
560
 
169
- module.exports = { getDevConsoleConfig, javaContentRegular, decryptCloudCCDevInfo }
561
+ module.exports = {
562
+ getDevConsoleConfig,
563
+ javaContentRegular,
564
+ decryptCloudCCDevInfo,
565
+ parseVueDataFunction,
566
+ parseVueDataFunctionWithRegex,
567
+ collectDependencies,
568
+ collectDependenciesWithTree,
569
+ parseDependencies,
570
+ parseJsDependencies,
571
+ parseCssDependencies
572
+ }