mcp-xdx-schema-ctx 1.1.9
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/.env.example +43 -0
- package/README.md +269 -0
- package/dist/config.d.ts +131 -0
- package/dist/config.js +138 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto-utils.d.ts +29 -0
- package/dist/crypto-utils.js +118 -0
- package/dist/crypto-utils.js.map +1 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +149 -0
- package/dist/db.js.map +1 -0
- package/dist/diff-utils.d.ts +42 -0
- package/dist/diff-utils.js +130 -0
- package/dist/diff-utils.js.map +1 -0
- package/dist/encrypt-secrets.d.ts +12 -0
- package/dist/encrypt-secrets.js +190 -0
- package/dist/encrypt-secrets.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate-utils.d.ts +91 -0
- package/dist/migrate-utils.js +399 -0
- package/dist/migrate-utils.js.map +1 -0
- package/dist/schema-compat.d.ts +46 -0
- package/dist/schema-compat.js +169 -0
- package/dist/schema-compat.js.map +1 -0
- package/dist/shared.d.ts +70 -0
- package/dist/shared.js +197 -0
- package/dist/shared.js.map +1 -0
- package/dist/sql-build.d.ts +121 -0
- package/dist/sql-build.js +254 -0
- package/dist/sql-build.js.map +1 -0
- package/dist/tool-availability.d.ts +35 -0
- package/dist/tool-availability.js +90 -0
- package/dist/tool-availability.js.map +1 -0
- package/dist/tools/data-tools.d.ts +2 -0
- package/dist/tools/data-tools.js +243 -0
- package/dist/tools/data-tools.js.map +1 -0
- package/dist/tools/dataflow-tools.d.ts +2 -0
- package/dist/tools/dataflow-tools.js +434 -0
- package/dist/tools/dataflow-tools.js.map +1 -0
- package/dist/tools/dbo-tools.d.ts +2 -0
- package/dist/tools/dbo-tools.js +228 -0
- package/dist/tools/dbo-tools.js.map +1 -0
- package/dist/tools/diff-tools.d.ts +2 -0
- package/dist/tools/diff-tools.js +224 -0
- package/dist/tools/diff-tools.js.map +1 -0
- package/dist/tools/form-tools.d.ts +2 -0
- package/dist/tools/form-tools.js +715 -0
- package/dist/tools/form-tools.js.map +1 -0
- package/dist/tools/migrate-tools.d.ts +2 -0
- package/dist/tools/migrate-tools.js +423 -0
- package/dist/tools/migrate-tools.js.map +1 -0
- package/dist/tools/system-tools.d.ts +2 -0
- package/dist/tools/system-tools.js +1102 -0
- package/dist/tools/system-tools.js.map +1 -0
- package/dist/tools/table-tools.d.ts +2 -0
- package/dist/tools/table-tools.js +1322 -0
- package/dist/tools/table-tools.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { query } from "./db.js";
|
|
2
|
+
import { T, T2 } from "./shared.js";
|
|
3
|
+
// ============================================================
|
|
4
|
+
// ID 映射器
|
|
5
|
+
// ============================================================
|
|
6
|
+
export class IdMapper {
|
|
7
|
+
map = new Map();
|
|
8
|
+
/** key 格式统一使用全限定表名(T2(tableKey) 的结果) */
|
|
9
|
+
set(srcTable, srcId, tgtId) {
|
|
10
|
+
this.map.set(`${srcTable}:${srcId}`, tgtId);
|
|
11
|
+
}
|
|
12
|
+
get(srcTable, srcId) {
|
|
13
|
+
return this.map.get(`${srcTable}:${srcId}`);
|
|
14
|
+
}
|
|
15
|
+
/** 查询某个源 ID 在映射表中的目标 ID,若未映射则返回源 ID 本身 */
|
|
16
|
+
resolve(srcTable, srcId) {
|
|
17
|
+
return this.map.get(`${srcTable}:${srcId}`) ?? srcId;
|
|
18
|
+
}
|
|
19
|
+
/** 映射表是否为空 */
|
|
20
|
+
get isEmpty() {
|
|
21
|
+
return this.map.size === 0;
|
|
22
|
+
}
|
|
23
|
+
/** 映射条目数 */
|
|
24
|
+
get size() {
|
|
25
|
+
return this.map.size;
|
|
26
|
+
}
|
|
27
|
+
toSqlComment() {
|
|
28
|
+
const lines = ["-- ID 映射表 (源ID → 目标ID)"];
|
|
29
|
+
for (const [k, v] of this.map) {
|
|
30
|
+
const [table, id] = k.split(":");
|
|
31
|
+
lines.push(`-- ${table}.${id} → ${v}`);
|
|
32
|
+
}
|
|
33
|
+
return lines.join("\n");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// ============================================================
|
|
37
|
+
// ID 冲突检测与重映射
|
|
38
|
+
// ============================================================
|
|
39
|
+
/**
|
|
40
|
+
* 查询目标系统(系统 B)中指定表的指定 ID 是否已被占用
|
|
41
|
+
* @returns 占用该 ID 的实体名称,null 表示未占用
|
|
42
|
+
*/
|
|
43
|
+
export async function checkIdConflict(tableKey, idField, nameField, id) {
|
|
44
|
+
const rows = await query(`SELECT TOP 1 ${nameField} FROM ${T2(tableKey)} WHERE ${idField} = ${id}`, "b");
|
|
45
|
+
if (rows.length === 0)
|
|
46
|
+
return { exists: false, name: null };
|
|
47
|
+
return { exists: true, name: String(rows[0][nameField] ?? "?") };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 在目标系统(系统 B)中找一个未被占用的新 ID
|
|
51
|
+
* 策略:取当前最大 ID + 1,保证不冲突
|
|
52
|
+
*/
|
|
53
|
+
export async function findNextAvailableId(tableKey, idField) {
|
|
54
|
+
const rows = await query(`SELECT ISNULL(MAX(${idField}), 0) + 1 AS maxId FROM ${T2(tableKey)}`, "b");
|
|
55
|
+
return rows[0]?.maxId ?? 1;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 为目标系统构建 ID 映射器
|
|
59
|
+
* 检查源 ID 在目标系统是否冲突(被不同实体占用),若冲突则分配新 ID
|
|
60
|
+
*/
|
|
61
|
+
export async function buildMigrationIdMap(tableKey, idField, nameField, srcId, featureName) {
|
|
62
|
+
const idMap = new IdMapper();
|
|
63
|
+
const conflict = await checkIdConflict(tableKey, idField, nameField, srcId);
|
|
64
|
+
if (conflict.exists && conflict.name !== featureName) {
|
|
65
|
+
// ID 被目标系统中的其他实体占用,需要重映射
|
|
66
|
+
const newId = await findNextAvailableId(tableKey, idField);
|
|
67
|
+
idMap.set(T2(tableKey), srcId, newId);
|
|
68
|
+
}
|
|
69
|
+
else if (!conflict.exists) {
|
|
70
|
+
// ID 空闲,直接使用源 ID,但依然记录映射(无变化)
|
|
71
|
+
idMap.set(T2(tableKey), srcId, srcId);
|
|
72
|
+
}
|
|
73
|
+
// else: conflict.name === featureName — 同名实体已存在,由冲突策略处理(skip/replace)
|
|
74
|
+
return idMap;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 检查迁移一个功能时,其引用的外部实体在目标系统中是否存在
|
|
78
|
+
* - 窗体引用 DBO / 数据流
|
|
79
|
+
* - DBO 引用数据表
|
|
80
|
+
* - 数据流引用 DBO
|
|
81
|
+
* - 功能引用窗体
|
|
82
|
+
*
|
|
83
|
+
* severity 语义:
|
|
84
|
+
* error — 依赖缺失,目标系统不存在
|
|
85
|
+
* info — 依赖已存在
|
|
86
|
+
* warning — 部分存在或其他潜在问题
|
|
87
|
+
*/
|
|
88
|
+
export async function checkCrossFeatureDependencies(featureType, featureName) {
|
|
89
|
+
const warnings = [];
|
|
90
|
+
const safeName = featureName.replace(/'/g, "''");
|
|
91
|
+
if (featureType === "form") {
|
|
92
|
+
// 检查 FormRule 引用的 DBO 是否在目标存在
|
|
93
|
+
const formRows = await query(`SELECT TOP 1 FormID FROM ${T("formDef")} WHERE FormName = N'${safeName}'`, "default");
|
|
94
|
+
if (formRows.length === 0)
|
|
95
|
+
return warnings;
|
|
96
|
+
const fid = formRows[0].FormID;
|
|
97
|
+
// 检查 formRuleDataSource 引用的 DBO
|
|
98
|
+
const dsRows = await query(`SELECT TOP 100 RuleDataSourceID, DataSourceName FROM ${T("formRuleDataSource")} WHERE FormID = ${fid} AND DataSourceName IS NOT NULL AND DataSourceName != ''`, "default");
|
|
99
|
+
for (const ds of dsRows) {
|
|
100
|
+
const targetDs = await query(`SELECT TOP 1 DBOID FROM ${T2("dboSet")} WHERE DBOName = N'${String(ds.DataSourceName).replace(/'/g, "''")}'`, "b");
|
|
101
|
+
warnings.push({
|
|
102
|
+
severity: targetDs.length === 0 ? "error" : "info",
|
|
103
|
+
message: targetDs.length === 0
|
|
104
|
+
? `窗体 "${featureName}" 引用的 DBO "${ds.DataSourceName}" 在目标系统中不存在`
|
|
105
|
+
: `窗体 "${featureName}" 引用的 DBO "${ds.DataSourceName}" 在目标系统中已存在 ✓`,
|
|
106
|
+
dependencyType: "DBO",
|
|
107
|
+
dependencyName: String(ds.DataSourceName),
|
|
108
|
+
existsInTarget: targetDs.length > 0,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// 检查 formRuleDataFlow 引用的数据流
|
|
112
|
+
const dfRows = await query(`SELECT TOP 100 RuleDataFlowID, DataFlowName FROM ${T("formRuleDataFlow")} WHERE FormID = ${fid} AND DataFlowName IS NOT NULL AND DataFlowName != ''`, "default");
|
|
113
|
+
for (const df of dfRows) {
|
|
114
|
+
const targetDf = await query(`SELECT TOP 1 DataFlowID FROM ${T2("dataFlowHed")} WHERE DataFlowName = N'${String(df.DataFlowName).replace(/'/g, "''")}'`, "b");
|
|
115
|
+
warnings.push({
|
|
116
|
+
severity: targetDf.length === 0 ? "error" : "info",
|
|
117
|
+
message: targetDf.length === 0
|
|
118
|
+
? `窗体 "${featureName}" 引用的数据流 "${df.DataFlowName}" 在目标系统中不存在`
|
|
119
|
+
: `窗体 "${featureName}" 引用的数据流 "${df.DataFlowName}" 在目标系统中已存在 ✓`,
|
|
120
|
+
dependencyType: "DataFlow",
|
|
121
|
+
dependencyName: String(df.DataFlowName),
|
|
122
|
+
existsInTarget: targetDf.length > 0,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (featureType === "dbo") {
|
|
127
|
+
// 检查 DBO 引用的表在目标是否存在
|
|
128
|
+
const dboRows = await query(`SELECT TOP 1 DBOID FROM ${T("dboSet")} WHERE DBOName = N'${safeName}'`, "default");
|
|
129
|
+
if (dboRows.length === 0)
|
|
130
|
+
return warnings;
|
|
131
|
+
const did = dboRows[0].DBOID;
|
|
132
|
+
const fieldRows = await query(`SELECT DISTINCT TOP 50 TableName FROM ${T("dboSetField")} WHERE DBOID = ${did} AND TableName IS NOT NULL AND TableName != ''`, "default");
|
|
133
|
+
for (const f of fieldRows) {
|
|
134
|
+
const targetTable = await query(`SELECT TOP 1 TableID FROM ${T2("tableDef")} WHERE TableName = N'${String(f.TableName).replace(/'/g, "''")}'`, "b");
|
|
135
|
+
warnings.push({
|
|
136
|
+
severity: targetTable.length === 0 ? "error" : "info",
|
|
137
|
+
message: targetTable.length === 0
|
|
138
|
+
? `DBO "${featureName}" 引用的表 "${f.TableName}" 在目标系统中不存在`
|
|
139
|
+
: `DBO "${featureName}" 引用的表 "${f.TableName}" 在目标系统中已存在 ✓`,
|
|
140
|
+
dependencyType: "Table",
|
|
141
|
+
dependencyName: String(f.TableName),
|
|
142
|
+
existsInTarget: targetTable.length > 0,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (featureType === "dataflow") {
|
|
147
|
+
// 检查数据流引用
|
|
148
|
+
const dfRows = await query(`SELECT TOP 1 DataFlowID FROM ${T("dataFlowHed")} WHERE DataFlowName = N'${safeName}'`, "default");
|
|
149
|
+
if (dfRows.length === 0)
|
|
150
|
+
return warnings;
|
|
151
|
+
const dfid = dfRows[0].DataFlowID;
|
|
152
|
+
// 检查 dataFlowDet 引用的 DBO
|
|
153
|
+
const detRows = await query(`SELECT TOP 100 DBOID, DBOName FROM ${T("dataFlowDet")} WHERE DataFlowID = ${dfid} AND DBOName IS NOT NULL AND DBOName != ''`, "default");
|
|
154
|
+
for (const det of detRows) {
|
|
155
|
+
const targetDbo = await query(`SELECT TOP 1 DBOID FROM ${T2("dboSet")} WHERE DBOName = N'${String(det.DBOName).replace(/'/g, "''")}'`, "b");
|
|
156
|
+
warnings.push({
|
|
157
|
+
severity: targetDbo.length === 0 ? "error" : "info",
|
|
158
|
+
message: targetDbo.length === 0
|
|
159
|
+
? `数据流 "${featureName}" 引用的 DBO "${det.DBOName}" 在目标系统中不存在`
|
|
160
|
+
: `数据流 "${featureName}" 引用的 DBO "${det.DBOName}" 在目标系统中已存在 ✓`,
|
|
161
|
+
dependencyType: "DBO",
|
|
162
|
+
dependencyName: String(det.DBOName),
|
|
163
|
+
existsInTarget: targetDbo.length > 0,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (featureType === "function") {
|
|
168
|
+
// 功能菜单引用检查
|
|
169
|
+
const fnRows = await query(`SELECT TOP 1 FunctionID FROM ${T("function")} WHERE FunctionName = N'${safeName}'`, "default");
|
|
170
|
+
if (fnRows.length === 0)
|
|
171
|
+
return warnings;
|
|
172
|
+
const fnid = fnRows[0].FunctionID;
|
|
173
|
+
// 检查 menuFunction 引用的 Form
|
|
174
|
+
const menuRows = await query(`SELECT TOP 100 MenuID, FormName FROM ${T("menuFunction")} WHERE FunctionID = ${fnid} AND FormName IS NOT NULL AND FormName != ''`, "default");
|
|
175
|
+
for (const m of menuRows) {
|
|
176
|
+
const targetForm = await query(`SELECT TOP 1 FormID FROM ${T2("formDef")} WHERE FormName = N'${String(m.FormName).replace(/'/g, "''")}'`, "b");
|
|
177
|
+
warnings.push({
|
|
178
|
+
severity: targetForm.length === 0 ? "error" : "info",
|
|
179
|
+
message: targetForm.length === 0
|
|
180
|
+
? `功能 "${featureName}" 引用的窗体 "${m.FormName}" 在目标系统中不存在`
|
|
181
|
+
: `功能 "${featureName}" 引用的窗体 "${m.FormName}" 在目标系统中已存在 ✓`,
|
|
182
|
+
dependencyType: "Form",
|
|
183
|
+
dependencyName: String(m.FormName),
|
|
184
|
+
existsInTarget: targetForm.length > 0,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return warnings;
|
|
189
|
+
}
|
|
190
|
+
// ============================================================
|
|
191
|
+
// 依赖追踪引擎
|
|
192
|
+
// ============================================================
|
|
193
|
+
const FORM_ID_FIELD = {
|
|
194
|
+
form: "FormID",
|
|
195
|
+
dbo: "DBOID",
|
|
196
|
+
dataflow: "DataFlowID",
|
|
197
|
+
function: "FunctionID",
|
|
198
|
+
};
|
|
199
|
+
const FORM_NAME_FIELD = {
|
|
200
|
+
form: "FormName",
|
|
201
|
+
dbo: "DBOName",
|
|
202
|
+
dataflow: "DataFlowName",
|
|
203
|
+
function: "FunctionName",
|
|
204
|
+
};
|
|
205
|
+
const FORM_TABLE_KEY = {
|
|
206
|
+
form: "formDef",
|
|
207
|
+
dbo: "dboSet",
|
|
208
|
+
dataflow: "dataFlowHed",
|
|
209
|
+
function: "function",
|
|
210
|
+
};
|
|
211
|
+
/** 获取功能类型对应的 ID 字段名 */
|
|
212
|
+
export function getIdField(featureType) {
|
|
213
|
+
return FORM_ID_FIELD[featureType];
|
|
214
|
+
}
|
|
215
|
+
/** 获取功能类型对应的名称字段名 */
|
|
216
|
+
export function getNameField(featureType) {
|
|
217
|
+
return FORM_NAME_FIELD[featureType];
|
|
218
|
+
}
|
|
219
|
+
/** 获取功能类型对应的主表 TableKey */
|
|
220
|
+
export function getMainTableKey(featureType) {
|
|
221
|
+
return FORM_TABLE_KEY[featureType];
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 追踪功能的完整依赖树 — 支持 form/dbo/dataflow/function 四种类型
|
|
225
|
+
*/
|
|
226
|
+
export async function traceDependencies(featureType, featureName) {
|
|
227
|
+
const tableKey = FORM_TABLE_KEY[featureType];
|
|
228
|
+
const nameField = FORM_NAME_FIELD[featureType];
|
|
229
|
+
const idField = FORM_ID_FIELD[featureType];
|
|
230
|
+
// 1. 查找根记录
|
|
231
|
+
const rootRows = await query(`SELECT * FROM ${T(tableKey)} WHERE ${nameField} = N'${featureName.replace(/'/g, "''")}'`, "default");
|
|
232
|
+
if (rootRows.length === 0) {
|
|
233
|
+
return {
|
|
234
|
+
featureName, featureType,
|
|
235
|
+
dependencyTree: [],
|
|
236
|
+
totalTables: 0, totalRecords: 0,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const root = rootRows[0];
|
|
240
|
+
const rootId = root[idField];
|
|
241
|
+
// 2. 递归追踪
|
|
242
|
+
const visited = new Set();
|
|
243
|
+
const tree = [];
|
|
244
|
+
let totalRecords = 0;
|
|
245
|
+
async function trace(label, tableKey, sql) {
|
|
246
|
+
const visitKey = `${tableKey}:${sql}`;
|
|
247
|
+
if (visited.has(visitKey))
|
|
248
|
+
return null;
|
|
249
|
+
visited.add(visitKey);
|
|
250
|
+
const rows = await query(sql, "default");
|
|
251
|
+
totalRecords += rows.length;
|
|
252
|
+
const node = {
|
|
253
|
+
table: tableKey, recordCount: rows.length, children: [],
|
|
254
|
+
};
|
|
255
|
+
// === form 子表追踪 ===
|
|
256
|
+
if (label === "form" && rows.length > 0) {
|
|
257
|
+
const formId = rows[0]["FormID"];
|
|
258
|
+
const ruleTables = [
|
|
259
|
+
"FormRuleSetHedTB", "FormRuleSetDetTB", "FormRuleSetButtonTB",
|
|
260
|
+
"FormRuleSetDataSourceTB", "FormRuleSetLinkTB", "FormRuleSetMenuTB",
|
|
261
|
+
"FormRuleSetReferHedTB", "FormRuleSetReferTB", "FormRuleSetReferCaseTB",
|
|
262
|
+
"FormRuleSetReferFilterTB", "FormRuleSQLReplaceTB", "FormRuleDataFlowTB",
|
|
263
|
+
"FormRuleColorInfoTB",
|
|
264
|
+
];
|
|
265
|
+
for (const rt of ruleTables) {
|
|
266
|
+
const child = await trace("rule", rt, `SELECT * FROM ${T(tableKey)} WHERE FormID = ${formId}`);
|
|
267
|
+
if (child)
|
|
268
|
+
node.children.push(child);
|
|
269
|
+
}
|
|
270
|
+
const state = await trace("state", "FormStateSetTB", `SELECT * FROM ${T("formState")} WHERE FormID = ${formId}`);
|
|
271
|
+
if (state)
|
|
272
|
+
node.children.push(state);
|
|
273
|
+
}
|
|
274
|
+
// === dbo 子表追踪 ===
|
|
275
|
+
if (label === "dbo" && rows.length > 0) {
|
|
276
|
+
const dboId = rows[0]["DBOID"];
|
|
277
|
+
const subKeys = ["DBOSetFieldTB", "DBOPrSetHedTB", "DBOPrSetFieldTB", "DBOPrSetParamTB"];
|
|
278
|
+
for (const sk of subKeys) {
|
|
279
|
+
const child = await trace("dbosub", sk, `SELECT * FROM ${T("dboSet").replace(/DBOSetTB/g, sk)} WHERE DBOID = ${dboId}`);
|
|
280
|
+
if (child)
|
|
281
|
+
node.children.push(child);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// === dataflow 子表追踪 ===
|
|
285
|
+
if (label === "dataflow" && rows.length > 0) {
|
|
286
|
+
const dfId = rows[0]["DataFlowID"];
|
|
287
|
+
const subKeys = ["DataFlowDetTB", "DataFlowNodeTB", "DataFlowRelationTB"];
|
|
288
|
+
const subTableKeys = ["dataFlowDet", "dataFlowNode", "dataFlowRelation"];
|
|
289
|
+
for (let i = 0; i < subKeys.length; i++) {
|
|
290
|
+
const child = await trace("dfsub", subKeys[i], `SELECT * FROM ${T(subTableKeys[i])} WHERE DataFlowID = ${dfId}`);
|
|
291
|
+
if (child)
|
|
292
|
+
node.children.push(child);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// === function 子表追踪 ===
|
|
296
|
+
if (label === "function" && rows.length > 0) {
|
|
297
|
+
const fnId = rows[0]["FunctionID"];
|
|
298
|
+
const subKeys = ["FunctionKindTB", "MenuFunction"];
|
|
299
|
+
const subTableKeys = ["functionKind", "menuFunction"];
|
|
300
|
+
for (let i = 0; i < subKeys.length; i++) {
|
|
301
|
+
const child = await trace("fnsub", subKeys[i], `SELECT * FROM ${T(subTableKeys[i])} WHERE FunctionID = ${fnId}`);
|
|
302
|
+
if (child)
|
|
303
|
+
node.children.push(child);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return node;
|
|
307
|
+
}
|
|
308
|
+
const rootSql = `SELECT * FROM ${T(tableKey)} WHERE ${idField} = ${rootId}`;
|
|
309
|
+
const rootNode = await trace(featureType, `${tableKey} (根)`, rootSql);
|
|
310
|
+
if (rootNode)
|
|
311
|
+
tree.push(rootNode);
|
|
312
|
+
return {
|
|
313
|
+
featureName, featureType,
|
|
314
|
+
dependencyTree: tree,
|
|
315
|
+
totalTables: visited.size,
|
|
316
|
+
totalRecords,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
// ============================================================
|
|
320
|
+
// 功能列表查询
|
|
321
|
+
// ============================================================
|
|
322
|
+
export async function listFeatures(featureType, keyword) {
|
|
323
|
+
const types = featureType ? [featureType] : ["form", "dbo", "dataflow", "function"];
|
|
324
|
+
const results = [];
|
|
325
|
+
for (const ft of types) {
|
|
326
|
+
const tk = FORM_TABLE_KEY[ft];
|
|
327
|
+
const nf = FORM_NAME_FIELD[ft];
|
|
328
|
+
let sql = `SELECT TOP 50 ${nf} as name FROM ${T(tk)} WHERE 1=1`;
|
|
329
|
+
if (keyword) {
|
|
330
|
+
sql += ` AND ${nf} LIKE N'%${keyword.replace(/'/g, "''")}%'`;
|
|
331
|
+
}
|
|
332
|
+
sql += ` ORDER BY ${nf}`;
|
|
333
|
+
const rows = await query(sql, "default");
|
|
334
|
+
for (const r of rows) {
|
|
335
|
+
results.push({ name: r.name, type: ft, description: "", recordCount: 0 });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return results;
|
|
339
|
+
}
|
|
340
|
+
// ============================================================
|
|
341
|
+
// SQL 生成
|
|
342
|
+
// ============================================================
|
|
343
|
+
/**
|
|
344
|
+
* 把行数据转为 INSERT 语句
|
|
345
|
+
* @param rows 数据行
|
|
346
|
+
* @param fullTableName 全限定表名,如 [XDWmsCommon].[dbo].[TableSetTB]
|
|
347
|
+
* @param idColumn 自增 ID 列名,非空时开启 IDENTITY_INSERT
|
|
348
|
+
* @param idMap ID 映射器(源ID→目标ID),用于映射 ID 列和外键列的值
|
|
349
|
+
* @param fkRemap 需要根据 idMap 重映射的外键列列表
|
|
350
|
+
*/
|
|
351
|
+
export function generateInsertSql(rows, fullTableName, idColumn, idMap, fkRemap) {
|
|
352
|
+
if (rows.length === 0)
|
|
353
|
+
return "";
|
|
354
|
+
const cols = Object.keys(rows[0]);
|
|
355
|
+
const lines = [];
|
|
356
|
+
// 需要重映射的列:ID 列 + 外键列
|
|
357
|
+
const remapCols = new Set();
|
|
358
|
+
if (idColumn)
|
|
359
|
+
remapCols.add(idColumn);
|
|
360
|
+
if (fkRemap)
|
|
361
|
+
for (const c of fkRemap)
|
|
362
|
+
remapCols.add(c);
|
|
363
|
+
if (idColumn && idMap && !idMap.isEmpty) {
|
|
364
|
+
lines.push(`-- 注意:ID 存在重映射,使用 SET IDENTITY_INSERT`);
|
|
365
|
+
lines.push(`SET IDENTITY_INSERT ${fullTableName} ON;`);
|
|
366
|
+
}
|
|
367
|
+
else if (idColumn) {
|
|
368
|
+
lines.push(`SET IDENTITY_INSERT ${fullTableName} ON;`);
|
|
369
|
+
}
|
|
370
|
+
for (const row of rows) {
|
|
371
|
+
const values = cols.map((c) => {
|
|
372
|
+
let v = row[c];
|
|
373
|
+
// ID 重映射:如果此列需要重映射且 idMap 中有对应关系
|
|
374
|
+
if (remapCols.has(c) && idMap && !idMap.isEmpty && typeof v === "number") {
|
|
375
|
+
v = idMap.resolve(fullTableName, v);
|
|
376
|
+
}
|
|
377
|
+
if (v === null || v === undefined)
|
|
378
|
+
return "NULL";
|
|
379
|
+
if (typeof v === "number")
|
|
380
|
+
return String(v);
|
|
381
|
+
if (typeof v === "boolean")
|
|
382
|
+
return v ? "1" : "0";
|
|
383
|
+
// string / date: 转义单引号
|
|
384
|
+
return `N'${String(v).replace(/'/g, "''")}'`;
|
|
385
|
+
});
|
|
386
|
+
lines.push(`INSERT INTO ${fullTableName} (${cols.join(", ")}) VALUES (${values.join(", ")});`);
|
|
387
|
+
}
|
|
388
|
+
if (idColumn && idMap && !idMap.isEmpty) {
|
|
389
|
+
lines.push(`SET IDENTITY_INSERT ${fullTableName} OFF;`);
|
|
390
|
+
}
|
|
391
|
+
else if (idColumn) {
|
|
392
|
+
lines.push(`SET IDENTITY_INSERT ${fullTableName} OFF;`);
|
|
393
|
+
}
|
|
394
|
+
if (idMap && !idMap.isEmpty) {
|
|
395
|
+
lines.unshift(idMap.toSqlComment());
|
|
396
|
+
}
|
|
397
|
+
return lines.join("\n");
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=migrate-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-utils.js","sourceRoot":"","sources":["../src/migrate-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Warning } from "./shared.js";
|
|
2
|
+
/** 获取指定表在当前环境中的实际列集合(带缓存,列名统一大写) */
|
|
3
|
+
export declare function getTableColumns(tableRef: string, poolName?: string): Promise<Set<string>>;
|
|
4
|
+
/** 判断表是否在当前环境中实际存在(带缓存) */
|
|
5
|
+
export declare function tableExists(tableRef: string, poolName?: string): Promise<boolean>;
|
|
6
|
+
/** 判断用户库(dbName)中的表是否存在(带缓存) */
|
|
7
|
+
export declare function userTableExists(dbName: string, tableName: string, poolName?: string): Promise<boolean>;
|
|
8
|
+
/** 列存在性判断(不区分大小写)— 取代所有 cols.has("Xxx") */
|
|
9
|
+
export declare function hasCol(available: Set<string>, name: string): boolean;
|
|
10
|
+
/** 按 wanted 顺序过滤出实际存在的列(对 available 的大小写不敏感) */
|
|
11
|
+
export declare function pickCols(available: Set<string>, wanted: readonly string[]): string[];
|
|
12
|
+
export interface ResolvedSelect {
|
|
13
|
+
/** 可直接拼进 SELECT 的列清单 */
|
|
14
|
+
select: string;
|
|
15
|
+
/** 真实存在的列 */
|
|
16
|
+
present: string[];
|
|
17
|
+
/** 缺失的列(在 select 中以 NULL 占位) */
|
|
18
|
+
missing: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 构造 SELECT 列清单(纯函数):
|
|
22
|
+
* - 存在的列原样输出;
|
|
23
|
+
* - 缺失的列以 `CAST(NULL AS nvarchar(1)) AS [Col]` 占位,保证返回行结构稳定,
|
|
24
|
+
* 下游 `row.Xxx` 不会因缺列而拿到 undefined 与真实值混淆(缺列信息由 missing 透出)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildSelect(present: Set<string>, wanted: readonly string[]): ResolvedSelect;
|
|
27
|
+
/** 异步封装:查询实际列集合后构造 SELECT 列清单 */
|
|
28
|
+
export declare function resolveSelect(tableRef: string, wanted: readonly string[], poolName?: string): Promise<ResolvedSelect>;
|
|
29
|
+
/** 便捷方法:返回可直接拼进 SELECT 的列清单字符串(逗号分隔) */
|
|
30
|
+
export declare function buildSelectList(tableRef: string, wanted: readonly string[], poolName?: string): Promise<string>;
|
|
31
|
+
/** 一次性拿到表的"是否存在"与"实际列集合" */
|
|
32
|
+
export declare function getTableInfo(tableRef: string, poolName?: string): Promise<{
|
|
33
|
+
exists: boolean;
|
|
34
|
+
columns: Set<string>;
|
|
35
|
+
}>;
|
|
36
|
+
export interface DbErrorInfo {
|
|
37
|
+
message: string;
|
|
38
|
+
hint: string;
|
|
39
|
+
fallback?: string;
|
|
40
|
+
}
|
|
41
|
+
/** 纯函数:把 mssql 原生错误映射为可执行的提示 */
|
|
42
|
+
export declare function mapDbError(err: unknown): DbErrorInfo;
|
|
43
|
+
/** 单条子查询的容错执行:失败时降级为 [] 并写入 warnings,不让整个工具调用失败 */
|
|
44
|
+
export declare function tryQuery<T = Record<string, unknown>>(label: string, sql: string, warnings: Warning[], poolName?: string): Promise<T[]>;
|
|
45
|
+
/** 清空全部 schema 探测缓存(供 get_capabilities 刷新或测试使用) */
|
|
46
|
+
export declare function clearSchemaCache(): void;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { query } from "./db.js";
|
|
2
|
+
/**
|
|
3
|
+
* 环境库兼容辅助:XDX 各环境的元数据表(TableSetTB 等)字段并不完全一致,
|
|
4
|
+
* 有的环境缺字段(如 EnglishDesc/OtherDesc/IsDelete/iLineNo),有的环境甚至缺整张表(如 FunctionKindTB)。
|
|
5
|
+
* 这些工具在拼接 SQL 前先查询实际的列集合/表存在性,只使用真实存在的列,避免
|
|
6
|
+
* "Invalid column name ..." / "Invalid object name ..." 报错。
|
|
7
|
+
*
|
|
8
|
+
* 重要:getTableColumns 返回的列名统一为大写,因此**禁止**直接使用 `cols.has("TableName")`
|
|
9
|
+
* 判断列是否存在(Set.has 区分大小写,恒为 false)。请统一使用 hasCol()。
|
|
10
|
+
*/
|
|
11
|
+
const colCache = new Map();
|
|
12
|
+
const existsCache = new Map();
|
|
13
|
+
const userExistsCache = new Map();
|
|
14
|
+
/** 解析 [db].[schema].[table] 形式的全限定表名 */
|
|
15
|
+
function parseTableRef(tableRef) {
|
|
16
|
+
const m = tableRef.match(/^\[([^\]]+)\]\.\[([^\]]+)\]\.\[([^\]]+)\]$/);
|
|
17
|
+
if (!m)
|
|
18
|
+
return null;
|
|
19
|
+
return { db: m[1], table: m[3] };
|
|
20
|
+
}
|
|
21
|
+
/** 安全化数据库/表名(用于 INFORMATION_SCHEMA 拼接) */
|
|
22
|
+
function safeName(name) {
|
|
23
|
+
return name.replace(/'/g, "''");
|
|
24
|
+
}
|
|
25
|
+
/** 获取指定表在当前环境中的实际列集合(带缓存,列名统一大写) */
|
|
26
|
+
export async function getTableColumns(tableRef, poolName = "default") {
|
|
27
|
+
const parsed = parseTableRef(tableRef);
|
|
28
|
+
if (!parsed)
|
|
29
|
+
return new Set();
|
|
30
|
+
const key = `${poolName}|${parsed.db}|${parsed.table}`;
|
|
31
|
+
const cached = colCache.get(key);
|
|
32
|
+
if (cached)
|
|
33
|
+
return cached;
|
|
34
|
+
const rows = await query(`SELECT COLUMN_NAME FROM [${parsed.db}].INFORMATION_SCHEMA.COLUMNS ` +
|
|
35
|
+
`WHERE TABLE_SCHEMA='dbo' AND TABLE_NAME='${safeName(parsed.table)}'`, poolName);
|
|
36
|
+
const cols = new Set(rows.map((r) => String(r.COLUMN_NAME ?? "").toUpperCase()).filter(Boolean));
|
|
37
|
+
colCache.set(key, cols);
|
|
38
|
+
return cols;
|
|
39
|
+
}
|
|
40
|
+
/** 判断表是否在当前环境中实际存在(带缓存) */
|
|
41
|
+
export async function tableExists(tableRef, poolName = "default") {
|
|
42
|
+
const parsed = parseTableRef(tableRef);
|
|
43
|
+
if (!parsed)
|
|
44
|
+
return false;
|
|
45
|
+
const key = `${poolName}|${parsed.db}|${parsed.table}`;
|
|
46
|
+
const cached = existsCache.get(key);
|
|
47
|
+
if (cached !== undefined)
|
|
48
|
+
return cached;
|
|
49
|
+
const rows = await query(`SELECT TABLE_NAME FROM [${parsed.db}].INFORMATION_SCHEMA.TABLES ` +
|
|
50
|
+
`WHERE TABLE_SCHEMA='dbo' AND TABLE_NAME='${safeName(parsed.table)}'`, poolName);
|
|
51
|
+
const exists = rows.length > 0;
|
|
52
|
+
existsCache.set(key, exists);
|
|
53
|
+
return exists;
|
|
54
|
+
}
|
|
55
|
+
/** 判断用户库(dbName)中的表是否存在(带缓存) */
|
|
56
|
+
export async function userTableExists(dbName, tableName, poolName = "default") {
|
|
57
|
+
if (!dbName)
|
|
58
|
+
return false;
|
|
59
|
+
const key = `${poolName}|${dbName}|${tableName}`;
|
|
60
|
+
const cached = userExistsCache.get(key);
|
|
61
|
+
if (cached !== undefined)
|
|
62
|
+
return cached;
|
|
63
|
+
const rows = await query(`SELECT TABLE_NAME FROM [${dbName}].INFORMATION_SCHEMA.TABLES ` +
|
|
64
|
+
`WHERE TABLE_SCHEMA='dbo' AND TABLE_NAME='${safeName(tableName)}'`, poolName);
|
|
65
|
+
const exists = rows.length > 0;
|
|
66
|
+
userExistsCache.set(key, exists);
|
|
67
|
+
return exists;
|
|
68
|
+
}
|
|
69
|
+
/** 列存在性判断(不区分大小写)— 取代所有 cols.has("Xxx") */
|
|
70
|
+
export function hasCol(available, name) {
|
|
71
|
+
return available.has(name.toUpperCase());
|
|
72
|
+
}
|
|
73
|
+
/** 按 wanted 顺序过滤出实际存在的列(对 available 的大小写不敏感) */
|
|
74
|
+
export function pickCols(available, wanted) {
|
|
75
|
+
// available 通常来自 getTableColumns(已统一大写),这里对任意大小写都做兜底
|
|
76
|
+
const upper = new Set([...available].map((c) => c.toUpperCase()));
|
|
77
|
+
return wanted.filter((c) => upper.has(c.toUpperCase()));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 构造 SELECT 列清单(纯函数):
|
|
81
|
+
* - 存在的列原样输出;
|
|
82
|
+
* - 缺失的列以 `CAST(NULL AS nvarchar(1)) AS [Col]` 占位,保证返回行结构稳定,
|
|
83
|
+
* 下游 `row.Xxx` 不会因缺列而拿到 undefined 与真实值混淆(缺列信息由 missing 透出)。
|
|
84
|
+
*/
|
|
85
|
+
export function buildSelect(present, wanted) {
|
|
86
|
+
const presentList = [];
|
|
87
|
+
const missing = [];
|
|
88
|
+
const parts = [];
|
|
89
|
+
const upper = new Set([...present].map((c) => c.toUpperCase()));
|
|
90
|
+
for (const w of wanted) {
|
|
91
|
+
if (!/^[A-Za-z0-9_]+$/.test(w)) {
|
|
92
|
+
missing.push(w);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (upper.has(w.toUpperCase())) {
|
|
96
|
+
presentList.push(w);
|
|
97
|
+
parts.push(`[${w}]`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
missing.push(w);
|
|
101
|
+
parts.push(`CAST(NULL AS nvarchar(1)) AS [${w}]`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { select: parts.join(", "), present: presentList, missing };
|
|
105
|
+
}
|
|
106
|
+
/** 异步封装:查询实际列集合后构造 SELECT 列清单 */
|
|
107
|
+
export async function resolveSelect(tableRef, wanted, poolName = "default") {
|
|
108
|
+
return buildSelect(await getTableColumns(tableRef, poolName), wanted);
|
|
109
|
+
}
|
|
110
|
+
/** 便捷方法:返回可直接拼进 SELECT 的列清单字符串(逗号分隔) */
|
|
111
|
+
export async function buildSelectList(tableRef, wanted, poolName = "default") {
|
|
112
|
+
return (await resolveSelect(tableRef, wanted, poolName)).select;
|
|
113
|
+
}
|
|
114
|
+
/** 一次性拿到表的"是否存在"与"实际列集合" */
|
|
115
|
+
export async function getTableInfo(tableRef, poolName = "default") {
|
|
116
|
+
const [exists, columns] = await Promise.all([
|
|
117
|
+
tableExists(tableRef, poolName),
|
|
118
|
+
getTableColumns(tableRef, poolName),
|
|
119
|
+
]);
|
|
120
|
+
return { exists, columns };
|
|
121
|
+
}
|
|
122
|
+
/** 纯函数:把 mssql 原生错误映射为可执行的提示 */
|
|
123
|
+
export function mapDbError(err) {
|
|
124
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
125
|
+
const col = /Invalid column name '([^']+)'/i.exec(message);
|
|
126
|
+
if (col) {
|
|
127
|
+
return {
|
|
128
|
+
message,
|
|
129
|
+
hint: `列 ${col[1]} 在当前环境库中不存在(各环境库元数据表字段不一致)。请用 describe_table 查看实际字段,或先用 get_capabilities 确认本环境可用能力。`,
|
|
130
|
+
fallback: "describe_table",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const obj = /Invalid object name '([^']+)'/i.exec(message);
|
|
134
|
+
if (obj) {
|
|
135
|
+
return {
|
|
136
|
+
message,
|
|
137
|
+
hint: `表 ${obj[1]} 在当前环境库中不存在。可用 get_capabilities 查看本环境支持的元数据表。`,
|
|
138
|
+
fallback: "get_capabilities",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
message,
|
|
143
|
+
hint: "查询失败。可用 get_capabilities 确认本环境可用能力,或缩小查询范围后重试。",
|
|
144
|
+
fallback: "get_capabilities",
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/** 单条子查询的容错执行:失败时降级为 [] 并写入 warnings,不让整个工具调用失败 */
|
|
148
|
+
export async function tryQuery(label, sql, warnings, poolName = "default") {
|
|
149
|
+
try {
|
|
150
|
+
return await query(sql, poolName);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const info = mapDbError(err);
|
|
154
|
+
warnings.push({
|
|
155
|
+
module: label,
|
|
156
|
+
message: info.message,
|
|
157
|
+
hint: info.hint,
|
|
158
|
+
fallback: info.fallback,
|
|
159
|
+
});
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** 清空全部 schema 探测缓存(供 get_capabilities 刷新或测试使用) */
|
|
164
|
+
export function clearSchemaCache() {
|
|
165
|
+
colCache.clear();
|
|
166
|
+
existsCache.clear();
|
|
167
|
+
userExistsCache.clear();
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=schema-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-compat.js","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC;;;;;;;;GAQG;AAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;AAChD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAmB,CAAC;AAC/C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAmB,CAAC;AAEnD,wCAAwC;AACxC,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;IACvE,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnC,CAAC;AAED,0CAA0C;AAC1C,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,QAAQ,GAAG,SAAS;IAEpB,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAG,MAAM,KAAK,CACtB,4BAA4B,MAAM,CAAC,EAAE,+BAA+B;QAClE,4CAA4C,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EACvE,QAAQ,CACT,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,GAAG,CAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAC3E,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2BAA2B;AAC3B,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,QAAQ,GAAG,SAAS;IAEpB,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,KAAK,CACtB,2BAA2B,MAAM,CAAC,EAAE,8BAA8B;QAChE,4CAA4C,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EACvE,QAAQ,CACT,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,SAAiB,EACjB,QAAQ,GAAG,SAAS;IAEpB,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,KAAK,CACtB,2BAA2B,MAAM,8BAA8B;QAC7D,4CAA4C,QAAQ,CAAC,SAAS,CAAC,GAAG,EACpE,QAAQ,CACT,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,MAAM,CAAC,SAAsB,EAAE,IAAY;IACzD,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CACtB,SAAsB,EACtB,MAAyB;IAEzB,qDAAqD;IACrD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC1D,CAAC;AAWD;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,OAAoB,EACpB,MAAyB;IAEzB,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAEhE,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC/B,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,iCAAiC;AACjC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,MAAyB,EACzB,QAAQ,GAAG,SAAS;IAEpB,OAAO,WAAW,CAAC,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;AACxE,CAAC;AAED,wCAAwC;AACxC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,MAAyB,EACzB,QAAQ,GAAG,SAAS;IAEpB,OAAO,CAAC,MAAM,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;AAClE,CAAC;AAED,4BAA4B;AAC5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,QAAQ,GAAG,SAAS;IAEpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1C,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC/B,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC;KACpC,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAYD,gCAAgC;AAChC,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAEjE,MAAM,GAAG,GAAG,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,GAAG,EAAE,CAAC;QACR,OAAO;YACL,OAAO;YACP,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,qFAAqF;YACtG,QAAQ,EAAE,gBAAgB;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,GAAG,EAAE,CAAC;QACR,OAAO;YACL,OAAO;YACP,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,+CAA+C;YAChE,QAAQ,EAAE,kBAAkB;SAC7B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO;QACP,IAAI,EAAE,gDAAgD;QACtD,QAAQ,EAAE,kBAAkB;KAC7B,CAAC;AACJ,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAAa,EACb,GAAW,EACX,QAAmB,EACnB,QAAQ,GAAG,SAAS;IAEpB,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAI,GAAG,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,gBAAgB;IAC9B,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,eAAe,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|