@nokecy/qc-ui 1.0.66 → 1.0.67
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/cjs/components/RegexEditor/core/RegexEditor.d.ts +34 -0
- package/dist/cjs/components/RegexEditor/core/RegexEditor.js +223 -0
- package/dist/cjs/components/RegexEditor/core/RegexEditor.less +119 -0
- package/dist/cjs/components/RegexEditor/core/extensions/errorMarker.d.ts +49 -0
- package/dist/cjs/components/RegexEditor/core/extensions/errorMarker.js +158 -0
- package/dist/cjs/components/RegexEditor/core/types.d.ts +79 -0
- package/dist/cjs/components/RegexEditor/core/types.js +5 -0
- package/dist/cjs/components/RegexEditor/hooks/index.d.ts +9 -0
- package/dist/cjs/components/RegexEditor/hooks/index.js +19 -0
- package/dist/cjs/components/RegexEditor/hooks/useRegexTester.d.ts +95 -0
- package/dist/cjs/components/RegexEditor/hooks/useRegexTester.js +234 -0
- package/dist/cjs/components/RegexEditor/hooks/useRegexValidation.d.ts +71 -0
- package/dist/cjs/components/RegexEditor/hooks/useRegexValidation.js +215 -0
- package/dist/cjs/components/RegexEditor/hooks/useTemplateManager.d.ts +64 -0
- package/dist/cjs/components/RegexEditor/hooks/useTemplateManager.js +438 -0
- package/dist/cjs/components/RegexEditor/index.d.ts +16 -0
- package/dist/cjs/components/RegexEditor/index.js +232 -0
- package/dist/cjs/components/RegexEditor/templates/TemplateSelector.d.ts +36 -0
- package/dist/cjs/components/RegexEditor/templates/TemplateSelector.js +322 -0
- package/dist/cjs/components/RegexEditor/templates/builtinTemplates.d.ts +36 -0
- package/dist/cjs/components/RegexEditor/templates/builtinTemplates.js +340 -0
- package/dist/cjs/components/RegexEditor/templates/index.d.ts +10 -0
- package/dist/cjs/components/RegexEditor/templates/index.js +184 -0
- package/dist/cjs/components/RegexEditor/templates/storage.d.ts +74 -0
- package/dist/cjs/components/RegexEditor/templates/storage.js +337 -0
- package/dist/cjs/components/RegexEditor/templates/templateManager.d.ts +67 -0
- package/dist/cjs/components/RegexEditor/templates/templateManager.js +277 -0
- package/dist/cjs/components/RegexEditor/templates/types.d.ts +111 -0
- package/dist/cjs/components/RegexEditor/templates/types.js +94 -0
- package/dist/cjs/components/RegexEditor/testing/types.d.ts +55 -0
- package/dist/cjs/components/RegexEditor/testing/types.js +5 -0
- package/dist/cjs/components/RegexEditor/validation/complexity.d.ts +22 -0
- package/dist/cjs/components/RegexEditor/validation/complexity.js +196 -0
- package/dist/cjs/components/RegexEditor/validation/parser.d.ts +53 -0
- package/dist/cjs/components/RegexEditor/validation/parser.js +129 -0
- package/dist/cjs/components/RegexEditor/validation/types.d.ts +146 -0
- package/dist/cjs/components/RegexEditor/validation/types.js +5 -0
- package/dist/cjs/components/RegexEditor/validation/validator.d.ts +60 -0
- package/dist/cjs/components/RegexEditor/validation/validator.js +218 -0
- package/dist/cjs/components/RegexEditor/visualizer/FlagsSelector.d.ts +20 -0
- package/dist/cjs/components/RegexEditor/visualizer/FlagsSelector.js +98 -0
- package/dist/cjs/components/RegexEditor/visualizer/MatchItem.d.ts +25 -0
- package/dist/cjs/components/RegexEditor/visualizer/MatchItem.js +201 -0
- package/dist/cjs/components/RegexEditor/visualizer/RegexRailroadDiagram.d.ts +32 -0
- package/dist/cjs/components/RegexEditor/visualizer/RegexRailroadDiagram.js +192 -0
- package/dist/cjs/components/RegexEditor/visualizer/RegexTester.d.ts +22 -0
- package/dist/cjs/components/RegexEditor/visualizer/RegexTester.js +255 -0
- package/dist/cjs/components/RegexEditor/visualizer/astToRailroad.d.ts +19 -0
- package/dist/cjs/components/RegexEditor/visualizer/astToRailroad.js +155 -0
- package/dist/cjs/components/RegexEditor/visualizer/index.d.ts +12 -0
- package/dist/cjs/components/RegexEditor/visualizer/index.js +76 -0
- package/dist/cjs/components/RegexEditor/visualizer/types.d.ts +131 -0
- package/dist/cjs/components/RegexEditor/visualizer/types.js +5 -0
- package/dist/cjs/components/RegexEditor/visualizer/utils.d.ts +106 -0
- package/dist/cjs/components/RegexEditor/visualizer/utils.js +268 -0
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/index.js +55 -0
- package/dist/cjs/standardFormDialog/useStandardFormSchema.d.ts +1 -1
- package/dist/cjs/standardFormDialog/withStandardForm.d.ts +2 -2
- package/dist/cjs/types/railroad-diagrams.d.ts +59 -0
- package/dist/cjs/types/regexp-tree.d.ts +175 -0
- package/dist/esm/components/RegexEditor/core/RegexEditor.d.ts +34 -0
- package/dist/esm/components/RegexEditor/core/RegexEditor.js +214 -0
- package/dist/esm/components/RegexEditor/core/RegexEditor.less +119 -0
- package/dist/esm/components/RegexEditor/core/extensions/errorMarker.d.ts +49 -0
- package/dist/esm/components/RegexEditor/core/extensions/errorMarker.js +154 -0
- package/dist/esm/components/RegexEditor/core/types.d.ts +79 -0
- package/dist/esm/components/RegexEditor/core/types.js +1 -0
- package/dist/esm/components/RegexEditor/hooks/index.d.ts +9 -0
- package/dist/esm/components/RegexEditor/hooks/index.js +8 -0
- package/dist/esm/components/RegexEditor/hooks/useRegexTester.d.ts +95 -0
- package/dist/esm/components/RegexEditor/hooks/useRegexTester.js +230 -0
- package/dist/esm/components/RegexEditor/hooks/useRegexValidation.d.ts +71 -0
- package/dist/esm/components/RegexEditor/hooks/useRegexValidation.js +211 -0
- package/dist/esm/components/RegexEditor/hooks/useTemplateManager.d.ts +64 -0
- package/dist/esm/components/RegexEditor/hooks/useTemplateManager.js +430 -0
- package/dist/esm/components/RegexEditor/index.d.ts +16 -0
- package/dist/esm/components/RegexEditor/index.js +27 -0
- package/dist/esm/components/RegexEditor/templates/TemplateSelector.d.ts +36 -0
- package/dist/esm/components/RegexEditor/templates/TemplateSelector.js +316 -0
- package/dist/esm/components/RegexEditor/templates/builtinTemplates.d.ts +36 -0
- package/dist/esm/components/RegexEditor/templates/builtinTemplates.js +335 -0
- package/dist/esm/components/RegexEditor/templates/index.d.ts +10 -0
- package/dist/esm/components/RegexEditor/templates/index.js +19 -0
- package/dist/esm/components/RegexEditor/templates/storage.d.ts +74 -0
- package/dist/esm/components/RegexEditor/templates/storage.js +335 -0
- package/dist/esm/components/RegexEditor/templates/templateManager.d.ts +67 -0
- package/dist/esm/components/RegexEditor/templates/templateManager.js +274 -0
- package/dist/esm/components/RegexEditor/templates/types.d.ts +111 -0
- package/dist/esm/components/RegexEditor/templates/types.js +90 -0
- package/dist/esm/components/RegexEditor/testing/types.d.ts +55 -0
- package/dist/esm/components/RegexEditor/testing/types.js +1 -0
- package/dist/esm/components/RegexEditor/validation/complexity.d.ts +22 -0
- package/dist/esm/components/RegexEditor/validation/complexity.js +190 -0
- package/dist/esm/components/RegexEditor/validation/parser.d.ts +53 -0
- package/dist/esm/components/RegexEditor/validation/parser.js +123 -0
- package/dist/esm/components/RegexEditor/validation/types.d.ts +145 -0
- package/dist/esm/components/RegexEditor/validation/types.js +1 -0
- package/dist/esm/components/RegexEditor/validation/validator.d.ts +60 -0
- package/dist/esm/components/RegexEditor/validation/validator.js +213 -0
- package/dist/esm/components/RegexEditor/visualizer/FlagsSelector.d.ts +20 -0
- package/dist/esm/components/RegexEditor/visualizer/FlagsSelector.js +93 -0
- package/dist/esm/components/RegexEditor/visualizer/MatchItem.d.ts +25 -0
- package/dist/esm/components/RegexEditor/visualizer/MatchItem.js +194 -0
- package/dist/esm/components/RegexEditor/visualizer/RegexRailroadDiagram.d.ts +32 -0
- package/dist/esm/components/RegexEditor/visualizer/RegexRailroadDiagram.js +186 -0
- package/dist/esm/components/RegexEditor/visualizer/RegexTester.d.ts +22 -0
- package/dist/esm/components/RegexEditor/visualizer/RegexTester.js +248 -0
- package/dist/esm/components/RegexEditor/visualizer/astToRailroad.d.ts +18 -0
- package/dist/esm/components/RegexEditor/visualizer/astToRailroad.js +150 -0
- package/dist/esm/components/RegexEditor/visualizer/index.d.ts +12 -0
- package/dist/esm/components/RegexEditor/visualizer/index.js +17 -0
- package/dist/esm/components/RegexEditor/visualizer/types.d.ts +131 -0
- package/dist/esm/components/RegexEditor/visualizer/types.js +1 -0
- package/dist/esm/components/RegexEditor/visualizer/utils.d.ts +106 -0
- package/dist/esm/components/RegexEditor/visualizer/utils.js +256 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +5 -2
- package/dist/esm/types/railroad-diagrams.d.ts +59 -0
- package/dist/esm/types/regexp-tree.d.ts +175 -0
- package/dist/umd/qc-ui.min.css +1 -1
- package/dist/umd/qc-ui.min.js +1 -1
- package/package.json +23 -7
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式复杂度分析器
|
|
3
|
+
*
|
|
4
|
+
* @module RegexEditor/validation/complexity
|
|
5
|
+
* @description 分析正则表达式的复杂度,评估性能风险并提供优化建议
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* 该模块通过遍历 AST 来统计以下复杂度指标:
|
|
9
|
+
* - 节点总数
|
|
10
|
+
* - 最大嵌套深度
|
|
11
|
+
* - 分支数量(alternation)
|
|
12
|
+
* - 量词数量(quantifier)
|
|
13
|
+
* - 捕获组数量
|
|
14
|
+
* - 字符类数量
|
|
15
|
+
*
|
|
16
|
+
* 基于这些指标计算:
|
|
17
|
+
* - 回溯风险等级(low/medium/high)
|
|
18
|
+
* - 性能评分(0-100分)
|
|
19
|
+
* - 优化建议列表
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { traverseAST } from "./parser";
|
|
23
|
+
/**
|
|
24
|
+
* 分析正则表达式复杂度
|
|
25
|
+
*
|
|
26
|
+
* @param ast - 正则表达式的抽象语法树
|
|
27
|
+
* @returns {ComplexityMetrics} 复杂度指标
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const result = parseRegex('(a+)+b');
|
|
32
|
+
* const metrics = analyzeComplexity(result.ast!);
|
|
33
|
+
*
|
|
34
|
+
* if (metrics.backtrackingRisk === 'high') {
|
|
35
|
+
* console.warn('警告: 高回溯风险');
|
|
36
|
+
* console.log('建议:', metrics.suggestions);
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* console.log('性能评分:', metrics.performanceScore);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* 计算节点深度
|
|
44
|
+
* 通过递归遍历 parentPath 计算从根节点到当前节点的深度
|
|
45
|
+
*/
|
|
46
|
+
var calculateDepth = function calculateDepth(path) {
|
|
47
|
+
var depth = 1;
|
|
48
|
+
var currentPath = path;
|
|
49
|
+
|
|
50
|
+
// 递归向上查找父节点
|
|
51
|
+
while (currentPath.parentPath) {
|
|
52
|
+
depth++;
|
|
53
|
+
currentPath = currentPath.parentPath;
|
|
54
|
+
}
|
|
55
|
+
return depth;
|
|
56
|
+
};
|
|
57
|
+
export var analyzeComplexity = function analyzeComplexity(ast) {
|
|
58
|
+
// 统计指标
|
|
59
|
+
var nodeCount = 0;
|
|
60
|
+
var maxDepth = 1; // 初始深度为1
|
|
61
|
+
var alternationCount = 0;
|
|
62
|
+
var quantifierCount = 0;
|
|
63
|
+
var groupCount = 0;
|
|
64
|
+
var characterClassCount = 0;
|
|
65
|
+
var nestedQuantifiers = 0;
|
|
66
|
+
|
|
67
|
+
// 遍历 AST 统计各项指标
|
|
68
|
+
traverseAST(ast, {
|
|
69
|
+
// 通配符: 统计所有节点
|
|
70
|
+
'*': function _(path) {
|
|
71
|
+
nodeCount++;
|
|
72
|
+
|
|
73
|
+
// 计算深度: 递归计算父节点数量
|
|
74
|
+
var depth = calculateDepth(path);
|
|
75
|
+
maxDepth = Math.max(maxDepth, depth);
|
|
76
|
+
},
|
|
77
|
+
// 分支(Disjunction): a|b|c
|
|
78
|
+
// 注意: regexp-tree 中使用 Disjunction 表示分支(|)
|
|
79
|
+
// 每个 Disjunction 节点有 left 和 right 两个分支
|
|
80
|
+
Disjunction: function Disjunction() {
|
|
81
|
+
alternationCount++;
|
|
82
|
+
},
|
|
83
|
+
// 量词(Repetition): +, *, ?, {n,m}
|
|
84
|
+
Repetition: function Repetition(path) {
|
|
85
|
+
var _path$parent, _path$node$expression;
|
|
86
|
+
quantifierCount++;
|
|
87
|
+
|
|
88
|
+
// 检测嵌套量词: (a+)+ 或 (a*)*
|
|
89
|
+
// 检查父节点是否也是量词
|
|
90
|
+
if (((_path$parent = path.parent) === null || _path$parent === void 0 ? void 0 : _path$parent.type) === 'Repetition') {
|
|
91
|
+
nestedQuantifiers++;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 检查子节点是否包含量词
|
|
95
|
+
// 如果子节点是分组,且分组内有量词,也算嵌套
|
|
96
|
+
if (((_path$node$expression = path.node.expression) === null || _path$node$expression === void 0 ? void 0 : _path$node$expression.type) === 'Group') {
|
|
97
|
+
var _group$expression;
|
|
98
|
+
var group = path.node.expression;
|
|
99
|
+
if (((_group$expression = group.expression) === null || _group$expression === void 0 ? void 0 : _group$expression.type) === 'Repetition') {
|
|
100
|
+
nestedQuantifiers++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
// 捕获组(Group): (...)
|
|
105
|
+
Group: function Group() {
|
|
106
|
+
groupCount++;
|
|
107
|
+
},
|
|
108
|
+
// 字符类(CharacterClass): [abc], [a-z], [^0-9]
|
|
109
|
+
CharacterClass: function CharacterClass() {
|
|
110
|
+
characterClassCount++;
|
|
111
|
+
},
|
|
112
|
+
// 元字符: \d, \w, \s 等
|
|
113
|
+
// regexp-tree 将 \d 等解析为 type='Char', kind='meta' 的节点
|
|
114
|
+
Char: function Char(path) {
|
|
115
|
+
if (path.node.kind === 'meta') {
|
|
116
|
+
characterClassCount++;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 计算回溯风险
|
|
122
|
+
var backtrackingRisk = 'low';
|
|
123
|
+
if (nestedQuantifiers > 0) {
|
|
124
|
+
// 嵌套量词必然导致高风险
|
|
125
|
+
backtrackingRisk = 'high';
|
|
126
|
+
} else if (alternationCount > 3 && quantifierCount > 5) {
|
|
127
|
+
// 多分支 + 多量词 = 中等风险
|
|
128
|
+
backtrackingRisk = 'medium';
|
|
129
|
+
} else if (alternationCount > 5 || quantifierCount > 10) {
|
|
130
|
+
// 单独过多分支或量词 = 中等风险
|
|
131
|
+
backtrackingRisk = 'medium';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 计算性能评分 (0-100)
|
|
135
|
+
// 基础分: 100
|
|
136
|
+
// 扣分规则:
|
|
137
|
+
// - 每个节点 -0.5分
|
|
138
|
+
// - 每层嵌套深度 -2分
|
|
139
|
+
// - 每个分支 -3分
|
|
140
|
+
// - 每个量词 -1.5分
|
|
141
|
+
// - 每个嵌套量词 -30分 (灾难性回溯风险,重度惩罚)
|
|
142
|
+
var performanceScore = 100;
|
|
143
|
+
performanceScore -= nodeCount * 0.5;
|
|
144
|
+
performanceScore -= maxDepth * 2;
|
|
145
|
+
performanceScore -= alternationCount * 3;
|
|
146
|
+
performanceScore -= quantifierCount * 1.5;
|
|
147
|
+
performanceScore -= nestedQuantifiers * 30;
|
|
148
|
+
|
|
149
|
+
// 确保分数在 0-100 之间
|
|
150
|
+
performanceScore = Math.max(0, Math.min(100, performanceScore));
|
|
151
|
+
|
|
152
|
+
// 生成优化建议
|
|
153
|
+
var suggestions = [];
|
|
154
|
+
|
|
155
|
+
// 建议1: 嵌套量词
|
|
156
|
+
if (nestedQuantifiers > 0) {
|
|
157
|
+
suggestions.push('避免嵌套量词,考虑使用原子组或重新设计表达式');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 建议2: 过多分支
|
|
161
|
+
if (alternationCount > 5) {
|
|
162
|
+
suggestions.push('过多的分支可能影响性能,考虑拆分或优化');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 建议3: 表达式过于复杂
|
|
166
|
+
if (nodeCount > 50) {
|
|
167
|
+
suggestions.push('表达式过于复杂,建议拆分为多个简单的表达式');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 建议4: 量词使用过多
|
|
171
|
+
if (quantifierCount > 10) {
|
|
172
|
+
suggestions.push('量词使用过多,考虑优化匹配逻辑');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// 建议5: 嵌套层级过深
|
|
176
|
+
if (maxDepth > 5) {
|
|
177
|
+
suggestions.push('嵌套层级过深,建议简化结构');
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
nodeCount: nodeCount,
|
|
181
|
+
depth: maxDepth,
|
|
182
|
+
alternationCount: alternationCount,
|
|
183
|
+
quantifierCount: quantifierCount,
|
|
184
|
+
groupCount: groupCount,
|
|
185
|
+
characterClassCount: characterClassCount,
|
|
186
|
+
backtrackingRisk: backtrackingRisk,
|
|
187
|
+
performanceScore: Math.round(performanceScore),
|
|
188
|
+
suggestions: suggestions
|
|
189
|
+
};
|
|
190
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式解析器
|
|
3
|
+
*
|
|
4
|
+
* @module RegexEditor/validation/parser
|
|
5
|
+
* @description 基于 regexp-tree 的正则表达式解析器,提供 AST 解析和遍历功能
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* 该模块封装了 regexp-tree 库,提供类型安全的解析和遍历功能。
|
|
9
|
+
* 主要功能:
|
|
10
|
+
* - 将正则表达式字符串解析为抽象语法树(AST)
|
|
11
|
+
* - 统一的错误处理和转换
|
|
12
|
+
* - AST 节点遍历工具
|
|
13
|
+
*
|
|
14
|
+
* @see https://github.com/DmitrySoshnikov/regexp-tree
|
|
15
|
+
*/
|
|
16
|
+
import type { ParseResult, ASTNode } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* 解析正则表达式
|
|
19
|
+
*
|
|
20
|
+
* @param pattern - 正则表达式字符串
|
|
21
|
+
* @param flags - 可选的正则表达式标志(g, i, m, s, u, y)
|
|
22
|
+
* @returns {ParseResult} 解析结果,包含 AST 或错误信息
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const result = parseRegex('^LOT\\d{6}$');
|
|
27
|
+
* if (result.success) {
|
|
28
|
+
* console.log('AST:', result.ast);
|
|
29
|
+
* } else {
|
|
30
|
+
* console.error('Error:', result.error);
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const parseRegex: (pattern: string, flags?: string) => ParseResult;
|
|
35
|
+
/**
|
|
36
|
+
* 遍历 AST 节点
|
|
37
|
+
*
|
|
38
|
+
* @param ast - 抽象语法树节点
|
|
39
|
+
* @param handlers - 节点类型处理器映射
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const result = parseRegex('(\\d+)');
|
|
44
|
+
* const groups: any[] = [];
|
|
45
|
+
*
|
|
46
|
+
* traverseAST(result.ast!, {
|
|
47
|
+
* Group(path) {
|
|
48
|
+
* groups.push(path.node);
|
|
49
|
+
* }
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare const traverseAST: (ast: ASTNode | undefined, handlers: Record<string, (path: any) => void>) => void;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式解析器
|
|
3
|
+
*
|
|
4
|
+
* @module RegexEditor/validation/parser
|
|
5
|
+
* @description 基于 regexp-tree 的正则表达式解析器,提供 AST 解析和遍历功能
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* 该模块封装了 regexp-tree 库,提供类型安全的解析和遍历功能。
|
|
9
|
+
* 主要功能:
|
|
10
|
+
* - 将正则表达式字符串解析为抽象语法树(AST)
|
|
11
|
+
* - 统一的错误处理和转换
|
|
12
|
+
* - AST 节点遍历工具
|
|
13
|
+
*
|
|
14
|
+
* @see https://github.com/DmitrySoshnikov/regexp-tree
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { parse, traverse } from 'regexp-tree';
|
|
18
|
+
/**
|
|
19
|
+
* 解析正则表达式
|
|
20
|
+
*
|
|
21
|
+
* @param pattern - 正则表达式字符串
|
|
22
|
+
* @param flags - 可选的正则表达式标志(g, i, m, s, u, y)
|
|
23
|
+
* @returns {ParseResult} 解析结果,包含 AST 或错误信息
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const result = parseRegex('^LOT\\d{6}$');
|
|
28
|
+
* if (result.success) {
|
|
29
|
+
* console.log('AST:', result.ast);
|
|
30
|
+
* } else {
|
|
31
|
+
* console.error('Error:', result.error);
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export var parseRegex = function parseRegex(pattern, flags) {
|
|
36
|
+
try {
|
|
37
|
+
// 空字符串特殊处理
|
|
38
|
+
if (pattern === '') {
|
|
39
|
+
// regexp-tree 可以解析空字符串,使用非捕获组表示
|
|
40
|
+
var _ast = parse('/(?:)/');
|
|
41
|
+
return {
|
|
42
|
+
success: true,
|
|
43
|
+
ast: _ast,
|
|
44
|
+
pattern: pattern
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 构建完整的正则表达式字符串
|
|
49
|
+
// regexp-tree 需要完整的 /pattern/flags 格式
|
|
50
|
+
var regexStr = flags ? "/".concat(pattern, "/").concat(flags) : "/".concat(pattern, "/");
|
|
51
|
+
|
|
52
|
+
// 尝试解析
|
|
53
|
+
var ast = parse(regexStr);
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
ast: ast,
|
|
57
|
+
pattern: pattern
|
|
58
|
+
};
|
|
59
|
+
} catch (error) {
|
|
60
|
+
// 提取错误信息
|
|
61
|
+
var errorMessage = error.message || '解析失败';
|
|
62
|
+
|
|
63
|
+
// 处理不同格式的位置信息
|
|
64
|
+
var startPos = 0;
|
|
65
|
+
var endPos = pattern.length;
|
|
66
|
+
if (error.position !== undefined) {
|
|
67
|
+
if (typeof error.position === 'number') {
|
|
68
|
+
startPos = error.position;
|
|
69
|
+
endPos = error.position + 1;
|
|
70
|
+
} else if (error.position.start !== undefined) {
|
|
71
|
+
startPos = error.position.start;
|
|
72
|
+
endPos = error.position.end || startPos + 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 转换为标准错误格式
|
|
77
|
+
var regexError = {
|
|
78
|
+
type: 'syntax_error',
|
|
79
|
+
message: errorMessage,
|
|
80
|
+
position: {
|
|
81
|
+
start: startPos,
|
|
82
|
+
end: endPos
|
|
83
|
+
},
|
|
84
|
+
severity: 'error'
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
pattern: pattern,
|
|
89
|
+
error: regexError
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 遍历 AST 节点
|
|
96
|
+
*
|
|
97
|
+
* @param ast - 抽象语法树节点
|
|
98
|
+
* @param handlers - 节点类型处理器映射
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const result = parseRegex('(\\d+)');
|
|
103
|
+
* const groups: any[] = [];
|
|
104
|
+
*
|
|
105
|
+
* traverseAST(result.ast!, {
|
|
106
|
+
* Group(path) {
|
|
107
|
+
* groups.push(path.node);
|
|
108
|
+
* }
|
|
109
|
+
* });
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export var traverseAST = function traverseAST(ast, handlers) {
|
|
113
|
+
// 安全处理空 AST
|
|
114
|
+
if (!ast) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
traverse(ast, handlers);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
// 遍历错误时静默失败,避免影响主流程
|
|
121
|
+
console.error('AST traversal error:', error);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式验证引擎 - 类型定义
|
|
3
|
+
*
|
|
4
|
+
* @module RegexEditor/validation/types
|
|
5
|
+
* @description 定义正则表达式解析、验证、复杂度分析相关的核心类型
|
|
6
|
+
*/
|
|
7
|
+
/// <reference types="dist/esm/types/regexp-tree" />
|
|
8
|
+
/// <reference types="regexp-tree" />
|
|
9
|
+
/// <reference types="src/types/regexp-tree" />
|
|
10
|
+
/**
|
|
11
|
+
* regexp-tree 的 AST 节点类型
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* 使用 regexp-tree 库提供的官方类型定义。
|
|
15
|
+
* 节点包含 type, loc, expression 等属性,支持完整的类型推导。
|
|
16
|
+
*
|
|
17
|
+
* 注意: 'regexp-tree/ast' 子模块的类型声明在 src/types/regexp-tree-ast.d.ts 中定义
|
|
18
|
+
*
|
|
19
|
+
* @see https://github.com/DmitrySoshnikov/regexp-tree
|
|
20
|
+
*/
|
|
21
|
+
import type { AstNode, AstRegExp as RegExpAstNode } from 'regexp-tree/ast';
|
|
22
|
+
export type ASTNode = AstNode;
|
|
23
|
+
export type AstRegExp = RegExpAstNode;
|
|
24
|
+
/**
|
|
25
|
+
* 正则表达式解析结果
|
|
26
|
+
*
|
|
27
|
+
* @interface ParseResult
|
|
28
|
+
* @property {boolean} success - 解析是否成功
|
|
29
|
+
* @property {ASTNode} [ast] - 抽象语法树节点(成功时存在)
|
|
30
|
+
* @property {string} pattern - 原始正则表达式字符串
|
|
31
|
+
* @property {RegexError} [error] - 解析错误信息(失败时存在)
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const result = parseRegex('^LOT\\d{6}$');
|
|
36
|
+
* if (result.success) {
|
|
37
|
+
* console.log(result.ast);
|
|
38
|
+
* } else {
|
|
39
|
+
* console.error(result.error);
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export interface ParseResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
ast?: ASTNode;
|
|
46
|
+
pattern: string;
|
|
47
|
+
error?: RegexError;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 正则表达式验证结果
|
|
51
|
+
*
|
|
52
|
+
* @interface ValidationResult
|
|
53
|
+
* @property {boolean} valid - 验证是否通过(无错误,可能有警告)
|
|
54
|
+
* @property {RegexError[]} errors - 错误列表(仅包含 severity='error' 的项)
|
|
55
|
+
* @property {RegexError[]} warnings - 警告列表(仅包含 severity='warning' 的项)
|
|
56
|
+
* @property {RegexError[]} infos - 信息列表(仅包含 severity='info' 的项)
|
|
57
|
+
* @property {string} pattern - 被验证的正则表达式字符串
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const result = validateRegex(pattern);
|
|
62
|
+
*
|
|
63
|
+
* if (result.errors.length > 0) {
|
|
64
|
+
* console.error('验证失败:', result.errors);
|
|
65
|
+
* } else if (result.warnings.length > 0) {
|
|
66
|
+
* console.warn('验证通过但有警告:', result.warnings);
|
|
67
|
+
* } else {
|
|
68
|
+
* console.log('验证完全通过');
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export interface ValidationResult {
|
|
73
|
+
valid: boolean;
|
|
74
|
+
errors: RegexError[];
|
|
75
|
+
warnings: RegexError[];
|
|
76
|
+
infos: RegexError[];
|
|
77
|
+
pattern: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 正则表达式错误信息
|
|
81
|
+
*
|
|
82
|
+
* @interface RegexError
|
|
83
|
+
* @property {string} type - 错误类型标识符
|
|
84
|
+
* @property {string} message - 人类可读的错误描述
|
|
85
|
+
* @property {Object} position - 错误位置范围
|
|
86
|
+
* @property {number} position.start - 起始位置(字符索引)
|
|
87
|
+
* @property {number} position.end - 结束位置(字符索引)
|
|
88
|
+
* @property {'error' | 'warning' | 'info'} severity - 严重程度
|
|
89
|
+
* @property {string} [suggestion] - 修复建议(可选)
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const error: RegexError = {
|
|
94
|
+
* type: 'empty_group',
|
|
95
|
+
* message: '空的捕获组,建议使用非捕获组 (?:)',
|
|
96
|
+
* position: { start: 5, end: 7 },
|
|
97
|
+
* severity: 'warning',
|
|
98
|
+
* suggestion: '使用 (?:) 代替 ()'
|
|
99
|
+
* };
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export interface RegexError {
|
|
103
|
+
type: string;
|
|
104
|
+
message: string;
|
|
105
|
+
position: {
|
|
106
|
+
start: number;
|
|
107
|
+
end: number;
|
|
108
|
+
};
|
|
109
|
+
severity: 'error' | 'warning' | 'info';
|
|
110
|
+
suggestion?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 正则表达式复杂度指标
|
|
114
|
+
*
|
|
115
|
+
* @interface ComplexityMetrics
|
|
116
|
+
* @property {number} nodeCount - AST 节点总数
|
|
117
|
+
* @property {number} depth - 最大嵌套深度
|
|
118
|
+
* @property {number} alternationCount - 分支数量 (|)
|
|
119
|
+
* @property {number} quantifierCount - 量词数量 (+, *, {n,m})
|
|
120
|
+
* @property {number} groupCount - 捕获组数量
|
|
121
|
+
* @property {number} characterClassCount - 字符类数量 ([...])
|
|
122
|
+
* @property {'low' | 'medium' | 'high'} backtrackingRisk - 回溯风险等级
|
|
123
|
+
* @property {number} performanceScore - 性能评分 (0-100)
|
|
124
|
+
* @property {string[]} suggestions - 优化建议列表
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const metrics = analyzeComplexity(ast);
|
|
129
|
+
* if (metrics.backtrackingRisk === 'high') {
|
|
130
|
+
* console.warn('高回溯风险:', metrics.suggestions);
|
|
131
|
+
* }
|
|
132
|
+
* console.log('性能评分:', metrics.performanceScore);
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export interface ComplexityMetrics {
|
|
136
|
+
nodeCount: number;
|
|
137
|
+
depth: number;
|
|
138
|
+
alternationCount: number;
|
|
139
|
+
quantifierCount: number;
|
|
140
|
+
groupCount: number;
|
|
141
|
+
characterClassCount: number;
|
|
142
|
+
backtrackingRisk: 'low' | 'medium' | 'high';
|
|
143
|
+
performanceScore: number;
|
|
144
|
+
suggestions: string[];
|
|
145
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式语法验证器
|
|
3
|
+
*
|
|
4
|
+
* @module RegexEditor/validation/validator
|
|
5
|
+
* @description 检测正则表达式的常见语法错误和安全问题
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* 该模块基于 regexp-tree AST 提供以下验证规则:
|
|
9
|
+
* 1. 空捕获组检测 - 检测 () 并建议使用 (?:)
|
|
10
|
+
* 2. 无效量词检测 - 检测 {min,max} 中 min > max
|
|
11
|
+
* 3. 嵌套量词检测 - 检测 (a+)+ 等导致灾难性回溯的模式
|
|
12
|
+
* 4. 未闭合组检测 - 通过解析错误自动检测
|
|
13
|
+
*
|
|
14
|
+
* @see {@link parseRegex} 用于解析正则表达式
|
|
15
|
+
*/
|
|
16
|
+
import type { ASTNode, RegexError, ValidationResult } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* 验证正则表达式 AST
|
|
19
|
+
*
|
|
20
|
+
* @param ast - 抽象语法树节点
|
|
21
|
+
* @returns {RegexError[]} 错误和警告列表
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* 该函数遍历 AST 节点,应用以下验证规则:
|
|
25
|
+
* - 空捕获组 (警告)
|
|
26
|
+
* - 无效量词 (错误)
|
|
27
|
+
* - 嵌套量词/灾难性回溯 (错误)
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const result = parseRegex('()test');
|
|
32
|
+
* const errors = validateRegex(result.ast!);
|
|
33
|
+
* console.log(errors); // [{ type: 'empty_group', severity: 'warning', ... }]
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare const validateRegex: (ast: ASTNode) => RegexError[];
|
|
37
|
+
/**
|
|
38
|
+
* 整合验证流程: 解析 + 语法验证
|
|
39
|
+
*
|
|
40
|
+
* @param pattern - 正则表达式字符串
|
|
41
|
+
* @param flags - 可选的正则表达式标志
|
|
42
|
+
* @returns {ValidationResult} 完整的验证结果
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* 该函数整合了以下步骤:
|
|
46
|
+
* 1. 解析正则表达式 {@link parseRegex}
|
|
47
|
+
* 2. 语法验证 {@link validateRegex}
|
|
48
|
+
* 3. 分类错误、警告和信息
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const result = validatePattern('^LOT\\d{6}$');
|
|
53
|
+
* if (result.valid) {
|
|
54
|
+
* console.log('验证通过');
|
|
55
|
+
* } else {
|
|
56
|
+
* console.error('错误:', result.errors);
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const validatePattern: (pattern: string, flags?: string) => ValidationResult;
|