@appthen/cli 1.2.2 → 1.2.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appthen/cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Appthen Cli Tool",
5
5
  "files": [
6
6
  "dist",
@@ -51,6 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@alilc/lowcode-types": "^1.3.1",
54
+ "@appthen/base-generator": "^1.0.1",
54
55
  "@babel/core": "^7.24.0",
55
56
  "@babel/generator": "^7.24.0",
56
57
  "@babel/helpers": "^7.24.0",
@@ -60,20 +61,20 @@
60
61
  "@babel/preset-typescript": "^7.24.0",
61
62
  "@babel/traverse": "^7.24.0",
62
63
  "@babel/types": "^7.24.0",
63
- "babel-plugin-import": "^1.13.8",
64
- "babel-plugin-module-resolver": "^4.1.0",
65
64
  "@liangshen/youdao": "^1.0.3",
66
- "@appthen/base-generator": "^1.0.1",
67
65
  "@types/http-proxy": "^1.17.16",
68
66
  "@types/node-fetch": "^2.6.12",
69
67
  "@types/socket.io-client": "^3.0.0",
70
68
  "@weapp-core/logger": "^1.0.1",
71
69
  "adm-zip": "^0.5.12",
72
70
  "axios": "^0.27.2",
71
+ "babel-plugin-import": "^1.13.8",
72
+ "babel-plugin-module-resolver": "^4.1.0",
73
73
  "base-64": "^1.0.0",
74
74
  "bufferutil": "^4.0.8",
75
75
  "chalk": "^4.0.0",
76
76
  "change-case": "^3.1.0",
77
+ "chokidar": "^4.0.3",
77
78
  "commander": "^6.1.0",
78
79
  "cssjson": "^2.1.3",
79
80
  "execa": "9.3.1",
@@ -81,9 +82,11 @@
81
82
  "form-data": "^4.0.0",
82
83
  "fp-ts": "^2.11.9",
83
84
  "fs-extra": "^11.2.0",
85
+ "fsevents": "^2.3.3",
84
86
  "getpinyin": "^1.1.4",
85
87
  "glob": "^7.1.6",
86
88
  "http-proxy": "^1.18.1",
89
+ "inquirer": "^8.2.7",
87
90
  "minimatch": "^3.1.2",
88
91
  "nanoid": "3.3.4",
89
92
  "nanomatch": "^1.2.13",
@@ -1,321 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.TSXComplianceChecker = void 0;
30
- const parser_1 = require("@babel/parser");
31
- const traverse_1 = __importDefault(require("@babel/traverse"));
32
- const t = __importStar(require("@babel/types"));
33
- class TSXComplianceChecker {
34
- /**
35
- * 使用 AST 检查 TSX 规范
36
- */
37
- static checkTSXCompliance(content, filename) {
38
- const issues = [];
39
- try {
40
- // 使用 Babel 解析 TSX 代码
41
- const ast = (0, parser_1.parse)(content, {
42
- sourceType: 'module',
43
- plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],
44
- errorRecovery: true,
45
- });
46
- // 遍历 AST 进行检查
47
- (0, traverse_1.default)(ast, {
48
- // 检查变量声明
49
- VariableDeclarator(path) {
50
- TSXComplianceChecker.checkVariableDeclaration(path, content, issues);
51
- },
52
- // 检查方法定义
53
- ClassMethod(path) {
54
- TSXComplianceChecker.checkMethodDefinition(path, content, issues);
55
- },
56
- // 检查 JSX 使用
57
- JSXElement(path) {
58
- TSXComplianceChecker.checkJSXUsage(path, content, issues);
59
- },
60
- // 检查类型注解
61
- TSTypeAnnotation(path) {
62
- TSXComplianceChecker.checkTypeAnnotation(path, content, issues);
63
- },
64
- });
65
- // 检查必需的结构
66
- this.checkRequiredStructures(ast, content, issues);
67
- }
68
- catch (error) {
69
- issues.push({
70
- type: 'error',
71
- code: 'PARSE_ERROR',
72
- message: `代码解析失败: ${error.message}`,
73
- suggestion: '检查代码语法是否正确',
74
- });
75
- }
76
- return {
77
- isCompliant: issues.filter((issue) => issue.type === 'error').length === 0,
78
- issues,
79
- };
80
- }
81
- /**
82
- * 检查变量声明
83
- */
84
- static checkVariableDeclaration(path, content, issues) {
85
- const node = path.node;
86
- // 检查是否在 render 方法中
87
- const renderMethod = path.findParent((p) => p.isClassMethod() &&
88
- t.isIdentifier(p.node.key) &&
89
- p.node.key.name === 'render');
90
- if (!renderMethod)
91
- return;
92
- // 检查是否在事件处理函数中
93
- const isInEventHandler = this.isInEventHandler(path);
94
- if (isInEventHandler)
95
- return;
96
- // 检查是否在非 JSX 返回的回调函数中
97
- const isInNonJSXCallback = this.isInNonJSXCallback(path);
98
- if (isInNonJSXCallback)
99
- return;
100
- // 检查是否在返回 JSX 的回调函数中(如 .map())
101
- const isInJSXCallback = this.isInJSXCallback(path);
102
- if (isInJSXCallback) {
103
- // 这种情况需要报错
104
- const { line, column } = this.getLocation(path, content);
105
- const snippet = this.extractCodeSnippet(content, line);
106
- issues.push({
107
- type: 'error',
108
- code: 'CALLBACK_VARIABLE_DECLARATION',
109
- message: '返回 JSX 的回调函数中不能包含变量声明',
110
- suggestion: '将变量声明移到回调函数外部,或使用内联表达式',
111
- line,
112
- column,
113
- codeSnippet: snippet.snippet,
114
- snippetStartLine: snippet.startLine,
115
- snippetEndLine: snippet.endLine,
116
- });
117
- return;
118
- }
119
- // 其他在 render 方法中的变量声明都是错误的
120
- const { line, column } = this.getLocation(path, content);
121
- const snippet = this.extractCodeSnippet(content, line);
122
- issues.push({
123
- type: 'error',
124
- code: 'RENDER_VARIABLE_DECLARATION',
125
- message: 'render() 方法中不能包含变量声明',
126
- suggestion: '移除所有 const/let/var 声明,直接使用 this.state.xxx',
127
- line,
128
- column,
129
- codeSnippet: snippet.snippet,
130
- snippetStartLine: snippet.startLine,
131
- snippetEndLine: snippet.endLine,
132
- });
133
- }
134
- /**
135
- * 检查是否在事件处理函数中
136
- */
137
- static isInEventHandler(path) {
138
- // 查找父级 JSX 属性
139
- const jsxAttribute = path.findParent((p) => p.isJSXAttribute());
140
- if (jsxAttribute && t.isJSXIdentifier(jsxAttribute.node.name)) {
141
- const attrName = jsxAttribute.node.name.name;
142
- // 检查是否是事件处理属性(onXxx)
143
- if (/^on[A-Z]/.test(attrName)) {
144
- return true;
145
- }
146
- }
147
- // 检查是否在 addEventListener 回调中
148
- const callExpression = path.findParent((p) => p.isCallExpression());
149
- if (callExpression && t.isMemberExpression(callExpression.node.callee)) {
150
- const memberExpr = callExpression.node.callee;
151
- if (t.isIdentifier(memberExpr.property) &&
152
- memberExpr.property.name === 'addEventListener') {
153
- return true;
154
- }
155
- }
156
- return false;
157
- }
158
- /**
159
- * 检查是否在非 JSX 返回的回调函数中
160
- */
161
- static isInNonJSXCallback(path) {
162
- // 查找父级函数
163
- const parentFunction = path.findParent((p) => p.isArrowFunctionExpression() || p.isFunctionExpression());
164
- if (!parentFunction)
165
- return false;
166
- // 检查函数是否返回 JSX
167
- const returnsJSX = this.functionReturnsJSX(parentFunction);
168
- // 如果不返回 JSX,则认为是非 JSX 回调
169
- return !returnsJSX;
170
- }
171
- /**
172
- * 检查是否在返回 JSX 的回调函数中
173
- */
174
- static isInJSXCallback(path) {
175
- // 查找父级函数
176
- const parentFunction = path.findParent((p) => p.isArrowFunctionExpression() || p.isFunctionExpression());
177
- if (!parentFunction)
178
- return false;
179
- // 检查函数是否返回 JSX
180
- return this.functionReturnsJSX(parentFunction);
181
- }
182
- /**
183
- * 检查函数是否返回 JSX
184
- */
185
- static functionReturnsJSX(functionPath) {
186
- let returnsJSX = false;
187
- functionPath.traverse({
188
- ReturnStatement(path) {
189
- if (path.node.argument && t.isJSXElement(path.node.argument)) {
190
- returnsJSX = true;
191
- }
192
- },
193
- JSXElement(path) {
194
- // 如果函数体直接包含 JSX(箭头函数的隐式返回)
195
- if (path.parent === functionPath.node.body) {
196
- returnsJSX = true;
197
- }
198
- },
199
- });
200
- return returnsJSX;
201
- }
202
- /**
203
- * 检查方法定义
204
- */
205
- static checkMethodDefinition(path, content, issues) {
206
- const node = path.node;
207
- // 跳过 render 方法和渲染相关方法
208
- if (t.isIdentifier(node.key)) {
209
- const methodName = node.key.name;
210
- const renderMethods = [
211
- 'render',
212
- 'renderItem',
213
- 'renderContent',
214
- 'renderHeader',
215
- 'renderFooter',
216
- ];
217
- if (renderMethods.includes(methodName))
218
- return;
219
- // 检查方法中是否包含 JSX
220
- let containsJSX = false;
221
- path.traverse({
222
- JSXElement() {
223
- containsJSX = true;
224
- },
225
- });
226
- if (containsJSX) {
227
- const { line, column } = this.getLocation(path, content);
228
- const snippet = this.extractCodeSnippet(content, line);
229
- issues.push({
230
- type: 'error',
231
- code: 'METHOD_CONTAINS_JSX',
232
- message: `方法 ${methodName} 不能包含 JSX 语法`,
233
- suggestion: '只有 render() 方法可以包含 JSX,其他方法只处理逻辑',
234
- line,
235
- column,
236
- codeSnippet: snippet.snippet,
237
- snippetStartLine: snippet.startLine,
238
- snippetEndLine: snippet.endLine,
239
- });
240
- }
241
- }
242
- }
243
- /**
244
- * 检查 JSX 使用
245
- */
246
- static checkJSXUsage(path, content, issues) {
247
- // 暂时不实现,专注于变量声明检查
248
- }
249
- /**
250
- * 检查类型注解
251
- */
252
- static checkTypeAnnotation(path, content, issues) {
253
- // 暂时不实现,专注于变量声明检查
254
- }
255
- /**
256
- * 检查必需的结构
257
- */
258
- static checkRequiredStructures(ast, content, issues) {
259
- // 这里可以添加对必需结构的检查
260
- // 如 IProps, IState, Document 类等
261
- }
262
- /**
263
- * 获取节点在源码中的位置
264
- */
265
- static getLocation(path, content) {
266
- const loc = path.node.loc;
267
- return {
268
- line: loc ? loc.start.line : 1,
269
- column: loc ? loc.start.column : 0,
270
- };
271
- }
272
- /**
273
- * 提取代码片段
274
- */
275
- static extractCodeSnippet(content, lineNumber, contextLines = 3) {
276
- const lines = content.split('\n');
277
- const startLine = Math.max(1, lineNumber - contextLines);
278
- const endLine = Math.min(lines.length, lineNumber + contextLines);
279
- const snippetLines = [];
280
- for (let i = startLine; i <= endLine; i++) {
281
- const line = lines[i - 1] || '';
282
- const prefix = i === lineNumber ? '>>> ' : ' ';
283
- snippetLines.push(`${prefix}${i.toString().padStart(3)}: ${line}`);
284
- }
285
- return {
286
- snippet: snippetLines.join('\n'),
287
- startLine,
288
- endLine,
289
- };
290
- }
291
- /**
292
- * 生成检查报告
293
- */
294
- static generateReport(result, filename) {
295
- const { isCompliant, issues } = result;
296
- let report = '=== TSX 规范检查报告 ===\n';
297
- report += `文件: ${filename}\n`;
298
- if (isCompliant) {
299
- report += '✅ 检查通过:文件符合 TSX 规范\n';
300
- }
301
- else {
302
- const errorCount = issues.filter((issue) => issue.type === 'error').length;
303
- report += `❌ 检查失败:发现 ${errorCount} 个错误\n\n`;
304
- report += '--- 问题详情 ---\n';
305
- issues.forEach((issue, index) => {
306
- const icon = issue.type === 'error' ? '❌' : '⚠️';
307
- report += `${index + 1}. ${icon} [${issue.code}] ${issue.message}\n`;
308
- if (issue.line) {
309
- report += ` 📍 位置: 第 ${issue.line} 行\n`;
310
- }
311
- report += ` 💡 建议: ${issue.suggestion}\n`;
312
- if (issue.codeSnippet) {
313
- report += ` 📝 代码片段:\n${issue.codeSnippet}\n`;
314
- }
315
- report += '\n';
316
- });
317
- }
318
- return report;
319
- }
320
- }
321
- exports.TSXComplianceChecker = TSXComplianceChecker;