abapgit-agent 1.2.0 → 1.3.0

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.
@@ -0,0 +1,83 @@
1
+ *"*"use source
2
+ *"*"Local Interface:
3
+ *"**********************************************************************
4
+ CLASS zcl_abgagt_viewer_ddls DEFINITION PUBLIC FINAL CREATE PUBLIC.
5
+
6
+ PUBLIC SECTION.
7
+ INTERFACES zif_abgagt_viewer.
8
+
9
+ ENDCLASS.
10
+
11
+ CLASS zcl_abgagt_viewer_ddls IMPLEMENTATION.
12
+
13
+ METHOD zif_abgagt_viewer~get_info.
14
+ DATA: lv_ddls_name TYPE ddlname,
15
+ lo_handler TYPE REF TO if_dd_ddl_handler,
16
+ ls_ddlsrcv TYPE ddddlsrcv,
17
+ lv_devclass TYPE tadir-devclass,
18
+ lv_found TYPE abap_bool.
19
+
20
+ rs_info-name = iv_name.
21
+ rs_info-type = 'DDLS'.
22
+ rs_info-type_text = 'CDS View'.
23
+
24
+ " Get package from TADIR
25
+ SELECT SINGLE devclass FROM tadir
26
+ INTO lv_devclass
27
+ WHERE obj_name = iv_name
28
+ AND object = 'DDLS'.
29
+ IF sy-subrc = 0.
30
+ rs_info-description = |CDS View { iv_name } in { lv_devclass }|.
31
+ ELSE.
32
+ rs_info-not_found = abap_true.
33
+ RETURN.
34
+ ENDIF.
35
+
36
+ " Use DDL handler to read CDS view source
37
+ lo_handler = cl_dd_ddl_handler_factory=>create( ).
38
+ lv_ddls_name = iv_name.
39
+
40
+ " First try to read inactive version (get_state = 'M')
41
+ TRY.
42
+ lo_handler->read(
43
+ EXPORTING
44
+ name = lv_ddls_name
45
+ get_state = 'M'
46
+ IMPORTING
47
+ ddddlsrcv_wa = ls_ddlsrcv ).
48
+
49
+ IF ls_ddlsrcv-source IS NOT INITIAL.
50
+ lv_found = abap_true.
51
+ ENDIF.
52
+
53
+ CATCH cx_dd_ddl_check.
54
+ " Ignore - will try active version
55
+ ENDTRY.
56
+
57
+ " If no inactive version, try active version
58
+ IF lv_found = abap_false.
59
+ TRY.
60
+ lo_handler->read(
61
+ EXPORTING
62
+ name = lv_ddls_name
63
+ get_state = 'A'
64
+ IMPORTING
65
+ ddddlsrcv_wa = ls_ddlsrcv ).
66
+
67
+ IF ls_ddlsrcv-source IS NOT INITIAL.
68
+ lv_found = abap_true.
69
+ ENDIF.
70
+ CATCH cx_dd_ddl_check.
71
+ " Not found
72
+ ENDTRY.
73
+ ENDIF.
74
+
75
+ " Set source code if found
76
+ IF lv_found = abap_true.
77
+ rs_info-source = ls_ddlsrcv-source.
78
+ ELSE.
79
+ rs_info-not_found = abap_true.
80
+ ENDIF.
81
+ ENDMETHOD.
82
+
83
+ ENDCLASS.
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
3
+ <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
4
+ <asx:values>
5
+ <VSEOCLASS>
6
+ <CLSNAME>ZCL_ABGAGT_VIEWER_DDLS</CLSNAME>
7
+ <LANGU>E</LANGU>
8
+ <DESCRIPT>Viewer for CDS Views</DESCRIPT>
9
+ <EXPOSURE>2</EXPOSURE>
10
+ <STATE>1</STATE>
11
+ <UNICODE>X</UNICODE>
12
+ </VSEOCLASS>
13
+ </asx:values>
14
+ </asx:abap>
15
+ </abapGit>
@@ -0,0 +1,93 @@
1
+ *"*"use source
2
+ *"*"Local Interface:
3
+ *"**********************************************************************
4
+ CLASS zcl_abgagt_viewer_ttyp DEFINITION PUBLIC FINAL CREATE PUBLIC.
5
+
6
+ PUBLIC SECTION.
7
+ INTERFACES zif_abgagt_viewer.
8
+
9
+ ENDCLASS.
10
+
11
+ CLASS zcl_abgagt_viewer_ttyp IMPLEMENTATION.
12
+
13
+ METHOD zif_abgagt_viewer~get_info.
14
+ DATA: lv_obj_name TYPE tadir-obj_name,
15
+ lv_devclass TYPE tadir-devclass,
16
+ lv_linetype TYPE string,
17
+ lv_tabprottype TYPE string,
18
+ lv_keydef TYPE string,
19
+ lv_access_mode TYPE string,
20
+ lv_key_definition TYPE string.
21
+
22
+ rs_info-name = iv_name.
23
+ rs_info-type = 'TTYP'.
24
+ rs_info-type_text = 'Table Type'.
25
+
26
+ " Get package from TADIR
27
+ SELECT SINGLE obj_name devclass FROM tadir
28
+ INTO (lv_obj_name, lv_devclass)
29
+ WHERE obj_name = iv_name
30
+ AND object = 'TTYP'.
31
+ IF sy-subrc = 0.
32
+ rs_info-description = |Table Type { iv_name } in { lv_devclass }|.
33
+ ELSE.
34
+ rs_info-not_found = abap_true.
35
+ ENDIF.
36
+
37
+ " Get TTYP details from DD40L
38
+ SELECT SINGLE rowtype accessmode keydef FROM dd40l
39
+ INTO (lv_linetype, lv_tabprottype, lv_keydef)
40
+ WHERE typename = iv_name
41
+ AND as4local = 'A'.
42
+
43
+ " Build components table with TTYP details
44
+ IF lv_linetype IS NOT INITIAL.
45
+ APPEND VALUE #(
46
+ field = 'LINE_TYPE'
47
+ key = abap_false
48
+ type = 'CHAR'
49
+ length = 30
50
+ dataelement = ''
51
+ description = |Line Type: { lv_linetype }|
52
+ ) TO rs_info-components.
53
+ ENDIF.
54
+
55
+ " Convert access mode to text
56
+ CASE lv_tabprottype.
57
+ WHEN 'T'. lv_access_mode = 'STANDARD'.
58
+ WHEN 'S'. lv_access_mode = 'SORTED'.
59
+ WHEN 'H'. lv_access_mode = 'HASHED'.
60
+ WHEN OTHERS. lv_access_mode = lv_tabprottype.
61
+ ENDCASE.
62
+
63
+ IF lv_access_mode IS NOT INITIAL.
64
+ APPEND VALUE #(
65
+ field = 'ACCESS_MODE'
66
+ key = abap_false
67
+ type = 'CHAR'
68
+ length = 10
69
+ dataelement = ''
70
+ description = |Access Mode: { lv_access_mode }|
71
+ ) TO rs_info-components.
72
+ ENDIF.
73
+
74
+ " Convert key definition to text
75
+ CASE lv_keydef.
76
+ WHEN 'D'. lv_key_definition = 'WITH KEY'.
77
+ WHEN 'N'. lv_key_definition = 'NO KEY'.
78
+ WHEN OTHERS. lv_key_definition = lv_keydef.
79
+ ENDCASE.
80
+
81
+ IF lv_key_definition IS NOT INITIAL.
82
+ APPEND VALUE #(
83
+ field = 'KEY_DEFINITION'
84
+ key = abap_false
85
+ type = 'CHAR'
86
+ length = 10
87
+ dataelement = ''
88
+ description = |Key Definition: { lv_key_definition }|
89
+ ) TO rs_info-components.
90
+ ENDIF.
91
+ ENDMETHOD.
92
+
93
+ ENDCLASS.
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
3
+ <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
4
+ <asx:values>
5
+ <VSEOCLASS>
6
+ <CLSNAME>ZCL_ABGAGT_VIEWER_TTYP</CLSNAME>
7
+ <LANGU>E</LANGU>
8
+ <DESCRIPT>Viewer for ABAP Table Types</DESCRIPT>
9
+ <EXPOSURE>2</EXPOSURE>
10
+ <STATE>1</STATE>
11
+ <UNICODE>X</UNICODE>
12
+ </VSEOCLASS>
13
+ </asx:values>
14
+ </asx:abap>
15
+ </abapGit>
@@ -6,6 +6,7 @@ INTERFACE zif_abgagt_viewer PUBLIC.
6
6
  " @parameter rs_info | Object information structure
7
7
  METHODS get_info
8
8
  IMPORTING iv_name TYPE string
9
- RETURNING VALUE(rs_info) TYPE zcl_abgagt_command_view=>ty_view_object.
9
+ RETURNING VALUE(rs_info) TYPE zcl_abgagt_command_view=>ty_view_object
10
+ RAISING cx_dd_ddl_read.
10
11
 
11
12
  ENDINTERFACE.
package/bin/abapgit-agent CHANGED
@@ -309,33 +309,70 @@ async function syntaxCheckSource(sourceFile, csrfToken, config) {
309
309
 
310
310
  const result = await request('POST', '/sap/bc/z_abapgit_agent/inspect', data, { csrfToken: csrfToken });
311
311
 
312
- // Handle uppercase keys from ABAP - handle both 'X'/true (success) and false
313
- const success = result.SUCCESS !== undefined ? result.SUCCESS : (result.success !== undefined ? result.success : null);
314
- const errorCount = result.ERROR_COUNT || result.error_count || 0;
315
- const errors = result.ERRORS || result.errors || [];
312
+ // Handle new table-based result format (array) or old single result
313
+ let results = [];
314
+ if (Array.isArray(result)) {
315
+ results = result;
316
+ } else {
317
+ // Convert old single result to array format for compatibility
318
+ results = [{
319
+ OBJECT_TYPE: 'UNKNOWN',
320
+ OBJECT_NAME: pathModule.basename(sourceFile),
321
+ SUCCESS: result.SUCCESS !== undefined ? result.SUCCESS === 'X' || result.SUCCESS === true : result.success,
322
+ ERROR_COUNT: result.ERROR_COUNT || result.error_count || 0,
323
+ ERRORS: result.ERRORS || result.errors || [],
324
+ WARNINGS: result.warnings || []
325
+ }];
326
+ }
316
327
 
317
- console.log('\n');
328
+ // Process each result
329
+ let hasErrors = false;
330
+ for (const res of results) {
331
+ // Handle both uppercase and lowercase keys
332
+ const success = res.SUCCESS !== undefined ? res.SUCCESS : res.success;
333
+ const objectType = res.OBJECT_TYPE !== undefined ? res.OBJECT_TYPE : res.object_type;
334
+ const objectName = res.OBJECT_NAME !== undefined ? res.OBJECT_NAME : res.object_name;
335
+ const errorCount = res.ERROR_COUNT !== undefined ? res.ERROR_COUNT : (res.error_count || 0);
336
+ const errors = res.ERRORS !== undefined ? res.ERRORS : (res.errors || []);
337
+ const warnings = res.WARNINGS !== undefined ? res.WARNINGS : (res.warnings || []);
338
+
339
+ console.log('\n');
340
+
341
+ if (errorCount > 0 || warnings.length > 0) {
342
+ if (errorCount > 0) {
343
+ console.log(`❌ ${objectType} ${objectName} - Syntax check failed (${errorCount} error(s)):`);
344
+ } else {
345
+ console.log(`⚠️ ${objectType} ${objectName} - Syntax check passed with warnings (${warnings.length}):`);
346
+ }
347
+ console.log('\nErrors:');
348
+ console.log('─'.repeat(60));
318
349
 
319
- if (errorCount > 0) {
320
- console.log(`❌ Syntax check failed (${errorCount} error(s)):`);
321
- console.log('\nErrors:');
322
- console.log(''.repeat(60));
350
+ for (const err of errors) {
351
+ const line = err.LINE || err.line || '?';
352
+ const column = err.COLUMN || err.column || '?';
353
+ const text = err.TEXT || err.text || 'Unknown error';
323
354
 
324
- for (const err of errors) {
325
- const line = err.LINE || err.line || '?';
326
- const column = err.COLUMN || err.column || '?';
327
- const text = err.TEXT || err.text || 'Unknown error';
355
+ console.log(` Line ${line}, Column ${column}:`);
356
+ console.log(` ${text}`);
357
+ console.log('');
358
+ }
328
359
 
329
- console.log(` Line ${line}, Column ${column}:`);
330
- console.log(` ${text}`);
331
- console.log('');
360
+ // Show warnings if any
361
+ if (warnings.length > 0) {
362
+ console.log('Warnings:');
363
+ console.log('─'.repeat(60));
364
+ for (const warn of warnings) {
365
+ const line = warn.LINE || warn.line || '?';
366
+ const text = warn.MESSAGE || warn.message || 'Unknown warning';
367
+ console.log(` Line ${line}: ${text}`);
368
+ }
369
+ }
370
+ hasErrors = true;
371
+ } else if (success === true || success === 'X') {
372
+ console.log(`✅ ${objectType} ${objectName} - Syntax check passed`);
373
+ } else {
374
+ console.log(`⚠️ ${objectType} ${objectName} - Syntax check returned unexpected status`);
332
375
  }
333
- } else if (success === 'X' || success === true) {
334
- console.log(`✅ ${pathModule.basename(sourceFile)} - Syntax check passed (0 errors)`);
335
- } else if (success === false) {
336
- console.log(`❌ ${pathModule.basename(sourceFile)} - Syntax check failed`);
337
- } else {
338
- console.log(`⚠️ Syntax check returned unexpected status: ${success}`);
339
376
  }
340
377
 
341
378
  return result;
@@ -345,6 +382,95 @@ async function syntaxCheckSource(sourceFile, csrfToken, config) {
345
382
  }
346
383
  }
347
384
 
385
+ /**
386
+ * Inspect all files in one request
387
+ */
388
+ async function inspectAllFiles(files, csrfToken, config) {
389
+ // Convert files to uppercase names (same as syntaxCheckSource does)
390
+ const fileNames = files.map(f => {
391
+ const baseName = pathModule.basename(f).toUpperCase();
392
+ return baseName;
393
+ });
394
+
395
+ try {
396
+ // Send all files in one request
397
+ const data = {
398
+ files: fileNames
399
+ };
400
+
401
+ const result = await request('POST', '/sap/bc/z_abapgit_agent/inspect', data, { csrfToken: csrfToken });
402
+
403
+ // Handle both table result and old single result
404
+ let results = [];
405
+ if (Array.isArray(result)) {
406
+ results = result;
407
+ } else {
408
+ // Convert single result to array format
409
+ results = [{
410
+ OBJECT_TYPE: 'UNKNOWN',
411
+ OBJECT_NAME: files.join(', '),
412
+ SUCCESS: result.SUCCESS !== undefined ? result.SUCCESS === 'X' || result.SUCCESS === true : result.success,
413
+ ERROR_COUNT: result.ERROR_COUNT || result.error_count || 0,
414
+ ERRORS: result.ERRORS || result.errors || [],
415
+ WARNINGS: result.warnings || []
416
+ }];
417
+ }
418
+
419
+ return results;
420
+ } catch (error) {
421
+ console.error(`\n Error: ${error.message}`);
422
+ process.exit(1);
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Process a single inspect result
428
+ */
429
+ async function processInspectResult(res) {
430
+ // Handle both uppercase and lowercase keys
431
+ const success = res.SUCCESS !== undefined ? res.SUCCESS : res.success;
432
+ const objectType = res.OBJECT_TYPE !== undefined ? res.OBJECT_TYPE : res.object_type;
433
+ const objectName = res.OBJECT_NAME !== undefined ? res.OBJECT_NAME : res.object_name;
434
+ const errorCount = res.ERROR_COUNT !== undefined ? res.ERROR_COUNT : (res.error_count || 0);
435
+ const errors = res.ERRORS !== undefined ? res.ERRORS : (res.errors || []);
436
+ const warnings = res.WARNINGS !== undefined ? res.WARNINGS : (res.warnings || []);
437
+
438
+ if (errorCount > 0 || warnings.length > 0) {
439
+ if (errorCount > 0) {
440
+ console.log(`❌ ${objectType} ${objectName} - Syntax check failed (${errorCount} error(s)):`);
441
+ } else {
442
+ console.log(`⚠️ ${objectType} ${objectName} - Syntax check passed with warnings (${warnings.length}):`);
443
+ }
444
+ console.log('\nErrors:');
445
+ console.log('─'.repeat(60));
446
+
447
+ for (const err of errors) {
448
+ const line = err.LINE || err.line || '?';
449
+ const column = err.COLUMN || err.column || '?';
450
+ const text = err.TEXT || err.text || 'Unknown error';
451
+
452
+ console.log(` Line ${line}, Column ${column}:`);
453
+ console.log(` ${text}`);
454
+ console.log('');
455
+ }
456
+
457
+ // Show warnings if any
458
+ if (warnings.length > 0) {
459
+ console.log('Warnings:');
460
+ console.log('─'.repeat(60));
461
+ for (const warn of warnings) {
462
+ const line = warn.LINE || warn.line || '?';
463
+ const text = warn.MESSAGE || warn.message || 'Unknown warning';
464
+ console.log(` Line ${line}: ${text}`);
465
+ }
466
+ }
467
+ } else if (success === true || success === 'X') {
468
+ console.log(`✅ ${objectType} ${objectName} - Syntax check passed`);
469
+ } else {
470
+ console.log(`⚠️ ${objectType} ${objectName} - Syntax check returned unexpected status`);
471
+ }
472
+ }
473
+
348
474
  /**
349
475
  * Run unit tests for package or objects
350
476
  */
@@ -691,7 +817,46 @@ async function pull(gitUrl, branch = 'main', files = null, transportRequest = nu
691
817
  'W': '⚠️', // Warning
692
818
  'A': '🛑' // Abort
693
819
  };
694
- return icons[type] || ' ';
820
+ return icons[type] || '';
821
+ };
822
+
823
+ // Calculate display width accounting for emoji (2 cells) vs ASCII (1 cell)
824
+ const calcWidth = (str) => {
825
+ if (!str) return 0;
826
+ let width = 0;
827
+ let i = 0;
828
+ while (i < str.length) {
829
+ const code = str.codePointAt(i);
830
+ if (!code) break;
831
+ // Variation selectors (FE00-FE0F) and ZWJ (200D) take 0 width
832
+ if (code >= 0xFE00 && code <= 0xFE0F) {
833
+ i += 1;
834
+ continue;
835
+ }
836
+ if (code === 0x200D) { // Zero width joiner
837
+ i += 1;
838
+ continue;
839
+ }
840
+ // Emoji and wide characters take 2 cells
841
+ if (code > 0xFFFF) {
842
+ width += 2;
843
+ i += 2; // Skip surrogate pair
844
+ } else if (code > 127) {
845
+ width += 2;
846
+ i += 1;
847
+ } else {
848
+ width += 1;
849
+ i += 1;
850
+ }
851
+ }
852
+ return width;
853
+ };
854
+
855
+ // Pad string to display width
856
+ const padToWidth = (str, width) => {
857
+ const s = str || '';
858
+ const currentWidth = calcWidth(s);
859
+ return s + ' '.repeat(Math.max(0, width - currentWidth));
695
860
  };
696
861
 
697
862
  if (success === 'X' || success === true) {
@@ -719,23 +884,15 @@ async function pull(gitUrl, branch = 'main', files = null, transportRequest = nu
719
884
 
720
885
  // Calculate column widths based on terminal width
721
886
  const tableWidth = Math.min(TERM_WIDTH, 120);
722
- const iconCol = 5; // Width for emoji column (emoji takes 2 visual cells)
887
+ const iconCol = 4; // Fixed width for icon column
723
888
  const objCol = 28;
724
889
  const msgCol = tableWidth - iconCol - objCol - 6; // Account for vertical lines (3 chars)
725
890
 
726
- // Helper to get visible width (emoji takes 2 cells)
727
- const getVisibleWidth = (str) => {
728
- let width = 0;
729
- for (const char of str) {
730
- width += (char.charCodeAt(0) > 127) ? 2 : 1; // Emoji/wide chars = 2
731
- }
732
- return width;
733
- };
734
-
735
- // Helper to pad to visible width
891
+ // Pad string to display width using calcWidth for emoji support
736
892
  const padToWidth = (str, width) => {
737
- const currentWidth = getVisibleWidth(str);
738
- return str + ' '.repeat(width - currentWidth);
893
+ const s = str || '';
894
+ const currentWidth = calcWidth(s);
895
+ return s + ' '.repeat(Math.max(0, width - currentWidth));
739
896
  };
740
897
 
741
898
  const headerLine = '─'.repeat(iconCol) + '┼' + '─'.repeat(objCol) + '┼' + '─'.repeat(msgCol);
@@ -1293,8 +1450,12 @@ Examples:
1293
1450
  const config = loadConfig();
1294
1451
  const csrfToken = await fetchCsrfToken(config);
1295
1452
 
1296
- for (const sourceFile of filesSyntaxCheck) {
1297
- await syntaxCheckSource(sourceFile, csrfToken, config);
1453
+ // Send all files in one request
1454
+ const results = await inspectAllFiles(filesSyntaxCheck, csrfToken, config);
1455
+
1456
+ // Process results
1457
+ for (const result of results) {
1458
+ await processInspectResult(result);
1298
1459
  }
1299
1460
  break;
1300
1461
  }
@@ -1430,9 +1591,9 @@ Examples:
1430
1591
  console.log(` ${description}`);
1431
1592
  }
1432
1593
 
1433
- // Display source code for classes and interfaces
1594
+ // Display source code for classes, interfaces, and CDS views
1434
1595
  const source = obj.SOURCE || obj.source || '';
1435
- if (source && (objType === 'INTF' || objType === 'Interface' || objType === 'CLAS' || objType === 'Class')) {
1596
+ if (source && (objType === 'INTF' || objType === 'Interface' || objType === 'CLAS' || objType === 'Class' || objType === 'DDLS' || objType === 'CDS View')) {
1436
1597
  console.log('');
1437
1598
  // Replace escaped newlines with actual newlines and display
1438
1599
  const displaySource = source.replace(/\\n/g, '\n');
@@ -1500,6 +1661,15 @@ Examples:
1500
1661
  }
1501
1662
 
1502
1663
  console.log(end);
1664
+ } else if (objType === 'TTYP' || objType === 'Table Type') {
1665
+ // Show TTYP details as simple text lines
1666
+ console.log('');
1667
+ for (const comp of components) {
1668
+ const desc = comp.DESCRIPTION || comp.description || '';
1669
+ if (desc) {
1670
+ console.log(` ${desc}`);
1671
+ }
1672
+ }
1503
1673
  } else {
1504
1674
  // Build table display for TABL/STRU with Data Element and Description
1505
1675
  const colWidths = {
@@ -28,6 +28,8 @@ abapgit-agent view --objects ZIF_MY_INT --type INTF
28
28
  abapgit-agent view --objects ZMY_STRUCT --type STRU
29
29
  abapgit-agent view --objects ZMY_TABLE --type TABL
30
30
  abapgit-agent view --objects ZMY_DTEL --type DTEL
31
+ abapgit-agent view --objects ZMY_TTYP --type TTYP
32
+ abapgit-agent view --objects ZC_MY_CDS_VIEW --type DDLS
31
33
 
32
34
  # View multiple objects
33
35
  abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2,ZIF_INTERFACE1
@@ -49,7 +51,7 @@ abapgit-agent view --objects ZCL_MY_CLASS --json
49
51
  | Parameter | Required | Description |
50
52
  |-----------|----------|-------------|
51
53
  | `--objects` | Yes | Comma-separated list of object names (e.g., `ZCL_MY_CLASS,ZIF_MY_INTERFACE`) |
52
- | `--type` | No | Object type for all objects (CLAS, INTF, TABL, STRU, DTEL). Auto-detected from TADIR if not specified |
54
+ | `--type` | No | Object type for all objects (CLAS, INTF, TABL, STRU, DTEL, TTYP, DDLS). Auto-detected from TADIR if not specified |
53
55
  | `--json` | No | Output raw JSON only (for scripting) |
54
56
 
55
57
  ---
@@ -185,6 +187,36 @@ DATA ELEMENT S_CARR_ID:
185
187
  └────────────────────┴──────────────────────────────────────────┘
186
188
  ```
187
189
 
190
+ ### Table Type Definition (TTYP)
191
+
192
+ ```
193
+ 📖 DDL2DDICWARNINGS (Table Type)
194
+ Table Type DDL2DDICWARNINGS in SDDL_BASIC_FUNCTIONS
195
+
196
+ Line Type: DDL2DDICERR
197
+ Access Mode: STANDARD
198
+ Key Definition: WITH KEY
199
+ ```
200
+
201
+ ### CDS View Definition (DDLS)
202
+
203
+ ```
204
+ 📖 ZC_MY_CDS_VIEW (CDS View)
205
+ CDS View ZC_MY_CDS_VIEW in $PACKAGE
206
+
207
+ @AbapCatalog.sqlViewName: 'ZCMYVIEW'
208
+ @AbapCatalog.compiler.compareFilter: true
209
+ @AccessControl.authorizationCheck: #NOT_REQUIRED
210
+ @EndUserText.label: 'My CDS View'
211
+ define view ZC_MY_CDS_VIEW as select from tdevc
212
+ {
213
+ key devclass as Devclass,
214
+ parentcl as ParentPackage,
215
+ ctext as Description
216
+ }
217
+ where devclass not like '$%'
218
+ ```
219
+
188
220
  ### Multiple Objects
189
221
 
190
222
  ```
@@ -240,7 +272,7 @@ DATA ELEMENT S_CARR_ID:
240
272
  "OBJECTS": [
241
273
  {
242
274
  "NAME": "string",
243
- "TYPE": "CLAS|INTF|TABL|STRU|DTEL",
275
+ "TYPE": "CLAS|INTF|TABL|STRU|DTEL|TTYP|DDLS",
244
276
  "TYPE_TEXT": "string",
245
277
  "DESCRIPTION": "string",
246
278
  "DOMAIN": "string", // For DTEL
@@ -307,6 +339,8 @@ DATA ELEMENT S_CARR_ID:
307
339
  | `TABL` | Table | Database table |
308
340
  | `STRU` | Structure | Structure type |
309
341
  | `DTEL` | Data Element | Data element/domain type |
342
+ | `TTYP` | Table Type | Table type definition |
343
+ | `DDLS` | CDS View | CDS View/Entity definition |
310
344
 
311
345
  ---
312
346
 
@@ -325,6 +359,9 @@ abapgit-agent view --objects SFLIGHT --type TABL
325
359
  # View data element
326
360
  abapgit-agent view --objects S_CARR_ID --type DTEL
327
361
 
362
+ # View CDS view definition
363
+ abapgit-agent view --objects ZC_MY_CDS_VIEW --type DDLS
364
+
328
365
  # View multiple objects
329
366
  abapgit-agent view --objects ZCL_CONFIG,ZIF_LOGGER,ZCL_UTILS
330
367
 
@@ -350,6 +387,7 @@ abapgit-agent view --objects sflight --type tabl
350
387
  | **DD02L** | Table/structure definitions |
351
388
  | **DD03L** | Table/structure fields |
352
389
  | **DD04L** | Data element definitions |
390
+ | **DD40L** | Table type definitions |
353
391
 
354
392
  ### Class Source Retrieval (CLAS)
355
393
 
@@ -407,3 +445,57 @@ SELECT SINGLE rollname, ddtext, datatype, leng, decimals
407
445
  INTO (lv_domain, lv_desc, lv_type, lv_len, lv_decimals)
408
446
  WHERE rollname = iv_name.
409
447
  ```
448
+
449
+ ### Table Type Retrieval (TTYP)
450
+
451
+ ```abap
452
+ " Get TTYP details from DD40L
453
+ SELECT SINGLE rowtype accessmode keydef FROM dd40l
454
+ INTO (lv_linetype, lv_tabprottype, lv_keydef)
455
+ WHERE typename = iv_name
456
+ AND as4local = 'A'.
457
+
458
+ " Convert codes to text:
459
+ " - Access mode: T=STANDARD, S=SORTED, H=HASHED
460
+ " - Key definition: D=WITH KEY, N=NO KEY
461
+ ```
462
+
463
+ ### CDS View Retrieval (DDLS)
464
+
465
+ ```abap
466
+ " Use DDL handler to read CDS view source
467
+ lo_handler = cl_dd_ddl_handler_factory=>create( ).
468
+
469
+ " First try to read inactive version (get_state = 'M')
470
+ TRY.
471
+ lo_handler->read(
472
+ EXPORTING
473
+ name = lv_ddls_name
474
+ get_state = 'M'
475
+ IMPORTING
476
+ ddddlsrcv_wa = ls_ddlsrcv ).
477
+
478
+ IF ls_ddlsrcv-source IS NOT INITIAL.
479
+ lv_found = abap_true.
480
+ ENDIF.
481
+
482
+ CATCH cx_dd_ddl_check.
483
+ " Ignore - will try active version
484
+ ENDTRY.
485
+
486
+ " If no inactive version, try active version
487
+ IF lv_found = abap_false.
488
+ TRY.
489
+ lo_handler->read(
490
+ EXPORTING
491
+ name = lv_ddls_name
492
+ get_state = 'A'
493
+ IMPORTING
494
+ ddddlsrcv_wa = ls_ddlsrcv ).
495
+ CATCH cx_dd_ddl_check.
496
+ " Not found
497
+ ENDTRY.
498
+ ENDIF.
499
+
500
+ " Source code is in ls_ddlsrcv-source
501
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "ABAP Git Agent - Pull and activate ABAP code via abapGit from any git repository",
5
5
  "main": "src/index.js",
6
6
  "bin": {