arc-1 0.6.10 → 0.7.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.
Files changed (115) hide show
  1. package/README.md +8 -7
  2. package/bin/arc1-cli.js +10 -0
  3. package/bin/arc1.js +1 -1
  4. package/dist/adt/cds-impact.d.ts +35 -0
  5. package/dist/adt/cds-impact.d.ts.map +1 -1
  6. package/dist/adt/cds-impact.js +71 -0
  7. package/dist/adt/cds-impact.js.map +1 -1
  8. package/dist/adt/client.d.ts +4 -1
  9. package/dist/adt/client.d.ts.map +1 -1
  10. package/dist/adt/client.js +18 -5
  11. package/dist/adt/client.js.map +1 -1
  12. package/dist/adt/crud.d.ts.map +1 -1
  13. package/dist/adt/crud.js +32 -5
  14. package/dist/adt/crud.js.map +1 -1
  15. package/dist/adt/devtools.d.ts +39 -3
  16. package/dist/adt/devtools.d.ts.map +1 -1
  17. package/dist/adt/devtools.js +237 -25
  18. package/dist/adt/devtools.js.map +1 -1
  19. package/dist/adt/diagnostics.d.ts +69 -7
  20. package/dist/adt/diagnostics.d.ts.map +1 -1
  21. package/dist/adt/diagnostics.js +694 -36
  22. package/dist/adt/diagnostics.js.map +1 -1
  23. package/dist/adt/errors.d.ts +14 -1
  24. package/dist/adt/errors.d.ts.map +1 -1
  25. package/dist/adt/errors.js +40 -9
  26. package/dist/adt/errors.js.map +1 -1
  27. package/dist/adt/http.d.ts.map +1 -1
  28. package/dist/adt/http.js +86 -1
  29. package/dist/adt/http.js.map +1 -1
  30. package/dist/adt/rap-handlers.d.ts +165 -0
  31. package/dist/adt/rap-handlers.d.ts.map +1 -0
  32. package/dist/adt/rap-handlers.js +835 -0
  33. package/dist/adt/rap-handlers.js.map +1 -0
  34. package/dist/adt/rap-preflight.d.ts +43 -0
  35. package/dist/adt/rap-preflight.d.ts.map +1 -0
  36. package/dist/adt/rap-preflight.js +405 -0
  37. package/dist/adt/rap-preflight.js.map +1 -0
  38. package/dist/adt/safety.d.ts +60 -36
  39. package/dist/adt/safety.d.ts.map +1 -1
  40. package/dist/adt/safety.js +202 -120
  41. package/dist/adt/safety.js.map +1 -1
  42. package/dist/adt/transport.d.ts +1 -1
  43. package/dist/adt/transport.js +2 -2
  44. package/dist/adt/transport.js.map +1 -1
  45. package/dist/adt/types.d.ts +88 -0
  46. package/dist/adt/types.d.ts.map +1 -1
  47. package/dist/adt/xml-parser.d.ts +13 -1
  48. package/dist/adt/xml-parser.d.ts.map +1 -1
  49. package/dist/adt/xml-parser.js +26 -15
  50. package/dist/adt/xml-parser.js.map +1 -1
  51. package/dist/authz/policy.d.ts +53 -0
  52. package/dist/authz/policy.d.ts.map +1 -0
  53. package/dist/authz/policy.js +199 -0
  54. package/dist/authz/policy.js.map +1 -0
  55. package/dist/cli-args.d.ts +14 -0
  56. package/dist/cli-args.d.ts.map +1 -0
  57. package/dist/cli-args.js +62 -0
  58. package/dist/cli-args.js.map +1 -0
  59. package/dist/cli.d.ts +13 -7
  60. package/dist/cli.d.ts.map +1 -1
  61. package/dist/cli.js +252 -55
  62. package/dist/cli.js.map +1 -1
  63. package/dist/extract-sap-cookies.d.ts +24 -0
  64. package/dist/extract-sap-cookies.d.ts.map +1 -0
  65. package/dist/extract-sap-cookies.js +317 -0
  66. package/dist/extract-sap-cookies.js.map +1 -0
  67. package/dist/handlers/hyperfocused.d.ts +4 -3
  68. package/dist/handlers/hyperfocused.d.ts.map +1 -1
  69. package/dist/handlers/hyperfocused.js +25 -16
  70. package/dist/handlers/hyperfocused.js.map +1 -1
  71. package/dist/handlers/intent.d.ts +4 -12
  72. package/dist/handlers/intent.d.ts.map +1 -1
  73. package/dist/handlers/intent.js +1238 -114
  74. package/dist/handlers/intent.js.map +1 -1
  75. package/dist/handlers/schemas.d.ts +38 -10
  76. package/dist/handlers/schemas.d.ts.map +1 -1
  77. package/dist/handlers/schemas.js +69 -4
  78. package/dist/handlers/schemas.js.map +1 -1
  79. package/dist/handlers/tools.d.ts.map +1 -1
  80. package/dist/handlers/tools.js +251 -164
  81. package/dist/handlers/tools.js.map +1 -1
  82. package/dist/index.d.ts +1 -1
  83. package/dist/index.js +7 -6
  84. package/dist/index.js.map +1 -1
  85. package/dist/server/audit.d.ts +26 -3
  86. package/dist/server/audit.d.ts.map +1 -1
  87. package/dist/server/audit.js.map +1 -1
  88. package/dist/server/config.d.ts +34 -19
  89. package/dist/server/config.d.ts.map +1 -1
  90. package/dist/server/config.js +320 -193
  91. package/dist/server/config.js.map +1 -1
  92. package/dist/server/deny-actions.d.ts +31 -0
  93. package/dist/server/deny-actions.d.ts.map +1 -0
  94. package/dist/server/deny-actions.js +156 -0
  95. package/dist/server/deny-actions.js.map +1 -0
  96. package/dist/server/effective-policy-log.d.ts +27 -0
  97. package/dist/server/effective-policy-log.d.ts.map +1 -0
  98. package/dist/server/effective-policy-log.js +103 -0
  99. package/dist/server/effective-policy-log.js.map +1 -0
  100. package/dist/server/http.d.ts.map +1 -1
  101. package/dist/server/http.js +15 -16
  102. package/dist/server/http.js.map +1 -1
  103. package/dist/server/server.d.ts +37 -3
  104. package/dist/server/server.d.ts.map +1 -1
  105. package/dist/server/server.js +231 -30
  106. package/dist/server/server.js.map +1 -1
  107. package/dist/server/types.d.ts +29 -13
  108. package/dist/server/types.d.ts.map +1 -1
  109. package/dist/server/types.js +10 -11
  110. package/dist/server/types.js.map +1 -1
  111. package/dist/server/xsuaa.d.ts +1 -2
  112. package/dist/server/xsuaa.d.ts.map +1 -1
  113. package/dist/server/xsuaa.js +13 -14
  114. package/dist/server/xsuaa.js.map +1 -1
  115. package/package.json +8 -3
@@ -0,0 +1,835 @@
1
+ /**
2
+ * RAP behavior-pool handler scaffolding.
3
+ *
4
+ * Context — this module exists because on-prem RAP development has a tight
5
+ * contract between a BDEF (behavior definition source) and its behavior pool
6
+ * (the ABAP global class named in `managed implementation in class ZBP_...`).
7
+ * Every `action` / `determination` / `validation` / `authorization master`
8
+ * declared in the BDEF requires a matching METHOD signature inside a local
9
+ * handler class (`lhc_<alias>`). If any signature is missing, the class will
10
+ * not activate and the error reported by ADT doesn't tell the developer
11
+ * which signatures are missing — they see a generic "behavior pool does not
12
+ * implement the required method for ..." message.
13
+ *
14
+ * The exported helpers cooperate:
15
+ * 1. extractRapHandlerRequirements — parse BDEF → list of required methods
16
+ * 2. findMissingRapHandlerRequirements — diff required vs. present in class
17
+ * 3. applyRapHandlerSignatures — insert the missing METHODS lines
18
+ * 4. applyRapHandlerImplementationStubs — insert empty METHOD stubs
19
+ * 5. applyRapHandlerScaffold — plan multi-include auto-apply
20
+ *
21
+ * The scaffolder writes declarations plus empty implementations only.
22
+ * Business logic remains the developer's responsibility and can be filled
23
+ * with edit_method.
24
+ *
25
+ * Naming convention: handler classes use the prefix `lhc_` (local handler
26
+ * class) followed by the lowercased alias from the BDEF. This is the RAP
27
+ * convention SAP's own templates use (see cl_abap_behavior_handler examples
28
+ * in /DMO/* and the "Create Behavior Implementation Class" wizard in ADT).
29
+ */
30
+ // AI-maintenance guide:
31
+ // If SAP adds or changes RAP handler syntax, update these parser patterns first,
32
+ // then add one fixture-style test in tests/unit/adt/rap-handlers.test.ts. Keeping
33
+ // the grammar fragments here avoids subtly divergent regexes in detection,
34
+ // missing-checks, and auto-apply.
35
+ const BDEF_DEFINE_BEHAVIOR_RE = /^\s*define\s+behavior\s+for\s+([^\s{]+)(?:\s+alias\s+([A-Za-z_]\w*))?/i;
36
+ const BDEF_ACTION_DECLARATION_RE = /^\s*(?:static\s+)?(?:(?:internal|factory)\s+)*action(?:\s*\([^)]*\))?\s+([A-Za-z_]\w*)\b/i;
37
+ const BDEF_DETERMINATION_DECLARATION_RE = /^\s*determination\s+([A-Za-z_]\w*)\s+on\s+(modify|save)\b/i;
38
+ const BDEF_VALIDATION_DECLARATION_RE = /^\s*validation\s+([A-Za-z_]\w*)\s+on\s+(modify|save)\b/i;
39
+ const BDEF_INSTANCE_AUTH_RE = /\bauthorization\s+master\s*\(\s*instance\s*\)/i;
40
+ const BDEF_GLOBAL_AUTH_RE = /\bauthorization\s+master\s*\(\s*global\s*\)/i;
41
+ const CLASS_DEFINITION_START_RE = /^\s*CLASS\s+([A-Za-z_][\w$]*)\s+DEFINITION\b/i;
42
+ const CLASS_DEFINITION_DEFERRED_RE = /\bDEFINITION\b.*\bDEFERRED\b/i;
43
+ const CLASS_IMPLEMENTATION_START_RE = /^\s*CLASS\s+([A-Za-z_][\w$]*)\s+IMPLEMENTATION\s*\./i;
44
+ const PRIVATE_SECTION_RE = /^\s*PRIVATE\s+SECTION\./i;
45
+ const ENDCLASS_RE = /^\s*ENDCLASS\./i;
46
+ const METHOD_DECLARATION_RE = /^\s*(?:CLASS-)?METHODS\s+([A-Za-z_~][\w~]*)/i;
47
+ const METHOD_IMPLEMENTATION_RE = /^\s*METHOD\s+([A-Za-z_~][\w~]*)\s*\./i;
48
+ const HANDLER_ACTION_BINDING_RE = /\bFOR\s+ACTION\s+([A-Za-z_]\w*)\s*~\s*([A-Za-z_]\w*)/i;
49
+ const HANDLER_ENTITY_BINDING_RE = /\bFOR\s+(?!ACTION\b|MODIFY\b|READ\b|VALIDATE\b|DETERMINE\b|INSTANCE\b|GLOBAL\b)([A-Za-z_]\w*)\s*~\s*([A-Za-z_]\w*)/i;
50
+ const HANDLER_AUTH_BINDING_RE = /\bAUTHORIZATION\b.*\bFOR\s+([A-Za-z_]\w*)\s+RESULT\b/i;
51
+ const HANDLER_DETERMINE_STATEMENT_RE = /\bFOR\s+DETERMINE\s+ON\b/i;
52
+ const HANDLER_VALIDATE_STATEMENT_RE = /\bFOR\s+VALIDATE\s+ON\b/i;
53
+ const HANDLER_INSTANCE_AUTH_STATEMENT_RE = /\bFOR\s+INSTANCE\s+AUTHORIZATION\b/i;
54
+ const HANDLER_GLOBAL_AUTH_STATEMENT_RE = /\bFOR\s+GLOBAL\s+AUTHORIZATION\b/i;
55
+ function bindingKey(targetHandlerClass, kind, methodName, entityAlias) {
56
+ return [targetHandlerClass.toLowerCase(), kind, normalizeMethodName(methodName), entityAlias.toLowerCase()].join('|');
57
+ }
58
+ export function rapHandlerRequirementKey(requirement) {
59
+ return bindingKey(requirement.targetHandlerClass, requirement.kind, requirement.methodName, requirement.entityAlias);
60
+ }
61
+ function countChar(value, char) {
62
+ return value.split(char).length - 1;
63
+ }
64
+ /**
65
+ * Collect a BDEF statement that may span multiple lines.
66
+ *
67
+ * RAP behavior definitions are terminated by `;`, but developers routinely
68
+ * split long declarations across lines for readability, e.g.:
69
+ * action acceptTravel
70
+ * result [1] $self;
71
+ * We must join the continuation lines before deciding whether a `result`
72
+ * clause is present — otherwise we'd emit `FOR ACTION ... RESULT result` for
73
+ * actions that don't return anything, producing an invalid handler signature.
74
+ *
75
+ * The 20-line safety cutoff guards against runaway scans when the BDEF is
76
+ * malformed or truncated; real declarations rarely exceed 5-6 lines.
77
+ */
78
+ function collectStatement(lines, startIdx) {
79
+ let statement = lines[startIdx] ?? '';
80
+ if (statement.includes(';'))
81
+ return statement;
82
+ for (let j = startIdx + 1; j < lines.length; j += 1) {
83
+ const next = lines[j] ?? '';
84
+ statement += ` ${next}`;
85
+ if (next.includes(';'))
86
+ break;
87
+ if (j - startIdx > 20)
88
+ break;
89
+ }
90
+ return statement;
91
+ }
92
+ /**
93
+ * Collect a multi-line ABAP statement terminated by `.`.
94
+ *
95
+ * Behavior handler declarations are often split across lines:
96
+ * METHODS set_status_accepted FOR MODIFY
97
+ * IMPORTING keys FOR ACTION travel~acceptTravel RESULT result.
98
+ * Binding parsing needs the continuation lines; otherwise semantic method
99
+ * names cannot be mapped back to the BDEF action/determination/validation.
100
+ */
101
+ function collectAbapStatement(lines, startIdx, endIdx, maxContinuation = 10) {
102
+ let statement = lines[startIdx] ?? '';
103
+ for (let j = startIdx + 1; j <= endIdx && j < startIdx + maxContinuation; j += 1) {
104
+ const cont = lines[j] ?? '';
105
+ statement += ` ${cont}`;
106
+ if (/\.\s*$/.test(cont.trim()))
107
+ break;
108
+ }
109
+ return statement;
110
+ }
111
+ /**
112
+ * Lowercase a BDEF identifier for use as an ABAP METHOD name.
113
+ *
114
+ * BDEF is case-insensitive for identifier matching but ABAP source code is
115
+ * rendered in lowercase by SAP's pretty printer. We emit lowercase here so
116
+ * the scaffolded METHODS lines match both the `lhc_<alias>` class name and
117
+ * SAP's default code-style. The trailing period (from a terminating `.` or
118
+ * `;` accidentally included by the regex match) is stripped defensively.
119
+ */
120
+ function normalizeMethodName(name) {
121
+ return name.replace(/\.$/, '').trim().toLowerCase();
122
+ }
123
+ /**
124
+ * Derive an alias from an entity name when the BDEF author omits `alias X`.
125
+ *
126
+ * RAP aliases are optional; if absent, SAP falls back to the entity name
127
+ * itself for handler-class derivation. We emulate that by stripping namespace
128
+ * prefixes (`/DMO/ZI_TRAVEL` → `ZI_TRAVEL`) and a short leading prefix like
129
+ * `ZI_` or `I_` (→ `TRAVEL`), then sanitizing any leftover non-identifier
130
+ * characters. Final fallback is `Entity` so the generated `lhc_entity`
131
+ * remains a valid ABAP identifier.
132
+ */
133
+ function deriveAlias(entityName) {
134
+ const noNamespace = entityName.split('/').at(-1) ?? entityName;
135
+ const noPrefix = noNamespace.replace(/^[A-Z]{1,4}_/, '');
136
+ const normalized = (noPrefix || noNamespace).replace(/[^A-Za-z0-9_]/g, '');
137
+ return normalized || 'Entity';
138
+ }
139
+ /**
140
+ * Split a BDEF into per-entity blocks bounded by `define behavior for ... { ... }`.
141
+ *
142
+ * A single interface BDEF can declare behavior for multiple entities
143
+ * (root + compositions), and each block has its own alias, its own actions,
144
+ * and produces its own `lhc_<alias>` handler class. We need the block
145
+ * boundaries so that an action declared under entity A isn't attributed to
146
+ * entity B's handler class.
147
+ *
148
+ * We track brace depth rather than simply splitting on `define behavior` so
149
+ * nested `{ ... }` inside features/draft/etag clauses doesn't close the block
150
+ * prematurely. `seenOpening` avoids closing a block before the first `{` is
151
+ * consumed — `define behavior for X` and the opening brace may be on
152
+ * separate lines.
153
+ */
154
+ function parseBehaviorBlocks(source) {
155
+ const blocks = [];
156
+ const lines = source.split('\n');
157
+ let current;
158
+ for (let i = 0; i < lines.length; i += 1) {
159
+ const line = lines[i] ?? '';
160
+ if (!current) {
161
+ const defineMatch = line.match(BDEF_DEFINE_BEHAVIOR_RE);
162
+ if (!defineMatch)
163
+ continue;
164
+ const entityName = defineMatch[1] ?? '';
165
+ const alias = defineMatch[2] ?? deriveAlias(entityName);
166
+ current = {
167
+ entityName,
168
+ alias,
169
+ startLine: i + 1,
170
+ lines: [],
171
+ depth: 0,
172
+ seenOpening: false,
173
+ };
174
+ }
175
+ current.lines.push(line);
176
+ if (line.includes('{'))
177
+ current.seenOpening = true;
178
+ current.depth += countChar(line, '{') - countChar(line, '}');
179
+ if (current.seenOpening && current.depth <= 0) {
180
+ blocks.push({
181
+ entityName: current.entityName,
182
+ alias: current.alias,
183
+ startLine: current.startLine,
184
+ lines: current.lines,
185
+ });
186
+ current = undefined;
187
+ }
188
+ }
189
+ return blocks;
190
+ }
191
+ function pushRequirement(out, requirement, seen) {
192
+ const key = rapHandlerRequirementKey(requirement);
193
+ if (seen.has(key))
194
+ return;
195
+ seen.add(key);
196
+ out.push(requirement);
197
+ }
198
+ function groupRequirementsByTargetClass(requirements) {
199
+ const grouped = new Map();
200
+ for (const req of requirements) {
201
+ const key = req.targetHandlerClass.toLowerCase();
202
+ const list = grouped.get(key) ?? [];
203
+ list.push(req);
204
+ grouped.set(key, list);
205
+ }
206
+ return grouped;
207
+ }
208
+ function hasActionResultClause(actionDeclaration) {
209
+ return /\bresult\b/i.test(actionDeclaration);
210
+ }
211
+ /**
212
+ * Extract RAP behavior-pool handler method requirements from interface BDEF source.
213
+ *
214
+ * For every behavior block (one per entity in the BDEF), this produces the
215
+ * exact METHOD signatures that the behavior pool's `lhc_<alias>` class must
216
+ * declare for the class to activate. The output is used by:
217
+ * - findMissingRapHandlerRequirements: to diff against an existing class
218
+ * - applyRapHandlerSignatures: to synthesize the missing METHODS lines
219
+ *
220
+ * The emitted signatures mirror what SAP's "Create Behavior Implementation"
221
+ * wizard would generate — same FOR MODIFY/FOR DETERMINE ON/FOR VALIDATE ON
222
+ * syntax, same `alias~method` entity reference, same RESULT clause only when
223
+ * the BDEF declares a `result` cardinality.
224
+ */
225
+ export function extractRapHandlerRequirements(bdefSource) {
226
+ const requirements = [];
227
+ const seen = new Set();
228
+ const blocks = parseBehaviorBlocks(bdefSource);
229
+ for (const block of blocks) {
230
+ const alias = block.alias;
231
+ // RAP convention: one handler class per entity, named lhc_<alias>.
232
+ // This matches SAP's own templates and the ADT "Create Behavior
233
+ // Implementation Class" wizard — see /DMO/BP_TRAVEL_M and similar.
234
+ const targetHandlerClass = `lhc_${alias.toLowerCase()}`;
235
+ const body = block.lines.join('\n');
236
+ for (let idx = 0; idx < block.lines.length; idx += 1) {
237
+ const line = block.lines[idx] ?? '';
238
+ const declarationLine = block.startLine + idx;
239
+ // Match all BDEF action variants. Order of the optional prefixes matters:
240
+ // - `static` can appear alone or before `factory`: `static action`,
241
+ // `static factory action`
242
+ // - `internal` and `factory` are mutually exclusive but each may
243
+ // appear after `static`: `internal action`, `factory action`
244
+ // - the optional `( features: ... )` clause sits between the keyword
245
+ // `action` and the action name — `action ( features: instance ) Foo`
246
+ // Missing any of these prefixes used to silently drop the requirement,
247
+ // which was the original bug on live /DMO/BP_TRAVEL_M samples.
248
+ const actionMatch = line.match(BDEF_ACTION_DECLARATION_RE);
249
+ if (actionMatch?.[1]) {
250
+ const actionName = actionMatch[1];
251
+ const methodName = normalizeMethodName(actionName);
252
+ // Collapse continuation lines so the `result` clause is visible even
253
+ // when the author split the declaration across multiple lines.
254
+ const actionDecl = collectStatement(block.lines, idx);
255
+ // Emit `RESULT result` only when the BDEF declares a result cardinality.
256
+ // Factory/internal/static actions without a result clause must NOT
257
+ // carry RESULT in the handler signature — the activation check is strict
258
+ // and rejects mismatched signatures with a cryptic "method signature
259
+ // does not match BDL declaration" error.
260
+ const hasResult = hasActionResultClause(actionDecl);
261
+ const resultPart = hasResult ? ' RESULT result' : '';
262
+ pushRequirement(requirements, {
263
+ kind: 'action',
264
+ methodName,
265
+ entityName: block.entityName,
266
+ entityAlias: alias,
267
+ targetHandlerClass,
268
+ declarationLine,
269
+ signature: `METHODS ${methodName} FOR MODIFY\n` + ` IMPORTING keys FOR ACTION ${alias}~${actionName}${resultPart}.`,
270
+ }, seen);
271
+ }
272
+ const determinationMatch = line.match(BDEF_DETERMINATION_DECLARATION_RE);
273
+ if (determinationMatch?.[1] && determinationMatch[2]) {
274
+ const determinationName = determinationMatch[1];
275
+ const event = determinationMatch[2].toUpperCase();
276
+ const methodName = normalizeMethodName(determinationName);
277
+ pushRequirement(requirements, {
278
+ kind: 'determination',
279
+ methodName,
280
+ entityName: block.entityName,
281
+ entityAlias: alias,
282
+ targetHandlerClass,
283
+ declarationLine,
284
+ signature: `METHODS ${methodName} FOR DETERMINE ON ${event}\n` +
285
+ ` IMPORTING keys FOR ${alias}~${determinationName}.`,
286
+ }, seen);
287
+ }
288
+ const validationMatch = line.match(BDEF_VALIDATION_DECLARATION_RE);
289
+ if (validationMatch?.[1] && validationMatch[2]) {
290
+ const validationName = validationMatch[1];
291
+ const event = validationMatch[2].toUpperCase();
292
+ const methodName = normalizeMethodName(validationName);
293
+ pushRequirement(requirements, {
294
+ kind: 'validation',
295
+ methodName,
296
+ entityName: block.entityName,
297
+ entityAlias: alias,
298
+ targetHandlerClass,
299
+ declarationLine,
300
+ signature: `METHODS ${methodName} FOR VALIDATE ON ${event}\n` + ` IMPORTING keys FOR ${alias}~${validationName}.`,
301
+ }, seen);
302
+ }
303
+ }
304
+ // `authorization master ( instance )` → the pool must implement
305
+ // get_instance_authorizations (per-instance row-level checks, imports
306
+ // keys so the handler can evaluate each row individually).
307
+ const instanceAuthMatch = body.match(BDEF_INSTANCE_AUTH_RE);
308
+ if (instanceAuthMatch) {
309
+ pushRequirement(requirements, {
310
+ kind: 'instance_authorization',
311
+ methodName: 'get_instance_authorizations',
312
+ entityName: block.entityName,
313
+ entityAlias: alias,
314
+ targetHandlerClass,
315
+ declarationLine: block.startLine,
316
+ signature: 'METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION\n' +
317
+ ` IMPORTING keys REQUEST requested_authorizations FOR ${alias} RESULT result.`,
318
+ }, seen);
319
+ }
320
+ // `authorization master ( global )` → the pool must implement
321
+ // get_global_authorizations (a single, stateless check for the whole
322
+ // entity; no keys parameter because the decision is not per-row).
323
+ const globalAuthMatch = body.match(BDEF_GLOBAL_AUTH_RE);
324
+ if (globalAuthMatch) {
325
+ pushRequirement(requirements, {
326
+ kind: 'global_authorization',
327
+ methodName: 'get_global_authorizations',
328
+ entityName: block.entityName,
329
+ entityAlias: alias,
330
+ targetHandlerClass,
331
+ declarationLine: block.startLine,
332
+ signature: 'METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION\n' +
333
+ ` IMPORTING REQUEST requested_authorizations FOR ${alias} RESULT result.`,
334
+ }, seen);
335
+ }
336
+ }
337
+ return requirements;
338
+ }
339
+ /**
340
+ * Find every `CLASS ... DEFINITION` block in an ABAP source, returning the
341
+ * line index range and — if present — the line index of PRIVATE SECTION.
342
+ *
343
+ * Behavior pool sources frequently contain:
344
+ * - multiple concrete handler classes (`lhc_travel`, `lhc_booking`, ...)
345
+ * - deferred declarations (`CLASS lhc_travel DEFINITION DEFERRED.`) used
346
+ * to satisfy forward references in the implementation section; these
347
+ * have no matching ENDCLASS and must not be confused with the real
348
+ * definition that follows later in the same file
349
+ *
350
+ * The `i = end` advance at the bottom skips past the ENDCLASS of the class
351
+ * we just processed, so the outer loop doesn't re-enter the same class and
352
+ * double-register ranges.
353
+ */
354
+ function parseClassDefinitionRanges(source) {
355
+ const lines = source.split('\n');
356
+ const ranges = [];
357
+ for (let i = 0; i < lines.length; i += 1) {
358
+ const line = lines[i] ?? '';
359
+ const startMatch = line.match(CLASS_DEFINITION_START_RE);
360
+ if (!startMatch?.[1])
361
+ continue;
362
+ const name = startMatch[1];
363
+ const isDeferred = CLASS_DEFINITION_DEFERRED_RE.test(line);
364
+ if (isDeferred)
365
+ continue;
366
+ let end = i;
367
+ let privateSection;
368
+ for (let j = i + 1; j < lines.length; j += 1) {
369
+ const inner = lines[j] ?? '';
370
+ if (privateSection === undefined && PRIVATE_SECTION_RE.test(inner)) {
371
+ privateSection = j;
372
+ }
373
+ if (ENDCLASS_RE.test(inner)) {
374
+ end = j;
375
+ break;
376
+ }
377
+ }
378
+ ranges.push({ name, start: i, end, privateSection });
379
+ i = end;
380
+ }
381
+ return ranges;
382
+ }
383
+ function parseClassImplementationRanges(source) {
384
+ const lines = source.split('\n');
385
+ const ranges = [];
386
+ for (let i = 0; i < lines.length; i += 1) {
387
+ const line = lines[i] ?? '';
388
+ const startMatch = line.match(CLASS_IMPLEMENTATION_START_RE);
389
+ if (!startMatch?.[1])
390
+ continue;
391
+ const name = startMatch[1];
392
+ let end = i;
393
+ for (let j = i + 1; j < lines.length; j += 1) {
394
+ const inner = lines[j] ?? '';
395
+ if (ENDCLASS_RE.test(inner)) {
396
+ end = j;
397
+ break;
398
+ }
399
+ }
400
+ ranges.push({ name, start: i, end });
401
+ i = end;
402
+ }
403
+ return ranges;
404
+ }
405
+ function parseClassImplementationMethods(source) {
406
+ const lines = source.split('\n');
407
+ const ranges = parseClassImplementationRanges(source);
408
+ const out = new Map();
409
+ for (const range of ranges) {
410
+ const key = range.name.toLowerCase();
411
+ const methods = out.get(key) ?? new Set();
412
+ for (let i = range.start; i <= range.end; i += 1) {
413
+ const line = lines[i] ?? '';
414
+ const match = line.match(METHOD_IMPLEMENTATION_RE);
415
+ if (match?.[1])
416
+ methods.add(normalizeMethodName(match[1]));
417
+ }
418
+ out.set(key, methods);
419
+ }
420
+ return out;
421
+ }
422
+ function parseHandlerDeclarationBinding(statement) {
423
+ const actionBinding = statement.match(HANDLER_ACTION_BINDING_RE);
424
+ if (actionBinding?.[1] && actionBinding[2]) {
425
+ return { kind: 'action', entityAlias: actionBinding[1], methodName: actionBinding[2] };
426
+ }
427
+ const entityBinding = statement.match(HANDLER_ENTITY_BINDING_RE);
428
+ if (entityBinding?.[1] && entityBinding[2]) {
429
+ if (HANDLER_DETERMINE_STATEMENT_RE.test(statement)) {
430
+ return { kind: 'determination', entityAlias: entityBinding[1], methodName: entityBinding[2] };
431
+ }
432
+ if (HANDLER_VALIDATE_STATEMENT_RE.test(statement)) {
433
+ return { kind: 'validation', entityAlias: entityBinding[1], methodName: entityBinding[2] };
434
+ }
435
+ }
436
+ const authBinding = statement.match(HANDLER_AUTH_BINDING_RE);
437
+ if (authBinding?.[1]) {
438
+ if (HANDLER_INSTANCE_AUTH_STATEMENT_RE.test(statement)) {
439
+ return {
440
+ kind: 'instance_authorization',
441
+ entityAlias: authBinding[1],
442
+ methodName: 'get_instance_authorizations',
443
+ };
444
+ }
445
+ if (HANDLER_GLOBAL_AUTH_STATEMENT_RE.test(statement)) {
446
+ return {
447
+ kind: 'global_authorization',
448
+ entityAlias: authBinding[1],
449
+ methodName: 'get_global_authorizations',
450
+ };
451
+ }
452
+ }
453
+ return undefined;
454
+ }
455
+ /**
456
+ * Map BDEF requirement keys to the concrete ABAP method name used in the
457
+ * handler declaration.
458
+ *
459
+ * The generated method name for a BDEF action `acceptTravel` is `accepttravel`,
460
+ * but real behavior pools often declare semantic method names such as
461
+ * `set_status_accepted FOR ACTION travel~acceptTravel`. Stub detection and
462
+ * stub generation must use the declared ABAP method name, otherwise a pool
463
+ * that is already implemented under semantic names is reported as missing.
464
+ */
465
+ function parseClassDefinitionHandlerBindings(source) {
466
+ const lines = source.split('\n');
467
+ const ranges = parseClassDefinitionRanges(source);
468
+ const out = new Map();
469
+ for (const range of ranges) {
470
+ const targetHandlerClass = range.name;
471
+ for (let i = range.start; i <= range.end; i += 1) {
472
+ const line = lines[i] ?? '';
473
+ const match = line.match(METHOD_DECLARATION_RE);
474
+ if (!match?.[1])
475
+ continue;
476
+ const declaredMethodName = normalizeMethodName(match[1]);
477
+ const statement = collectAbapStatement(lines, i, range.end);
478
+ const binding = parseHandlerDeclarationBinding(statement);
479
+ if (binding)
480
+ out.set(bindingKey(targetHandlerClass, binding.kind, binding.methodName, binding.entityAlias), declaredMethodName);
481
+ }
482
+ }
483
+ return out;
484
+ }
485
+ /**
486
+ * Parse method declarations (`METHODS ...`) per class definition.
487
+ *
488
+ * The returned Set contains BOTH:
489
+ * 1. Every declared METHOD name in the class (e.g. `submitforapproval`,
490
+ * `set_status_accepted`, `validate_customer`)
491
+ * 2. Every RAP binding-key those methods are bound to (the action /
492
+ * determination / validation / authorization referenced in the
493
+ * `FOR ACTION <alias>~<name>` / `FOR <alias>~<name>` /
494
+ * `FOR INSTANCE AUTHORIZATION ... FOR <alias>` clauses)
495
+ *
496
+ * Why both? Hand-crafted behavior pools (like SAP's own /DMO/BP_TRAVEL_M)
497
+ * routinely use semantic method names that differ from the BDEF action
498
+ * names — e.g. BDEF `action acceptTravel` bound to METHOD
499
+ * `set_status_accepted` via `FOR ACTION travel~acceptTravel`. The
500
+ * scaffolder's missing-requirement check compares by BDEF identifier, so if
501
+ * we only indexed method names, it would incorrectly report
502
+ * `accepttravel` as missing and try to inject a duplicate METHOD line.
503
+ *
504
+ * METHOD declarations can span multiple lines (one line for the name +
505
+ * continuation lines for FOR / IMPORTING / RESULT), so we join the
506
+ * statement up to its terminating `.` before pattern-matching the binding.
507
+ */
508
+ export function parseClassDefinitionMethods(source) {
509
+ const lines = source.split('\n');
510
+ const ranges = parseClassDefinitionRanges(source);
511
+ const out = new Map();
512
+ for (const range of ranges) {
513
+ const key = range.name.toLowerCase();
514
+ const methods = out.get(key) ?? new Set();
515
+ for (let i = range.start; i <= range.end; i += 1) {
516
+ const line = lines[i] ?? '';
517
+ const match = line.match(METHOD_DECLARATION_RE);
518
+ if (!match?.[1])
519
+ continue;
520
+ methods.add(normalizeMethodName(match[1]));
521
+ // Collect the full multi-line METHODS statement so FOR-clause patterns
522
+ // (which usually sit on a continuation line) are visible to the regex.
523
+ const statement = collectAbapStatement(lines, i, range.end);
524
+ // Also index the BDEF-side binding key. This is different from the
525
+ // ABAP method name when developers use semantic names such as
526
+ // `set_status_accepted FOR ACTION travel~acceptTravel`.
527
+ const binding = parseHandlerDeclarationBinding(statement);
528
+ if (binding)
529
+ methods.add(normalizeMethodName(binding.methodName));
530
+ }
531
+ out.set(key, methods);
532
+ }
533
+ return out;
534
+ }
535
+ /**
536
+ * Determine which RAP handler requirements are missing from class definitions.
537
+ *
538
+ * If the target handler class (`lhc_<alias>`) doesn't exist in the source at
539
+ * all, every requirement for that class is reported missing so the caller
540
+ * can decide whether to create the class or fall through to another include
541
+ * (the scaffold flow searches `main` → `definitions` → `implementations`).
542
+ *
543
+ * Method-name comparison is case-insensitive because ABAP identifiers
544
+ * are — we normalize on both sides so `METHODS SubmitForApproval ...`
545
+ * matches a BDEF `action SubmitForApproval`.
546
+ */
547
+ export function findMissingRapHandlerRequirements(requirements, classSource) {
548
+ const classMethods = parseClassDefinitionMethods(classSource);
549
+ return requirements.filter((req) => {
550
+ const methods = classMethods.get(req.targetHandlerClass.toLowerCase());
551
+ if (!methods)
552
+ return true;
553
+ return !methods.has(normalizeMethodName(req.methodName));
554
+ });
555
+ }
556
+ export function findMissingRapHandlerImplementationStubs(requirements, classSource) {
557
+ const classMethods = parseClassImplementationMethods(classSource);
558
+ const declaredMethodByRequirement = parseClassDefinitionHandlerBindings(classSource);
559
+ return requirements.filter((req) => {
560
+ const methods = classMethods.get(req.targetHandlerClass.toLowerCase());
561
+ if (!methods)
562
+ return true;
563
+ const implementationMethodName = declaredMethodByRequirement.get(rapHandlerRequirementKey(req)) ?? normalizeMethodName(req.methodName);
564
+ return !methods.has(implementationMethodName);
565
+ });
566
+ }
567
+ /**
568
+ * Insert missing RAP handler signatures into matching `lhc_*` class definitions.
569
+ *
570
+ * Scope and contract:
571
+ * - Only DEFINITION sections are modified. Use
572
+ * applyRapHandlerImplementationStubs after this step when the scaffold
573
+ * should be immediately patchable with edit_method.
574
+ * - Requirements whose target class (`lhc_<alias>`) is not present in this
575
+ * source are returned in `skipped`, not silently dropped. The caller can
576
+ * then try another include (definitions/implementations) or surface a
577
+ * clear error to the user.
578
+ * - Edits are applied bottom-up (highest line index first) so that earlier
579
+ * splice operations don't shift the indices of later ones.
580
+ * - When a target class exists but has no PRIVATE SECTION at all, the
581
+ * entire PRIVATE SECTION with the signatures is inserted just before
582
+ * ENDCLASS — this covers freshly-generated behavior pools where ADT
583
+ * produced a skeleton without method declarations.
584
+ */
585
+ export function applyRapHandlerSignatures(classSource, requirements) {
586
+ if (requirements.length === 0) {
587
+ return { updatedSource: classSource, inserted: [], skipped: [], changed: false };
588
+ }
589
+ const lines = classSource.split('\n');
590
+ const ranges = parseClassDefinitionRanges(classSource);
591
+ const methodsByClass = parseClassDefinitionMethods(classSource);
592
+ const grouped = groupRequirementsByTargetClass(requirements);
593
+ const edits = [];
594
+ const inserted = [];
595
+ const skipped = [];
596
+ for (const [targetClassName, classRequirements] of grouped.entries()) {
597
+ const range = ranges.find((r) => r.name.toLowerCase() === targetClassName);
598
+ if (!range) {
599
+ for (const req of classRequirements) {
600
+ skipped.push({
601
+ requirement: req,
602
+ reason: `Handler class ${req.targetHandlerClass} not found in behavior pool.`,
603
+ });
604
+ }
605
+ continue;
606
+ }
607
+ const existingMethods = methodsByClass.get(targetClassName) ?? new Set();
608
+ const toInsert = classRequirements.filter((req) => !existingMethods.has(normalizeMethodName(req.methodName)));
609
+ if (toInsert.length === 0)
610
+ continue;
611
+ const signatureLines = [];
612
+ for (let i = 0; i < toInsert.length; i += 1) {
613
+ const req = toInsert[i];
614
+ signatureLines.push(...req.signature.split('\n').map((line) => ` ${line}`));
615
+ if (i < toInsert.length - 1)
616
+ signatureLines.push('');
617
+ inserted.push(req);
618
+ }
619
+ if (range.privateSection === undefined) {
620
+ const block = [' PRIVATE SECTION.', ...signatureLines, ''];
621
+ edits.push({ index: range.end, lines: block });
622
+ continue;
623
+ }
624
+ edits.push({
625
+ index: range.privateSection + 1,
626
+ lines: [...signatureLines, ''],
627
+ });
628
+ }
629
+ if (edits.length === 0) {
630
+ return { updatedSource: classSource, inserted, skipped, changed: false };
631
+ }
632
+ const sorted = edits.sort((a, b) => b.index - a.index);
633
+ for (const edit of sorted) {
634
+ lines.splice(edit.index, 0, ...edit.lines);
635
+ }
636
+ return {
637
+ updatedSource: lines.join('\n'),
638
+ inserted,
639
+ skipped,
640
+ changed: inserted.length > 0,
641
+ };
642
+ }
643
+ export function applyRapHandlerImplementationStubs(classSource, requirements, options = {}) {
644
+ if (requirements.length === 0) {
645
+ return { updatedSource: classSource, inserted: [], skipped: [], changed: false };
646
+ }
647
+ const lines = classSource.split('\n');
648
+ const definitionRanges = parseClassDefinitionRanges(classSource);
649
+ const implementationRanges = parseClassImplementationRanges(classSource);
650
+ const methodsByClass = parseClassImplementationMethods(classSource);
651
+ const definitionLookupSource = options.definitionSource ? `${options.definitionSource}\n${classSource}` : classSource;
652
+ const declaredMethodByRequirement = parseClassDefinitionHandlerBindings(definitionLookupSource);
653
+ const grouped = groupRequirementsByTargetClass(requirements);
654
+ const edits = [];
655
+ const inserted = [];
656
+ const skipped = [];
657
+ for (const [targetClassName, classRequirements] of grouped.entries()) {
658
+ const existingMethods = methodsByClass.get(targetClassName) ?? new Set();
659
+ const seenMethods = new Set(existingMethods);
660
+ const toInsert = [];
661
+ for (const req of classRequirements) {
662
+ const implementationMethodName = declaredMethodByRequirement.get(rapHandlerRequirementKey(req)) ?? normalizeMethodName(req.methodName);
663
+ if (seenMethods.has(implementationMethodName))
664
+ continue;
665
+ seenMethods.add(implementationMethodName);
666
+ toInsert.push({ requirement: req, implementationMethodName });
667
+ }
668
+ if (toInsert.length === 0)
669
+ continue;
670
+ const stubLines = [];
671
+ for (let i = 0; i < toInsert.length; i += 1) {
672
+ const { requirement, implementationMethodName } = toInsert[i];
673
+ stubLines.push(` METHOD ${implementationMethodName}.`, ' ENDMETHOD.');
674
+ if (i < toInsert.length - 1)
675
+ stubLines.push('');
676
+ inserted.push(requirement);
677
+ }
678
+ const implementationRange = implementationRanges.find((r) => r.name.toLowerCase() === targetClassName);
679
+ if (implementationRange) {
680
+ edits.push({ index: implementationRange.end, lines: [...stubLines, ''] });
681
+ continue;
682
+ }
683
+ const hasDefinition = definitionRanges.some((r) => r.name.toLowerCase() === targetClassName);
684
+ if (options.createImplementationBlocks && hasDefinition) {
685
+ edits.push({
686
+ index: lines.length,
687
+ lines: ['', `CLASS ${classRequirements[0].targetHandlerClass} IMPLEMENTATION.`, ...stubLines, 'ENDCLASS.'],
688
+ });
689
+ continue;
690
+ }
691
+ for (const { requirement } of toInsert) {
692
+ skipped.push({
693
+ requirement,
694
+ reason: `Implementation class ${requirement.targetHandlerClass} not found in behavior pool.`,
695
+ });
696
+ }
697
+ inserted.splice(inserted.length - toInsert.length, toInsert.length);
698
+ }
699
+ if (edits.length === 0) {
700
+ return { updatedSource: classSource, inserted, skipped, changed: false };
701
+ }
702
+ const sorted = edits.sort((a, b) => b.index - a.index);
703
+ for (const edit of sorted) {
704
+ lines.splice(edit.index, 0, ...edit.lines);
705
+ }
706
+ return {
707
+ updatedSource: lines.join('\n'),
708
+ inserted,
709
+ skipped,
710
+ changed: inserted.length > 0,
711
+ };
712
+ }
713
+ function countInserted(results) {
714
+ return (results.main.inserted.length +
715
+ (results.definitions?.inserted.length ?? 0) +
716
+ (results.implementations?.inserted.length ?? 0));
717
+ }
718
+ function changedSectionsFrom(changed) {
719
+ return Object.keys(changed).filter((section) => changed[section]);
720
+ }
721
+ /**
722
+ * Build the source used to resolve semantic method names while creating stubs.
723
+ *
724
+ * The declaration (`METHODS set_status_accepted FOR ACTION travel~acceptTravel`)
725
+ * and implementation (`METHOD set_status_accepted.`) can live in different ADT
726
+ * includes. Stub generation therefore needs the post-signature sources for all
727
+ * sections, not only the include currently being edited.
728
+ */
729
+ function buildDefinitionLookupSource(originalSections, signaturePlan) {
730
+ return [
731
+ signaturePlan.updatedSections.main,
732
+ signaturePlan.updatedSections.definitions ?? originalSections.definitions,
733
+ signaturePlan.updatedSections.implementations ?? originalSections.implementations,
734
+ ]
735
+ .filter(Boolean)
736
+ .join('\n\n');
737
+ }
738
+ /**
739
+ * Try signature insertion in ADT include order: main → definitions → implementations.
740
+ *
741
+ * A handler class can legally exist in any of these includes depending on how
742
+ * ADT generated the behavior pool. The unresolved list is deliberately carried
743
+ * forward between sections so a requirement is inserted exactly once, in the
744
+ * first include that contains its concrete `lhc_<alias> DEFINITION`.
745
+ */
746
+ function applySignaturesAcrossSections(sections, missingSignatures) {
747
+ const main = applyRapHandlerSignatures(sections.main, missingSignatures);
748
+ let unresolved = main.skipped.map((entry) => entry.requirement);
749
+ let definitions;
750
+ if (unresolved.length > 0 && sections.definitions) {
751
+ definitions = applyRapHandlerSignatures(sections.definitions, unresolved);
752
+ unresolved = definitions.skipped.map((entry) => entry.requirement);
753
+ }
754
+ let implementations;
755
+ if (unresolved.length > 0 && sections.implementations) {
756
+ implementations = applyRapHandlerSignatures(sections.implementations, unresolved);
757
+ unresolved = implementations.skipped.map((entry) => entry.requirement);
758
+ }
759
+ return {
760
+ signatures: { main, definitions, implementations },
761
+ updatedSections: {
762
+ main: main.updatedSource,
763
+ definitions: definitions?.updatedSource ?? sections.definitions,
764
+ implementations: implementations?.updatedSource ?? sections.implementations,
765
+ },
766
+ unresolved,
767
+ };
768
+ }
769
+ /**
770
+ * Build the complete auto-apply plan for a behavior pool without doing I/O.
771
+ *
772
+ * This is intentionally pure: the MCP handler owns safety checks, locks,
773
+ * linting, and ADT writes; this helper owns the RAP-specific sequencing:
774
+ * 1. insert missing METHODS declarations into whichever include contains
775
+ * the matching `lhc_<alias> DEFINITION`
776
+ * 2. skip stubs whose declarations still could not be placed
777
+ * 3. insert empty METHOD stubs using the concrete ABAP method name from
778
+ * existing/new declarations, including semantic names bound via
779
+ * `FOR ACTION alias~ActionName`
780
+ *
781
+ * Keeping this plan here prevents `intent.ts` from duplicating RAP parser
782
+ * invariants such as "deferred classes are not editable" and "stub method
783
+ * names come from declarations, not necessarily from BDEF action names".
784
+ */
785
+ export function applyRapHandlerScaffold(sections, missingSignatures, missingImplementationStubs) {
786
+ const signaturePlan = applySignaturesAcrossSections(sections, missingSignatures);
787
+ // A METHOD stub is only useful after its declaration exists. If the target
788
+ // `lhc_*` class was not found anywhere, suppress the stub for that unresolved
789
+ // declaration rather than creating an implementation block with no matching
790
+ // RAP handler signature.
791
+ const unresolvedDeclarationKeys = new Set(signaturePlan.unresolved.map(rapHandlerRequirementKey));
792
+ const stubRequirements = missingImplementationStubs.filter((req) => !unresolvedDeclarationKeys.has(rapHandlerRequirementKey(req)));
793
+ const definitionLookupSource = buildDefinitionLookupSource(sections, signaturePlan);
794
+ const stubMain = applyRapHandlerImplementationStubs(signaturePlan.updatedSections.main, stubRequirements, {
795
+ createImplementationBlocks: true,
796
+ definitionSource: definitionLookupSource,
797
+ });
798
+ const stubDefinitions = sections.definitions
799
+ ? applyRapHandlerImplementationStubs(signaturePlan.updatedSections.definitions ?? sections.definitions, stubRequirements, {
800
+ definitionSource: definitionLookupSource,
801
+ })
802
+ : undefined;
803
+ const stubImplementations = sections.implementations
804
+ ? applyRapHandlerImplementationStubs(signaturePlan.updatedSections.implementations ?? sections.implementations, stubRequirements, { createImplementationBlocks: true, definitionSource: definitionLookupSource })
805
+ : undefined;
806
+ const changed = {
807
+ main: signaturePlan.signatures.main.changed || stubMain.changed,
808
+ definitions: (signaturePlan.signatures.definitions?.changed ?? false) || (stubDefinitions?.changed ?? false),
809
+ implementations: (signaturePlan.signatures.implementations?.changed ?? false) || (stubImplementations?.changed ?? false),
810
+ };
811
+ const changedSections = changedSectionsFrom(changed);
812
+ return {
813
+ sections: {
814
+ main: stubMain.updatedSource,
815
+ definitions: stubDefinitions?.updatedSource ?? signaturePlan.updatedSections.definitions,
816
+ implementations: stubImplementations?.updatedSource ?? signaturePlan.updatedSections.implementations,
817
+ },
818
+ signatures: signaturePlan.signatures,
819
+ implementationStubs: {
820
+ main: stubMain,
821
+ definitions: stubDefinitions,
822
+ implementations: stubImplementations,
823
+ },
824
+ unresolved: signaturePlan.unresolved,
825
+ changed,
826
+ changedSections,
827
+ insertedSignatureCount: countInserted(signaturePlan.signatures),
828
+ insertedImplementationStubCount: countInserted({
829
+ main: stubMain,
830
+ definitions: stubDefinitions,
831
+ implementations: stubImplementations,
832
+ }),
833
+ };
834
+ }
835
+ //# sourceMappingURL=rap-handlers.js.map