abapgit-agent 1.14.4 → 1.14.5
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/abap/CLAUDE.md +21 -4
- package/abap/guidelines/abapgit.md +150 -0
- package/abap/guidelines/debug-session.md +61 -39
- package/package.json +1 -1
- package/src/commands/debug.js +40 -7
- package/src/commands/view.js +53 -5
package/abap/CLAUDE.md
CHANGED
|
@@ -426,17 +426,34 @@ Never assume — wait for the user's answer before proceeding.
|
|
|
426
426
|
|
|
427
427
|
**Finding the right line number for a breakpoint:**
|
|
428
428
|
|
|
429
|
-
Use `view --full --lines` to get
|
|
429
|
+
Use `view --full --lines` to get ready-to-use `debug set` commands per method:
|
|
430
430
|
|
|
431
431
|
```bash
|
|
432
432
|
abapgit-agent view --objects ZCL_FOO --full --lines
|
|
433
433
|
```
|
|
434
434
|
|
|
435
|
-
|
|
435
|
+
**Regular methods (CM\*):** output shows `G [N] code` — the method header has the exact hint:
|
|
436
|
+
```
|
|
437
|
+
* ---- Method: DO_SOMETHING (CM002) — breakpoint: debug set --objects ZCL_FOO:90 ----
|
|
438
|
+
88 [ 1] METHOD do_something.
|
|
439
|
+
89 [ 2] DATA lv_x TYPE i.
|
|
440
|
+
90 [ 3] lv_x = 1.
|
|
441
|
+
```
|
|
442
|
+
`G` = global assembled-source line (for `debug set`), `[N]` = include-relative (navigation only).
|
|
443
|
+
|
|
444
|
+
**Unit test methods (CCAU) and local class methods (CCIMP):** use `--include` flag with section-local line numbers:
|
|
445
|
+
```
|
|
446
|
+
* ---- Method: SETUP — breakpoint: debug set --objects ZCL_FOO:12 --include testclasses ----
|
|
447
|
+
* ---- Method: ZIF_BAR~DO_IT — breakpoint: debug set --objects ZCL_FOO:5 --include locals_imp ----
|
|
448
|
+
```
|
|
436
449
|
|
|
437
450
|
```bash
|
|
438
|
-
#
|
|
439
|
-
abapgit-agent debug set --objects ZCL_FOO:90
|
|
451
|
+
# Regular method:
|
|
452
|
+
abapgit-agent debug set --objects ZCL_FOO:90
|
|
453
|
+
# Unit test method:
|
|
454
|
+
abapgit-agent debug set --objects ZCL_FOO:12 --include testclasses
|
|
455
|
+
# Local class method:
|
|
456
|
+
abapgit-agent debug set --objects ZCL_FOO:5 --include locals_imp
|
|
440
457
|
```
|
|
441
458
|
|
|
442
459
|
Minimal correct sequence:
|
|
@@ -284,6 +284,156 @@ abapGit's serializer **omits fields that have their default value**. Writing ext
|
|
|
284
284
|
|
|
285
285
|
**Why this matters**: Missing `SHLPORIGIN` or wrong `MASK`/`DDTEXT` order causes a permanent diff between git and the system-serialized XML.
|
|
286
286
|
|
|
287
|
+
#### Text Tables and Foreign Keys
|
|
288
|
+
|
|
289
|
+
A **text table** stores translatable texts for another table (the "main table"). It shares the same key fields as the main table plus a language field (`SPRAS` with data element `SPRAS`, or `LANGU` with data element `LANGU`).
|
|
290
|
+
|
|
291
|
+
**How to recognise a text table relationship in the XML:**
|
|
292
|
+
- `<DD09L>` has `<UEBERSETZ>X</UEBERSETZ>` — marks this table as a text table
|
|
293
|
+
- `<DD08V>` has `<FRKART>TEXT</FRKART>` — marks the foreign key as a text-table relationship (ordinary foreign keys omit this field)
|
|
294
|
+
|
|
295
|
+
**Three sections required in the text table XML:**
|
|
296
|
+
|
|
297
|
+
| Section | Purpose |
|
|
298
|
+
|---|---|
|
|
299
|
+
| `DD03P_TABLE` | Field definitions — same key fields as main table + language field + text fields |
|
|
300
|
+
| `DD05M_TABLE` | Foreign key field mappings — one entry per key field of the main table (excluding the language field) |
|
|
301
|
+
| `DD08V_TABLE` | Foreign key relationship — one entry with `FRKART>TEXT` |
|
|
302
|
+
|
|
303
|
+
**`DD03P` rules for the text table:**
|
|
304
|
+
- First key field (`MANDT`) must have `<CHECKTABLE>` pointing to the main table and `<SHLPORIGIN>P</SHLPORIGIN>`
|
|
305
|
+
- Language field (`SPRAS` or `LANGU`) gets `<SHLPORIGIN>D</SHLPORIGIN>` (added by serializer after activation — omit when writing manually)
|
|
306
|
+
|
|
307
|
+
**`DD05M` rules:**
|
|
308
|
+
- `FIELDNAME` = the anchor field in the text table (typically `MANDT` — the first key field)
|
|
309
|
+
- `FORTABLE` = text table name
|
|
310
|
+
- `FORKEY` = key field name in the main table
|
|
311
|
+
- `CHECKFIELD` = same as `FORKEY`
|
|
312
|
+
- `CHECKTABLE` = main table name
|
|
313
|
+
- `PRIMPOS` = position sequence (0001, 0002, …)
|
|
314
|
+
- `DOMNAME` / `DATATYPE` = domain and type of the check field (omit `DOMNAME` if unknown — serializer fills it in)
|
|
315
|
+
|
|
316
|
+
**`DD08V` rules:**
|
|
317
|
+
- `FIELDNAME` = same anchor field as used in `DD05M` (typically `MANDT`)
|
|
318
|
+
- `CHECKTABLE` = main table name
|
|
319
|
+
- `FRKART` = `TEXT` (text table) or omit (ordinary foreign key)
|
|
320
|
+
- `CARD` = `CN` (n:1 cardinality)
|
|
321
|
+
- `CARDLEFT` = `1`
|
|
322
|
+
|
|
323
|
+
**Example — text table `ZMY_TABLE_T` for main table `ZMY_TABLE` (keys: MANDT, ID1, ID2):**
|
|
324
|
+
|
|
325
|
+
```xml
|
|
326
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
327
|
+
<abapGit version="v1.0.0" serializer="LCL_OBJECT_TABL" serializer_version="v1.0.0">
|
|
328
|
+
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
|
|
329
|
+
<asx:values>
|
|
330
|
+
<DD02V>
|
|
331
|
+
<TABNAME>ZMY_TABLE_T</TABNAME>
|
|
332
|
+
<DDLANGUAGE>E</DDLANGUAGE>
|
|
333
|
+
<TABCLASS>TRANSP</TABCLASS>
|
|
334
|
+
<CLIDEP>X</CLIDEP>
|
|
335
|
+
<DDTEXT>My Table: Texts</DDTEXT>
|
|
336
|
+
<CONTFLAG>C</CONTFLAG>
|
|
337
|
+
</DD02V>
|
|
338
|
+
<DD09L>
|
|
339
|
+
<TABNAME>ZMY_TABLE_T</TABNAME>
|
|
340
|
+
<AS4LOCAL>A</AS4LOCAL>
|
|
341
|
+
<TABKAT>0</TABKAT>
|
|
342
|
+
<TABART>APPL0</TABART>
|
|
343
|
+
<UEBERSETZ>X</UEBERSETZ>
|
|
344
|
+
<BUFALLOW>N</BUFALLOW>
|
|
345
|
+
</DD09L>
|
|
346
|
+
<DD03P_TABLE>
|
|
347
|
+
<DD03P>
|
|
348
|
+
<FIELDNAME>MANDT</FIELDNAME>
|
|
349
|
+
<KEYFLAG>X</KEYFLAG>
|
|
350
|
+
<ROLLNAME>MANDT</ROLLNAME>
|
|
351
|
+
<CHECKTABLE>ZMY_TABLE</CHECKTABLE>
|
|
352
|
+
<ADMINFIELD>0</ADMINFIELD>
|
|
353
|
+
<NOTNULL>X</NOTNULL>
|
|
354
|
+
<SHLPORIGIN>P</SHLPORIGIN>
|
|
355
|
+
<COMPTYPE>E</COMPTYPE>
|
|
356
|
+
</DD03P>
|
|
357
|
+
<DD03P>
|
|
358
|
+
<FIELDNAME>ID1</FIELDNAME>
|
|
359
|
+
<KEYFLAG>X</KEYFLAG>
|
|
360
|
+
<ROLLNAME>ZMY_ID1</ROLLNAME>
|
|
361
|
+
<ADMINFIELD>0</ADMINFIELD>
|
|
362
|
+
<NOTNULL>X</NOTNULL>
|
|
363
|
+
<COMPTYPE>E</COMPTYPE>
|
|
364
|
+
</DD03P>
|
|
365
|
+
<DD03P>
|
|
366
|
+
<FIELDNAME>ID2</FIELDNAME>
|
|
367
|
+
<KEYFLAG>X</KEYFLAG>
|
|
368
|
+
<ROLLNAME>ZMY_ID2</ROLLNAME>
|
|
369
|
+
<ADMINFIELD>0</ADMINFIELD>
|
|
370
|
+
<NOTNULL>X</NOTNULL>
|
|
371
|
+
<COMPTYPE>E</COMPTYPE>
|
|
372
|
+
</DD03P>
|
|
373
|
+
<DD03P>
|
|
374
|
+
<FIELDNAME>SPRAS</FIELDNAME>
|
|
375
|
+
<KEYFLAG>X</KEYFLAG>
|
|
376
|
+
<ROLLNAME>SPRAS</ROLLNAME>
|
|
377
|
+
<ADMINFIELD>0</ADMINFIELD>
|
|
378
|
+
<NOTNULL>X</NOTNULL>
|
|
379
|
+
<COMPTYPE>E</COMPTYPE>
|
|
380
|
+
</DD03P>
|
|
381
|
+
<DD03P>
|
|
382
|
+
<FIELDNAME>DESCRIPTION</FIELDNAME>
|
|
383
|
+
<ROLLNAME>ZMY_DESCRIPTION</ROLLNAME>
|
|
384
|
+
<ADMINFIELD>0</ADMINFIELD>
|
|
385
|
+
<COMPTYPE>E</COMPTYPE>
|
|
386
|
+
</DD03P>
|
|
387
|
+
</DD03P_TABLE>
|
|
388
|
+
<DD05M_TABLE>
|
|
389
|
+
<DD05M>
|
|
390
|
+
<FIELDNAME>MANDT</FIELDNAME>
|
|
391
|
+
<FORTABLE>ZMY_TABLE_T</FORTABLE>
|
|
392
|
+
<FORKEY>MANDT</FORKEY>
|
|
393
|
+
<CHECKTABLE>ZMY_TABLE</CHECKTABLE>
|
|
394
|
+
<CHECKFIELD>MANDT</CHECKFIELD>
|
|
395
|
+
<PRIMPOS>0001</PRIMPOS>
|
|
396
|
+
<DOMNAME>MANDT</DOMNAME>
|
|
397
|
+
<DATATYPE>CLNT</DATATYPE>
|
|
398
|
+
</DD05M>
|
|
399
|
+
<DD05M>
|
|
400
|
+
<FIELDNAME>MANDT</FIELDNAME>
|
|
401
|
+
<FORTABLE>ZMY_TABLE_T</FORTABLE>
|
|
402
|
+
<FORKEY>ID1</FORKEY>
|
|
403
|
+
<CHECKTABLE>ZMY_TABLE</CHECKTABLE>
|
|
404
|
+
<CHECKFIELD>ID1</CHECKFIELD>
|
|
405
|
+
<PRIMPOS>0002</PRIMPOS>
|
|
406
|
+
<DATATYPE>CHAR</DATATYPE>
|
|
407
|
+
</DD05M>
|
|
408
|
+
<DD05M>
|
|
409
|
+
<FIELDNAME>MANDT</FIELDNAME>
|
|
410
|
+
<FORTABLE>ZMY_TABLE_T</FORTABLE>
|
|
411
|
+
<FORKEY>ID2</FORKEY>
|
|
412
|
+
<CHECKTABLE>ZMY_TABLE</CHECKTABLE>
|
|
413
|
+
<CHECKFIELD>ID2</CHECKFIELD>
|
|
414
|
+
<PRIMPOS>0003</PRIMPOS>
|
|
415
|
+
<DATATYPE>CHAR</DATATYPE>
|
|
416
|
+
</DD05M>
|
|
417
|
+
</DD05M_TABLE>
|
|
418
|
+
<DD08V_TABLE>
|
|
419
|
+
<DD08V>
|
|
420
|
+
<FIELDNAME>MANDT</FIELDNAME>
|
|
421
|
+
<CHECKTABLE>ZMY_TABLE</CHECKTABLE>
|
|
422
|
+
<FRKART>TEXT</FRKART>
|
|
423
|
+
<CARD>CN</CARD>
|
|
424
|
+
<CARDLEFT>1</CARDLEFT>
|
|
425
|
+
</DD08V>
|
|
426
|
+
</DD08V_TABLE>
|
|
427
|
+
</asx:values>
|
|
428
|
+
</asx:abap>
|
|
429
|
+
</abapGit>
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Key rules:**
|
|
433
|
+
- Always activate the main table **before** the text table — the foreign key check requires the main table to exist
|
|
434
|
+
- Language field can be `SPRAS` (data element `SPRAS`) or `LANGU` (data element `LANGU`) — both are recognised by the system
|
|
435
|
+
- For an **ordinary foreign key** (not a text table): same `DD05M`/`DD08V` structure, but omit `<FRKART>TEXT</FRKART>` from `DD08V`
|
|
436
|
+
|
|
287
437
|
---
|
|
288
438
|
|
|
289
439
|
### CDS View / View Entity (DDLS)
|
|
@@ -17,7 +17,7 @@ Use `debug` when:
|
|
|
17
17
|
|
|
18
18
|
**Step 1 — set a breakpoint** on the first executable statement you want to inspect:
|
|
19
19
|
|
|
20
|
-
Use `view --objects ZCL_MY_CLASS --full --lines` to see the full source with
|
|
20
|
+
Use `view --objects ZCL_MY_CLASS --full --lines` to see the full source with line numbers and ready-to-use `debug set` commands:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
abapgit-agent view --objects ZCL_MY_CLASS --full --lines
|
|
@@ -25,16 +25,11 @@ abapgit-agent view --objects ZCL_MY_CLASS --full --lines
|
|
|
25
25
|
|
|
26
26
|
> **Tip**: `view --full` (without `--lines`) shows the same full source as clean readable code without line numbers — useful for understanding logic. Add `--lines` when you need line numbers for breakpoints.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
- **G** = assembled-source global line → use with `debug set --objects CLASS:G` or `debug set --files src/cls.clas.abap:G`
|
|
30
|
-
- **[N]** = include-relative (restarts at 1 per method) → for code navigation only, not for breakpoints
|
|
28
|
+
The output varies by section type:
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
**Regular methods (CM\* sections)** — dual line numbers `G [N]` per line, with a `debug set` hint at the method header:
|
|
33
31
|
|
|
34
32
|
```
|
|
35
|
-
1 CLASS zcl_my_class DEFINITION.
|
|
36
|
-
2 PUBLIC SECTION.
|
|
37
|
-
3 ENDCLASS.
|
|
38
33
|
* ---- Method: EXECUTE (CM002) — breakpoint: debug set --objects ZCL_MY_CLASS:9 ----
|
|
39
34
|
7 [ 1] METHOD execute.
|
|
40
35
|
8 [ 2] DATA lv_x TYPE i.
|
|
@@ -42,44 +37,69 @@ The method header shows the ready-to-use `debug set` command pointing to the fir
|
|
|
42
37
|
10 [ 4] ENDMETHOD.
|
|
43
38
|
```
|
|
44
39
|
|
|
45
|
-
**
|
|
40
|
+
- **G** = assembled-source global line → use with `debug set --objects CLASS:G` or `--files src/cls.clas.abap:G`
|
|
41
|
+
- **[N]** = include-relative (restarts at 1 per method) → for code navigation only, not for breakpoints
|
|
42
|
+
|
|
43
|
+
The hint already points to the first **executable** line, skipping `METHOD`, blank lines, comments, and all declaration forms (`DATA`, `DATA:`, `DATA(`).
|
|
44
|
+
|
|
45
|
+
**Two scenarios for CM* methods:**
|
|
46
46
|
|
|
47
47
|
| Scenario | Command |
|
|
48
48
|
|---|---|
|
|
49
49
|
| Source available locally (your own classes) | `debug set --files src/zcl_my_class.clas.abap:9` |
|
|
50
50
|
| No local source (abapGit library, SAP standard) | `debug set --objects ZCL_MY_CLASS:9` |
|
|
51
51
|
|
|
52
|
-
Both use the same assembled-source global line number **G** shown in the output. To set a breakpoint at `lv_x = 1.` (global line 9):
|
|
53
52
|
```bash
|
|
54
|
-
# With local file:
|
|
55
|
-
abapgit-agent debug set --files src/zcl_my_class.clas.abap:9
|
|
56
|
-
# Without local file:
|
|
57
53
|
abapgit-agent debug set --objects ZCL_MY_CLASS:9
|
|
58
54
|
abapgit-agent debug list # confirm it was registered
|
|
59
55
|
```
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
57
|
+
**Unit test methods (CCAU section)** and **local class methods (CCIMP section)** live in separate ADT includes — they cannot be addressed by the assembled-source global line. Their sections show section-local line numbers with a `--include` hint per method:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
* ---- Section: Unit Test (from .clas.testclasses.abap) ----
|
|
61
|
+
* ---- Method: SETUP — breakpoint: debug set --objects ZCL_MY_CLASS:12 --include testclasses ----
|
|
62
|
+
10 METHOD setup.
|
|
63
|
+
11 DATA lv_x TYPE i.
|
|
64
|
+
12 mo_cut = NEW #( ).
|
|
65
|
+
13 ENDMETHOD.
|
|
66
|
+
* ---- Method: TEST_PULL_SUCCESS — breakpoint: debug set --objects ZCL_MY_CLASS:18 --include testclasses ----
|
|
67
|
+
15 METHOD test_pull_success.
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
* ---- Section: Local Implementations (from .clas.locals_imp.abap) ----
|
|
71
|
+
* ---- Method: ZIF_FOO~DO_SOMETHING — breakpoint: debug set --objects ZCL_MY_CLASS:5 --include locals_imp ----
|
|
72
|
+
3 METHOD zif_foo~do_something.
|
|
73
|
+
4 DATA lv_x TYPE i.
|
|
74
|
+
5 lv_x = iv_input.
|
|
75
|
+
6 ENDMETHOD.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The line numbers in these sections are **section-local** (same coordinate system as the `.clas.testclasses.abap` / `.clas.locals_imp.abap` file). Use the `--include` flag to target the correct ADT sub-include:
|
|
79
|
+
|
|
80
|
+
| Section | `--include` value |
|
|
81
|
+
|---|---|
|
|
82
|
+
| Unit Test (`.clas.testclasses.abap`) | `testclasses` |
|
|
83
|
+
| Local Implementations (`.clas.locals_imp.abap`) | `locals_imp` |
|
|
84
|
+
| Local Definitions (`.clas.locals_def.abap`) | `locals_def` |
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Unit test method:
|
|
88
|
+
abapgit-agent debug set --objects ZCL_MY_CLASS:12 --include testclasses
|
|
89
|
+
# Local class method:
|
|
90
|
+
abapgit-agent debug set --objects ZCL_MY_CLASS:5 --include locals_imp
|
|
91
|
+
abapgit-agent debug list # confirm both were registered
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> **Line number must point to an executable statement.** The hints already skip `METHOD`, blank lines, comments (`"`, `*`), and all declaration forms (`DATA`, `DATA:`, `DATA(`). One case still requires manual attention:
|
|
80
95
|
>
|
|
81
|
-
>
|
|
82
|
-
>
|
|
96
|
+
> **Multi-line inline `DATA(x) = call(`** — the ABAP debugger treats the whole expression as a declaration. Set the breakpoint on the **next standalone statement** after the closing `).`:
|
|
97
|
+
> ```
|
|
98
|
+
> 100 [ 1] DATA(ls_checks) = prepare_deserialize_checks( ← NOT valid (inline decl)
|
|
99
|
+
> 101 [ 2] it_files = it_files ← NOT valid (continuation)
|
|
100
|
+
> 104 [ 5] io_repo_desc = lo_repo_desc1 ). ← NOT valid (continuation)
|
|
101
|
+
> 106 [ 7] mo_repo->create_new_log( ). ← valid ✅ (use global 106)
|
|
102
|
+
> ```
|
|
83
103
|
|
|
84
104
|
**Step 2 — attach and trigger**
|
|
85
105
|
|
|
@@ -259,22 +279,24 @@ HTTP Request
|
|
|
259
279
|
|
|
260
280
|
### Known Limitations and Planned Improvements
|
|
261
281
|
|
|
262
|
-
The following issues were identified during
|
|
282
|
+
The following issues were identified during live debugging sessions and resolved:
|
|
263
283
|
|
|
264
284
|
#### ~~1. `view --full` global line numbers don't match ADT line numbers~~ ✅ Fixed
|
|
265
285
|
|
|
266
|
-
**Fixed**: `view --full --lines` now shows dual line numbers per line: `G [N] code` where G is the assembled-source global line
|
|
286
|
+
**Fixed**: `view --full --lines` now shows dual line numbers per line: `G [N] code` where G is the assembled-source global line and `[N]` is the include-relative counter. Method headers show the ready-to-use `debug set --objects CLASS:G` command pointing to the first executable statement (skipping `METHOD`, blank lines, comments, and all `DATA`/`DATA:`/`DATA(` declaration forms).
|
|
267
287
|
|
|
268
288
|
Global line numbers are computed **client-side** in Node.js, not in ABAP:
|
|
269
289
|
- **Own classes** (local `.clas.abap` file exists): reads the local file — guaranteed exact match with ADT
|
|
270
290
|
- **Library classes** (no local file, e.g. abapGit): fetches assembled source from `/sap/bc/adt/oo/classes/<name>/source/main`
|
|
271
291
|
|
|
272
|
-
|
|
292
|
+
#### ~~2. No breakpoint support for unit test and local class methods~~ ✅ Fixed
|
|
293
|
+
|
|
294
|
+
**Fixed**: CCAU (unit test) and CCIMP (local class implementation) sections in `view --full --lines` now show per-method `debug set --objects CLASS:N --include <type>` hints. These use the `/includes/<type>` ADT sub-include URI which ADT accepts for CCAU/CCIMP includes. See Step 1 above for details.
|
|
273
295
|
|
|
274
|
-
#### ~~
|
|
296
|
+
#### ~~3. Include-relative breakpoint form (`=====CMxxx:N`) not implemented in the CLI~~ ✅ Superseded
|
|
275
297
|
|
|
276
298
|
**Superseded**: The `/programs/includes/` ADT endpoint was found to not accept breakpoints for OO class method includes — ADT only accepts the `/oo/classes/.../source/main` URI with assembled-source line numbers. The `=====CMxxx:N` approach was dropped. Instead, `view --full --lines` now provides the correct assembled-source global line number G directly, and both `--objects CLASS:G` and `--files src/cls.clas.abap:G` work reliably.
|
|
277
299
|
|
|
278
|
-
#### ~~
|
|
300
|
+
#### ~~4. `stepContinue` re-attach pattern missing from docs~~ ✅ Fixed
|
|
279
301
|
|
|
280
302
|
**Fixed**: Step 3 of the debug guide now documents the two possible return values of `step --type continue` and includes the re-attach pattern for when the program hits a second breakpoint instead of finishing.
|
package/package.json
CHANGED
package/src/commands/debug.js
CHANGED
|
@@ -60,6 +60,23 @@ function hasFlag(args, flag) {
|
|
|
60
60
|
return args.includes(flag);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Valid class include types for --include flag.
|
|
65
|
+
* User-facing names mirror the abapGit file suffixes (.clas.<name>.abap).
|
|
66
|
+
* Maps user-facing name → ADT /includes/<type> path segment.
|
|
67
|
+
* Verified by live ADT testing: breakpoints accepted for all three.
|
|
68
|
+
* testclasses → testclasses → CCAU (unit test class file)
|
|
69
|
+
* locals_imp → implementations → CCIMP (local class implementations)
|
|
70
|
+
* locals_def → definitions → CCDEF (local class definitions)
|
|
71
|
+
*/
|
|
72
|
+
const CLASS_INCLUDE_TYPES = new Set(['testclasses', 'locals_imp', 'locals_def']);
|
|
73
|
+
|
|
74
|
+
const INCLUDE_TYPE_TO_ADT = {
|
|
75
|
+
testclasses: 'testclasses',
|
|
76
|
+
locals_imp: 'implementations',
|
|
77
|
+
locals_def: 'definitions',
|
|
78
|
+
};
|
|
79
|
+
|
|
63
80
|
/**
|
|
64
81
|
* Determine ADT object URI from object name (class/interface vs program vs include).
|
|
65
82
|
* Must use /source/main suffix for classes — verified by live testing: ADT
|
|
@@ -71,11 +88,19 @@ function hasFlag(args, flag) {
|
|
|
71
88
|
* Class method includes are named <ClassName padded to 30 chars with '='>CM<suffix>
|
|
72
89
|
* e.g. ZCL_ABGAGT_AGENT=============CM00D
|
|
73
90
|
* These must be routed to the programs/includes ADT endpoint.
|
|
91
|
+
*
|
|
92
|
+
* When includeType is supplied (testclasses|locals_imp|locals_def),
|
|
93
|
+
* the URI targets the sub-include of the class instead of /source/main.
|
|
94
|
+
* Line numbers are then section-local (from the .clas.<file>.abap file).
|
|
74
95
|
*/
|
|
75
|
-
function objectUri(name) {
|
|
96
|
+
function objectUri(name, includeType) {
|
|
76
97
|
const upper = (name || '').toUpperCase();
|
|
77
98
|
const lower = upper.toLowerCase();
|
|
78
99
|
if (/^[ZY](CL|IF)_/.test(upper) || /^(ZCL|ZIF|YCL|YIF)/.test(upper)) {
|
|
100
|
+
if (includeType && CLASS_INCLUDE_TYPES.has(includeType)) {
|
|
101
|
+
const adtType = INCLUDE_TYPE_TO_ADT[includeType];
|
|
102
|
+
return `/sap/bc/adt/oo/classes/${lower}/includes/${adtType}`;
|
|
103
|
+
}
|
|
79
104
|
return `/sap/bc/adt/oo/classes/${lower}/source/main`;
|
|
80
105
|
}
|
|
81
106
|
return `/sap/bc/adt/programs/programs/${lower}`;
|
|
@@ -247,11 +272,18 @@ function parseBreakpointToken(token) {
|
|
|
247
272
|
}
|
|
248
273
|
|
|
249
274
|
async function cmdSet(args, config, adt) {
|
|
250
|
-
const objectName
|
|
251
|
-
const lineRaw
|
|
252
|
-
const filesArg
|
|
253
|
-
const objectsArg
|
|
254
|
-
const
|
|
275
|
+
const objectName = val(args, '--object');
|
|
276
|
+
const lineRaw = val(args, '--line');
|
|
277
|
+
const filesArg = val(args, '--files');
|
|
278
|
+
const objectsArg = val(args, '--objects');
|
|
279
|
+
const includeType = val(args, '--include');
|
|
280
|
+
const jsonOutput = hasFlag(args, '--json');
|
|
281
|
+
|
|
282
|
+
// Validate --include if supplied
|
|
283
|
+
if (includeType && !CLASS_INCLUDE_TYPES.has(includeType)) {
|
|
284
|
+
console.error(` Error: --include must be one of: ${[...CLASS_INCLUDE_TYPES].join(', ')}`);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
255
287
|
|
|
256
288
|
// Collect all breakpoints to add from every accepted input form
|
|
257
289
|
const toAdd = []; // [{ name, line }]
|
|
@@ -304,6 +336,7 @@ async function cmdSet(args, config, adt) {
|
|
|
304
336
|
console.error(' debug set --files src/zcl_my_class.clas.abap:42');
|
|
305
337
|
console.error(' debug set --objects ZCL_MY_CLASS:42');
|
|
306
338
|
console.error(' debug set --object ZCL_MY_CLASS --line 42');
|
|
339
|
+
console.error(' debug set --objects ZCL_MY_CLASS:16 --include testclasses');
|
|
307
340
|
process.exit(1);
|
|
308
341
|
}
|
|
309
342
|
|
|
@@ -312,7 +345,7 @@ async function cmdSet(args, config, adt) {
|
|
|
312
345
|
const added = [];
|
|
313
346
|
|
|
314
347
|
for (const { name, line } of toAdd) {
|
|
315
|
-
const uri = objectUri(name);
|
|
348
|
+
const uri = objectUri(name, includeType);
|
|
316
349
|
const objUpper = name.toUpperCase();
|
|
317
350
|
// Skip if an identical breakpoint already exists
|
|
318
351
|
if (existing.some(bp => bp.object === objUpper && bp.line === line)) {
|
package/src/commands/view.js
CHANGED
|
@@ -145,18 +145,31 @@ async function computeGlobalStarts(objName, sections, config) {
|
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
147
|
* Given the lines of a CM method section, return the 0-based index of the
|
|
148
|
-
* first "executable" line — i.e. skip METHOD, blank lines,
|
|
149
|
-
* declaration lines (DATA/FINAL/TYPES/CONSTANTS/CLASS-DATA)
|
|
148
|
+
* first "executable" line — i.e. skip METHOD, blank lines, comment lines,
|
|
149
|
+
* and declaration lines (DATA/FINAL/TYPES/CONSTANTS/CLASS-DATA), including
|
|
150
|
+
* multi-line DATA: blocks whose continuation lines end with a period.
|
|
150
151
|
* Returns 0 if no better line is found (falls back to METHOD statement).
|
|
151
152
|
*/
|
|
152
153
|
function findFirstExecutableLine(lines) {
|
|
153
|
-
const declPattern = /^\s*(data|final|types|constants|class-data)[\s:]/i;
|
|
154
|
+
const declPattern = /^\s*(data|final|types|constants|class-data)[\s:(]/i;
|
|
154
155
|
const methodPattern = /^\s*method\s+/i;
|
|
156
|
+
const commentPattern = /^\s*[*"]/;
|
|
157
|
+
let inDeclBlock = false; // true while inside a multi-line DATA:/TYPES: block
|
|
155
158
|
for (let i = 0; i < lines.length; i++) {
|
|
156
159
|
const trimmed = lines[i].trim();
|
|
160
|
+
if (inDeclBlock) {
|
|
161
|
+
// continuation line — skip until the block closes with a period
|
|
162
|
+
if (trimmed.endsWith('.')) inDeclBlock = false;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
157
165
|
if (!trimmed) continue; // blank line
|
|
158
166
|
if (methodPattern.test(trimmed)) continue; // METHOD statement itself
|
|
159
|
-
if (
|
|
167
|
+
if (commentPattern.test(trimmed)) continue; // comment line
|
|
168
|
+
if (declPattern.test(trimmed)) {
|
|
169
|
+
// Multi-line block (DATA: ...,\n ...) stays open until period
|
|
170
|
+
if (!trimmed.endsWith('.')) inDeclBlock = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
160
173
|
return i;
|
|
161
174
|
}
|
|
162
175
|
return 0;
|
|
@@ -282,6 +295,16 @@ module.exports = {
|
|
|
282
295
|
// --full --lines: dual line numbers (G [N]) for debugging
|
|
283
296
|
const globalStart = section.globalStart || 0;
|
|
284
297
|
|
|
298
|
+
// Map abapGit file suffix to the --include flag value used in debug set hints.
|
|
299
|
+
// User-facing names mirror the abapGit file suffixes (.clas.<name>.abap).
|
|
300
|
+
// Verified by live ADT testing: /includes/<adtType> endpoint accepts BPs.
|
|
301
|
+
const INCLUDE_FLAG_VALUE = {
|
|
302
|
+
testclasses: 'testclasses',
|
|
303
|
+
locals_imp: 'locals_imp',
|
|
304
|
+
locals_def: 'locals_def',
|
|
305
|
+
};
|
|
306
|
+
const includeFlag = INCLUDE_FLAG_VALUE[file] || null;
|
|
307
|
+
|
|
285
308
|
if (isCmSection) {
|
|
286
309
|
let bpHint;
|
|
287
310
|
if (globalStart) {
|
|
@@ -299,6 +322,11 @@ module.exports = {
|
|
|
299
322
|
}
|
|
300
323
|
|
|
301
324
|
let includeRelLine = 0;
|
|
325
|
+
// Track when we're inside a METHOD block in a sub-include section
|
|
326
|
+
// so we can emit a breakpoint hint at the first executable line.
|
|
327
|
+
let inSubMethod = false;
|
|
328
|
+
let subMethodName = '';
|
|
329
|
+
let subMethodStartLine = 0; // 1-based line of METHOD statement
|
|
302
330
|
for (const codeLine of lines) {
|
|
303
331
|
includeRelLine++;
|
|
304
332
|
const globalLine = globalStart ? globalStart + includeRelLine - 1 : 0;
|
|
@@ -307,7 +335,27 @@ module.exports = {
|
|
|
307
335
|
const iStr = String(includeRelLine).padStart(3);
|
|
308
336
|
console.log(` ${gStr} [${iStr}] ${codeLine}`);
|
|
309
337
|
} else {
|
|
310
|
-
|
|
338
|
+
// For sub-include sections with a known ADT include type,
|
|
339
|
+
// detect METHOD..ENDMETHOD blocks and emit breakpoint hints.
|
|
340
|
+
if (includeFlag) {
|
|
341
|
+
const trimmed = codeLine.trim();
|
|
342
|
+
if (!inSubMethod && /^method\s+/i.test(trimmed)) {
|
|
343
|
+
// Entering a new method — find first executable line offset
|
|
344
|
+
// by scanning ahead from this line
|
|
345
|
+
const mName = (trimmed.match(/^method\s+([\w~]+)/i) || [])[1] || '';
|
|
346
|
+
// Collect lines from this METHOD onwards to find exec offset
|
|
347
|
+
const remainingLines = lines.slice(includeRelLine - 1); // 0-based from current
|
|
348
|
+
const execOffset = findFirstExecutableLine(remainingLines);
|
|
349
|
+
const execLine = includeRelLine + execOffset; // section-local line
|
|
350
|
+
const bpHint = `debug set --objects ${objName}:${execLine} --include ${includeFlag}`;
|
|
351
|
+
console.log(` * ---- Method: ${mName.toUpperCase()} — breakpoint: ${bpHint} ----`);
|
|
352
|
+
inSubMethod = true;
|
|
353
|
+
subMethodName = mName;
|
|
354
|
+
} else if (inSubMethod && /^endmethod\s*\./i.test(codeLine.trim())) {
|
|
355
|
+
inSubMethod = false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const lStr = String(includeRelLine).padStart(4);
|
|
311
359
|
console.log(` ${lStr} ${codeLine}`);
|
|
312
360
|
}
|
|
313
361
|
}
|