@bimatrix-aud-platform/aud_mcp_server 1.1.19 → 1.1.20

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.
@@ -56,7 +56,9 @@ export function fixMtsd(filePath) {
56
56
  fixOlapGridFields(doc, datas, fixes);
57
57
  // Rule 2-2: OlapGrid Fields 내 CreateType=1 (Measures) 필드 보정
58
58
  fixOlapMeasuresField(doc, fixes);
59
- // Rule 3: DataSource Params에 Value 누락 보정
59
+ // Rule 3: Enum/Range 범위 초과 보정
60
+ fixEnumAndRangeValues(doc, datas, fixes);
61
+ // Rule (disabled): DataSource Params에 Value 누락 보정
60
62
  //fixParamsMissingValue(datas, fixes);
61
63
  // Rule 4: DataSource Columns에 Type 누락 보정
62
64
  //fixColumnsMissingType(datas, fixes);
@@ -308,6 +310,137 @@ const BORDER_DEFAULTS = {
308
310
  // });
309
311
  // }
310
312
  // }
313
+ // ---- Rule 3: Enum/Range 값 범위 초과 보정 ----
314
+ // string enum 검증: 허용값에 없으면 기본값으로 보정
315
+ function fixStringEnum(obj, key, allowed, defaultVal, path, fixes) {
316
+ if (!(key in obj))
317
+ return;
318
+ const val = obj[key];
319
+ if (typeof val !== "string" || !allowed.includes(val)) {
320
+ obj[key] = defaultVal;
321
+ fixes.push(`[Rule3] ${path}.${key}: "${val}" → "${defaultVal}" 보정 (허용값: ${allowed.join(", ")})`);
322
+ }
323
+ }
324
+ // integer 범위 검증: min~max 범위 밖이면 기본값으로 보정
325
+ function fixIntRange(obj, key, min, max, defaultVal, path, fixes) {
326
+ if (!(key in obj))
327
+ return;
328
+ const val = obj[key];
329
+ if (typeof val !== "number" || !Number.isInteger(val) || val < min || val > max) {
330
+ obj[key] = defaultVal;
331
+ fixes.push(`[Rule3] ${path}.${key}: ${val} → ${defaultVal} 보정 (범위: ${min}~${max})`);
332
+ }
333
+ }
334
+ // integer enum 검증: 허용 값 집합에 없으면 기본값으로 보정 (비연속 enum용)
335
+ function fixIntEnum(obj, key, allowed, defaultVal, path, fixes) {
336
+ if (!(key in obj))
337
+ return;
338
+ const val = obj[key];
339
+ if (typeof val !== "number" || !allowed.includes(val)) {
340
+ obj[key] = defaultVal;
341
+ fixes.push(`[Rule3] ${path}.${key}: ${val} → ${defaultVal} 보정 (허용값: ${allowed.join(", ")})`);
342
+ }
343
+ }
344
+ // RGBA 색상 clamp (0~255)
345
+ function clampColorRGBA(obj, path, fixes) {
346
+ if (!obj || typeof obj !== "object")
347
+ return;
348
+ for (const key of ["R", "G", "B", "A", "ColorR", "ColorG", "ColorB", "ColorA"]) {
349
+ if (!(key in obj))
350
+ continue;
351
+ const val = obj[key];
352
+ if (typeof val !== "number")
353
+ continue;
354
+ if (val < 0) {
355
+ obj[key] = 0;
356
+ fixes.push(`[Rule3] ${path}.${key}: ${val} → 0 보정 (범위: 0~255)`);
357
+ }
358
+ else if (val > 255) {
359
+ obj[key] = 255;
360
+ fixes.push(`[Rule3] ${path}.${key}: ${val} → 255 보정 (범위: 0~255)`);
361
+ }
362
+ }
363
+ }
364
+ function fixEnumAndRangeValues(doc, datas, fixes) {
365
+ // ── 1. ReportInfo ──
366
+ const ri = doc.ReportInfo;
367
+ if (ri) {
368
+ fixIntRange(ri, "TabPosition", 0, 2, 0, "ReportInfo", fixes); // 기본값: 1(None)
369
+ fixIntRange(ri, "RefreshType", 0, 1, 0, "ReportInfo", fixes); // 기본값: 0(All)
370
+ }
371
+ // ── 2. DataSources ──
372
+ for (const ds of datas) {
373
+ const dsPath = `DataSource("${ds.Name || ds.Id || "?"}")`;
374
+ fixIntRange(ds, "DSType", 0, 5, 2, dsPath, fixes); // 기본값: 2(DataSource)
375
+ }
376
+ // ── 3. FormStyle ──
377
+ const forms = doc.Forms || [];
378
+ for (const form of forms) {
379
+ if (form.Style) {
380
+ fixIntRange(form.Style, "Type", 0, 2, 0, `Form("${form.Name}").Style`, fixes); // 기본값: 0(Skin)
381
+ }
382
+ }
383
+ // ── 4. Elements (walkElements 순회) ──
384
+ for (const form of forms) {
385
+ const elements = form.Elements || [];
386
+ walkElements(elements, (el, path) => {
387
+ // ---- Style.Border.LineType ----
388
+ const border = el.Style?.Border;
389
+ if (border) {
390
+ fixStringEnum(border, "LineType", ["none", "solid", "dashed", "dotted"], "solid", // 기본값: "solid"
391
+ `${path}.Style.Border`, fixes);
392
+ clampColorRGBA(border, `${path}.Style.Border`, fixes);
393
+ if (border.Color)
394
+ clampColorRGBA(border.Color, `${path}.Style.Border.Color`, fixes);
395
+ }
396
+ // ---- Style.Font.HorizontalAlignment / VerticalAlignment ----
397
+ const font = el.Style?.Font;
398
+ if (font) {
399
+ fixStringEnum(font, "HorizontalAlignment", ["left", "center", "right"], "left", // 기본값: "left"
400
+ `${path}.Style.Font`, fixes);
401
+ fixStringEnum(font, "VerticalAlignment", ["top", "middle", "bottom"], "middle", // 기본값: "middle"
402
+ `${path}.Style.Font`, fixes);
403
+ if (font.Color)
404
+ clampColorRGBA(font.Color, `${path}.Style.Font.Color`, fixes);
405
+ }
406
+ // ---- Style.Background Color ----
407
+ const bg = el.Style?.Background;
408
+ if (bg) {
409
+ clampColorRGBA(bg, `${path}.Style.Background`, fixes);
410
+ if (bg.Color)
411
+ clampColorRGBA(bg.Color, `${path}.Style.Background.Color`, fixes);
412
+ }
413
+ // ---- DataGrid / TreeGrid Columns ----
414
+ if ((el.Type === "DataGrid" || el.Type === "TreeGrid") && Array.isArray(el.Columns)) {
415
+ for (let i = 0; i < el.Columns.length; i++) {
416
+ const col = el.Columns[i];
417
+ const colPath = `${path}.Columns[${i}]("${col.Name || ""}")`;
418
+ fixStringEnum(col, "HeaderPosition", ["left", "center", "right", "start", "end"], "center", // 기본값: "center"
419
+ colPath, fixes);
420
+ fixStringEnum(col, "TextPosition", ["left", "center", "right", "start", "end"], "left", // 기본값: "left"
421
+ colPath, fixes);
422
+ // 0:None, 1:Text, 2:CheckBox, 3:NumberBox, 4:ComboBox, 5:DateTime, 6:MaskEdit, 8:Image, 9:MultiLineText, 10:TrendLine, 11:SingleBarChart, 12:ColorPicker, 15:Time
423
+ fixIntEnum(col, "ColumnType", [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 15], 1, colPath, fixes); // 기본값: 0(None)
424
+ fixIntRange(col, "KeyType", 0, 3, 2, colPath, fixes); // 기본값: 2(Nullable)
425
+ fixIntRange(col, "DataType", 0, 2, 0, colPath, fixes); // 기본값: 1(String)
426
+ }
427
+ }
428
+ // ---- OlapGrid Fields ----
429
+ if (el.Type === "OlapGrid") {
430
+ const fields = el.iOLAPView?.Fields;
431
+ if (fields && Array.isArray(fields)) {
432
+ for (const field of fields) {
433
+ const fPath = `${path}.Fields["${field.Key || "?"}"]`;
434
+ fixIntRange(field, "Category", 0, 4, 1, fPath, fixes); // 기본값: 1(Dimension)
435
+ fixIntRange(field, "Area", 0, 4, 3, fPath, fixes); // 기본값: 3(Filter)
436
+ fixIntRange(field, "SortType", 0, 5, 0, fPath, fixes); // 기본값: 0(None)
437
+ fixIntRange(field, "CreateType", 0, 3, 0, fPath, fixes); // 기본값: 0(Default)
438
+ }
439
+ }
440
+ }
441
+ });
442
+ }
443
+ }
311
444
  // ---- 유틸: Element 트리 순회 ----
312
445
  function walkElements(elements, callback, parentPath = "") {
313
446
  for (const el of elements) {
package/dist/index.js CHANGED
@@ -545,7 +545,7 @@ const tools = [
545
545
  },
546
546
  {
547
547
  name: "fix_mtsd",
548
- description: "MTSD 파일을 읽어 자동 보정 규칙을 적용하고 파일을 덮어씁니다. DataSource Name→Id 참조 보정, Params Value 누락 보정, Columns Type 누락 보정, Docking/Border 필수 속성 보정을 수행합니다.",
548
+ description: "MTSD 파일을 읽어 자동 보정 규칙을 적용하고 파일을 덮어씁니다. [Rule1] DataSource Name→Id 참조 보정, [Rule2] OlapGrid DataSource 기반 Fields 자동 생성, [Rule2-2] OlapGrid Fields 내 CreateType=1 중복 보정 (#MEASURES_HEADER#만 허용), [Rule3] Enum/Range 값 범위 초과 보정 (Border.LineType, Font 정렬, Color RGBA clamp, GridColumn 속성, OlapField 속성 등), Params ParamType 누락 보정을 수행합니다.",
549
549
  inputSchema: {
550
550
  type: "object",
551
551
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bimatrix-aud-platform/aud_mcp_server",
3
- "version": "1.1.19",
3
+ "version": "1.1.20",
4
4
  "description": "MCP Server for i-AUD MTSD document validation and generation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -115,7 +115,7 @@ export interface IDataSource {
115
115
  ConnectionCode: string;
116
116
  /** SQL 쿼리 암호화 여부 */
117
117
  Encrypted: boolean;
118
- /** 데이터소스 타입 (0: DataSource, 1: MetaData, 2: Template, 3: ServerDataSource) */
118
+ /** 데이터소스 타입 (0:메타 템플릿,1:메타 쿼리, 2:일반 SQL,3:OLAP Drill to Detail,4:공통데이터소스,5:메타 필터) */
119
119
  DSType: number;
120
120
  /** 실행할 SQL 쿼리문 */
121
121
  SQL: string;
@@ -657,13 +657,13 @@ export interface IGridColumn {
657
657
  Resizable?: boolean;
658
658
  /** 내보내기 포함 여부 */
659
659
  UseExport?: boolean;
660
- /** 컬럼 타입 (0: Text, 1: CheckBox, 2: ComboBox ) */
660
+ /** 컬럼 타입 (0:None, 1:Text, 2:CheckBox, 3:NumberBox, 4:ComboBox, 5:DateTime, 6:MaskEdit, 8:Image, 9:MultiLineText, 10:TrendLine, 11:SingleBarChart, 12:ColorPicker, 15:Time) */
661
661
  ColumnType?: number;
662
662
  /** 커서 타입 */
663
663
  CursorType?: string;
664
- /** 키 타입 (0: None, 1: Primary, 2: Foreign 등) */
664
+ /** 키 타입 (0:None, 1:NotNull, 2:Nullable, 3:Primary) */
665
665
  KeyType: number;
666
- /** 데이터 타입 (0: String, 1: Number, 2: Date ) */
666
+ /** 데이터 타입 (0:Numeric, 1:String, 2:DateTime8(yyyyMMdd), 3:DateTimeNow, 4:UserCode, 5:CLOB, 7:UUID) */
667
667
  DataType?: number;
668
668
  /** 헤더 텍스트 정렬 */
669
669
  HeaderPosition: 'left' | 'center' | 'right' | 'start' | 'end';
@@ -1433,7 +1433,7 @@ export interface IOlapField {
1433
1433
  ToolTipField?: string;
1434
1434
  /** 툴팁 텍스트 */
1435
1435
  ToolTipText?: string;
1436
- /** 필드 카테고리 (0: Dimension, 1: Measure, 2: Attribute, 3: Period, 4: Datas) */
1436
+ /** 필드 카테고리 (0: Default, 1: Dimension, 2: Measure, 3: Attribute, 4: Period) */
1437
1437
  Category: number;
1438
1438
  /** 필드 영역 (0: None, 1: Row, 2: Column, 3: Data, 4: Filter) */
1439
1439
  Area: number;
@@ -102,7 +102,7 @@
102
102
  "UseCache": { "type": "boolean", "description": "쿼리 결과 캐싱 사용 여부" },
103
103
  "ConnectionCode": { "type": "string", "description": "연결된 DB 커넥션 코드" },
104
104
  "Encrypted": { "type": "boolean", "description": "SQL 쿼리 암호화 여부" },
105
- "DSType": { "type": "integer", "enum": [0, 1, 2, 3], "description": "데이터소스 타입 (0:DataSource, 1:MetaData, 2:Template, 3:ServerDataSource)" },
105
+ "DSType": { "type": "integer", "enum": [0, 1, 2, 3,4,5], "description": "데이터소스 타입 (0:메타 템플릿,1:메타 쿼리, 2:일반 SQL,3:OLAP Drill to Detail,4:공통데이터소스,5:메타 필터)" },
106
106
  "SQL": { "type": "string", "description": "실행할 SQL 쿼리문" },
107
107
  "Params": {
108
108
  "type": "array",
@@ -1019,7 +1019,7 @@
1019
1019
  "Caption": { "type": "string", "description": "필드 캡션" },
1020
1020
  "ToolTipField": { "type": "string", "description": "툴팁 필드 키" },
1021
1021
  "ToolTipText": { "type": "string", "description": "툴팁 텍스트" },
1022
- "Category": { "type": "number", "description": "카테고리 (0:Dimension, 1:Measure, 2:Attribute, 3:Period, 4:Datas)" },
1022
+ "Category": { "type": "number", "description": "카테고리 (0: Default, 1: Dimension, 2: Measure, 3: Attribute, 4: Period)" },
1023
1023
  "Area": { "type": "number", "description": "영역 (0:None, 1:Row, 2:Column, 3:Data, 4:Filter)" },
1024
1024
  "SummaryType": { "type": "number", "description": "요약 유형 (0:Sum, 1:Count, 2:Average, 3:Min, 4:Max 등)" },
1025
1025
  "TotalSummaryType": { "type": "number", "description": "합계 요약 유형" },
@@ -1325,10 +1325,10 @@
1325
1325
  "Mergeable": { "type": "boolean" },
1326
1326
  "Resizable": { "type": "boolean" },
1327
1327
  "UseExport": { "type": "boolean" },
1328
- "ColumnType": { "type": "integer", "description": "컬럼 타입 (0:Text, 1:CheckBox, 2:ComboBox)" },
1328
+ "ColumnType": { "type": "integer", "description": "컬럼 타입 (0:None, 1:Text, 2:CheckBox, 3:NumberBox, 4:ComboBox, 5:DateTime, 6:MaskEdit, 8:Image, 9:MultiLineText, 10:TrendLine, 11:SingleBarChart, 12:ColorPicker, 15:Time)" },
1329
1329
  "CursorType": { "type": "string" },
1330
- "KeyType": { "type": "integer", "description": "키 타입 (0:None, 1:Primary, 2:Foreign)" },
1331
- "DataType": { "type": "integer", "description": "데이터 타입 (0:String, 1:Number, 2:Date)" },
1330
+ "KeyType": { "type": "integer", "description": "키 타입 (0:None, 1:NotNull, 2:Nullable, 3:Primary)" },
1331
+ "DataType": { "type": "integer", "description": "데이터 타입 (0:Numeric, 1:String, 2:DateTime8(yyyyMMdd), 3:DateTimeNow, 4:UserCode, 5:CLOB, 7:UUID)" },
1332
1332
  "HeaderPosition": { "type": "string", "enum": ["left", "center", "right", "start", "end"] },
1333
1333
  "TextPosition": { "type": "string", "enum": ["left", "center", "right", "start", "end"] },
1334
1334
  "GridColumnWidthType": { "type": "integer" },