abapgit-agent 1.13.7 → 1.14.1
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/README.md +8 -5
- package/abap/CLAUDE.md +18 -2
- package/abap/guidelines/abaplint.md +52 -1
- package/abap/guidelines/branch-workflow.md +45 -3
- package/package.json +1 -1
- package/src/commands/index.js +2 -1
- package/src/commands/lint.js +199 -0
package/README.md
CHANGED
|
@@ -97,14 +97,17 @@ abapgit-agent health # Verify ABAP connection
|
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
99
|
# Install dependencies
|
|
100
|
-
cd abapgit-agent
|
|
101
100
|
npm install
|
|
102
101
|
|
|
103
|
-
# Run
|
|
104
|
-
|
|
102
|
+
# Run unit tests (no ABAP system needed)
|
|
103
|
+
npm test
|
|
105
104
|
|
|
106
|
-
#
|
|
107
|
-
|
|
105
|
+
# Test a command manually
|
|
106
|
+
node bin/abapgit-agent --help
|
|
107
|
+
node bin/abapgit-agent syntax --files src/zcl_my_class.clas.abap
|
|
108
|
+
|
|
109
|
+
# Run integration tests against a real ABAP system (requires .abapGitAgent)
|
|
110
|
+
npm run test:integration
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
## Documentation
|
package/abap/CLAUDE.md
CHANGED
|
@@ -471,7 +471,7 @@ Run abaplint as step 4b — after `syntax`, before `git commit`:
|
|
|
471
471
|
|
|
472
472
|
```bash
|
|
473
473
|
# Only if .abaplint.json exists
|
|
474
|
-
|
|
474
|
+
abapgit-agent lint
|
|
475
475
|
```
|
|
476
476
|
|
|
477
477
|
Fix any reported issues, then commit.
|
|
@@ -539,6 +539,21 @@ See **AI Tool Guidelines** below for how to react to each setting.
|
|
|
539
539
|
### Branch Workflow (`"mode": "branch"`)
|
|
540
540
|
|
|
541
541
|
Always work on feature branches. Before every `pull`: rebase to default branch. On completion: create PR with squash merge.
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
git checkout main # or master/develop (auto-detected)
|
|
545
|
+
git pull origin main
|
|
546
|
+
git checkout -b feature/my-change
|
|
547
|
+
# edit your ABAP file (name from objects.local.md)
|
|
548
|
+
abapgit-agent syntax --files src/<name>.clas.abap
|
|
549
|
+
ls .abaplint.json 2>/dev/null && abapgit-agent lint # abaplint (if configured)
|
|
550
|
+
git add . && git commit -m "feat: description"
|
|
551
|
+
git push origin feature/my-change
|
|
552
|
+
git fetch origin main && git rebase origin/main
|
|
553
|
+
git push origin feature/my-change --force-with-lease
|
|
554
|
+
abapgit-agent pull --files src/<name>.clas.abap --sync-xml
|
|
555
|
+
```
|
|
556
|
+
|
|
542
557
|
→ See `guidelines/branch-workflow.md` — run: `abapgit-agent ref --topic branch-workflow`
|
|
543
558
|
|
|
544
559
|
### Trunk Workflow (`"mode": "trunk"`)
|
|
@@ -550,6 +565,7 @@ git checkout main # or master/develop (auto-detected)
|
|
|
550
565
|
git pull origin main
|
|
551
566
|
# edit your ABAP file (name from objects.local.md)
|
|
552
567
|
abapgit-agent syntax --files src/<name>.clas.abap
|
|
568
|
+
ls .abaplint.json 2>/dev/null && abapgit-agent lint # abaplint (if configured)
|
|
553
569
|
git add . && git commit -m "feat: description"
|
|
554
570
|
git push origin main
|
|
555
571
|
abapgit-agent pull --files src/<name>.clas.abap --sync-xml
|
|
@@ -649,7 +665,7 @@ Modified ABAP files?
|
|
|
649
665
|
└─ FUGR and other complex objects?
|
|
650
666
|
└─ ✅ Use: skip syntax → [abaplint] → commit → push → pull --sync-xml → (if errors: inspect)
|
|
651
667
|
|
|
652
|
-
[abaplint] = run
|
|
668
|
+
[abaplint] = run abapgit-agent lint only if .abaplint.json exists in repo root
|
|
653
669
|
before applying any quickfix: run abapgit-agent ref --topic abaplint
|
|
654
670
|
```
|
|
655
671
|
|
|
@@ -9,7 +9,9 @@ grand_parent: ABAP Development
|
|
|
9
9
|
# abaplint Rule Guidelines
|
|
10
10
|
|
|
11
11
|
**Searchable keywords**: abaplint, prefer_inline, inline declaration, char literal, string truncation,
|
|
12
|
-
no_inline_in_optional_branches, fully_type_constants, linting, static analysis
|
|
12
|
+
no_inline_in_optional_branches, fully_type_constants, linting, static analysis,
|
|
13
|
+
run abaplint locally, check changed file, abapgit-agent lint,
|
|
14
|
+
keyword_case, sequential_blank, double_space, use_new, local_variable_names
|
|
13
15
|
|
|
14
16
|
This file covers rules that have **non-obvious or dangerous implications** — cases where applying
|
|
15
17
|
a rule mechanically (or accepting its quickfix) can introduce subtle bugs.
|
|
@@ -166,8 +168,57 @@ on rv_result — no intermediate lv_response variable at all.
|
|
|
166
168
|
|
|
167
169
|
---
|
|
168
170
|
|
|
171
|
+
## Running abaplint Locally Against Changed Files
|
|
172
|
+
|
|
173
|
+
Run this before pushing to catch issues early, matching what CI does.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
abapgit-agent lint
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
This automatically detects changed `.abap` files (via `git diff`), creates a scoped
|
|
180
|
+
abaplint config for just those files, runs the check, and cleans up.
|
|
181
|
+
|
|
182
|
+
### Options
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Diff against a specific base branch (useful on a feature branch)
|
|
186
|
+
abapgit-agent lint --base main
|
|
187
|
+
|
|
188
|
+
# Check specific files explicitly
|
|
189
|
+
abapgit-agent lint --files src/zcl_foo.clas.abap,src/zcl_foo.clas.testclasses.abap
|
|
190
|
+
|
|
191
|
+
# Use a different abaplint config (default: .abaplint.json)
|
|
192
|
+
abapgit-agent lint --config .abaplint.json
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Run repeatedly after each fix until you see:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
abaplint: 0 issue(s) found, 1 file(s) analyzed
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Common Issues and Fixes
|
|
204
|
+
|
|
205
|
+
| Rule | Error message | Fix |
|
|
206
|
+
|------|--------------|-----|
|
|
207
|
+
| `keyword_case` | `Keyword should be upper case: "class"` | Uppercase the keyword: `CLASS` |
|
|
208
|
+
| `sequential_blank` | `Remove sequential blank lines` | Max 1 blank line between blocks |
|
|
209
|
+
| `local_variable_names` | `<fs_data> does not match pattern` | Use `l`-prefixed name: `<ls_data>` |
|
|
210
|
+
| `double_space` | `Remove double space` | Single space around `=` in parameters |
|
|
211
|
+
| `use_new` | `Use NEW #() to instantiate` | Replace `CREATE OBJECT mo_foo` → `mo_foo = NEW #( )` |
|
|
212
|
+
| `method_parameter_names` | `Parameter name does not match pattern` | Use `iv_`, `it_`, `is_`, `io_` etc. prefixes |
|
|
213
|
+
|
|
214
|
+
See **abaplint-local.md** for the full naming convention prefix reference.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
|
|
169
219
|
## See Also
|
|
170
220
|
|
|
171
221
|
- **common-errors.md** — char-literal truncation listed as a known error pattern
|
|
172
222
|
- **json.md** — safe patterns for building JSON strings in ABAP
|
|
173
223
|
- **workflow-detailed.md** — where abaplint fits in the development workflow
|
|
224
|
+
- **abaplint-local.md** — naming convention reference (prefixes for variables, parameters, field-symbols)
|
|
@@ -21,6 +21,7 @@ edit src/zcl_auth_handler.clas.abap
|
|
|
21
21
|
|
|
22
22
|
# 3. Check syntax (CLAS/INTF/PROG/DDLS only, if independent)
|
|
23
23
|
abapgit-agent syntax --files src/zcl_auth_handler.clas.abap
|
|
24
|
+
ls .abaplint.json 2>/dev/null && abapgit-agent lint # abaplint (if configured)
|
|
24
25
|
|
|
25
26
|
# 4. Commit
|
|
26
27
|
git add src/zcl_auth_handler.clas.abap
|
|
@@ -72,10 +73,47 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
|
|
|
72
73
|
abapgit-agent unit --files src/zcl_auth_handler.clas.testclasses.abap
|
|
73
74
|
|
|
74
75
|
# 3. Create PR (squash merge enabled on GitHub/GitLab)
|
|
75
|
-
#
|
|
76
|
-
# Select "Squash and merge" option to combine all commits into one
|
|
76
|
+
# See "Creating a PR" section below for transport handling
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
#### Creating a PR
|
|
80
|
+
|
|
81
|
+
When creating a PR with `gh pr create`:
|
|
82
|
+
|
|
83
|
+
**Check `.abapgit-agent.json` for `transports.hook`.**
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
transports.hook present?
|
|
87
|
+
├─ NO → create PR normally, no transport line needed. STOP here.
|
|
88
|
+
└─ YES → continue below
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**If hook is configured — resolve which transport to include:**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
abapgit-agent transport list --scope task --json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- **One result** → use it directly, no need to ask the user
|
|
98
|
+
- **Multiple results** → show the list to the user and ask which one to use for this PR
|
|
99
|
+
- **No results** → ask the user to provide a transport number manually, or confirm to skip
|
|
100
|
+
|
|
101
|
+
**Append `transport: <number>` as the last line of the PR body:**
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
## Summary
|
|
105
|
+
- Implemented user authentication handler
|
|
106
|
+
|
|
107
|
+
## Changed Objects
|
|
108
|
+
- ZCL_AUTH_HANDLER (CLAS)
|
|
109
|
+
|
|
110
|
+
transport: DEVK900001
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Why:** The CI pipeline reads this line from the PR description and uses it for the
|
|
114
|
+
Activate stage, overriding the automatic hook selection. This lets the user control
|
|
115
|
+
which transport request receives the activated changes.
|
|
116
|
+
|
|
79
117
|
#### Why Rebase Before Pull?
|
|
80
118
|
|
|
81
119
|
ABAP is a **centralized system**. Multiple developers may modify the same files:
|
|
@@ -112,6 +150,7 @@ git checkout main && git pull origin main
|
|
|
112
150
|
git checkout -b feature/user-authentication
|
|
113
151
|
edit src/zcl_auth_handler.clas.abap
|
|
114
152
|
abapgit-agent syntax --files src/zcl_auth_handler.clas.abap
|
|
153
|
+
ls .abaplint.json 2>/dev/null && abapgit-agent lint # abaplint (if configured)
|
|
115
154
|
git add . && git commit -m "wip: add basic auth logic"
|
|
116
155
|
git push origin feature/user-authentication
|
|
117
156
|
git fetch origin main && git rebase origin/main
|
|
@@ -123,6 +162,8 @@ git fetch origin main && git rebase origin/main
|
|
|
123
162
|
# If conflicts: resolve, git add, git rebase --continue
|
|
124
163
|
git push origin feature/user-authentication --force-with-lease
|
|
125
164
|
edit src/zcl_auth_handler.clas.abap
|
|
165
|
+
abapgit-agent syntax --files src/zcl_auth_handler.clas.abap
|
|
166
|
+
ls .abaplint.json 2>/dev/null && abapgit-agent lint # abaplint (if configured)
|
|
126
167
|
git add . && git commit -m "feat: complete auth logic"
|
|
127
168
|
git push origin feature/user-authentication
|
|
128
169
|
git fetch origin main && git rebase origin/main
|
|
@@ -133,5 +174,6 @@ abapgit-agent pull --files src/zcl_auth_handler.clas.abap
|
|
|
133
174
|
abapgit-agent unit --files src/zcl_auth_handler.clas.testclasses.abap
|
|
134
175
|
git fetch origin main && git rebase origin/main
|
|
135
176
|
git push origin feature/user-authentication --force-with-lease
|
|
136
|
-
# Create PR
|
|
177
|
+
# Create PR: check transport hook, resolve transport, include in PR body
|
|
178
|
+
# abapgit-agent transport list --scope task --json → pick transport → append to PR body
|
|
137
179
|
```
|
package/package.json
CHANGED
package/src/commands/index.js
CHANGED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* lint command - Run abaplint on changed ABAP files
|
|
5
|
+
*
|
|
6
|
+
* Detects files changed relative to a base branch (or HEAD~1),
|
|
7
|
+
* creates a scoped abaplint config for just those files, and runs the check.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* abapgit-agent lint
|
|
11
|
+
* abapgit-agent lint --config .abaplint.json
|
|
12
|
+
* abapgit-agent lint --base main
|
|
13
|
+
* abapgit-agent lint --files src/foo.clas.abap,src/foo.clas.testclasses.abap
|
|
14
|
+
* abapgit-agent lint --outformat checkstyle --outfile reports/abaplint-results.xml
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { execSync, spawnSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
name: 'lint',
|
|
23
|
+
description: 'Run abaplint on changed ABAP files',
|
|
24
|
+
requiresAbapConfig: false,
|
|
25
|
+
|
|
26
|
+
execute(args) {
|
|
27
|
+
const configPath = argValue(args, '--config') || '.abaplint.json';
|
|
28
|
+
const baseBranch = argValue(args, '--base');
|
|
29
|
+
const filesArg = argValue(args, '--files');
|
|
30
|
+
const outformat = argValue(args, '--outformat');
|
|
31
|
+
const outfile = argValue(args, '--outfile');
|
|
32
|
+
|
|
33
|
+
// ── Resolve changed files ─────────────────────────────────────────────────
|
|
34
|
+
let abapFiles;
|
|
35
|
+
if (filesArg) {
|
|
36
|
+
abapFiles = filesArg.split(',').map(f => f.trim()).filter(f => f.endsWith('.abap'));
|
|
37
|
+
} else {
|
|
38
|
+
abapFiles = detectChangedAbapFiles(baseBranch);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (abapFiles.length === 0) {
|
|
42
|
+
console.log('No changed .abap files found — nothing to lint.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!outfile) {
|
|
47
|
+
console.log(`\nLinting ${abapFiles.length} file(s):`);
|
|
48
|
+
abapFiles.forEach(f => console.log(` ${f}`));
|
|
49
|
+
console.log('');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── Load and scope the abaplint config ────────────────────────────────────
|
|
53
|
+
if (!fs.existsSync(configPath)) {
|
|
54
|
+
console.error(`Error: abaplint config not found: ${configPath}`);
|
|
55
|
+
console.error('Run from the project root, or pass --config <path>.');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
60
|
+
|
|
61
|
+
// Scope to changed files + their direct dependencies (interfaces, superclasses)
|
|
62
|
+
// so abaplint can resolve cross-references without including the whole repo.
|
|
63
|
+
const abapDir = cfg.global.files.replace(/\/\*\*.*$/, '').replace(/^\//, '') || 'abap';
|
|
64
|
+
const depFiles = resolveDependencies(abapFiles, abapDir);
|
|
65
|
+
const allFiles = [...new Set([...abapFiles, ...depFiles])];
|
|
66
|
+
cfg.global.files = allFiles.map(f => `/${f}`);
|
|
67
|
+
|
|
68
|
+
const scopedConfig = '.abaplint-local.json';
|
|
69
|
+
fs.writeFileSync(scopedConfig, JSON.stringify(cfg, null, 2));
|
|
70
|
+
|
|
71
|
+
// ── Run abaplint ──────────────────────────────────────────────────────────
|
|
72
|
+
try {
|
|
73
|
+
const formatArgs = outformat ? `--outformat ${outformat}` : '';
|
|
74
|
+
const fileArgs = outfile ? `--outfile ${outfile}` : '';
|
|
75
|
+
const result = spawnSync(
|
|
76
|
+
`npx @abaplint/cli@latest ${scopedConfig} ${formatArgs} ${fileArgs}`,
|
|
77
|
+
{ stdio: 'inherit', shell: true }
|
|
78
|
+
);
|
|
79
|
+
if (result.status !== 0) {
|
|
80
|
+
process.exitCode = result.status;
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
fs.unlinkSync(scopedConfig);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
function argValue(args, flag) {
|
|
91
|
+
const idx = args.indexOf(flag);
|
|
92
|
+
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Detect changed .abap files using git diff.
|
|
97
|
+
* - If on a PR branch (CHANGE_TARGET set, e.g. in CI): diffs against that target.
|
|
98
|
+
* - If --base is given: diffs against that branch.
|
|
99
|
+
* - Otherwise: diffs HEAD~1..HEAD (last commit).
|
|
100
|
+
*/
|
|
101
|
+
function detectChangedAbapFiles(baseBranch) {
|
|
102
|
+
const base = baseBranch
|
|
103
|
+
|| (process.env.CHANGE_TARGET ? `origin/${process.env.CHANGE_TARGET}` : null);
|
|
104
|
+
|
|
105
|
+
let diffCmd;
|
|
106
|
+
if (base) {
|
|
107
|
+
diffCmd = `git diff --name-only ${base}...HEAD -- '*.abap'`;
|
|
108
|
+
} else {
|
|
109
|
+
// Fall back to uncommitted changes first, then last commit
|
|
110
|
+
const uncommitted = runGit('git diff --name-only HEAD -- *.abap').filter(Boolean);
|
|
111
|
+
if (uncommitted.length > 0) return filterAbapFiles(uncommitted);
|
|
112
|
+
diffCmd = `git diff --name-only HEAD~1 HEAD -- '*.abap'`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return filterAbapFiles(runGit(diffCmd));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function runGit(cmd) {
|
|
119
|
+
try {
|
|
120
|
+
return execSync(cmd, { encoding: 'utf8' }).trim().split('\n').filter(Boolean);
|
|
121
|
+
} catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolve direct dependencies of the given ABAP files by scanning their source
|
|
128
|
+
* for interface/superclass/type references and mapping them to local files.
|
|
129
|
+
*
|
|
130
|
+
* Handles:
|
|
131
|
+
* INTERFACES <name>. → <name>.intf.abap + <name>.intf.xml
|
|
132
|
+
* INHERITING FROM <name> → <name>.clas.abap + <name>.clas.xml
|
|
133
|
+
* TYPE REF TO <name> → <name>.intf.abap or <name>.clas.abap (whichever exists)
|
|
134
|
+
*
|
|
135
|
+
* Only resolves one level deep — enough for abaplint to check the changed files.
|
|
136
|
+
* XML companion files are always included alongside their .abap counterpart
|
|
137
|
+
* so xml_consistency checks can run.
|
|
138
|
+
*/
|
|
139
|
+
function resolveDependencies(abapFiles, abapDir) {
|
|
140
|
+
const deps = new Set();
|
|
141
|
+
const visited = new Set(abapFiles); // don't re-scan changed files as deps
|
|
142
|
+
|
|
143
|
+
// Patterns to extract referenced object names from ABAP source
|
|
144
|
+
const patterns = [
|
|
145
|
+
/^\s*INTERFACES\s+(\w+)\s*\./gim,
|
|
146
|
+
/INHERITING\s+FROM\s+(\w+)/gim,
|
|
147
|
+
/TYPE\s+REF\s+TO\s+(\w+)/gim,
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
// BFS queue — seed with the changed files, then expand transitively
|
|
151
|
+
const queue = [...abapFiles];
|
|
152
|
+
|
|
153
|
+
while (queue.length > 0) {
|
|
154
|
+
const file = queue.shift();
|
|
155
|
+
|
|
156
|
+
let source;
|
|
157
|
+
try { source = fs.readFileSync(file, 'utf8'); } catch { continue; }
|
|
158
|
+
|
|
159
|
+
for (const pattern of patterns) {
|
|
160
|
+
pattern.lastIndex = 0;
|
|
161
|
+
let match;
|
|
162
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
163
|
+
const name = match[1].toLowerCase();
|
|
164
|
+
for (const suffix of [`${name}.intf`, `${name}.clas`]) {
|
|
165
|
+
const abapFile = path.join(abapDir, `${suffix}.abap`);
|
|
166
|
+
const xmlFile = path.join(abapDir, `${suffix}.xml`);
|
|
167
|
+
if (fs.existsSync(abapFile)) {
|
|
168
|
+
deps.add(abapFile);
|
|
169
|
+
if (fs.existsSync(xmlFile)) deps.add(xmlFile);
|
|
170
|
+
// Recurse into this dep if not yet visited
|
|
171
|
+
if (!visited.has(abapFile)) {
|
|
172
|
+
visited.add(abapFile);
|
|
173
|
+
queue.push(abapFile);
|
|
174
|
+
}
|
|
175
|
+
break; // intf matched — don't also try clas
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Always include the XML companion of each scanned file
|
|
182
|
+
const xmlCompanion = file.replace(/\.abap$/, '.xml');
|
|
183
|
+
if (fs.existsSync(xmlCompanion)) deps.add(xmlCompanion);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return [...deps];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Keep only files that look like ABAP source files
|
|
191
|
+
* (name.type.abap or name.type.subtype.abap).
|
|
192
|
+
*/
|
|
193
|
+
function filterAbapFiles(files) {
|
|
194
|
+
return files.filter(f => {
|
|
195
|
+
const parts = path.basename(f).split('.');
|
|
196
|
+
return (parts.length === 3 || parts.length === 4) &&
|
|
197
|
+
parts[parts.length - 1].toLowerCase() === 'abap';
|
|
198
|
+
});
|
|
199
|
+
}
|