@tmsfe/tmskit 0.0.19 → 0.0.22

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.
@@ -1,64 +1,89 @@
1
1
  /**
2
2
  * 用来读取处理tms.config.js与module.config.json字段
3
3
  */
4
+ /* eslint-disable no-param-reassign, no-nested-ternary */
4
5
  const loadash = require('lodash');
5
6
  const fs = require('fs');
7
+ const path = require('path');
6
8
  const { TMS_CONFIG_FILENAME, MODULE_CONFIG_FILENAME, TMS_PRIVATE_FILENAME } = require('../config/constant');
7
- const { resolve, isObject, isArray } = require('../utils/widgets');
9
+ const { resolve, isObject, isArray, getAbsolutePath } = require('../utils/widgets');
8
10
  const defaultTmsConfig = require('../config/defaultTmsConfig');
9
11
  const { fail } = require('../utils/log');
10
12
 
11
13
  /**
12
14
  * 读取tms.config.js
13
- * @param env {string} 环境变量
15
+ * @param {string} configPath tms.config.js的路径
14
16
  */
15
- const readTmsConfig = function (env) {
16
- const tmsConfigPath = resolve(TMS_CONFIG_FILENAME);
17
+ const readTmsConfig = function (configPath) {
18
+ const tmsConfigPath = configPath ? `${configPath}/${TMS_CONFIG_FILENAME}` : resolve(TMS_CONFIG_FILENAME);
17
19
  if (!fs.existsSync(tmsConfigPath)) {
18
- fail('当前执行目录没有tms.config.js的配置项,请进行配置');
20
+ fail(`${path.dirname(tmsConfigPath)}没有找到tms.config.js,请进行配置`);
19
21
  process.exit(1);
20
22
  }
21
23
  const tmsConfigFn = require(tmsConfigPath);
22
- const tmsConfig = tmsConfigFn({
23
- env,
24
- });
24
+ const tmsConfig = typeof tmsConfigFn === 'function' ? tmsConfigFn() : tmsConfigFn;
25
25
 
26
26
  // 合并默认值
27
- return loadash.mergeWith(defaultTmsConfig, tmsConfig);
27
+ return loadash.mergeWith({}, defaultTmsConfig, tmsConfig);
28
28
  };
29
29
 
30
30
 
31
31
  /**
32
32
  * 读取tms.private.config.js
33
+ * @param {string} configPath tms.private.config.js的路径
33
34
  */
34
- const readTmsPrivateCf = function () {
35
+ const readTmsPrivateCf = function (configPath) {
35
36
  let tmsPrivateCf = {};
36
- const tmsPrivatePath = resolve(TMS_PRIVATE_FILENAME);
37
+ const tmsPrivatePath = configPath ? `${configPath}/${TMS_PRIVATE_FILENAME}` : resolve(TMS_PRIVATE_FILENAME);
37
38
  if (fs.existsSync(tmsPrivatePath)) {
38
- tmsPrivateCf = require(tmsPrivatePath);
39
+ const tmsPrivateFn = require(tmsPrivatePath);
40
+ tmsPrivateCf = typeof tmsPrivateFn === 'function' ? tmsPrivateFn() : tmsPrivateFn;
39
41
  }
40
42
 
41
43
  return tmsPrivateCf;
42
44
  };
43
45
 
44
46
  /**
45
- * tms.config.json中检索用户传入的有效modules
47
+ * 获取tms.config.js, tms.private.config.js的配置项
48
+ * @param {string} configPath config.js的路径
49
+ * @returns
50
+ */
51
+ const getTmsConfig = (configPath) => {
52
+ const tmsPrivateCf = readTmsPrivateCf(configPath);
53
+ const tmsConfig = readTmsConfig(configPath);
54
+
55
+ const modules = {};
56
+ if (Array.isArray(tmsConfig.modules)) {
57
+ modules.all = tmsConfig.modules;
58
+ tmsConfig.modules = modules;
59
+ }
60
+ // 合并默认值
61
+ const res = loadash.mergeWith(tmsConfig, tmsPrivateCf, (objValue, srcValue) => {
62
+ if (loadash.isArray(objValue) && objValue[0] && loadash.isObject(objValue[0])) {
63
+ return objValue.concat(srcValue);
64
+ }
65
+ });
66
+
67
+ return res;
68
+ };
69
+
70
+ /**
71
+ * 根据moduleNames获取modules
46
72
  * @param { object } tmsConfig
47
- * @param { array } modules
73
+ * @param { array } moduleNames
74
+ * @param {boolean} errorIsQuit 找不到配置文件是否退出
48
75
  * @returns
49
76
  */
50
- const checkModules = function (tmsConfig, modules, isQuit = false) {
77
+ const getModulesByModuleNames = function (tmsConfig, moduleNames = []) {
51
78
  const targetModules = [];
52
- modules.forEach((moduleName) => {
53
- const module = tmsConfig.modules.all.find(module => module.name === moduleName);
54
- module && targetModules.push(module);
79
+ moduleNames.forEach((moduleName) => {
80
+ const module = tmsConfig.modules.all.find(module => module.moduleName === moduleName);
81
+ if (!module) {
82
+ throw new Error(`你启动的模块${moduleName}在tms.config.js的modules.all中没有注册`);
83
+ }
84
+ targetModules.push(module);
55
85
  });
56
86
 
57
- if (targetModules.length === 0) {
58
- fail(`你启动的模块无效${modules.join(',')}无效,请检查tms.config.json>modules>${modules.join(',')}
59
- >name字段与module.config.json的name字段是否一致`);
60
- isQuit && process.exit(1);
61
- }
62
87
  return targetModules;
63
88
  };
64
89
 
@@ -79,7 +104,7 @@ function adaptMpCgContent(fileContent, appName) {
79
104
  return res;
80
105
  };
81
106
 
82
- let content = JSON.parse(fileContent);
107
+ let content = fileContent;
83
108
 
84
109
  if (isArray(content)) {
85
110
  let i = content.length - 1;
@@ -93,108 +118,175 @@ function adaptMpCgContent(fileContent, appName) {
93
118
  return content;
94
119
  }
95
120
 
121
+ const adaptDependencies = function (dependencies, subPackages) {
122
+ const newDependencies = dependencies || [];
123
+ subPackages.forEach((item) => {
124
+ if (item.dependencies) {
125
+ dependencies = newDependencies.concat(item.dependencies);
126
+ }
127
+ });
128
+ return newDependencies;
129
+ };
130
+
131
+ const adaptSubPackages = function (moduleConfig, appName) {
132
+ const subPackages = isObject(moduleConfig) && moduleConfig.subPackages
133
+ ? moduleConfig.subPackages
134
+ : isObject(moduleConfig) ? [moduleConfig] : moduleConfig;
135
+ return adaptMpCgContent(subPackages, appName);
136
+ };
137
+
96
138
  /**
97
- * 递归获取本地所有模块的配置信息
139
+ * 获取模块module.config.json中的配置信息
98
140
  * @param {array} modules 用户要编译的模块列表
99
141
  * @param { string } appName 小程序的名称
100
- * @param { string } moduleConfigFilename moduleConfig的文件名
101
142
  */
102
- function getModuleConfig(modules = [], appName, moduleConfigFilename) {
103
- const modulesConfig = {};
104
-
105
- modules.forEach(({ path }) => {
106
- const moduleConfigPath = resolve(path, moduleConfigFilename);
107
- if (fs.existsSync(moduleConfigPath)) {
108
- const content = fs.readFileSync(moduleConfigPath, 'utf-8');
109
- modulesConfig[moduleConfigPath] = adaptMpCgContent(content, appName);
143
+ function getModulesConfig(modules = [], appName) {
144
+ const modulesConfig = [];
145
+ modules.forEach((moduleItem) => {
146
+ const moduleConfigPath = resolve(moduleItem.path, MODULE_CONFIG_FILENAME);
147
+ let moduleConfig;
148
+ try {
149
+ moduleConfig = JSON.parse(fs.readFileSync(moduleConfigPath, 'utf-8'));
150
+ } catch (e) {
151
+ throw new Error(`${moduleConfigPath}json解析报错: ${e}`);
110
152
  }
153
+
154
+ // 兼容历史逻辑,后续可删除--- start
155
+ const subPackages = adaptSubPackages(moduleConfig, appName);
156
+ const dependencies = adaptDependencies(moduleConfig.dependencies, subPackages);
157
+ moduleConfig = {
158
+ ...(isObject(moduleConfig) ? moduleConfig : {}),
159
+ subPackages,
160
+ dependencies,
161
+ };
162
+ // 兼容逻辑--- end
163
+ modulesConfig.push(moduleConfig);
111
164
  });
112
165
 
113
166
  return modulesConfig;
114
167
  }
115
168
 
116
169
  /**
117
- * tms.config.js的modules 合并 module.config.json的配置项
170
+ * 获取分包内容 (读取module.config.json的配置项)
118
171
  * @param {array} modules
119
- * @param {string} appName
120
- * @param {string} moduleDir
121
172
  * @returns
122
173
  */
123
- const tmsModulesMergeLocalModuleCfg = (modules, appName) => {
124
- const newModules = [];
125
- modules.forEach(({ path: relativePath, name: moduleName }, moduleIndex) => {
126
- const moduleConfigPath = resolve(relativePath, MODULE_CONFIG_FILENAME);
127
- if (fs.existsSync(moduleConfigPath)) {
128
- try {
129
- let findModule = false;
130
- let moduleConfigContent = fs.readFileSync(moduleConfigPath, 'utf-8');
131
- moduleConfigContent = adaptMpCgContent(moduleConfigContent, appName);
132
- const moduleContentArr = isObject(moduleConfigContent) ? [moduleConfigContent] : moduleConfigContent;
133
- moduleContentArr.forEach(({ name }, moduleContentArrIndex) => {
134
- if (name === moduleName) {
135
- findModule = true;
136
- newModules.push({
137
- ...modules[moduleIndex],
138
- ...moduleContentArr[moduleContentArrIndex],
139
- });
140
- }
141
- });
142
- if (!findModule) {
143
- fail(`启动模块${moduleName}在${moduleConfigPath}没有找到,请检查配置`);
144
- process.exit(1);
145
- }
146
- } catch (e) {
147
- fail(`${moduleConfigPath}配置错误: ${e}`);
148
- newModules.push({
149
- ...modules[moduleIndex],
150
- });
151
- }
152
- } else {
153
- newModules.push({
154
- ...modules[moduleIndex],
174
+ const getSubPackages = (modules) => {
175
+ const newSubPackages = [];
176
+ modules.forEach((module) => {
177
+ (module.subPackages || []).forEach((subPackage) => {
178
+ newSubPackages.push({
179
+ ...subPackage,
155
180
  });
156
- }
181
+ });
157
182
  });
158
- return newModules;
183
+ return newSubPackages;
184
+ };
185
+
186
+ /**
187
+ * 获取分包的root字段
188
+ * @param {*} modulePath 模块的编译路径
189
+ * @param {*} root 分包的root字段
190
+ * @returns
191
+ */
192
+ const getSubPackageRoot = function (modulePath, root) {
193
+ return root.startsWith(modulePath) ? root : `${modulePath}/${root}`;
194
+ };
195
+
196
+ // 获取分包的源码路径
197
+ const getSubPackageSrcPath = function (tmsConfig, module, subPackage) {
198
+ const srcModulePath = getAbsolutePath(module.path);
199
+ const buildModulePath = resolve(tmsConfig.outputDir, module.modulePath);
200
+
201
+ const subPackageRoot = getSubPackageRoot(module.modulePath, subPackage.root);
202
+ const buildSubPackagePath = resolve(tmsConfig.outputDir, subPackageRoot);
203
+
204
+ const subPackageRelativeModule = path.relative(buildModulePath, buildSubPackagePath);
205
+ const srcSubPackagePath = path.join(srcModulePath, subPackageRelativeModule);
206
+
207
+ return srcSubPackagePath;
208
+ };
209
+
210
+ const checkModuleItem = (tmsConfig, tmsModuleItem, moduleConfig) => {
211
+ const newModuleItem = { ...tmsModuleItem, ...moduleConfig };
212
+
213
+ // 兼容逻辑
214
+ if (!newModuleItem.moduleName) newModuleItem.moduleName = newModuleItem.name;
215
+ delete newModuleItem.name;
216
+
217
+ // 参数校验-模块源码路径
218
+ if (!newModuleItem.path) {
219
+ throw new Error(`${newModuleItem.moduleName}模块没有找到path字段,请检查tms.config.js的modules.all>module>path路径`);
220
+ }
221
+
222
+ // 参数校验-模块编译路径
223
+ if (!newModuleItem.modulePath) {
224
+ throw new Error(`${newModuleItem.moduleName}模块的module.config.json中没有找到modulePath字段`);
225
+ }
226
+ // 参数校验-分包校验
227
+ for (const subPackage of newModuleItem.subPackages) {
228
+ if (!subPackage.root) {
229
+ throw new Error(`${newModuleItem.moduleName}模块的module.config.json中没有找到${subPackage.name}分包的root字段`);
230
+ }
231
+
232
+ // 参数校验-判断分包源码目录是否存在
233
+ const subPackageSrcPath = getSubPackageSrcPath(tmsConfig, newModuleItem, subPackage);
234
+ if (!subPackageSrcPath || !fs.existsSync(subPackageSrcPath)) {
235
+ throw new Error(`没有找到${newModuleItem.moduleName}模块的${subPackage.name}分包源码:${subPackageSrcPath}`);
236
+ }
237
+ subPackage.path = subPackageSrcPath;
238
+ }
239
+ return newModuleItem;
159
240
  };
160
241
 
161
242
  /**
162
- * 分包依赖了分包的模块 合并所依赖的modules
243
+ * 获取所有的模块,合并模块的依赖模块
163
244
  * @param { object } tmsConfig
164
245
  * @param {array} modules
165
- * @param {string} moduleDir
246
+ * @param {boolean} errorIsQuit 找不到配置文件是否退出
166
247
  * @returns
167
248
  */
168
- const subModulesMergeDepModules = (tmsConfig, modules) => {
169
- const moduleNames = [];
170
- modules.forEach(({ name: moduleName }) => {
171
- moduleNames.push(moduleName);
172
- });
173
- let mergeModules = modules;
174
- let isOver = true;
175
-
176
- modules.forEach(({ dependencies: dependencyModules }) => {
177
- dependencyModules?.forEach((item) => {
178
- // 如果所有模块的dep都在moduleNames内,则所有依赖都齐了
179
- // 否则递归处理,根据name找到相关配置加到modules里
180
- if (moduleNames.indexOf(item) === -1) {
181
- const tmpModules = checkModules(tmsConfig, [...new Set([item])]);
182
- if (tmpModules.length > 0) {
183
- isOver = false;
184
- mergeModules = [...mergeModules, ...tmpModules];
185
- mergeModules = tmsModulesMergeLocalModuleCfg(mergeModules, tmsConfig.appName);
249
+ const getModulesByMergeDepModules = (tmsConfig, modules, errorIsQuit = false) => {
250
+ const allModules = new Map();
251
+ function dfs(tmsConfig, modules) {
252
+ modules.forEach((moduleItem) => {
253
+ const moduleConfigPath = resolve(moduleItem.path, MODULE_CONFIG_FILENAME);
254
+ if (!fs.existsSync(moduleConfigPath)) {
255
+ if (!allModules.has(moduleItem.moduleName)) {
256
+ allModules.set(moduleItem.moduleName, moduleItem);
257
+ }
258
+ if (errorIsQuit) {
259
+ throw new Error(`${moduleItem.moduleName}模块的配置文件module.config.json在${moduleItem.path}目录下没有找到`);
260
+ }
261
+ return;
262
+ }
263
+ const [moduleConfig = {}] = getModulesConfig([moduleItem], tmsConfig.appName);
264
+
265
+ if (!allModules.has(moduleItem.moduleName)) {
266
+ allModules.set(moduleItem.moduleName, checkModuleItem(tmsConfig, moduleItem, moduleConfig));
267
+
268
+ const dependenciesModules = getModulesByModuleNames(tmsConfig, moduleConfig?.dependencies);
269
+ if (dependenciesModules.length) {
270
+ dfs(tmsConfig, dependenciesModules);
186
271
  }
187
272
  }
188
273
  });
189
- });
190
- return isOver ? mergeModules : subModulesMergeDepModules(tmsConfig, mergeModules);
274
+ }
275
+ dfs(tmsConfig, modules);
276
+
277
+ const modulesArr = [];
278
+ for (const module of allModules.values()) {
279
+ modulesArr.push(module);
280
+ }
281
+ return modulesArr;
191
282
  };
192
283
 
193
284
  module.exports = {
194
285
  readTmsConfig,
195
286
  readTmsPrivateCf,
196
- getModuleConfig,
197
- checkModules,
198
- tmsModulesMergeLocalModuleCfg,
199
- subModulesMergeDepModules,
287
+ getModulesConfig,
288
+ getModulesByModuleNames,
289
+ getSubPackages,
290
+ getModulesByMergeDepModules,
291
+ getTmsConfig,
200
292
  };
package/src/entry.js CHANGED
@@ -1,14 +1,25 @@
1
1
  module.exports = [
2
2
  {
3
- command: 'create <app-name>',
4
- description: '创建新的应用',
5
- action: (appName, cmd) => {
6
- require('./scripts/create')(appName, cmd);
3
+ command: 'create <project-name>',
4
+ description: '创建项目',
5
+ action: (projectName) => {
6
+ require('./scripts/create')(projectName);
7
+ },
8
+ },
9
+ {
10
+ command: 'install-cmd <npm-name>',
11
+ description: '安装扩展命令',
12
+ options: [
13
+ ['--registry [registry]', 'npm源'],
14
+ ],
15
+ action: (npmName, cmd) => {
16
+ const res = require('./scripts/extend-cmd');
17
+ res.installCmd(npmName, cmd);
7
18
  },
8
19
  },
9
20
  {
10
21
  name: 'run',
11
- type: 'child',
22
+ type: 'parent',
12
23
  description: '项目开发使用的命令',
13
24
  commands: [
14
25
  {
@@ -56,18 +67,6 @@ module.exports = [
56
67
  require('./scripts/run/index')('build', cmd);
57
68
  },
58
69
  },
59
- // 对外暂不暴露该命令
60
- // {
61
- // command: 'init',
62
- // description: '模块配置初始化项目(eg: 下载第三方模块代码、安装依赖、生成app.json等)',
63
- // options: [
64
- // ['-m, --module [moduleName]', '模块名称'],
65
- // ['-e, --env [env]', '环境变量'],
66
- // ],
67
- // action: (cmd) => {
68
- // require('./scripts/run/index')('init', cmd);
69
- // },
70
- // },
71
70
  ],
72
71
  },
73
72
  ];
package/src/index.js CHANGED
@@ -1,57 +1,98 @@
1
+ /* eslint-disable no-param-reassign */
1
2
  const chalk = require('chalk');
2
3
  const commander = require('commander');
3
- const { suggestCommands } = require('./utils/widgets');
4
- const { info } = require('./utils/log');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const { resolve } = require('./utils/widgets');
7
+ const { infoNoTime } = require('./utils/log');
8
+ const { getTmsConfig } = require('../src/core/tmsMpconfig');
5
9
  const { TMS_NAME } = require('./config/constant.js');
6
10
  const commands = require('./entry');
7
- const init = require('./init');
8
-
9
- init();
11
+ const check = require('./check');
12
+ const { loadExtendCmd } = require('./scripts/extend-cmd/index.js');
13
+ const report = require('./core/report');
10
14
 
15
+ check();
11
16
  const program = new commander.Command(TMS_NAME);
12
-
13
17
  program
14
18
  .version(`${TMS_NAME} ${require('../package.json').version}`, '-v, -V, --version');
15
19
 
20
+ // 注册命令底层实现
16
21
  function registerCommand(program, commands) {
17
22
  commands.forEach((cmd) => {
18
- if (cmd.type === 'child') {
23
+ if (cmd.type === 'parent') {
19
24
  const childProgram = new commander.Command(cmd.name);
20
25
  cmd.usage && childProgram.usage(cmd.usage);
21
26
  cmd.description && childProgram.description(cmd.description);
22
27
  registerCommand(childProgram, cmd.commands);
23
-
24
28
  program.addCommand(childProgram);
25
29
  } else {
26
30
  const command = program.command(cmd.command);
27
-
28
31
  cmd.usage && command.usage(cmd.usage);
29
-
30
32
  cmd.description && command.description(cmd.description);
31
-
32
33
  cmd.options?.forEach(opt => command.option(...opt));
33
-
34
+ // 上报
35
+ command.hook('preAction', (thisCommand) => {
36
+ report(`${thisCommand._name}-pre`);
37
+ });
38
+ // 上报
39
+ command.hook('postAction', (thisCommand) => {
40
+ report(`${thisCommand._name}-post`);
41
+ });
34
42
  command.action(cmd.action);
35
43
  }
36
44
  });
37
45
  }
38
46
 
39
- registerCommand(program, commands);
47
+ // 注册扩展命令
48
+ function registerExtendCommand(program, configPath) {
49
+ const tmsConfig = getTmsConfig(configPath);
50
+ if (tmsConfig?.commands) {
51
+ const commands = typeof tmsConfig.commands === 'function' ? tmsConfig.commands() : tmsConfig.commands;
52
+ if (Array.isArray(commands)) {
53
+ registerCommand(program, commands);
54
+ }
55
+ }
56
+ }
57
+ // 注册所有的命令
58
+ function registerAllCmds(program, commands) {
59
+ // 注册脚手架内部命令
60
+ registerCommand(program, commands);
40
61
 
41
- program.on('--help', () => {
42
- info(` Run ${chalk.cyan(`${TMS_NAME} <command> --help`)} for detailed usage of given command.`);
43
- });
62
+ // 注册npm包扩展命令
63
+ const cmdConfigs = loadExtendCmd();
64
+ cmdConfigs.forEach((cmdConfig) => {
65
+ registerExtendCommand(program, path.dirname(cmdConfig));
66
+ });
67
+
68
+ // 注册当前目录扩展命令
69
+ const tmsConfigPath = resolve('./tms.config.js');
70
+ if (fs.existsSync(tmsConfigPath)) {
71
+ registerExtendCommand(program, path.dirname(tmsConfigPath));
72
+ }
73
+ }
74
+ registerAllCmds(program, commands);
44
75
 
45
76
  // 捕获未注册的命令
46
77
  program
47
78
  .arguments('<command>')
79
+ .option('-c, --config <value>', '配置', (value) => {
80
+ // 注册指定配置的扩展命令
81
+ registerExtendCommand(program, path.dirname(resolve(value)));
82
+ })
48
83
  .action((cmd) => {
49
- program.outputHelp();
50
- info(` ${chalk.red(`Unknown command ${chalk.yellow(cmd)}.`)}`);
51
- suggestCommands(cmd);
52
- process.exitCode = 1;
84
+ infoNoTime(chalk.yellow(`
85
+ 没有找到${cmd}命令
86
+ 你可以通过${chalk.green('tmskit install-cmd <npm-name>')}安装扩展命令, ${chalk.green('扩展命令列表:https://www.npmjs.com/search?q=tmskit-cmd')}
87
+ 你也可以通过 ${chalk.green('tmskit <command> --config=../tms.config.js')} 指定本地的扩展命令
88
+ `));
89
+ report(`${cmd}-not-find`);
53
90
  });
54
91
 
92
+ program.on('--help', () => {
93
+ infoNoTime(`Run ${chalk.cyan(`${TMS_NAME} <command> --help`)} for detailed usage of given command.`);
94
+ });
95
+
55
96
  if (!process.argv.slice(2).length) {
56
97
  program.outputHelp();
57
98
  process.exit(-1);
@@ -3,8 +3,7 @@ const render = require('./render');
3
3
  const ask = require('./ask');
4
4
  const FILES_TO_IGNORE = require('./ignoreFiles');
5
5
 
6
-
7
- const generator = (buildDir, distDir, preMetadata) => new Promise((resolve, reject) => {
6
+ const generator = (buildDir, distDir, preMetadata = {}) => new Promise((resolve, reject) => {
8
7
  Metalsmith(buildDir)
9
8
  .metadata(preMetadata)
10
9
  .ignore(FILES_TO_IGNORE)