@appthen/cli 1.2.8 → 1.2.10
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/dist/index.js +224 -697
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,7 +29,6 @@ var prettier = require('prettier');
|
|
|
29
29
|
var fs$2 = require('fs-extra');
|
|
30
30
|
var io = require('socket.io-client');
|
|
31
31
|
var fs$3 = require('fs/promises');
|
|
32
|
-
var chokidar = require('chokidar');
|
|
33
32
|
var whatwgUrl = require('whatwg-url');
|
|
34
33
|
|
|
35
34
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -81,7 +80,6 @@ var fs__default$1 = /*#__PURE__*/_interopDefaultLegacy(fs$2);
|
|
|
81
80
|
var fs__namespace$1 = /*#__PURE__*/_interopNamespace(fs$2);
|
|
82
81
|
var io__default = /*#__PURE__*/_interopDefaultLegacy(io);
|
|
83
82
|
var fs__default$2 = /*#__PURE__*/_interopDefaultLegacy(fs$3);
|
|
84
|
-
var chokidar__default = /*#__PURE__*/_interopDefaultLegacy(chokidar);
|
|
85
83
|
var whatwgUrl__default = /*#__PURE__*/_interopDefaultLegacy(whatwgUrl);
|
|
86
84
|
|
|
87
85
|
/******************************************************************************
|
|
@@ -18821,8 +18819,9 @@ var request = function (url, params, _a) {
|
|
|
18821
18819
|
};
|
|
18822
18820
|
return [4 /*yield*/, axios({
|
|
18823
18821
|
method: method,
|
|
18824
|
-
url: (process.env.DEV
|
|
18825
|
-
|
|
18822
|
+
url: (process.env.DEV
|
|
18823
|
+
? 'http://127.0.0.1:1626'
|
|
18824
|
+
: 'https://editor.appthen.com') + url,
|
|
18826
18825
|
data: params,
|
|
18827
18826
|
headers: headers,
|
|
18828
18827
|
})];
|
|
@@ -37940,7 +37939,9 @@ var SocketStore = /** @class */ (function () {
|
|
|
37940
37939
|
var _this = this;
|
|
37941
37940
|
var _a = this.config, token = _a.token, onconnect = _a.onconnect, onlogined = _a.onlogined, onreconnect = _a.onreconnect; _a.onmsg;
|
|
37942
37941
|
console.log('token: ', token);
|
|
37943
|
-
var
|
|
37942
|
+
var SOCKET_SERVER = DEV_MODE$1 ? devServer : server;
|
|
37943
|
+
console.log('SOCKET_SERVER: ', SOCKET_SERVER);
|
|
37944
|
+
var socket = io__default["default"](SOCKET_SERVER, {
|
|
37944
37945
|
transports: ['websocket'],
|
|
37945
37946
|
query: {
|
|
37946
37947
|
token: token,
|
|
@@ -40667,6 +40668,7 @@ function regExpEscape (s) {
|
|
|
40667
40668
|
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
40668
40669
|
}
|
|
40669
40670
|
|
|
40671
|
+
// import chokidar, { FSWatcher } from 'chokidar';
|
|
40670
40672
|
var logger = function () { };
|
|
40671
40673
|
/**
|
|
40672
40674
|
* 影子空间管理器
|
|
@@ -41846,57 +41848,60 @@ var ShadowSpace = /** @class */ (function () {
|
|
|
41846
41848
|
* 启动文件监听
|
|
41847
41849
|
*/
|
|
41848
41850
|
ShadowSpace.prototype.startWatching = function () {
|
|
41849
|
-
var _this = this;
|
|
41850
41851
|
if (this.isWatching) {
|
|
41851
41852
|
return;
|
|
41852
41853
|
}
|
|
41853
41854
|
logger('[ShadowSpace] 监听目录:', this.config.projectRoot);
|
|
41854
41855
|
try {
|
|
41855
41856
|
// 🔥 使用轮询模式 + ignored 函数过滤
|
|
41856
|
-
this.watcher =
|
|
41857
|
-
|
|
41858
|
-
|
|
41859
|
-
|
|
41860
|
-
|
|
41861
|
-
|
|
41862
|
-
|
|
41863
|
-
|
|
41864
|
-
|
|
41865
|
-
|
|
41866
|
-
|
|
41867
|
-
|
|
41868
|
-
|
|
41869
|
-
|
|
41870
|
-
|
|
41871
|
-
|
|
41872
|
-
|
|
41873
|
-
|
|
41874
|
-
|
|
41875
|
-
|
|
41876
|
-
});
|
|
41857
|
+
// this.watcher = chokidar.watch(this.config.projectRoot, {
|
|
41858
|
+
// ignored: (filePath: string) => {
|
|
41859
|
+
// const relativePath = path.relative(this.config.projectRoot, filePath);
|
|
41860
|
+
// // 忽略根目录本身
|
|
41861
|
+
// if (!relativePath || relativePath === '.') {
|
|
41862
|
+
// return true;
|
|
41863
|
+
// }
|
|
41864
|
+
// // 使用白名单过滤
|
|
41865
|
+
// return this.shouldIgnoreFile(relativePath);
|
|
41866
|
+
// },
|
|
41867
|
+
// persistent: true,
|
|
41868
|
+
// ignoreInitial: true, // 忽略初始扫描
|
|
41869
|
+
// usePolling: true, // 🔥 macOS 上使用轮询模式(fsevents 在某些环境下不可靠)
|
|
41870
|
+
// interval: 2000, // 轮询间隔 2 秒(降低 CPU 占用)
|
|
41871
|
+
// binaryInterval: 3000, // 二进制文件轮询间隔 3 秒
|
|
41872
|
+
// depth: 99, // 监听所有子目录
|
|
41873
|
+
// awaitWriteFinish: {
|
|
41874
|
+
// stabilityThreshold: 500, // 文件稳定后 500ms 才触发
|
|
41875
|
+
// pollInterval: 100,
|
|
41876
|
+
// },
|
|
41877
|
+
// });
|
|
41877
41878
|
logger('[ShadowSpace] chokidar.watch 已调用,等待 ready 事件...');
|
|
41878
41879
|
}
|
|
41879
41880
|
catch (error) {
|
|
41880
41881
|
console.error('[ShadowSpace] 创建文件监听器失败:', error);
|
|
41881
41882
|
return;
|
|
41882
41883
|
}
|
|
41883
|
-
this.watcher
|
|
41884
|
-
|
|
41885
|
-
|
|
41886
|
-
})
|
|
41887
|
-
|
|
41888
|
-
|
|
41889
|
-
})
|
|
41890
|
-
|
|
41891
|
-
|
|
41892
|
-
})
|
|
41893
|
-
|
|
41894
|
-
|
|
41895
|
-
})
|
|
41896
|
-
|
|
41897
|
-
|
|
41898
|
-
|
|
41899
|
-
|
|
41884
|
+
// this.watcher
|
|
41885
|
+
// .on('change', (filePath: string) => {
|
|
41886
|
+
// this.onFileChanged(filePath);
|
|
41887
|
+
// })
|
|
41888
|
+
// .on('add', (filePath: string) => {
|
|
41889
|
+
// this.onFileAdded(filePath);
|
|
41890
|
+
// })
|
|
41891
|
+
// .on('unlink', (filePath: string) => {
|
|
41892
|
+
// this.onFileDeleted(filePath);
|
|
41893
|
+
// })
|
|
41894
|
+
// .on('error', (error) => {
|
|
41895
|
+
// console.error('[ShadowSpace] 文件监听错误:', error);
|
|
41896
|
+
// })
|
|
41897
|
+
// .on('ready', () => {
|
|
41898
|
+
// this.isWatching = true;
|
|
41899
|
+
// logger(
|
|
41900
|
+
// '[ShadowSpace] 文件监听已启动,正在监听:',
|
|
41901
|
+
// this.config.projectRoot
|
|
41902
|
+
// );
|
|
41903
|
+
// logger('[ShadowSpace] 监听配置: 轮询模式 (interval: 2s)');
|
|
41904
|
+
// });
|
|
41900
41905
|
};
|
|
41901
41906
|
/**
|
|
41902
41907
|
* 停止文件监听
|
|
@@ -41904,18 +41909,13 @@ var ShadowSpace = /** @class */ (function () {
|
|
|
41904
41909
|
ShadowSpace.prototype.stopWatching = function () {
|
|
41905
41910
|
return __awaiter(this, void 0, void 0, function () {
|
|
41906
41911
|
return __generator(this, function (_a) {
|
|
41907
|
-
|
|
41908
|
-
|
|
41909
|
-
if (!this.isWatching || !this.watcher) {
|
|
41910
|
-
return [2 /*return*/];
|
|
41911
|
-
}
|
|
41912
|
-
return [4 /*yield*/, this.watcher.close()];
|
|
41913
|
-
case 1:
|
|
41914
|
-
_a.sent();
|
|
41915
|
-
this.watcher = null;
|
|
41916
|
-
this.isWatching = false;
|
|
41917
|
-
return [2 /*return*/];
|
|
41912
|
+
if (!this.isWatching || !this.watcher) {
|
|
41913
|
+
return [2 /*return*/];
|
|
41918
41914
|
}
|
|
41915
|
+
// await this.watcher.close();
|
|
41916
|
+
this.watcher = null;
|
|
41917
|
+
this.isWatching = false;
|
|
41918
|
+
return [2 /*return*/];
|
|
41919
41919
|
});
|
|
41920
41920
|
});
|
|
41921
41921
|
};
|
|
@@ -47772,411 +47772,140 @@ function executeShadowSpaceDebug(options) {
|
|
|
47772
47772
|
});
|
|
47773
47773
|
}
|
|
47774
47774
|
|
|
47775
|
-
/**
|
|
47776
|
-
|
|
47777
|
-
* 同时支持CLI和编辑器使用
|
|
47778
|
-
*/
|
|
47779
|
-
var UnifiedTSXValidator = /** @class */ (function () {
|
|
47780
|
-
function UnifiedTSXValidator(debug) {
|
|
47781
|
-
if (debug === void 0) { debug = false; }
|
|
47782
|
-
this.debug = false;
|
|
47783
|
-
this.debug = debug;
|
|
47775
|
+
var TSXComplianceChecker = /** @class */ (function () {
|
|
47776
|
+
function TSXComplianceChecker() {
|
|
47784
47777
|
}
|
|
47785
47778
|
/**
|
|
47786
|
-
*
|
|
47779
|
+
* 使用 AST 检查 TSX 规范
|
|
47787
47780
|
*/
|
|
47788
|
-
|
|
47789
|
-
var _this = this;
|
|
47790
|
-
if (filename === void 0) { filename = 'unknown.tsx'; }
|
|
47791
|
-
this.content = content;
|
|
47792
|
-
this.filename = filename;
|
|
47781
|
+
TSXComplianceChecker.checkTSXCompliance = function (content, filename) {
|
|
47793
47782
|
var issues = [];
|
|
47794
47783
|
try {
|
|
47795
|
-
|
|
47784
|
+
// 使用 Babel 解析 TSX 代码
|
|
47785
|
+
var ast = parser$1.parse(content, {
|
|
47796
47786
|
sourceType: 'module',
|
|
47797
47787
|
plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],
|
|
47798
47788
|
errorRecovery: true,
|
|
47799
|
-
allowReturnOutsideFunction: true,
|
|
47800
47789
|
});
|
|
47801
|
-
|
|
47802
|
-
|
|
47803
|
-
|
|
47804
|
-
|
|
47805
|
-
|
|
47806
|
-
|
|
47807
|
-
|
|
47808
|
-
|
|
47809
|
-
|
|
47810
|
-
|
|
47811
|
-
|
|
47812
|
-
|
|
47813
|
-
|
|
47814
|
-
|
|
47815
|
-
|
|
47816
|
-
|
|
47817
|
-
|
|
47790
|
+
// 遍历 AST 进行检查
|
|
47791
|
+
traverse__default["default"](ast, {
|
|
47792
|
+
// 检查变量声明
|
|
47793
|
+
VariableDeclarator: function (path) {
|
|
47794
|
+
TSXComplianceChecker.checkVariableDeclaration(path, content, issues);
|
|
47795
|
+
},
|
|
47796
|
+
// 检查方法定义
|
|
47797
|
+
ClassMethod: function (path) {
|
|
47798
|
+
TSXComplianceChecker.checkMethodDefinition(path, content, issues);
|
|
47799
|
+
},
|
|
47800
|
+
// 检查 JSX 使用
|
|
47801
|
+
JSXElement: function (path) {
|
|
47802
|
+
TSXComplianceChecker.checkJSXUsage(path, content, issues);
|
|
47803
|
+
},
|
|
47804
|
+
// 检查类型注解
|
|
47805
|
+
TSTypeAnnotation: function (path) {
|
|
47806
|
+
TSXComplianceChecker.checkTypeAnnotation(path, content, issues);
|
|
47807
|
+
},
|
|
47808
|
+
});
|
|
47809
|
+
// 检查必需的结构
|
|
47810
|
+
this.checkRequiredStructures(ast, content, issues);
|
|
47818
47811
|
}
|
|
47819
47812
|
catch (error) {
|
|
47820
|
-
|
|
47821
|
-
|
|
47822
|
-
|
|
47823
|
-
|
|
47824
|
-
|
|
47825
|
-
|
|
47826
|
-
message: "\u4EE3\u7801\u89E3\u6790\u5931\u8D25: ".concat(error.message),
|
|
47827
|
-
suggestion: '检查代码语法是否正确',
|
|
47828
|
-
line: 1,
|
|
47829
|
-
column: 0,
|
|
47830
|
-
}],
|
|
47831
|
-
};
|
|
47832
|
-
}
|
|
47833
|
-
};
|
|
47834
|
-
/**
|
|
47835
|
-
* 检查文件结构
|
|
47836
|
-
*/
|
|
47837
|
-
UnifiedTSXValidator.prototype.checkFileStructure = function (ast, issues) {
|
|
47838
|
-
var _this = this;
|
|
47839
|
-
this.log('开始检查文件结构');
|
|
47840
|
-
var hasReactComponent = false;
|
|
47841
|
-
traverse__default["default"](ast, {
|
|
47842
|
-
ClassDeclaration: function (path) {
|
|
47843
|
-
var _a;
|
|
47844
|
-
var className = (_a = path.node.id) === null || _a === void 0 ? void 0 : _a.name;
|
|
47845
|
-
_this.log("\u53D1\u73B0\u7C7B: ".concat(className));
|
|
47846
|
-
// 检查是否有继承自React.Component的类(支持 extends Component 和 extends React.Component)
|
|
47847
|
-
if (_this.isReactComponent(path.node.superClass)) {
|
|
47848
|
-
hasReactComponent = true;
|
|
47849
|
-
_this.log("\u53D1\u73B0React\u7EC4\u4EF6\u7C7B: ".concat(className));
|
|
47850
|
-
}
|
|
47851
|
-
},
|
|
47852
|
-
});
|
|
47853
|
-
// 不再强制要求Document类,只要有React组件类即可
|
|
47854
|
-
if (!hasReactComponent) {
|
|
47855
|
-
issues.push(this.createIssue('MISSING_REACT_COMPONENT', 'error', '缺少React组件类定义,必须定义一个继承自React.Component的类', '请定义组件类,如: class MyComponent extends React.Component 或 class MyComponent extends Component', 1));
|
|
47813
|
+
issues.push({
|
|
47814
|
+
type: 'error',
|
|
47815
|
+
code: 'PARSE_ERROR',
|
|
47816
|
+
message: "\u4EE3\u7801\u89E3\u6790\u5931\u8D25: ".concat(error.message),
|
|
47817
|
+
suggestion: '检查代码语法是否正确',
|
|
47818
|
+
});
|
|
47856
47819
|
}
|
|
47820
|
+
return {
|
|
47821
|
+
isCompliant: issues.filter(function (issue) { return issue.type === 'error'; }).length === 0,
|
|
47822
|
+
issues: issues,
|
|
47823
|
+
};
|
|
47857
47824
|
};
|
|
47858
47825
|
/**
|
|
47859
|
-
*
|
|
47860
|
-
*/
|
|
47861
|
-
UnifiedTSXValidator.prototype.checkComponentDefinition = function (ast, issues) {
|
|
47862
|
-
var _this = this;
|
|
47863
|
-
this.log('开始检查组件定义');
|
|
47864
|
-
traverse__default["default"](ast, {
|
|
47865
|
-
ClassDeclaration: function (path) {
|
|
47866
|
-
var e_1, _a;
|
|
47867
|
-
var _b;
|
|
47868
|
-
// 检查所有继承自React.Component的类
|
|
47869
|
-
if (_this.isReactComponent(path.node.superClass)) {
|
|
47870
|
-
var className = (_b = path.node.id) === null || _b === void 0 ? void 0 : _b.name;
|
|
47871
|
-
_this.log("\u68C0\u67E5React\u7EC4\u4EF6\u7C7B: ".concat(className));
|
|
47872
|
-
// 检查render方法
|
|
47873
|
-
var hasRender = false;
|
|
47874
|
-
try {
|
|
47875
|
-
for (var _c = __values(path.node.body.body), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
47876
|
-
var member = _d.value;
|
|
47877
|
-
if (member.type === 'ClassMethod' && member.key.name === 'render') {
|
|
47878
|
-
hasRender = true;
|
|
47879
|
-
}
|
|
47880
|
-
// 检查constructor
|
|
47881
|
-
if (member.type === 'ClassMethod' && member.key.name === 'constructor') {
|
|
47882
|
-
issues.push(_this.createIssueFromNode('CONSTRUCTOR_NOT_ALLOWED', 'error', "".concat(className, "\u7C7B\u4E2D\u4E0D\u5141\u8BB8\u4F7F\u7528constructor"), '请使用state属性直接定义状态,使用componentDidMount进行初始化', member));
|
|
47883
|
-
}
|
|
47884
|
-
}
|
|
47885
|
-
}
|
|
47886
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
47887
|
-
finally {
|
|
47888
|
-
try {
|
|
47889
|
-
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
47890
|
-
}
|
|
47891
|
-
finally { if (e_1) throw e_1.error; }
|
|
47892
|
-
}
|
|
47893
|
-
// 移除对state属性的强制检查,React组件可以不定义state
|
|
47894
|
-
if (!hasRender) {
|
|
47895
|
-
issues.push(_this.createIssueFromNode('MISSING_RENDER_METHOD', 'error', "".concat(className, "\u7C7B\u5FC5\u987B\u5B9A\u4E49render\u65B9\u6CD5"), '请添加: render() { return <View>...</View> }', path.node));
|
|
47896
|
-
}
|
|
47897
|
-
}
|
|
47898
|
-
},
|
|
47899
|
-
});
|
|
47900
|
-
};
|
|
47901
|
-
/**
|
|
47902
|
-
* 检查render方法
|
|
47903
|
-
*/
|
|
47904
|
-
UnifiedTSXValidator.prototype.checkRenderMethod = function (ast, issues) {
|
|
47905
|
-
var _this = this;
|
|
47906
|
-
this.log('开始检查render方法');
|
|
47907
|
-
traverse__default["default"](ast, {
|
|
47908
|
-
ClassMethod: function (path) {
|
|
47909
|
-
var e_2, _a, e_3, _b;
|
|
47910
|
-
if (path.node.key.name === 'render') {
|
|
47911
|
-
var body = path.node.body.body;
|
|
47912
|
-
try {
|
|
47913
|
-
// 检查变量声明
|
|
47914
|
-
for (var body_1 = __values(body), body_1_1 = body_1.next(); !body_1_1.done; body_1_1 = body_1.next()) {
|
|
47915
|
-
var statement = body_1_1.value;
|
|
47916
|
-
if (statement.type === 'VariableDeclaration') {
|
|
47917
|
-
// 检查是否在事件处理函数中
|
|
47918
|
-
if (!_this.isInEventHandler(path)) {
|
|
47919
|
-
issues.push(_this.createIssueFromNode('RENDER_VARIABLE_DECLARATION', 'error', 'render方法中不允许声明变量', '直接使用this.state访问状态', statement));
|
|
47920
|
-
}
|
|
47921
|
-
}
|
|
47922
|
-
// 检查函数声明
|
|
47923
|
-
if (statement.type === 'FunctionDeclaration') {
|
|
47924
|
-
issues.push(_this.createIssueFromNode('RENDER_FUNCTION_DECLARATION', 'error', 'render方法中不允许声明函数', '将函数声明移到render方法外部', statement));
|
|
47925
|
-
}
|
|
47926
|
-
// 检查if语句
|
|
47927
|
-
if (statement.type === 'IfStatement') {
|
|
47928
|
-
issues.push(_this.createIssueFromNode('RENDER_IF_STATEMENT', 'error', 'render方法中不允许使用if语句进行条件渲染', '请使用JSX中的条件渲染语法 {condition && <View>}', statement));
|
|
47929
|
-
}
|
|
47930
|
-
}
|
|
47931
|
-
}
|
|
47932
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
47933
|
-
finally {
|
|
47934
|
-
try {
|
|
47935
|
-
if (body_1_1 && !body_1_1.done && (_a = body_1.return)) _a.call(body_1);
|
|
47936
|
-
}
|
|
47937
|
-
finally { if (e_2) throw e_2.error; }
|
|
47938
|
-
}
|
|
47939
|
-
// 检查是否有return语句
|
|
47940
|
-
var hasReturn = false;
|
|
47941
|
-
try {
|
|
47942
|
-
for (var body_2 = __values(body), body_2_1 = body_2.next(); !body_2_1.done; body_2_1 = body_2.next()) {
|
|
47943
|
-
var statement = body_2_1.value;
|
|
47944
|
-
if (statement.type === 'ReturnStatement') {
|
|
47945
|
-
hasReturn = true;
|
|
47946
|
-
break;
|
|
47947
|
-
}
|
|
47948
|
-
}
|
|
47949
|
-
}
|
|
47950
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
47951
|
-
finally {
|
|
47952
|
-
try {
|
|
47953
|
-
if (body_2_1 && !body_2_1.done && (_b = body_2.return)) _b.call(body_2);
|
|
47954
|
-
}
|
|
47955
|
-
finally { if (e_3) throw e_3.error; }
|
|
47956
|
-
}
|
|
47957
|
-
if (!hasReturn) {
|
|
47958
|
-
issues.push(_this.createIssueFromNode('MISSING_RETURN', 'error', 'render方法必须返回JSX元素', '请在render方法末尾添加return语句', path.node));
|
|
47959
|
-
}
|
|
47960
|
-
}
|
|
47961
|
-
},
|
|
47962
|
-
});
|
|
47963
|
-
};
|
|
47964
|
-
/**
|
|
47965
|
-
* 检查变量声明 - 兼容TSXComplianceChecker的逻辑
|
|
47966
|
-
*/
|
|
47967
|
-
UnifiedTSXValidator.prototype.checkVariableDeclarations = function (ast, issues) {
|
|
47968
|
-
var _this = this;
|
|
47969
|
-
this.log('开始检查变量声明');
|
|
47970
|
-
traverse__default["default"](ast, {
|
|
47971
|
-
VariableDeclarator: function (path) {
|
|
47972
|
-
// 检查是否在 render 方法中
|
|
47973
|
-
var renderMethod = path.findParent(function (p) {
|
|
47974
|
-
return p.isClassMethod() &&
|
|
47975
|
-
t__namespace.isIdentifier(p.node.key) &&
|
|
47976
|
-
p.node.key.name === 'render';
|
|
47977
|
-
});
|
|
47978
|
-
if (!renderMethod)
|
|
47979
|
-
return;
|
|
47980
|
-
// 检查是否在事件处理函数中
|
|
47981
|
-
if (_this.isInEventHandler(path))
|
|
47982
|
-
return;
|
|
47983
|
-
// 检查是否在非JSX回调函数中
|
|
47984
|
-
if (_this.isInNonJSXCallback(path))
|
|
47985
|
-
return;
|
|
47986
|
-
// 检查是否在返回JSX的回调函数中
|
|
47987
|
-
if (_this.isInJSXCallback(path)) {
|
|
47988
|
-
issues.push(_this.createIssueFromNode('CALLBACK_VARIABLE_DECLARATION', 'error', '返回JSX的回调函数中不能包含变量声明', '将变量声明移到回调函数外部,或使用内联表达式', path.node));
|
|
47989
|
-
return;
|
|
47990
|
-
}
|
|
47991
|
-
// 其他在render方法中的变量声明都是错误的
|
|
47992
|
-
issues.push(_this.createIssueFromNode('RENDER_VARIABLE_DECLARATION', 'error', 'render()方法中不能包含变量声明', '移除所有const/let/var声明,直接使用this.state.xxx', path.node));
|
|
47993
|
-
},
|
|
47994
|
-
});
|
|
47995
|
-
};
|
|
47996
|
-
/**
|
|
47997
|
-
* 检查条件渲染
|
|
47998
|
-
*/
|
|
47999
|
-
UnifiedTSXValidator.prototype.checkConditionalRendering = function (ast, issues) {
|
|
48000
|
-
var _this = this;
|
|
48001
|
-
this.log('开始检查条件渲染');
|
|
48002
|
-
traverse__default["default"](ast, {
|
|
48003
|
-
JSXExpressionContainer: function (path) {
|
|
48004
|
-
var expression = path.node.expression;
|
|
48005
|
-
if (expression.type === 'LogicalExpression') {
|
|
48006
|
-
// 检查右侧是否包含JSX元素
|
|
48007
|
-
var hasJSXInRight = _this.hasJSXInNode(expression.right);
|
|
48008
|
-
if (hasJSXInRight && expression.operator !== '&&') {
|
|
48009
|
-
issues.push(_this.createIssueFromNode('INVALID_CONDITIONAL_OPERATOR', 'error', '条件渲染必须使用&&运算符,不支持其他运算符', '请使用 && 运算符进行条件渲染', path.node));
|
|
48010
|
-
}
|
|
48011
|
-
if (hasJSXInRight && expression.left.type === 'Identifier') {
|
|
48012
|
-
issues.push(_this.createIssueFromNode('VARIABLE_IN_CONDITIONAL', 'error', '条件渲染中不允许使用变量', '请直接使用this.state访问状态', path.node));
|
|
48013
|
-
}
|
|
48014
|
-
}
|
|
48015
|
-
},
|
|
48016
|
-
});
|
|
48017
|
-
};
|
|
48018
|
-
/**
|
|
48019
|
-
* 检查列表渲染
|
|
48020
|
-
*/
|
|
48021
|
-
UnifiedTSXValidator.prototype.checkListRendering = function (ast, issues) {
|
|
48022
|
-
var _this = this;
|
|
48023
|
-
this.log('开始检查列表渲染');
|
|
48024
|
-
traverse__default["default"](ast, {
|
|
48025
|
-
CallExpression: function (path) {
|
|
48026
|
-
if (path.node.callee.type === 'MemberExpression' &&
|
|
48027
|
-
path.node.callee.property.name === 'map') {
|
|
48028
|
-
// 检查是否在render方法的JSX中使用
|
|
48029
|
-
if (_this.isInRenderJSX(path)) {
|
|
48030
|
-
var parent_1 = path.parentPath;
|
|
48031
|
-
if (parent_1.node.type === 'VariableDeclaration') {
|
|
48032
|
-
issues.push(_this.createIssueFromNode('LIST_RENDER_VARIABLE', 'error', '列表渲染中不允许使用变量', '请直接使用map方法渲染', path.node));
|
|
48033
|
-
}
|
|
48034
|
-
}
|
|
48035
|
-
}
|
|
48036
|
-
},
|
|
48037
|
-
});
|
|
48038
|
-
};
|
|
48039
|
-
/**
|
|
48040
|
-
* 检查样式使用
|
|
48041
|
-
*/
|
|
48042
|
-
UnifiedTSXValidator.prototype.checkStyleUsage = function (ast, issues) {
|
|
48043
|
-
var _this = this;
|
|
48044
|
-
this.log('开始检查样式使用');
|
|
48045
|
-
traverse__default["default"](ast, {
|
|
48046
|
-
JSXAttribute: function (path) {
|
|
48047
|
-
var _a;
|
|
48048
|
-
if (path.node.name.name === 'inlineStyle') {
|
|
48049
|
-
var parent_2 = path.parentPath.node;
|
|
48050
|
-
var componentName = (_a = parent_2.name) === null || _a === void 0 ? void 0 : _a.name;
|
|
48051
|
-
if (componentName !== 'View' && componentName !== 'Text') {
|
|
48052
|
-
issues.push(_this.createIssueFromNode('INVALID_INLINE_STYLE', 'error', 'inlineStyle属性仅支持View和Text组件使用', '请检查组件类型或使用其他样式属性', path.node));
|
|
48053
|
-
}
|
|
48054
|
-
}
|
|
48055
|
-
},
|
|
48056
|
-
});
|
|
48057
|
-
};
|
|
48058
|
-
/**
|
|
48059
|
-
* 检查状态管理
|
|
47826
|
+
* 检查变量声明
|
|
48060
47827
|
*/
|
|
48061
|
-
|
|
48062
|
-
|
|
48063
|
-
|
|
48064
|
-
|
|
48065
|
-
|
|
48066
|
-
if (_this.isDirectStateMutation(path.node.left)) {
|
|
48067
|
-
issues.push(_this.createIssueFromNode('DIRECT_STATE_MUTATION', 'error', '不允许直接修改state', '请使用this.setState方法', path.node));
|
|
48068
|
-
}
|
|
48069
|
-
},
|
|
48070
|
-
});
|
|
47828
|
+
TSXComplianceChecker.checkVariableDeclaration = function (path, content, issues) {
|
|
47829
|
+
// 现在的代码生成策略允许在 render 中声明变量(用于变量提升),
|
|
47830
|
+
// 也允许在 map 回调中声明变量(用于循环内部变量)。
|
|
47831
|
+
// 因此,不再对 render 方法内的变量声明进行限制。
|
|
47832
|
+
return;
|
|
48071
47833
|
};
|
|
48072
47834
|
/**
|
|
48073
|
-
*
|
|
47835
|
+
* 检查是否在事件处理函数中
|
|
48074
47836
|
*/
|
|
48075
|
-
|
|
48076
|
-
|
|
48077
|
-
this.log('开始检查数据源使用');
|
|
48078
|
-
traverse__default["default"](ast, {
|
|
48079
|
-
CallExpression: function (path) {
|
|
48080
|
-
var _a;
|
|
48081
|
-
if (_this.isDataSourceLoadCall(path.node)) {
|
|
48082
|
-
var isInRender = false;
|
|
48083
|
-
var isInCallback = false;
|
|
48084
|
-
var currentPath = path;
|
|
48085
|
-
while (currentPath) {
|
|
48086
|
-
var node = currentPath.node;
|
|
48087
|
-
if (node.type === 'ClassMethod' && ((_a = node.key) === null || _a === void 0 ? void 0 : _a.name) === 'render') {
|
|
48088
|
-
isInRender = true;
|
|
48089
|
-
}
|
|
48090
|
-
if ((node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression')) {
|
|
48091
|
-
var parentPath = currentPath.parentPath;
|
|
48092
|
-
if ((parentPath === null || parentPath === void 0 ? void 0 : parentPath.node.type) === 'JSXExpressionContainer') {
|
|
48093
|
-
isInCallback = true;
|
|
48094
|
-
break;
|
|
48095
|
-
}
|
|
48096
|
-
}
|
|
48097
|
-
currentPath = currentPath.parentPath;
|
|
48098
|
-
}
|
|
48099
|
-
if (isInRender && !isInCallback) {
|
|
48100
|
-
issues.push(_this.createIssueFromNode('DATA_SOURCE_IN_RENDER', 'error', 'render方法中不允许直接调用数据源', '请在回调函数中调用数据源', path.node));
|
|
48101
|
-
}
|
|
48102
|
-
}
|
|
48103
|
-
},
|
|
48104
|
-
});
|
|
48105
|
-
};
|
|
48106
|
-
// ========== 辅助方法 ==========
|
|
48107
|
-
UnifiedTSXValidator.prototype.isReactComponent = function (superClass) {
|
|
48108
|
-
if (!superClass)
|
|
48109
|
-
return false;
|
|
48110
|
-
// 支持 extends React.Component
|
|
48111
|
-
if (superClass.type === 'MemberExpression' &&
|
|
48112
|
-
superClass.object.name === 'React' &&
|
|
48113
|
-
superClass.property.name === 'Component') {
|
|
48114
|
-
return true;
|
|
48115
|
-
}
|
|
48116
|
-
// 支持 extends Component 和 extends Component<IProps, IState>
|
|
48117
|
-
// 泛型参数不会影响标识符本身的识别
|
|
48118
|
-
if (superClass.type === 'Identifier' &&
|
|
48119
|
-
superClass.name === 'Component') {
|
|
48120
|
-
return true;
|
|
48121
|
-
}
|
|
48122
|
-
// 额外检查:如果父节点是TSExpressionWithTypeArguments,检查其expression
|
|
48123
|
-
// 这种情况出现在 extends Component<IProps, IState> 中
|
|
48124
|
-
if (superClass.type === 'TSExpressionWithTypeArguments' &&
|
|
48125
|
-
superClass.expression &&
|
|
48126
|
-
superClass.expression.type === 'Identifier' &&
|
|
48127
|
-
superClass.expression.name === 'Component') {
|
|
48128
|
-
return true;
|
|
48129
|
-
}
|
|
48130
|
-
return false;
|
|
48131
|
-
};
|
|
48132
|
-
UnifiedTSXValidator.prototype.isReactComponentSuperClass = function (path) {
|
|
48133
|
-
var superClass = path.node.superClass;
|
|
48134
|
-
return this.isReactComponent(superClass);
|
|
48135
|
-
};
|
|
48136
|
-
UnifiedTSXValidator.prototype.hasJSXInNode = function (node) {
|
|
48137
|
-
if (!node)
|
|
48138
|
-
return false;
|
|
48139
|
-
if (node.type === 'JSXElement' || node.type === 'JSXFragment')
|
|
48140
|
-
return true;
|
|
48141
|
-
if (node.type === 'ConditionalExpression') {
|
|
48142
|
-
return this.hasJSXInNode(node.consequent) || this.hasJSXInNode(node.alternate);
|
|
48143
|
-
}
|
|
48144
|
-
return false;
|
|
48145
|
-
};
|
|
48146
|
-
UnifiedTSXValidator.prototype.isInEventHandler = function (path) {
|
|
47837
|
+
TSXComplianceChecker.isInEventHandler = function (path) {
|
|
47838
|
+
// 查找父级 JSX 属性
|
|
48147
47839
|
var jsxAttribute = path.findParent(function (p) { return p.isJSXAttribute(); });
|
|
48148
47840
|
if (jsxAttribute && t__namespace.isJSXIdentifier(jsxAttribute.node.name)) {
|
|
48149
47841
|
var attrName = jsxAttribute.node.name.name;
|
|
47842
|
+
// 检查是否是事件处理属性(onXxx)
|
|
48150
47843
|
if (/^on[A-Z]/.test(attrName)) {
|
|
48151
47844
|
return true;
|
|
48152
47845
|
}
|
|
48153
47846
|
}
|
|
47847
|
+
// 检查是否在 addEventListener 回调中
|
|
47848
|
+
var callExpression = path.findParent(function (p) { return p.isCallExpression(); });
|
|
47849
|
+
if (callExpression && t__namespace.isMemberExpression(callExpression.node.callee)) {
|
|
47850
|
+
var memberExpr = callExpression.node.callee;
|
|
47851
|
+
if (t__namespace.isIdentifier(memberExpr.property) &&
|
|
47852
|
+
memberExpr.property.name === 'addEventListener') {
|
|
47853
|
+
return true;
|
|
47854
|
+
}
|
|
47855
|
+
}
|
|
48154
47856
|
return false;
|
|
48155
47857
|
};
|
|
48156
|
-
|
|
47858
|
+
/**
|
|
47859
|
+
* 检查是否在非 JSX 返回的回调函数中
|
|
47860
|
+
*/
|
|
47861
|
+
TSXComplianceChecker.isInNonJSXCallback = function (path) {
|
|
47862
|
+
// 查找父级函数
|
|
48157
47863
|
var parentFunction = path.findParent(function (p) { return p.isArrowFunctionExpression() || p.isFunctionExpression(); });
|
|
48158
47864
|
if (!parentFunction)
|
|
48159
47865
|
return false;
|
|
48160
|
-
|
|
47866
|
+
// 检查是否在 JSX 属性回调中(如 beforeUpload, customRequest 等)
|
|
47867
|
+
var jsxAttribute = parentFunction.findParent(function (p) {
|
|
47868
|
+
return p.isJSXAttribute();
|
|
47869
|
+
});
|
|
48161
47870
|
if (jsxAttribute && t__namespace.isJSXIdentifier(jsxAttribute.node.name)) {
|
|
48162
47871
|
var attrName = jsxAttribute.node.name.name;
|
|
47872
|
+
// 这些属性通常不返回 JSX
|
|
48163
47873
|
var nonJSXAttributes = [
|
|
48164
|
-
'beforeUpload',
|
|
48165
|
-
'
|
|
47874
|
+
'beforeUpload',
|
|
47875
|
+
'customRequest',
|
|
47876
|
+
'onChange',
|
|
47877
|
+
'onFinish',
|
|
47878
|
+
'onSubmit',
|
|
47879
|
+
'onSuccess',
|
|
47880
|
+
'onError',
|
|
47881
|
+
'onProgress',
|
|
47882
|
+
'request',
|
|
47883
|
+
'dataHandler',
|
|
48166
47884
|
];
|
|
48167
47885
|
if (nonJSXAttributes.includes(attrName)) {
|
|
48168
47886
|
return true;
|
|
48169
47887
|
}
|
|
48170
47888
|
}
|
|
48171
|
-
|
|
47889
|
+
// 检查函数是否返回 JSX
|
|
47890
|
+
var returnsJSX = this.functionReturnsJSX(parentFunction);
|
|
47891
|
+
// 如果不返回 JSX,则认为是非 JSX 回调
|
|
47892
|
+
return !returnsJSX;
|
|
48172
47893
|
};
|
|
48173
|
-
|
|
47894
|
+
/**
|
|
47895
|
+
* 检查是否在返回 JSX 的回调函数中
|
|
47896
|
+
*/
|
|
47897
|
+
TSXComplianceChecker.isInJSXCallback = function (path) {
|
|
47898
|
+
// 查找父级函数
|
|
48174
47899
|
var parentFunction = path.findParent(function (p) { return p.isArrowFunctionExpression() || p.isFunctionExpression(); });
|
|
48175
47900
|
if (!parentFunction)
|
|
48176
47901
|
return false;
|
|
47902
|
+
// 检查函数是否返回 JSX
|
|
48177
47903
|
return this.functionReturnsJSX(parentFunction);
|
|
48178
47904
|
};
|
|
48179
|
-
|
|
47905
|
+
/**
|
|
47906
|
+
* 检查函数是否返回 JSX
|
|
47907
|
+
*/
|
|
47908
|
+
TSXComplianceChecker.functionReturnsJSX = function (functionPath) {
|
|
48180
47909
|
var returnsJSX = false;
|
|
48181
47910
|
functionPath.traverse({
|
|
48182
47911
|
ReturnStatement: function (path) {
|
|
@@ -48185,6 +47914,7 @@ var UnifiedTSXValidator = /** @class */ (function () {
|
|
|
48185
47914
|
}
|
|
48186
47915
|
},
|
|
48187
47916
|
JSXElement: function (path) {
|
|
47917
|
+
// 如果函数体直接包含 JSX(箭头函数的隐式返回)
|
|
48188
47918
|
if (path.parent === functionPath.node.body) {
|
|
48189
47919
|
returnsJSX = true;
|
|
48190
47920
|
}
|
|
@@ -48192,280 +47922,76 @@ var UnifiedTSXValidator = /** @class */ (function () {
|
|
|
48192
47922
|
});
|
|
48193
47923
|
return returnsJSX;
|
|
48194
47924
|
};
|
|
48195
|
-
UnifiedTSXValidator.prototype.isInRenderJSX = function (path) {
|
|
48196
|
-
var isInRender = false;
|
|
48197
|
-
var isInJSX = false;
|
|
48198
|
-
var currentPath = path;
|
|
48199
|
-
while (currentPath) {
|
|
48200
|
-
if (currentPath.node.type === 'ClassMethod' && currentPath.node.key.name === 'render') {
|
|
48201
|
-
isInRender = true;
|
|
48202
|
-
}
|
|
48203
|
-
if (currentPath.node.type === 'JSXExpressionContainer') {
|
|
48204
|
-
isInJSX = true;
|
|
48205
|
-
}
|
|
48206
|
-
currentPath = currentPath.parentPath;
|
|
48207
|
-
}
|
|
48208
|
-
return isInRender && isInJSX;
|
|
48209
|
-
};
|
|
48210
|
-
UnifiedTSXValidator.prototype.isDirectStateMutation = function (left) {
|
|
48211
|
-
return (left.type === 'MemberExpression' &&
|
|
48212
|
-
left.object.type === 'MemberExpression' &&
|
|
48213
|
-
left.object.object.type === 'ThisExpression' &&
|
|
48214
|
-
left.object.property.name === 'state');
|
|
48215
|
-
};
|
|
48216
|
-
UnifiedTSXValidator.prototype.isDataSourceLoadCall = function (node) {
|
|
48217
|
-
return (node.callee.type === 'MemberExpression' &&
|
|
48218
|
-
node.callee.object.type === 'MemberExpression' &&
|
|
48219
|
-
node.callee.object.object.type === 'MemberExpression' &&
|
|
48220
|
-
node.callee.object.object.object.type === 'ThisExpression' &&
|
|
48221
|
-
node.callee.object.object.property.name === 'dataSourceMap' &&
|
|
48222
|
-
node.callee.property.name === 'load');
|
|
48223
|
-
};
|
|
48224
|
-
UnifiedTSXValidator.prototype.createIssueFromNode = function (code, type, message, suggestion, node) {
|
|
48225
|
-
var loc = node.loc;
|
|
48226
|
-
return {
|
|
48227
|
-
type: type,
|
|
48228
|
-
code: code,
|
|
48229
|
-
message: message,
|
|
48230
|
-
suggestion: suggestion,
|
|
48231
|
-
line: loc ? loc.start.line : 1,
|
|
48232
|
-
column: loc ? loc.start.column : 0,
|
|
48233
|
-
};
|
|
48234
|
-
};
|
|
48235
|
-
UnifiedTSXValidator.prototype.createIssue = function (code, type, message, suggestion, line, column) {
|
|
48236
|
-
if (column === void 0) { column = 0; }
|
|
48237
|
-
return {
|
|
48238
|
-
type: type,
|
|
48239
|
-
code: code,
|
|
48240
|
-
message: message,
|
|
48241
|
-
suggestion: suggestion,
|
|
48242
|
-
line: line,
|
|
48243
|
-
column: column,
|
|
48244
|
-
};
|
|
48245
|
-
};
|
|
48246
47925
|
/**
|
|
48247
|
-
*
|
|
47926
|
+
* 检查方法定义
|
|
48248
47927
|
*/
|
|
48249
|
-
|
|
48250
|
-
var
|
|
48251
|
-
|
|
48252
|
-
|
|
48253
|
-
|
|
48254
|
-
|
|
48255
|
-
|
|
48256
|
-
|
|
48257
|
-
|
|
48258
|
-
|
|
48259
|
-
|
|
48260
|
-
|
|
48261
|
-
|
|
48262
|
-
if (member.type === 'ClassMethod') {
|
|
48263
|
-
var methodName_1 = (_a = member.key) === null || _a === void 0 ? void 0 : _a.name;
|
|
48264
|
-
// 跳过render方法的TypeScript语法检查(render方法本身已经单独处理)
|
|
48265
|
-
if (methodName_1 === 'render')
|
|
48266
|
-
return;
|
|
48267
|
-
// 检查方法参数中的TypeScript语法
|
|
48268
|
-
member.params.forEach(function (param, index) {
|
|
48269
|
-
// 检查是否有类型注解
|
|
48270
|
-
if (param.typeAnnotation) {
|
|
48271
|
-
issues.push(_this.createIssueFromNode('TYPESCRIPT_IN_METHOD_PARAMS', 'error', "\u65B9\u6CD5 ".concat(methodName_1, " \u7684\u7B2C ").concat(index + 1, " \u4E2A\u53C2\u6570\u5305\u542BTypeScript\u7C7B\u578B\u6CE8\u89E3"), "\u8BF7\u79FB\u9664\u53C2\u6570\u7684\u7C7B\u578B\u6CE8\u89E3\uFF0C\u4F7F\u7528\u7EAFJavaScript\u8BED\u6CD5\uFF0C\u5982\u5C06 '".concat(param.name.name || param.name, ": string' \u6539\u4E3A '").concat(param.name.name || param.name, "'"), param));
|
|
48272
|
-
}
|
|
48273
|
-
});
|
|
48274
|
-
// 检查方法返回值的TypeScript语法
|
|
48275
|
-
if (member.returnType) {
|
|
48276
|
-
issues.push(_this.createIssueFromNode('TYPESCRIPT_IN_RETURN_TYPE', 'error', "\u65B9\u6CD5 ".concat(methodName_1, " \u5305\u542BTypeScript\u8FD4\u56DE\u503C\u7C7B\u578B\u6CE8\u89E3"), "\u8BF7\u79FB\u9664\u8FD4\u56DE\u503C\u7684\u7C7B\u578B\u6CE8\u89E3\uFF0C\u4F7F\u7528\u7EAFJavaScript\u8BED\u6CD5", member));
|
|
48277
|
-
}
|
|
48278
|
-
// 检查方法中是否包含JSX返回
|
|
48279
|
-
if (_this.methodContainsJSX(member)) {
|
|
48280
|
-
issues.push(_this.createIssueFromNode('METHOD_CONTAINS_JSX', 'error', "\u65B9\u6CD5 ".concat(methodName_1, " \u4E0D\u80FD\u5305\u542B JSX \u8BED\u6CD5"), '只有 render() 方法可以包含 JSX,其他方法只处理逻辑', member));
|
|
48281
|
-
}
|
|
48282
|
-
// 检查方法体中的变量声明的TypeScript语法
|
|
48283
|
-
// 直接遍历AST节点而不使用traverse
|
|
48284
|
-
_this.checkVariableTypeAnnotationsInNode(member, methodName_1, issues);
|
|
48285
|
-
}
|
|
48286
|
-
});
|
|
48287
|
-
}
|
|
48288
|
-
},
|
|
48289
|
-
});
|
|
48290
|
-
};
|
|
48291
|
-
/**
|
|
48292
|
-
* 检查方法中是否包含JSX语法
|
|
48293
|
-
*/
|
|
48294
|
-
UnifiedTSXValidator.prototype.methodContainsJSX = function (methodNode) {
|
|
48295
|
-
var e_4, _a;
|
|
48296
|
-
if (!methodNode || !methodNode.body)
|
|
48297
|
-
return false;
|
|
48298
|
-
var containsJSX = false;
|
|
48299
|
-
var checkJSX = function (node) {
|
|
48300
|
-
if (!node)
|
|
47928
|
+
TSXComplianceChecker.checkMethodDefinition = function (path, content, issues) {
|
|
47929
|
+
var node = path.node;
|
|
47930
|
+
// 跳过 render 方法和渲染相关方法
|
|
47931
|
+
if (t__namespace.isIdentifier(node.key)) {
|
|
47932
|
+
var methodName = node.key.name;
|
|
47933
|
+
var renderMethods = [
|
|
47934
|
+
'render',
|
|
47935
|
+
'renderItem',
|
|
47936
|
+
'renderContent',
|
|
47937
|
+
'renderHeader',
|
|
47938
|
+
'renderFooter',
|
|
47939
|
+
];
|
|
47940
|
+
if (renderMethods.includes(methodName))
|
|
48301
47941
|
return;
|
|
48302
|
-
|
|
48303
|
-
|
|
48304
|
-
|
|
48305
|
-
|
|
48306
|
-
|
|
48307
|
-
|
|
48308
|
-
if (node[key] && typeof node[key] === 'object') {
|
|
48309
|
-
if (checkJSX(node[key])) {
|
|
48310
|
-
return true;
|
|
48311
|
-
}
|
|
48312
|
-
}
|
|
48313
|
-
}
|
|
48314
|
-
return false;
|
|
48315
|
-
};
|
|
48316
|
-
// 检查方法体中的所有语句
|
|
48317
|
-
if (Array.isArray(methodNode.body.body)) {
|
|
48318
|
-
try {
|
|
48319
|
-
for (var _b = __values(methodNode.body.body), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
48320
|
-
var statement = _c.value;
|
|
48321
|
-
if (checkJSX(statement)) {
|
|
48322
|
-
return true;
|
|
48323
|
-
}
|
|
48324
|
-
}
|
|
48325
|
-
}
|
|
48326
|
-
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
48327
|
-
finally {
|
|
48328
|
-
try {
|
|
48329
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
48330
|
-
}
|
|
48331
|
-
finally { if (e_4) throw e_4.error; }
|
|
48332
|
-
}
|
|
48333
|
-
}
|
|
48334
|
-
else if (methodNode.body) {
|
|
48335
|
-
if (checkJSX(methodNode.body)) {
|
|
48336
|
-
return true;
|
|
48337
|
-
}
|
|
48338
|
-
}
|
|
48339
|
-
return containsJSX;
|
|
48340
|
-
};
|
|
48341
|
-
/**
|
|
48342
|
-
* 递归检查节点中的变量类型注解
|
|
48343
|
-
*/
|
|
48344
|
-
UnifiedTSXValidator.prototype.checkVariableTypeAnnotationsInNode = function (node, methodName, issues) {
|
|
48345
|
-
var _this = this;
|
|
48346
|
-
if (!node)
|
|
48347
|
-
return;
|
|
48348
|
-
// 如果是数组,遍历每个元素
|
|
48349
|
-
if (Array.isArray(node)) {
|
|
48350
|
-
node.forEach(function (item) { return _this.checkVariableTypeAnnotationsInNode(item, methodName, issues); });
|
|
48351
|
-
return;
|
|
48352
|
-
}
|
|
48353
|
-
// 检查变量声明
|
|
48354
|
-
if (node.type === 'VariableDeclaration') {
|
|
48355
|
-
node.declarations.forEach(function (declaration) {
|
|
48356
|
-
if (declaration.id && declaration.id.typeAnnotation) {
|
|
48357
|
-
issues.push(_this.createIssueFromNode('TYPESCRIPT_IN_VARIABLES', 'error', "\u65B9\u6CD5 ".concat(methodName, " \u4E2D\u7684\u53D8\u91CF\u58F0\u660E\u5305\u542BTypeScript\u7C7B\u578B\u6CE8\u89E3"), "\u8BF7\u79FB\u9664\u53D8\u91CF\u7684\u7C7B\u578B\u6CE8\u89E3\uFF0C\u4F7F\u7528\u7EAFJavaScript\u8BED\u6CD5\uFF0C\u5982\u5C06 'let name: string' \u6539\u4E3A 'let name'", declaration));
|
|
48358
|
-
}
|
|
47942
|
+
// 检查方法中是否包含 JSX
|
|
47943
|
+
var containsJSX_1 = false;
|
|
47944
|
+
path.traverse({
|
|
47945
|
+
JSXElement: function () {
|
|
47946
|
+
containsJSX_1 = true;
|
|
47947
|
+
},
|
|
48359
47948
|
});
|
|
48360
|
-
|
|
48361
|
-
|
|
48362
|
-
|
|
48363
|
-
|
|
48364
|
-
|
|
48365
|
-
|
|
48366
|
-
|
|
48367
|
-
|
|
48368
|
-
|
|
48369
|
-
|
|
48370
|
-
|
|
48371
|
-
|
|
48372
|
-
|
|
48373
|
-
|
|
48374
|
-
|
|
48375
|
-
this.checkVariableTypeAnnotationsInNode(node.expression, methodName, issues);
|
|
47949
|
+
if (containsJSX_1) {
|
|
47950
|
+
var _a = this.getLocation(path, content), line = _a.line, column = _a.column;
|
|
47951
|
+
var snippet = this.extractCodeSnippet(content, line);
|
|
47952
|
+
issues.push({
|
|
47953
|
+
type: 'error',
|
|
47954
|
+
code: 'METHOD_CONTAINS_JSX',
|
|
47955
|
+
message: "\u65B9\u6CD5 ".concat(methodName, " \u4E0D\u80FD\u5305\u542B JSX \u8BED\u6CD5"),
|
|
47956
|
+
suggestion: '只有 render() 方法可以包含 JSX,其他方法只处理逻辑',
|
|
47957
|
+
line: line,
|
|
47958
|
+
column: column,
|
|
47959
|
+
codeSnippet: snippet.snippet,
|
|
47960
|
+
snippetStartLine: snippet.startLine,
|
|
47961
|
+
snippetEndLine: snippet.endLine,
|
|
47962
|
+
});
|
|
47963
|
+
}
|
|
48376
47964
|
}
|
|
48377
47965
|
};
|
|
48378
47966
|
/**
|
|
48379
|
-
*
|
|
47967
|
+
* 检查 JSX 使用
|
|
48380
47968
|
*/
|
|
48381
|
-
|
|
48382
|
-
|
|
48383
|
-
checkFunction();
|
|
48384
|
-
}
|
|
48385
|
-
catch (error) {
|
|
48386
|
-
this.log("".concat(methodName, " \u68C0\u67E5\u65F6\u53D1\u751F\u9519\u8BEF: ").concat(error.message));
|
|
48387
|
-
// 不抛出异常,只记录日志
|
|
48388
|
-
}
|
|
48389
|
-
};
|
|
48390
|
-
UnifiedTSXValidator.prototype.log = function (message) {
|
|
48391
|
-
if (this.debug) {
|
|
48392
|
-
console.log("[UnifiedTSXValidator] ".concat(message));
|
|
48393
|
-
}
|
|
47969
|
+
TSXComplianceChecker.checkJSXUsage = function (path, content, issues) {
|
|
47970
|
+
// 暂时不实现,专注于变量声明检查
|
|
48394
47971
|
};
|
|
48395
47972
|
/**
|
|
48396
|
-
*
|
|
47973
|
+
* 检查类型注解
|
|
48397
47974
|
*/
|
|
48398
|
-
|
|
48399
|
-
|
|
48400
|
-
.filter(function (issue) { return issue.type === 'error'; })
|
|
48401
|
-
.map(function (issue) {
|
|
48402
|
-
var location = issue.line ? " (\u7B2C".concat(issue.line, "\u884C)") : '';
|
|
48403
|
-
return "[".concat(issue.code, "] ").concat(issue.message).concat(location);
|
|
48404
|
-
});
|
|
47975
|
+
TSXComplianceChecker.checkTypeAnnotation = function (path, content, issues) {
|
|
47976
|
+
// 暂时不实现,专注于变量声明检查
|
|
48405
47977
|
};
|
|
48406
47978
|
/**
|
|
48407
|
-
*
|
|
47979
|
+
* 检查必需的结构
|
|
48408
47980
|
*/
|
|
48409
|
-
|
|
48410
|
-
|
|
48411
|
-
|
|
48412
|
-
report += "\u6587\u4EF6: ".concat(this.filename, "\n");
|
|
48413
|
-
if (isCompliant) {
|
|
48414
|
-
report += '✅ 检查通过:文件符合 TSX 规范\n';
|
|
48415
|
-
}
|
|
48416
|
-
else {
|
|
48417
|
-
var errorCount = issues.filter(function (issue) { return issue.type === 'error'; }).length;
|
|
48418
|
-
report += "\u274C \u68C0\u67E5\u5931\u8D25\uFF1A\u53D1\u73B0 ".concat(errorCount, " \u4E2A\u9519\u8BEF\n\n");
|
|
48419
|
-
report += '--- 问题详情 ---\n';
|
|
48420
|
-
issues.forEach(function (issue, index) {
|
|
48421
|
-
var icon = issue.type === 'error' ? '❌' : '⚠️';
|
|
48422
|
-
report += "".concat(index + 1, ". ").concat(icon, " [").concat(issue.code, "] ").concat(issue.message, "\n");
|
|
48423
|
-
if (issue.line) {
|
|
48424
|
-
report += " \uD83D\uDCCD \u4F4D\u7F6E: \u7B2C ".concat(issue.line, " \u884C\n");
|
|
48425
|
-
}
|
|
48426
|
-
report += " \uD83D\uDCA1 \u5EFA\u8BAE: ".concat(issue.suggestion, "\n\n");
|
|
48427
|
-
});
|
|
48428
|
-
}
|
|
48429
|
-
return report;
|
|
47981
|
+
TSXComplianceChecker.checkRequiredStructures = function (ast, content, issues) {
|
|
47982
|
+
// 这里可以添加对必需结构的检查
|
|
47983
|
+
// 如 IProps, IState, Document 类等
|
|
48430
47984
|
};
|
|
48431
|
-
return UnifiedTSXValidator;
|
|
48432
|
-
}());
|
|
48433
|
-
|
|
48434
|
-
var TSXComplianceChecker = /** @class */ (function () {
|
|
48435
|
-
function TSXComplianceChecker() {
|
|
48436
|
-
}
|
|
48437
47985
|
/**
|
|
48438
|
-
*
|
|
47986
|
+
* 获取节点在源码中的位置
|
|
48439
47987
|
*/
|
|
48440
|
-
TSXComplianceChecker.
|
|
48441
|
-
var
|
|
48442
|
-
|
|
48443
|
-
|
|
48444
|
-
|
|
48445
|
-
|
|
48446
|
-
// 为CLI添加代码片段
|
|
48447
|
-
codeSnippet: issue.line ? _this.extractCodeSnippet(content, issue.line).snippet : undefined, snippetStartLine: issue.line ? _this.extractCodeSnippet(content, issue.line).startLine : undefined, snippetEndLine: issue.line ? _this.extractCodeSnippet(content, issue.line).endLine : undefined })); });
|
|
48448
|
-
return {
|
|
48449
|
-
isCompliant: result.isCompliant,
|
|
48450
|
-
issues: compliantIssues,
|
|
48451
|
-
};
|
|
48452
|
-
}
|
|
48453
|
-
catch (error) {
|
|
48454
|
-
// 捕获任何异常并返回合规结果,而不是让异常向上传播
|
|
48455
|
-
return {
|
|
48456
|
-
isCompliant: false,
|
|
48457
|
-
issues: [{
|
|
48458
|
-
type: 'error',
|
|
48459
|
-
code: 'VALIDATION_ERROR',
|
|
48460
|
-
message: "\u9A8C\u8BC1\u8FC7\u7A0B\u53D1\u751F\u9519\u8BEF: ".concat(error.message),
|
|
48461
|
-
suggestion: '请检查代码语法或联系开发团队',
|
|
48462
|
-
line: 1,
|
|
48463
|
-
column: 0,
|
|
48464
|
-
}],
|
|
48465
|
-
};
|
|
48466
|
-
}
|
|
47988
|
+
TSXComplianceChecker.getLocation = function (path, content) {
|
|
47989
|
+
var loc = path.node.loc;
|
|
47990
|
+
return {
|
|
47991
|
+
line: loc ? loc.start.line : 1,
|
|
47992
|
+
column: loc ? loc.start.column : 0,
|
|
47993
|
+
};
|
|
48467
47994
|
};
|
|
48468
|
-
// 移除了所有旧的检查方法,现在使用UnifiedTSXValidator
|
|
48469
47995
|
/**
|
|
48470
47996
|
* 提取代码片段
|
|
48471
47997
|
*/
|
|
@@ -48487,33 +48013,34 @@ var TSXComplianceChecker = /** @class */ (function () {
|
|
|
48487
48013
|
};
|
|
48488
48014
|
};
|
|
48489
48015
|
/**
|
|
48490
|
-
*
|
|
48016
|
+
* 生成检查报告
|
|
48491
48017
|
*/
|
|
48492
48018
|
TSXComplianceChecker.generateReport = function (result, filename) {
|
|
48493
|
-
|
|
48494
|
-
|
|
48495
|
-
|
|
48496
|
-
|
|
48497
|
-
|
|
48498
|
-
*/
|
|
48499
|
-
TSXComplianceChecker.extractCodeSnippet = function (content, lineNumber, contextLines) {
|
|
48500
|
-
if (contextLines === void 0) { contextLines = 3; }
|
|
48501
|
-
var lines = content.split('\n');
|
|
48502
|
-
var startLine = Math.max(1, lineNumber - contextLines);
|
|
48503
|
-
var endLine = Math.min(lines.length, lineNumber + contextLines);
|
|
48504
|
-
var snippetLines = [];
|
|
48505
|
-
for (var i = startLine; i <= endLine; i++) {
|
|
48506
|
-
var line = lines[i - 1] || '';
|
|
48507
|
-
var prefix = i === lineNumber ? '>>> ' : ' ';
|
|
48508
|
-
snippetLines.push("".concat(prefix).concat(i.toString().padStart(3), ": ").concat(line));
|
|
48019
|
+
var isCompliant = result.isCompliant, issues = result.issues;
|
|
48020
|
+
var report = '=== TSX 规范检查报告 ===\n';
|
|
48021
|
+
report += "\u6587\u4EF6: ".concat(filename, "\n");
|
|
48022
|
+
if (isCompliant) {
|
|
48023
|
+
report += '✅ 检查通过:文件符合 TSX 规范\n';
|
|
48509
48024
|
}
|
|
48510
|
-
|
|
48511
|
-
|
|
48512
|
-
|
|
48513
|
-
|
|
48514
|
-
|
|
48025
|
+
else {
|
|
48026
|
+
var errorCount = issues.filter(function (issue) { return issue.type === 'error'; }).length;
|
|
48027
|
+
report += "\u274C \u68C0\u67E5\u5931\u8D25\uFF1A\u53D1\u73B0 ".concat(errorCount, " \u4E2A\u9519\u8BEF\n\n");
|
|
48028
|
+
report += '--- 问题详情 ---\n';
|
|
48029
|
+
issues.forEach(function (issue, index) {
|
|
48030
|
+
var icon = issue.type === 'error' ? '❌' : '⚠️';
|
|
48031
|
+
report += "".concat(index + 1, ". ").concat(icon, " [").concat(issue.code, "] ").concat(issue.message, "\n");
|
|
48032
|
+
if (issue.line) {
|
|
48033
|
+
report += " \uD83D\uDCCD \u4F4D\u7F6E: \u7B2C ".concat(issue.line, " \u884C\n");
|
|
48034
|
+
}
|
|
48035
|
+
report += " \uD83D\uDCA1 \u5EFA\u8BAE: ".concat(issue.suggestion, "\n");
|
|
48036
|
+
if (issue.codeSnippet) {
|
|
48037
|
+
report += " \uD83D\uDCDD \u4EE3\u7801\u7247\u6BB5:\n".concat(issue.codeSnippet, "\n");
|
|
48038
|
+
}
|
|
48039
|
+
report += '\n';
|
|
48040
|
+
});
|
|
48041
|
+
}
|
|
48042
|
+
return report;
|
|
48515
48043
|
};
|
|
48516
|
-
TSXComplianceChecker.validator = new UnifiedTSXValidator(false);
|
|
48517
48044
|
return TSXComplianceChecker;
|
|
48518
48045
|
}());
|
|
48519
48046
|
|
|
@@ -48550,11 +48077,11 @@ function checkTSX(options) {
|
|
|
48550
48077
|
'**/.next/**',
|
|
48551
48078
|
],
|
|
48552
48079
|
absolute: false,
|
|
48553
|
-
}, function (err,
|
|
48080
|
+
}, function (err, validatedFiles) {
|
|
48554
48081
|
if (err)
|
|
48555
48082
|
reject(err);
|
|
48556
48083
|
else
|
|
48557
|
-
resolve(
|
|
48084
|
+
resolve(validatedFiles || []);
|
|
48558
48085
|
});
|
|
48559
48086
|
})];
|
|
48560
48087
|
case 1:
|