abapgit-agent 1.6.1 → 1.7.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.
@@ -174,3 +174,27 @@ ENDTRY.
174
174
  | Multiple callers need to handle exception | Add RAISING to method definition |
175
175
  | Exception should be handled internally | Use TRY-CATCH in implementation |
176
176
  | Interface method | Add RAISING to interface, or use TRY-CATCH in class |
177
+
178
+ ### RAISING Clause in Method Calls
179
+
180
+ The `RAISING` clause **cannot be used in method call statements**. It can only be used in method definitions.
181
+
182
+ ```abap
183
+ " WRONG - syntax error
184
+ lo_handler->read( ... ) RAISING cx_dd_ddl_check.
185
+
186
+ " CORRECT - use TRY-CATCH
187
+ TRY.
188
+ lo_handler->read( ... ).
189
+ CATCH cx_dd_ddl_check.
190
+ " Handle error
191
+ ENDTRY.
192
+ ```
193
+
194
+ **Correct usage in method definitions:**
195
+ ```abap
196
+ " Interface/Class method definition
197
+ METHODS read
198
+ IMPORTING iv_name TYPE string
199
+ RAISING cx_static_check.
200
+ ``` |
@@ -79,6 +79,25 @@ Examples of compliant names:
79
79
  - `test_exec_files` (16 chars)
80
80
  - `test_interface` (15 chars)
81
81
 
82
+ ### Test Methods and RAISING Clause
83
+
84
+ If a test method calls methods that raise exceptions, add `RAISING` to the method definition:
85
+
86
+ ```abap
87
+ " CORRECT - declare that method can raise exceptions
88
+ METHODS test_validate_ddls FOR TESTING RAISING cx_static_check.
89
+ METHODS test_read_data FOR TESTING RAISING cx_dd_ddl_check.
90
+
91
+ " Then implement with TRY-CATCH if needed
92
+ METHOD test_validate_ddls.
93
+ TRY.
94
+ mo_cut->some_method( ).
95
+ CATCH cx_static_check.
96
+ " Handle exception
97
+ ENDTRY.
98
+ ENDMETHOD.
99
+ ```
100
+
82
101
  ### Common Assertions
83
102
 
84
103
  ```abap
@@ -7,6 +7,9 @@
7
7
  2. Constructor - line 20
8
8
  3. Interfaces - line 35
9
9
  4. Inline Declaration - line 50
10
+ 5. Abstract Methods - line 99
11
+ 6. FINAL Class Limitation - line 117
12
+ 7. Working with TYPE any - line 135
10
13
 
11
14
  ## ABAP Class Definition - Must Use PUBLIC
12
15
 
@@ -56,3 +59,111 @@ ENDCLASS.
56
59
 
57
60
  **Wrong**: `METHOD do_something.` - parameter `iv_param` will be unknown
58
61
  **Correct**: `METHOD zif_my_interface~do_something.` - parameters recognized
62
+
63
+ ## Use Interface Type for References
64
+
65
+ When a class implements an interface, use the **interface type** instead of the class type for references:
66
+
67
+ ```abap
68
+ " Interface definition
69
+ INTERFACE zif_my_interface PUBLIC.
70
+ METHODS do_something RETURNING VALUE(rv_result) TYPE string.
71
+ ENDINTERFACE.
72
+
73
+ " Class implements interface
74
+ CLASS zcl_my_class DEFINITION PUBLIC.
75
+ PUBLIC SECTION.
76
+ INTERFACES zif_my_interface.
77
+ CLASS-METHODS get_instance RETURNING VALUE(ro_instance) TYPE REF TO zif_my_interface.
78
+ ENDCLASS.
79
+
80
+ " Caller - use interface type, not class type
81
+ CLASS zcl_consumer DEFINITION PUBLIC.
82
+ PRIVATE SECTION.
83
+ DATA mo_instance TYPE REF TO zif_my_interface. " <- Use interface type
84
+ ENDCLASS.
85
+
86
+ METHOD zcl_consumer->do_something.
87
+ mo_instance = zcl_my_class=>get_instance( ).
88
+
89
+ " Call without interface prefix - cleaner code
90
+ DATA(lv_result) = mo_instance->do_something( ).
91
+ ENDMETHOD.
92
+ ```
93
+
94
+ **Benefits:**
95
+ - Cleaner code: `mo_instance->method( )` instead of `mo_instance->zif_my_interface~method( )`
96
+ - Flexibility: Can swap implementation class without changing caller (dependency inversion)
97
+ - Consistency: All callers use the same interface type
98
+
99
+ **Key rule:** Always use `REF TO zif_xxx` not `REF TO zcl_xxx` for instance variables and parameters.
100
+
101
+ ## Abstract Methods
102
+
103
+ The ABSTRACT keyword must come immediately after the method name:
104
+
105
+ ```abap
106
+ " ✅ Correct - ABSTRACT right after method name
107
+ METHODS get_name ABSTRACT
108
+ RETURNING VALUE(rv_name) TYPE string.
109
+
110
+ " ❌ Wrong - ABSTRACT after parameters (syntax error)
111
+ METHODS get_name
112
+ RETURNING VALUE(rv_name) TYPE string
113
+ ABSTRACT.
114
+ ```
115
+
116
+ ## FINAL Class Limitation
117
+
118
+ A FINAL class cannot have abstract methods. Use plain REDEFINITION instead:
119
+
120
+ ```abap
121
+ " ❌ Wrong in FINAL class - syntax error
122
+ CLASS zcl_my_class DEFINITION PUBLIC FINAL.
123
+ METHODS parse_request ABSTRACT REDEFINITION.
124
+ ENDCLASS.
125
+
126
+ " ✅ Correct in FINAL class - use REDEFINITION only
127
+ CLASS zcl_my_class DEFINITION PUBLIC FINAL.
128
+ METHODS parse_request REDEFINITION.
129
+ ENDCLASS.
130
+ ```
131
+
132
+ ## Working with TYPE any
133
+
134
+ TYPE any cannot be used with CREATE DATA. When a base class defines parameters with TYPE any, use a typed local variable in the subclass:
135
+
136
+ ```abap
137
+ " Base class defines:
138
+ CLASS zcl_base DEFINITION PUBLIC ABSTRACT.
139
+ PROTECTED SECTION.
140
+ METHODS parse_request
141
+ IMPORTING iv_json TYPE string
142
+ EXPORTING es_request TYPE any.
143
+ ENDCLASS.
144
+
145
+ " Subclass implementation:
146
+ CLASS zcl_subclass DEFINITION PUBLIC FINAL.
147
+ INHERITING FROM zcl_base.
148
+ PROTECTED SECTION.
149
+ METHODS parse_request REDEFINITION.
150
+ ENDCLASS.
151
+
152
+ CLASS zcl_subclass IMPLEMENTATION.
153
+ METHOD parse_request.
154
+ " Use typed local variable
155
+ DATA: ls_request TYPE ty_my_params.
156
+
157
+ /ui2/cl_json=>deserialize(
158
+ EXPORTING json = iv_json
159
+ CHANGING data = ls_request ).
160
+
161
+ es_request = ls_request. " Assign typed to generic
162
+ ENDMETHOD.
163
+ ENDCLASS.
164
+ ```
165
+
166
+ **Key points:**
167
+ - Declare a local variable with the concrete type
168
+ - Deserialize JSON into the typed local variable
169
+ - Assign to the generic TYPE any parameter
@@ -1,110 +1,63 @@
1
- # ABAP Objects
1
+ # ABAP Object Naming Conventions
2
2
 
3
- **Searchable keywords**: naming convention, Z prefix, namespace, object type, CLAS, INTF, PROG, TABL, DDLS, XML metadata, .abapGit.xml
3
+ **Searchable keywords**: naming convention, Z prefix, namespace, object type, CLAS, INTF, PROG, TABL, DDLS
4
4
 
5
5
  ## TOPICS IN THIS FILE
6
- 1. XML Metadata Required - line 3
7
- 2. Naming Conventions - line 30
8
- 3. Object Types - line 60
6
+ 1. Naming Conventions
7
+ 2. ABAP Object Types
8
+ 3. XML Metadata (see guidelines/08_abapgit.md)
9
9
 
10
- ## Creating New ABAP Objects - XML Metadata Required
11
-
12
- **CRITICAL CHECKLIST - Never Forget!**
13
-
14
- When creating ANY new ABAP object file, you MUST also create its XML metadata file:
10
+ ## Naming Conventions
15
11
 
16
- | ABAP File | Required XML File |
17
- |-----------|------------------|
18
- | `zcl_my_class.clas.abap` | `zcl_my_class.clas.xml` |
19
- | `zif_my_intf.intf.abap` | `zif_my_intf.intf.xml` |
12
+ Use `Z_` or `Y_` prefix for custom objects:
13
+
14
+ | Object Type | Prefix | Example |
15
+ |-------------|--------|---------|
16
+ | Class | ZCL_ | ZCL_MY_CLASS |
17
+ | Interface | ZIF_ | ZIF_MY_INTERFACE |
18
+ | Program | Z | ZMY_PROGRAM |
19
+ | Package | $ | $MY_PACKAGE |
20
+ | Table | Z | ZMY_TABLE |
21
+ | CDS View | ZC | ZC_MY_VIEW |
22
+ | CDS Entity | ZE | ZE_MY_ENTITY |
23
+ | Data Element | Z | ZMY_ELEMENT |
24
+ | Structure | Z | ZMY_STRUCTURE |
25
+ | Table Type | Z | ZMY_TABLE_TYPE |
20
26
 
21
- **Without XML files**, abapGit will NOT recognize the objects during pull, and they won't be activated.
27
+ ## ABAP Object Types
22
28
 
23
- ### XML Metadata Format for CLAS
29
+ Common object types in this project:
24
30
 
25
- For `zcl_abgagt_util.clas.abap`, create `zcl_abgagt_util.clas.xml`:
31
+ | Type | Description | File Suffix |
32
+ |------|-------------|-------------|
33
+ | CLAS | Classes | .clas.abap |
34
+ | PROG | Programs | .prog.abap |
35
+ | FUGR | Function Groups | .fugr.abap |
36
+ | INTF | Interfaces | .intf.abap |
37
+ | TABL | Tables | .tabl.abap |
38
+ | STRU | Structures | .stru.abap |
39
+ | DTEL | Data Elements | .dtel.abap |
40
+ | TTYP | Table Types | .ttyp.abap |
41
+ | DDLS | CDS Views | .ddls.asddls |
42
+ | DDLX | CDS Entities | .ddlx.asddlx |
26
43
 
27
- ```xml
28
- <?xml version="1.0" encoding="utf-8"?>
29
- <abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
30
- <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
31
- <asx:values>
32
- <VSEOCLASS>
33
- <CLSNAME>ZCL_ABGAGT_UTIL</CLSNAME>
34
- <LANGU>E</LANGU>
35
- <DESCRIPT>Description</DESCRIPT>
36
- <EXPOSURE>2</EXPOSURE>
37
- <STATE>1</STATE>
38
- <UNICODE>X</UNICODE>
39
- </VSEOCLASS>
40
- </asx:values>
41
- </asx:abap>
42
- </abapGit>
43
- ```
44
+ ## XML Metadata
44
45
 
45
- ### XML Metadata Format for INTF
46
+ **See guidelines/08_abapgit.md for XML templates.**
46
47
 
47
- For `zif_abgagt_util.intf.abap`, create `zif_abgagt_util.intf.xml`:
48
+ Each ABAP object requires an XML metadata file for abapGit. Quick reference:
48
49
 
49
- ```xml
50
- <?xml version="1.0" encoding="utf-8"?>
51
- <abapGit version="v1.0.0" serializer="LCL_OBJECT_INTF" serializer_version="v1.0.0">
52
- <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
53
- <asx:values>
54
- <VSEOINTERF>
55
- <CLSNAME>ZIF_ABGAGT_UTIL</CLSNAME>
56
- <LANGU>E</LANGU>
57
- <DESCRIPT>Description</DESCRIPT>
58
- <EXPOSURE>2</EXPOSURE>
59
- <STATE>1</STATE>
60
- <UNICODE>X</UNICODE>
61
- </VSEOINTERF>
62
- </asx:values>
63
- </asx:abap>
64
- </abapGit>
50
+ ```
51
+ Class: zcl_*.clas.xml
52
+ Interface: zif_*.intf.xml
53
+ Table: z*.tabl.xml
54
+ CDS View: zc_*.ddls.xml
65
55
  ```
66
56
 
67
- ### Important Notes
68
-
69
- 1. **CRITICAL: Push to git BEFORE pulling into ABAP**
70
- - Always commit and push ABAP files to git first
71
- - Then run `abapgit-agent pull` to activate in ABAP
72
- - Never run `abapgit-agent pull` without pushing changes first
73
-
74
- 2. **Only pull ABAP files** - The XML metadata stays in git:
75
- ```bash
76
- abapgit-agent pull --files zcl_my_class.clas.abap
77
- ```
78
- 3. abapGit reads the XML from git to deserialize the ABAP code
79
- 4. XML files are NOT activated in ABAP - they are only for abapGit
80
-
57
+ **Important**: Always push to git BEFORE running pull:
81
58
  ```bash
82
- # After making changes to ABAP files
83
59
  git add .
84
- git commit -m "Describe changes"
85
- git push # CRITICAL: Push BEFORE pulling
86
-
87
- # Then validate in ABAP system (single file - fast)
60
+ git commit -m "Changes"
61
+ git push # CRITICAL: Push FIRST
88
62
  abapgit-agent pull --files abap/zcl_my_class.clas.abap
89
-
90
- # Or validate all files
91
- abapgit-agent pull
92
63
  ```
93
-
94
- ## Naming Conventions
95
-
96
- - Use `Z_` or `Y_` prefix for custom objects
97
- - Class names: `ZCL_<NAME>`
98
- - Interface names: `ZIF_<NAME>`
99
- - Programs: `Z<NAME>`
100
- - Package: `$<PROJECT_NAME>`
101
-
102
- ## ABAP Object Types
103
-
104
- Common object types in this project:
105
- - `CLAS` - Classes
106
- - `PROG` - Programs
107
- - `FUGR` - Function Groups
108
- - `INTF` - Interfaces
109
- - `TABL` - Tables
110
- - `DDLS` - Data Definitions
@@ -27,6 +27,7 @@ Key XML Settings:
27
27
  Table DELIVERY: A=Application, C=Customizing
28
28
  CDS SOURCE_TYPE: V=View, C=Consumption
29
29
  Test Class XML: <WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
30
+ Local Classes: <CLSCCINCL>X</CLSCCINCL>
30
31
  ```
31
32
 
32
33
  **Searchable keywords**: class xml, interface xml, table xml, cds xml, test class, exposure, serializer, abapgit
@@ -69,6 +70,16 @@ abapGit needs XML files to:
69
70
  - `STATE`: State (1 = Active)
70
71
  - `UNICODE`: Unicode encoding (X = Yes)
71
72
 
73
+ **Local Classes**: If the class has local classes (e.g., test doubles), add:
74
+ - `<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>` - for test classes
75
+ - `<CLSCCINCL>X</CLSCCINCL>` - for local class definitions
76
+
77
+ **Local Class Files**:
78
+ | File | Purpose |
79
+ |------|---------|
80
+ | `zcl_xxx.clas.locals_def.abap` | Local class definitions |
81
+ | `zcl_xxx.clas.locals_imp.abap` | Local class implementations |
82
+
72
83
  ---
73
84
 
74
85
  ### Interface (INTF)
@@ -113,6 +113,27 @@ DATA mo_agent TYPE REF TO zcl_abgagt_agent. " Concrete class!
113
113
 
114
114
  This allows you to replace the implementation with test doubles.
115
115
 
116
+ ### Define Types in Interface
117
+
118
+ Define types needed by the interface directly in the interface to keep it self-contained:
119
+
120
+ ```abap
121
+ INTERFACE zif_my_handler.
122
+ " Define types needed by the interface
123
+ TYPES: BEGIN OF ty_response,
124
+ success TYPE abap_bool,
125
+ message TYPE string,
126
+ END OF ty_response.
127
+
128
+ " Use the type in method signatures
129
+ METHODS process
130
+ IMPORTING iv_data TYPE string
131
+ RETURNING VALUE(rs_response) TYPE ty_response.
132
+ ENDINTERFACE.
133
+ ```
134
+
135
+ This makes it easier for test doubles to implement the interface without needing separate type definitions.
136
+
116
137
  ### 3. Make Dependencies Injectable via Constructor
117
138
 
118
139
  **Use constructor injection, not setter injection.**
package/bin/abapgit-agent CHANGED
@@ -2067,9 +2067,9 @@ Examples:
2067
2067
  console.log(` ${description}`);
2068
2068
  }
2069
2069
 
2070
- // Display source code for classes, interfaces, and CDS views
2070
+ // Display source code for classes, interfaces, CDS views, and programs/source includes
2071
2071
  const source = obj.SOURCE || obj.source || '';
2072
- if (source && (objType === 'INTF' || objType === 'Interface' || objType === 'CLAS' || objType === 'Class' || objType === 'DDLS' || objType === 'CDS View')) {
2072
+ if (source && (objType === 'INTF' || objType === 'Interface' || objType === 'CLAS' || objType === 'Class' || objType === 'DDLS' || objType === 'CDS View' || objType === 'PROG' || objType === 'Program')) {
2073
2073
  console.log('');
2074
2074
  // Replace escaped newlines with actual newlines and display
2075
2075
  const displaySource = source.replace(/\\n/g, '\n');
@@ -2439,6 +2439,105 @@ Examples:
2439
2439
  break;
2440
2440
  }
2441
2441
 
2442
+ case 'where': {
2443
+ const objectsArgIndex = args.indexOf('--objects');
2444
+ if (objectsArgIndex === -1 || objectsArgIndex + 1 >= args.length) {
2445
+ console.error('Error: --objects parameter required');
2446
+ console.error('Usage: abapgit-agent where --objects <obj1>,<obj2>,... [--type <type>] [--limit <n>] [--json]');
2447
+ console.error('Example: abapgit-agent where --objects ZCL_MY_CLASS');
2448
+ console.error('Example: abapgit-agent where --objects ZIF_MY_INTERFACE');
2449
+ console.error('Example: abapgit-agent where --objects CL_SUT_AUNIT_RUNNER --limit 20');
2450
+ process.exit(1);
2451
+ }
2452
+
2453
+ const objects = args[objectsArgIndex + 1].split(',').map(o => o.trim().toUpperCase());
2454
+ const typeArg = args.indexOf('--type');
2455
+ const type = typeArg !== -1 ? args[typeArg + 1].toUpperCase() : null;
2456
+ const limitArg = args.indexOf('--limit');
2457
+ const limit = limitArg !== -1 ? parseInt(args[limitArg + 1], 10) : 100;
2458
+ const jsonOutput = args.includes('--json');
2459
+
2460
+ console.log(`\n Where-used list for ${objects.length} object(s)`);
2461
+
2462
+ const config = loadConfig();
2463
+ const csrfToken = await fetchCsrfToken(config);
2464
+
2465
+ const data = {
2466
+ objects: objects,
2467
+ limit: Math.min(Math.max(1, limit), 500)
2468
+ };
2469
+
2470
+ if (type) {
2471
+ data.type = type;
2472
+ }
2473
+
2474
+ const result = await request('POST', '/sap/bc/z_abapgit_agent/where', data, { csrfToken });
2475
+
2476
+ // Handle uppercase keys from ABAP
2477
+ const success = result.SUCCESS || result.success;
2478
+ const whereObjects = result.OBJECTS || result.objects || [];
2479
+ const message = result.MESSAGE || result.message || '';
2480
+ const error = result.ERROR || result.error;
2481
+
2482
+ if (!success || error) {
2483
+ console.error(`\n Error: ${error || 'Failed to get where-used list'}`);
2484
+ break;
2485
+ }
2486
+
2487
+ if (jsonOutput) {
2488
+ console.log(JSON.stringify(result, null, 2));
2489
+ } else {
2490
+ console.log(`\n ${message}`);
2491
+ console.log('');
2492
+
2493
+ for (let i = 0; i < whereObjects.length; i++) {
2494
+ const obj = whereObjects[i];
2495
+ const objName = obj.NAME || obj.name || `Object ${i + 1}`;
2496
+ const objType = obj.TYPE || obj.type || '';
2497
+ const error = obj.ERROR || obj.error || '';
2498
+ const references = obj.REFERENCES || obj.references || [];
2499
+ const count = obj.COUNT || obj.count || 0;
2500
+
2501
+ // Handle object not found error
2502
+ if (error) {
2503
+ console.log(` ❌ ${objName} (${objType})`);
2504
+ console.log(` ${error}`);
2505
+ console.log('');
2506
+ continue;
2507
+ }
2508
+
2509
+ if (count === 0) {
2510
+ console.log(` ❌ ${objName} (${objType})`);
2511
+ console.log(` No references found`);
2512
+ console.log('');
2513
+ continue;
2514
+ }
2515
+
2516
+ console.log(` 🔍 ${objName} (${objType})`);
2517
+ console.log(` Found ${count} reference(s):`);
2518
+ console.log('');
2519
+
2520
+ // Display references - one line format: include → method (type) or include (type)
2521
+ for (let j = 0; j < references.length; j++) {
2522
+ const ref = references[j];
2523
+ const includeName = ref.INCLUDE_NAME || ref.include_name || '';
2524
+ const includeType = ref.INCLUDE_TYPE || ref.include_type || '';
2525
+ const methodName = ref.METHOD_NAME || ref.method_name || '';
2526
+
2527
+ let line;
2528
+ if (methodName) {
2529
+ line = ` ${j + 1}. ${includeName} → ${methodName} (${includeType})`;
2530
+ } else {
2531
+ line = ` ${j + 1}. ${includeName} (${includeType})`;
2532
+ }
2533
+ console.log(line);
2534
+ }
2535
+ console.log('');
2536
+ }
2537
+ }
2538
+ break;
2539
+ }
2540
+
2442
2541
  case 'ref': {
2443
2542
  const refSearch = require('../src/ref-search');
2444
2543
  const topicIndex = args.indexOf('--topic');
@@ -2564,6 +2663,9 @@ Commands:
2564
2663
  view --objects <obj1>,<obj2>,... [--type <type>] [--json]
2565
2664
  View ABAP object definitions from the ABAP system
2566
2665
 
2666
+ where --objects <obj1>,<obj2>,... [--type <type>] [--limit <n>] [--json]
2667
+ Find where-used list for ABAP objects (classes, interfaces, programs)
2668
+
2567
2669
  ref <pattern> [--json]
2568
2670
  Search ABAP reference repositories for patterns. Requires referenceFolder in .abapGitAgent.
2569
2671
 
@@ -2610,6 +2712,10 @@ Examples:
2610
2712
  abapgit-agent view --objects ZIF_MY_INTERFACE --type INTF # View interface
2611
2713
  abapgit-agent view --objects ZMY_TABLE --type TABL # View table structure
2612
2714
  abapgit-agent view --objects ZCL_CLASS1,ZCL_CLASS2 --json # Multiple objects
2715
+ abapgit-agent where --objects ZCL_SUT_AUNIT_RUNNER # Find where class is used
2716
+ abapgit-agent where --objects ZIF_MY_INTERFACE # Find interface implementations
2717
+ abapgit-agent where --objects CL_SUT_AUNIT_RUNNER --limit 20 # Limit results
2718
+ abapgit-agent where --objects ZIF_MY_INTERFACE --json # JSON output
2613
2719
  abapgit-agent ref "CORRESPONDING" # Search all reference repos
2614
2720
  abapgit-agent ref "CX_SY_" # Search exceptions
2615
2721
  abapgit-agent ref --topic exceptions # View exception topic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abapgit-agent",
3
- "version": "1.6.1",
3
+ "version": "1.7.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
  "files": [
@@ -16,6 +16,10 @@
16
16
  "start": "node src/server.js",
17
17
  "dev": "nodemon src/server.js",
18
18
  "test": "jest",
19
+ "test:all": "node scripts/test-all.js",
20
+ "test:jest": "jest",
21
+ "test:aunit": "node scripts/test-all.js --jest --cmd",
22
+ "test:cmd": "node scripts/test-all.js --jest --aunit",
19
23
  "pull": "node bin/abapgit-agent",
20
24
  "release": "node scripts/release.js",
21
25
  "unrelease": "node scripts/unrelease.js"
@@ -459,6 +459,52 @@ class ABAPClient {
459
459
 
460
460
  return await this.request('POST', '/list', data, { csrfToken: this.csrfToken });
461
461
  }
462
+
463
+ /**
464
+ * View ABAP object definitions
465
+ * @param {Array} objects - Array of object names to view
466
+ * @param {string} type - Object type (optional, e.g., 'CLAS', 'TABL')
467
+ * @returns {object} View result with object definitions
468
+ */
469
+ async view(objects, type = null) {
470
+ await this.fetchCsrfToken();
471
+
472
+ const data = {
473
+ objects: objects
474
+ };
475
+
476
+ if (type) {
477
+ data.type = type;
478
+ }
479
+
480
+ logger.info('Viewing objects', { objects, type, service: 'abapgit-agent' });
481
+
482
+ return await this.request('POST', '/view', data, { csrfToken: this.csrfToken });
483
+ }
484
+
485
+ /**
486
+ * Find where-used list for ABAP objects
487
+ * @param {Array} objects - Array of object names to search
488
+ * @param {string} type - Object type (optional)
489
+ * @param {number} limit - Maximum results (default: 100, max: 500)
490
+ * @returns {object} Where-used result with found objects
491
+ */
492
+ async where(objects, type = null, limit = 100) {
493
+ await this.fetchCsrfToken();
494
+
495
+ const data = {
496
+ objects: objects,
497
+ limit: Math.min(Math.max(1, limit), 500)
498
+ };
499
+
500
+ if (type) {
501
+ data.type = type;
502
+ }
503
+
504
+ logger.info('Finding where-used', { objects, type, limit: data.limit, service: 'abapgit-agent' });
505
+
506
+ return await this.request('POST', '/where', data, { csrfToken: this.csrfToken });
507
+ }
462
508
  }
463
509
 
464
510
  // Singleton instance
package/src/agent.js CHANGED
@@ -264,6 +264,54 @@ class ABAPGitAgent {
264
264
  throw new Error(`List command failed: ${error.message}`);
265
265
  }
266
266
  }
267
+
268
+ /**
269
+ * View ABAP object definitions
270
+ * @param {Array} objects - Array of object names to view
271
+ * @param {string} type - Object type (optional, e.g., 'CLAS', 'TABL')
272
+ * @returns {object} View result with object definitions
273
+ */
274
+ async view(objects, type = null) {
275
+ logger.info('Viewing objects', { objects, type });
276
+
277
+ try {
278
+ const result = await this.abap.view(objects, type);
279
+ return {
280
+ success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
281
+ command: result.COMMAND || result.command || 'VIEW',
282
+ objects: result.OBJECTS || result.objects || [],
283
+ error: result.ERROR || result.error || null
284
+ };
285
+ } catch (error) {
286
+ logger.error('View command failed', { error: error.message });
287
+ throw new Error(`View command failed: ${error.message}`);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Find where-used list for ABAP objects
293
+ * @param {Array} objects - Array of object names to search
294
+ * @param {string} type - Object type (optional)
295
+ * @param {number} limit - Maximum results (default: 100, max: 500)
296
+ * @returns {object} Where-used result with found objects
297
+ */
298
+ async where(objects, type = null, limit = 100) {
299
+ logger.info('Finding where-used', { objects, type, limit });
300
+
301
+ try {
302
+ const result = await this.abap.where(objects, type, limit);
303
+ return {
304
+ success: result.SUCCESS === 'X' || result.success === 'X' || result.success === true,
305
+ command: result.COMMAND || result.command || 'WHERE',
306
+ objects: result.OBJECTS || result.objects || [],
307
+ message: result.MESSAGE || result.message || '',
308
+ error: result.ERROR || result.error || null
309
+ };
310
+ } catch (error) {
311
+ logger.error('Where command failed', { error: error.message });
312
+ throw new Error(`Where command failed: ${error.message}`);
313
+ }
314
+ }
267
315
  }
268
316
 
269
317
  module.exports = {