@mcp-abap-adt/adt-backup 1.3.0 → 1.6.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.
Files changed (58) hide show
  1. package/README.md +4 -1
  2. package/dist/lib/backup/backupObject.d.ts.map +1 -1
  3. package/dist/lib/backup/backupObject.js +45 -0
  4. package/dist/lib/backup/readMetadataXmlForType.d.ts +1 -1
  5. package/dist/lib/backup/readMetadataXmlForType.d.ts.map +1 -1
  6. package/dist/lib/backup/readMetadataXmlForType.js +34 -3
  7. package/dist/lib/backup/readSourceText.d.ts.map +1 -1
  8. package/dist/lib/backup/readSourceText.js +32 -3
  9. package/dist/lib/constants/typeOrder.d.ts.map +1 -1
  10. package/dist/lib/constants/typeOrder.js +5 -1
  11. package/dist/lib/dependencies/collectTreeDependencies.d.ts.map +1 -1
  12. package/dist/lib/dependencies/collectTreeDependencies.js +4 -1
  13. package/dist/lib/restore/analyzeDependencies.d.ts.map +1 -1
  14. package/dist/lib/restore/analyzeDependencies.js +40 -5
  15. package/dist/lib/restore/restoreObject.d.ts.map +1 -1
  16. package/dist/lib/restore/restoreObject.js +63 -3
  17. package/dist/lib/restore/restoreObjects.d.ts.map +1 -1
  18. package/dist/lib/restore/restoreObjects.js +5 -1
  19. package/dist/lib/restore/restoreTreeBackup.d.ts.map +1 -1
  20. package/dist/lib/restore/restoreTreeBackup.js +16 -2
  21. package/dist/lib/restore/restoreTreeNode.d.ts.map +1 -1
  22. package/dist/lib/restore/restoreTreeNode.js +63 -3
  23. package/dist/lib/run.d.ts.map +1 -1
  24. package/dist/lib/run.js +6 -1
  25. package/dist/lib/tree/buildPackageBackupTree.d.ts.map +1 -1
  26. package/dist/lib/tree/buildPackageBackupTree.js +2 -0
  27. package/dist/lib/tree/enrichTreeNode.d.ts.map +1 -1
  28. package/dist/lib/tree/enrichTreeNode.js +67 -2
  29. package/dist/lib/tree/getNodeFunctionGroupName.js +1 -1
  30. package/dist/lib/tree/getNodeObjectSpec.js +1 -1
  31. package/dist/lib/tree/isRestoreImplemented.d.ts.map +1 -1
  32. package/dist/lib/tree/isRestoreImplemented.js +5 -1
  33. package/dist/lib/tree/mapAdtTypeToSupported.d.ts +3 -1
  34. package/dist/lib/tree/mapAdtTypeToSupported.d.ts.map +1 -1
  35. package/dist/lib/tree/mapAdtTypeToSupported.js +21 -6
  36. package/dist/lib/tree/readPayloadForType.d.ts.map +1 -1
  37. package/dist/lib/tree/readPayloadForType.js +5 -1
  38. package/dist/lib/types.d.ts +1 -1
  39. package/dist/lib/types.d.ts.map +1 -1
  40. package/dist/lib/utils/applyConfigName.d.ts.map +1 -1
  41. package/dist/lib/utils/applyConfigName.js +15 -2
  42. package/dist/lib/utils/formatObjectSpec.js +1 -1
  43. package/dist/lib/utils/normalizeType.d.ts.map +1 -1
  44. package/dist/lib/utils/normalizeType.js +11 -1
  45. package/dist/lib/utils/objectId.js +1 -1
  46. package/dist/lib/utils/parseObjectSpec.d.ts.map +1 -1
  47. package/dist/lib/utils/parseObjectSpec.js +2 -2
  48. package/dist/lib/verify/collectBackupNodes.d.ts.map +1 -1
  49. package/dist/lib/verify/collectBackupNodes.js +4 -1
  50. package/dist/lib/verify/findOtherType.d.ts.map +1 -1
  51. package/dist/lib/verify/findOtherType.js +4 -1
  52. package/dist/lib/xml/parseAppendStructureSource.d.ts +4 -0
  53. package/dist/lib/xml/parseAppendStructureSource.d.ts.map +1 -0
  54. package/dist/lib/xml/parseAppendStructureSource.js +7 -0
  55. package/dist/lib/xml/parseScalarFunctionImplementationConfig.d.ts +5 -0
  56. package/dist/lib/xml/parseScalarFunctionImplementationConfig.d.ts.map +1 -0
  57. package/dist/lib/xml/parseScalarFunctionImplementationConfig.js +21 -0
  58. package/package.json +2 -2
package/README.md CHANGED
@@ -73,7 +73,10 @@ See `docs/roadmap.yaml` for per-object backup/restore status and the plan for re
73
73
  | `structure` | implemented | implemented | source |
74
74
  | `table` | implemented | implemented | source |
75
75
  | `tableType` | implemented | implemented | metadata-xml |
76
- | `view` | implemented | implemented | source |
76
+ | `ddl` | implemented | implemented | source |
77
+ | `scalarFunction` | implemented | implemented | source |
78
+ | `scalarFunctionImplementation` | implemented | implemented | source |
79
+ | `appendStructure` | implemented | implemented | source |
77
80
  | `functionGroup` | implemented | implemented | metadata-xml |
78
81
  | `functionModule` | implemented | implemented | source |
79
82
  | `interface` | implemented | implemented | source |
@@ -1 +1 @@
1
- {"version":3,"file":"backupObject.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/backupObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAgB,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAcvE,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CA6OvB"}
1
+ {"version":3,"file":"backupObject.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/backupObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAgB,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgBvE,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CAsSvB"}
@@ -6,9 +6,11 @@ const objectId_1 = require("../utils/objectId");
6
6
  const parseBehaviorDefinitionFromClass_1 = require("../utils/parseBehaviorDefinitionFromClass");
7
7
  const toBackupConfig_1 = require("../utils/toBackupConfig");
8
8
  const extractMetadata_1 = require("../xml/extractMetadata");
9
+ const parseAppendStructureSource_1 = require("../xml/parseAppendStructureSource");
9
10
  const parseDataElementConfig_1 = require("../xml/parseDataElementConfig");
10
11
  const parseDomainConfig_1 = require("../xml/parseDomainConfig");
11
12
  const parsePackageConfig_1 = require("../xml/parsePackageConfig");
13
+ const parseScalarFunctionImplementationConfig_1 = require("../xml/parseScalarFunctionImplementationConfig");
12
14
  const parseServiceBindingConfig_1 = require("../xml/parseServiceBindingConfig");
13
15
  const readBasicMetadata_1 = require("./readBasicMetadata");
14
16
  const readMetadataXmlForType_1 = require("./readMetadataXmlForType");
@@ -161,6 +163,49 @@ async function backupObject(client, spec) {
161
163
  source: source ?? undefined,
162
164
  };
163
165
  }
166
+ case 'scalarFunctionImplementation': {
167
+ const basic = await (0, readBasicMetadata_1.readBasicMetadata)(client, spec);
168
+ const source = await (0, readSourceText_1.readSourceText)(client, spec);
169
+ const sfi = source ? (0, parseScalarFunctionImplementationConfig_1.parseScalarFunctionImplementationConfig)(source) : {};
170
+ if (!sfi.scalarFunctionName) {
171
+ throw new Error(`scalarFunctionImplementation ${spec.name}: could not extract scalarFunctionName from source (cannot produce a restorable backup)`);
172
+ }
173
+ const config = (0, applyConfigName_1.applyConfigName)(spec.type, spec.name, spec.functionGroupName, {
174
+ packageName: basic.packageName,
175
+ description: basic.description,
176
+ implementationName: spec.name,
177
+ scalarFunctionName: sfi.scalarFunctionName,
178
+ engineValue: sfi.engineValue ?? 'sqlEngine',
179
+ });
180
+ return {
181
+ id,
182
+ type: spec.type,
183
+ name: spec.name,
184
+ config,
185
+ source: source ?? undefined,
186
+ };
187
+ }
188
+ case 'appendStructure': {
189
+ const basic = await (0, readBasicMetadata_1.readBasicMetadata)(client, spec);
190
+ const source = await (0, readSourceText_1.readSourceText)(client, spec);
191
+ const { baseObject } = source ? (0, parseAppendStructureSource_1.parseAppendStructureSource)(source) : {};
192
+ if (!baseObject) {
193
+ throw new Error(`appendStructure ${spec.name}: could not extract baseObject from source (cannot produce a restorable backup)`);
194
+ }
195
+ const config = (0, applyConfigName_1.applyConfigName)(spec.type, spec.name, spec.functionGroupName, {
196
+ packageName: basic.packageName,
197
+ description: basic.description,
198
+ appendStructureName: spec.name,
199
+ ...(baseObject ? { baseObject } : {}),
200
+ });
201
+ return {
202
+ id,
203
+ type: spec.type,
204
+ name: spec.name,
205
+ config,
206
+ source: source ?? undefined,
207
+ };
208
+ }
164
209
  default: {
165
210
  const basic = await (0, readBasicMetadata_1.readBasicMetadata)(client, spec);
166
211
  const source = await (0, readSourceText_1.readSourceText)(client, spec);
@@ -1,4 +1,4 @@
1
1
  import type { AdtClient } from '@mcp-abap-adt/adt-clients';
2
2
  import type { SupportedType } from '../types';
3
- export declare function readMetadataXmlForType(client: AdtClient, type: SupportedType, name: string, _functionGroupName?: string): Promise<string | null | undefined>;
3
+ export declare function readMetadataXmlForType(client: AdtClient, type: SupportedType, name: string, functionGroupName?: string): Promise<string | null | undefined>;
4
4
  //# sourceMappingURL=readMetadataXmlForType.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"readMetadataXmlForType.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readMetadataXmlForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CA0IpC"}
1
+ {"version":3,"file":"readMetadataXmlForType.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readMetadataXmlForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAyKpC"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readMetadataXmlForType = readMetadataXmlForType;
4
4
  const responseToText_1 = require("../utils/responseToText");
5
- async function readMetadataXmlForType(client, type, name, _functionGroupName) {
5
+ async function readMetadataXmlForType(client, type, name, functionGroupName) {
6
6
  try {
7
7
  let result;
8
8
  switch (type) {
@@ -58,8 +58,8 @@ async function readMetadataXmlForType(client, type, name, _functionGroupName) {
58
58
  result = (0, responseToText_1.responseToText)(state.metadataResult);
59
59
  break;
60
60
  }
61
- case 'view': {
62
- const state = await client.getView().readMetadata({ viewName: name });
61
+ case 'ddl': {
62
+ const state = await client.getDdl().readMetadata({ ddlName: name });
63
63
  result = (0, responseToText_1.responseToText)(state.metadataResult);
64
64
  break;
65
65
  }
@@ -105,6 +105,16 @@ async function readMetadataXmlForType(client, type, name, _functionGroupName) {
105
105
  result = (0, responseToText_1.responseToText)(state.metadataResult);
106
106
  break;
107
107
  }
108
+ case 'functionInclude': {
109
+ if (!functionGroupName) {
110
+ return undefined;
111
+ }
112
+ const state = await client
113
+ .getFunctionInclude()
114
+ .readMetadata({ functionGroupName, includeName: name });
115
+ result = (0, responseToText_1.responseToText)(state.metadataResult);
116
+ break;
117
+ }
108
118
  case 'enhancement': {
109
119
  const state = await client
110
120
  .getEnhancement()
@@ -119,6 +129,27 @@ async function readMetadataXmlForType(client, type, name, _functionGroupName) {
119
129
  result = (0, responseToText_1.responseToText)(state.metadataResult);
120
130
  break;
121
131
  }
132
+ case 'scalarFunction': {
133
+ const state = await client
134
+ .getScalarFunction()
135
+ .readMetadata({ scalarFunctionName: name });
136
+ result = (0, responseToText_1.responseToText)(state.metadataResult);
137
+ break;
138
+ }
139
+ case 'scalarFunctionImplementation': {
140
+ const state = await client
141
+ .getScalarFunctionImplementation()
142
+ .readMetadata({ implementationName: name });
143
+ result = (0, responseToText_1.responseToText)(state.metadataResult);
144
+ break;
145
+ }
146
+ case 'appendStructure': {
147
+ const state = await client
148
+ .getAppendStructure()
149
+ .readMetadata({ appendStructureName: name });
150
+ result = (0, responseToText_1.responseToText)(state.metadataResult);
151
+ break;
152
+ }
122
153
  default:
123
154
  return undefined;
124
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"readSourceText.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readSourceText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,QAAQ,GAAG,UAAqB,GACxC,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CA8GpC"}
1
+ {"version":3,"file":"readSourceText.d.ts","sourceRoot":"","sources":["../../../src/lib/backup/readSourceText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,QAAQ,GAAG,UAAqB,GACxC,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CA6IpC"}
@@ -29,10 +29,10 @@ async function readSourceText(client, spec, version = 'active') {
29
29
  .read({ transformationName: spec.name }, version);
30
30
  return (0, responseToText_1.responseToText)(state?.readResult);
31
31
  }
32
- case 'view': {
32
+ case 'ddl': {
33
33
  const state = await client
34
- .getView()
35
- .read({ viewName: spec.name }, version);
34
+ .getDdl()
35
+ .read({ ddlName: spec.name }, version);
36
36
  return (0, responseToText_1.responseToText)(state?.readResult);
37
37
  }
38
38
  case 'table': {
@@ -86,6 +86,17 @@ async function readSourceText(client, spec, version = 'active') {
86
86
  }, version);
87
87
  return (0, responseToText_1.responseToText)(state?.readResult);
88
88
  }
89
+ case 'functionInclude': {
90
+ if (!spec.functionGroupName)
91
+ return undefined;
92
+ // read() returns the include source (adt-clients >= 5.8.0), consistent
93
+ // with class/program/functionModule.
94
+ const state = await client.getFunctionInclude().read({
95
+ functionGroupName: spec.functionGroupName,
96
+ includeName: spec.name,
97
+ }, version);
98
+ return (0, responseToText_1.responseToText)(state?.readResult);
99
+ }
89
100
  case 'enhancement': {
90
101
  const state = await client
91
102
  .getEnhancement()
@@ -98,6 +109,24 @@ async function readSourceText(client, spec, version = 'active') {
98
109
  .read({ accessControlName: spec.name }, version);
99
110
  return (0, responseToText_1.responseToText)(state?.readResult);
100
111
  }
112
+ case 'scalarFunction': {
113
+ const state = await client
114
+ .getScalarFunction()
115
+ .read({ scalarFunctionName: spec.name }, version);
116
+ return (0, responseToText_1.responseToText)(state?.readResult);
117
+ }
118
+ case 'scalarFunctionImplementation': {
119
+ const state = await client
120
+ .getScalarFunctionImplementation()
121
+ .read({ implementationName: spec.name }, version);
122
+ return (0, responseToText_1.responseToText)(state?.readResult);
123
+ }
124
+ case 'appendStructure': {
125
+ const state = await client
126
+ .getAppendStructure()
127
+ .read({ appendStructureName: spec.name }, version);
128
+ return (0, responseToText_1.responseToText)(state?.readResult);
129
+ }
101
130
  default:
102
131
  return undefined;
103
132
  }
@@ -1 +1 @@
1
- {"version":3,"file":"typeOrder.d.ts","sourceRoot":"","sources":["../../../src/lib/constants/typeOrder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,eAAO,MAAM,SAAS,EAAE,aAAa,EAoBpC,CAAC"}
1
+ {"version":3,"file":"typeOrder.d.ts","sourceRoot":"","sources":["../../../src/lib/constants/typeOrder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,eAAO,MAAM,SAAS,EAAE,aAAa,EAwBpC,CAAC"}
@@ -7,12 +7,16 @@ exports.typeOrder = [
7
7
  'dataElement',
8
8
  'structure',
9
9
  'table',
10
+ 'appendStructure',
10
11
  'tableType',
11
- 'view',
12
+ 'ddl',
13
+ 'scalarFunction',
12
14
  'functionGroup',
15
+ 'functionInclude',
13
16
  'functionModule',
14
17
  'interface',
15
18
  'class',
19
+ 'scalarFunctionImplementation',
16
20
  'program',
17
21
  'transformation',
18
22
  'serviceDefinition',
@@ -1 +1 @@
1
- {"version":3,"file":"collectTreeDependencies.d.ts","sourceRoot":"","sources":["../../../src/lib/dependencies/collectTreeDependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAK3D,OAAO,KAAK,EAAE,cAAc,EAA6B,MAAM,UAAU,CAAC;AAoC1E,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,IAAI,CAAC,CA+Ff"}
1
+ {"version":3,"file":"collectTreeDependencies.d.ts","sourceRoot":"","sources":["../../../src/lib/dependencies/collectTreeDependencies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAK3D,OAAO,KAAK,EAAE,cAAc,EAA6B,MAAM,UAAU,CAAC;AAuC1E,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,IAAI,CAAC,CA+Ff"}
@@ -12,8 +12,11 @@ const WHERE_USED_TYPE_MAP = {
12
12
  domain: 'DOMA/DD',
13
13
  dataElement: 'DTEL/DE',
14
14
  structure: 'STRU/DT',
15
+ appendStructure: 'TABL/DS',
15
16
  table: 'TABL/DT',
16
- view: 'DDLS/DF',
17
+ ddl: 'DDLS/DF',
18
+ scalarFunction: 'DSFD/SCF',
19
+ scalarFunctionImplementation: 'DSFI/SFI',
17
20
  class: 'CLAS/OC',
18
21
  interface: 'INTF/IF',
19
22
  program: 'PROG/P',
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeDependencies.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/analyzeDependencies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;CACrB;AA+MD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,CA2B3E;AA4BD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,GACtB,YAAY,EAAE,CA8DhB"}
1
+ {"version":3,"file":"analyzeDependencies.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/analyzeDependencies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;CACrB;AAoPD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,CA2B3E;AAgCD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EAAE,GACtB,YAAY,EAAE,CA8DhB"}
@@ -11,6 +11,10 @@ function nodeKey(node) {
11
11
  */
12
12
  function buildAdjacency(nodes, allNames, nameToIds, allIds) {
13
13
  const adj = new Map();
14
+ // Reverse edges to apply AFTER the loop, so the per-node adj.set() below
15
+ // does not clobber them. Used to force co-activation SCCs where only one
16
+ // side's source/config names the other (DDLS->class, DSFI->DSFD/class).
17
+ const reverseEdges = [];
14
18
  for (const node of nodes) {
15
19
  const deps = new Set();
16
20
  const id = nodeKey(node);
@@ -71,8 +75,35 @@ function buildAdjacency(nodes, allNames, nameToIds, allIds) {
71
75
  deps.add(srvdId);
72
76
  }
73
77
  }
78
+ // Scalar function implementation -> definition (and reverse), via config.
79
+ if (node.type === 'scalarFunctionImplementation' &&
80
+ node.config?.scalarFunctionName) {
81
+ const defName = String(node.config.scalarFunctionName).toUpperCase();
82
+ const defId = `SCALARFUNCTION:${defName}`;
83
+ if (allIds.has(defId) && defId !== id) {
84
+ deps.add(defId); // forward DSFI -> DSFD
85
+ reverseEdges.push([defId, id]); // reverse DSFD -> DSFI
86
+ }
87
+ }
88
+ // Reverse edges into AMDP classes that this DDLS / DSFI depends on, so the
89
+ // class joins their activation SCC. Forward edges (this -> class) already
90
+ // come from the source name-scan above. Restrict to class targets to avoid
91
+ // dragging unrelated lower-level objects (data elements, domains) into the
92
+ // group.
93
+ if (node.type === 'ddl' || node.type === 'scalarFunctionImplementation') {
94
+ for (const depId of deps) {
95
+ if (depId.startsWith('CLASS:')) {
96
+ reverseEdges.push([depId, id]);
97
+ }
98
+ }
99
+ }
74
100
  adj.set(id, deps);
75
101
  }
102
+ for (const [from, to] of reverseEdges) {
103
+ const set = adj.get(from) ?? new Set();
104
+ set.add(to);
105
+ adj.set(from, set);
106
+ }
76
107
  return adj;
77
108
  }
78
109
  /**
@@ -210,20 +241,24 @@ const TYPE_CREATION_ORDER = {
210
241
  structure: 2,
211
242
  table: 2,
212
243
  tableType: 2,
213
- view: 3,
244
+ appendStructure: 3,
245
+ ddl: 3,
246
+ scalarFunction: 3,
214
247
  behaviorDefinition: 4,
215
248
  behaviorImplementation: 5,
216
249
  class: 5,
250
+ scalarFunctionImplementation: 6,
217
251
  interface: 5,
218
252
  accessControl: 6,
219
253
  metadataExtension: 6,
220
254
  program: 7,
221
255
  transformation: 7,
222
256
  functionGroup: 7,
223
- functionModule: 8,
224
- serviceDefinition: 9,
225
- serviceBinding: 10,
226
- enhancement: 11,
257
+ functionInclude: 8,
258
+ functionModule: 9,
259
+ serviceDefinition: 10,
260
+ serviceBinding: 11,
261
+ enhancement: 12,
227
262
  };
228
263
  /**
229
264
  * Analyzes dependencies and merges SCCs at the same dependency level
@@ -1 +1 @@
1
- {"version":3,"file":"restoreObject.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAoBV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAO1D,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Tf"}
1
+ {"version":3,"file":"restoreObject.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAwBV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAO1D,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAsYf"}
@@ -78,13 +78,13 @@ async function restoreObject(client, obj, mode, activate, transportRequest) {
78
78
  }
79
79
  return;
80
80
  }
81
- case 'view': {
81
+ case 'ddl': {
82
82
  if (mode !== 'update') {
83
- await client.getView().create((0, asConfig_1.asConfig)(config), options);
83
+ await client.getDdl().create((0, asConfig_1.asConfig)(config), options);
84
84
  }
85
85
  if (obj.source) {
86
86
  await client
87
- .getView()
87
+ .getDdl()
88
88
  .update((0, asConfig_1.asConfig)({ ...config, ddlSource: obj.source }), options);
89
89
  }
90
90
  return;
@@ -175,6 +175,21 @@ async function restoreObject(client, obj, mode, activate, transportRequest) {
175
175
  }
176
176
  return;
177
177
  }
178
+ case 'functionInclude': {
179
+ const fgn = (obj.functionGroupName ?? '').toUpperCase();
180
+ // The TOP include is auto-created with the function group, so it can only
181
+ // be updated (a create would fail "already exists"). Custom includes are
182
+ // created — the create chain uploads source and activates.
183
+ const isTop = obj.name.toUpperCase() === `L${fgn}TOP`;
184
+ const cfg = (0, asConfig_1.asConfig)(obj.source ? { ...config, sourceCode: obj.source } : config);
185
+ if (!isTop && mode !== 'update') {
186
+ await client.getFunctionInclude().create(cfg, options);
187
+ }
188
+ else if (obj.source) {
189
+ await client.getFunctionInclude().update(cfg, options);
190
+ }
191
+ return;
192
+ }
178
193
  case 'serviceDefinition': {
179
194
  if (mode !== 'update') {
180
195
  await client
@@ -271,5 +286,50 @@ async function restoreObject(client, obj, mode, activate, transportRequest) {
271
286
  }
272
287
  return;
273
288
  }
289
+ case 'scalarFunction': {
290
+ if (mode !== 'update') {
291
+ await client
292
+ .getScalarFunction()
293
+ .create((0, asConfig_1.asConfig)(config), options);
294
+ }
295
+ if (obj.source) {
296
+ await client.getScalarFunction().update((0, asConfig_1.asConfig)({
297
+ ...config,
298
+ sourceCode: obj.source,
299
+ }), options);
300
+ }
301
+ return;
302
+ }
303
+ case 'scalarFunctionImplementation': {
304
+ if (mode !== 'update') {
305
+ await client
306
+ .getScalarFunctionImplementation()
307
+ .create((0, asConfig_1.asConfig)(config), options);
308
+ }
309
+ if (obj.source) {
310
+ await client.getScalarFunctionImplementation().update((0, asConfig_1.asConfig)({
311
+ ...config,
312
+ sourceCode: obj.source,
313
+ }), options);
314
+ }
315
+ return;
316
+ }
317
+ case 'appendStructure': {
318
+ if (mode !== 'update') {
319
+ if (!config.baseObject) {
320
+ throw new Error(`appendStructure ${obj.name}: missing baseObject (cannot create)`);
321
+ }
322
+ await client
323
+ .getAppendStructure()
324
+ .create((0, asConfig_1.asConfig)(config), options);
325
+ }
326
+ if (obj.source) {
327
+ await client.getAppendStructure().update((0, asConfig_1.asConfig)({
328
+ ...config,
329
+ sourceCode: obj.source,
330
+ }), options);
331
+ }
332
+ return;
333
+ }
274
334
  }
275
335
  }
@@ -1 +1 @@
1
- {"version":3,"file":"restoreObjects.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreObjects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,2BAA2B,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AA4B1D,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,YAAY,EAAE,EACvB,IAAI,EAAE,WAAW,EACjB,gBAAgB,EAAE,OAAO,EACzB,gBAAgB,CAAC,EAAE,MAAM,EACzB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,gBAAgB,UAAO,GACtB,OAAO,CAAC,IAAI,CAAC,CA+Df"}
1
+ {"version":3,"file":"restoreObjects.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreObjects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,2BAA2B,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAgC1D,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,YAAY,EAAE,EACvB,IAAI,EAAE,WAAW,EACjB,gBAAgB,EAAE,OAAO,EACzB,gBAAgB,CAAC,EAAE,MAAM,EACzB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,gBAAgB,UAAO,GACtB,OAAO,CAAC,IAAI,CAAC,CA+Df"}
@@ -10,15 +10,19 @@ const ADT_TYPE_MAP = {
10
10
  domain: 'DOMA/DT',
11
11
  dataElement: 'DTEL/DE',
12
12
  structure: 'TABL/DT',
13
+ appendStructure: 'TABL/DS',
13
14
  table: 'TABL/DT',
14
15
  tableType: 'TTYP/DT',
15
- view: 'VIEW/DV',
16
+ ddl: 'DDLS/DF',
17
+ scalarFunction: 'DSFD/SCF',
18
+ scalarFunctionImplementation: 'DSFI/SFI',
16
19
  class: 'CLAS/OC',
17
20
  interface: 'INTF/OI',
18
21
  program: 'PROG/P',
19
22
  transformation: 'XSLT/VT',
20
23
  functionGroup: 'FUGR/FF',
21
24
  functionModule: 'FUGR/I',
25
+ functionInclude: 'FUGR/I',
22
26
  serviceDefinition: 'SRVD/SRV',
23
27
  serviceBinding: 'SRVB/SRV',
24
28
  metadataExtension: 'DDLX/PX',
@@ -1 +1 @@
1
- {"version":3,"file":"restoreTreeBackup.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreTreeBackup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,2BAA2B,CAAC;AAK5E,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAmElB,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,EACzB,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,EAC/B,gBAAgB,UAAO,EACvB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,oBAAoB,CAAC,EAAE,MAAM,EAC7B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAiZf"}
1
+ {"version":3,"file":"restoreTreeBackup.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreTreeBackup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,2BAA2B,CAAC;AAK5E,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAiFlB,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,EACzB,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,EAC/B,gBAAgB,UAAO,EACvB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,oBAAoB,CAAC,EAAE,MAAM,EAC7B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAiZf"}
@@ -17,8 +17,22 @@ const RESTORE_PHASES = [
17
17
  { name: 'Data Elements', types: ['dataElement'], activation: 'individual' },
18
18
  { name: 'Structures', types: ['structure'], activation: 'individual' },
19
19
  { name: 'Tables', types: ['table'], activation: 'individual' },
20
+ {
21
+ name: 'Append Structures',
22
+ types: ['appendStructure'],
23
+ activation: 'individual',
24
+ },
20
25
  { name: 'Table Types', types: ['tableType'], activation: 'individual' },
21
- { name: 'CDS Views', types: ['view'], activation: 'cluster' },
26
+ {
27
+ name: 'Scalar Functions',
28
+ types: ['scalarFunction', 'scalarFunctionImplementation'],
29
+ activation: 'cluster',
30
+ },
31
+ {
32
+ name: 'DDL (CDS Views & Table Functions)',
33
+ types: ['ddl'],
34
+ activation: 'cluster',
35
+ },
22
36
  {
23
37
  name: 'Behavior',
24
38
  types: ['behaviorDefinition', 'behaviorImplementation'],
@@ -93,7 +107,7 @@ async function restoreTreeBackup(client, root, mode, activate, transportRequest,
93
107
  if (refs.length === 0)
94
108
  return;
95
109
  // Check which objects are actually inactive
96
- let toActivate = await findInactiveRefs(refs);
110
+ const toActivate = await findInactiveRefs(refs);
97
111
  if (toActivate.length === 0) {
98
112
  (0, logVerbose_1.logVerbose)(2, ` [*] ${phaseName}: all ${refs.length} objects already active`);
99
113
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"restoreTreeNode.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreTreeNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAqBV,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5D,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,EACzB,yBAAyB,CAAC,EAAE,MAAM,EAClC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAChC,oBAAoB,CAAC,EAAE,MAAM,EAC7B,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC,IAAI,CAAC,CAibf"}
1
+ {"version":3,"file":"restoreTreeNode.d.ts","sourceRoot":"","sources":["../../../src/lib/restore/restoreTreeNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAyBV,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5D,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,CAAC,EAAE,MAAM,EACzB,yBAAyB,CAAC,EAAE,MAAM,EAClC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAChC,oBAAoB,CAAC,EAAE,MAAM,EAC7B,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC,IAAI,CAAC,CA4ff"}
@@ -138,13 +138,13 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
138
138
  }
139
139
  return;
140
140
  }
141
- case 'view': {
141
+ case 'ddl': {
142
142
  if (mode !== 'update') {
143
- await client.getView().create((0, asConfig_1.asConfig)(config), options);
143
+ await client.getDdl().create((0, asConfig_1.asConfig)(config), options);
144
144
  }
145
145
  if (payload) {
146
146
  await client
147
- .getView()
147
+ .getDdl()
148
148
  .update((0, asConfig_1.asConfig)({ ...config, ddlSource: payload }), options);
149
149
  }
150
150
  return;
@@ -233,6 +233,21 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
233
233
  }
234
234
  return;
235
235
  }
236
+ case 'functionInclude': {
237
+ const fgn = (node.functionGroupName ?? '').toUpperCase();
238
+ // The TOP include is auto-created with the function group, so it can
239
+ // only be updated (a create would fail "already exists"). Custom
240
+ // includes are created — the create chain uploads source and activates.
241
+ const isTop = node.name.toUpperCase() === `L${fgn}TOP`;
242
+ const cfg = (0, asConfig_1.asConfig)(payload ? { ...config, sourceCode: payload } : config);
243
+ if (!isTop && mode !== 'update') {
244
+ await client.getFunctionInclude().create(cfg, options);
245
+ }
246
+ else if (payload) {
247
+ await client.getFunctionInclude().update(cfg, options);
248
+ }
249
+ return;
250
+ }
236
251
  case 'serviceDefinition': {
237
252
  if (mode !== 'update') {
238
253
  await client
@@ -370,6 +385,51 @@ async function restoreTreeNode(client, node, mode, activate, transportRequest, s
370
385
  .update((0, asConfig_1.asConfig)(config), options);
371
386
  return;
372
387
  }
388
+ case 'scalarFunction': {
389
+ if (mode !== 'update') {
390
+ await client
391
+ .getScalarFunction()
392
+ .create((0, asConfig_1.asConfig)(config), options);
393
+ }
394
+ if (payload) {
395
+ await client.getScalarFunction().update((0, asConfig_1.asConfig)({
396
+ ...config,
397
+ sourceCode: payload,
398
+ }), options);
399
+ }
400
+ return;
401
+ }
402
+ case 'scalarFunctionImplementation': {
403
+ if (mode !== 'update') {
404
+ await client
405
+ .getScalarFunctionImplementation()
406
+ .create((0, asConfig_1.asConfig)(config), options);
407
+ }
408
+ if (payload) {
409
+ await client.getScalarFunctionImplementation().update((0, asConfig_1.asConfig)({
410
+ ...config,
411
+ sourceCode: payload,
412
+ }), options);
413
+ }
414
+ return;
415
+ }
416
+ case 'appendStructure': {
417
+ if (mode !== 'update') {
418
+ if (!config.baseObject) {
419
+ throw new Error(`appendStructure ${node.name}: missing baseObject (cannot create)`);
420
+ }
421
+ await client
422
+ .getAppendStructure()
423
+ .create((0, asConfig_1.asConfig)(config), options);
424
+ }
425
+ if (payload) {
426
+ await client.getAppendStructure().update((0, asConfig_1.asConfig)({
427
+ ...config,
428
+ sourceCode: payload,
429
+ }), options);
430
+ }
431
+ return;
432
+ }
373
433
  }
374
434
  }
375
435
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAyDA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAytBzC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AA0DA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA8tBzC"}
package/dist/lib/run.js CHANGED
@@ -198,7 +198,12 @@ async function run() {
198
198
  const hierarchy = await client
199
199
  .getUtils()
200
200
  .getPackageHierarchy(packageName.toUpperCase());
201
- const rootTree = { ...hierarchy, restoreStatus: 'ok' };
201
+ const rootTree = {
202
+ ...hierarchy,
203
+ type: hierarchy.type,
204
+ children: hierarchy.children,
205
+ restoreStatus: 'ok',
206
+ };
202
207
  const enrichedRoot = await (0, enrichTreeNode_1.enrichTreeNode)(rootTree, client, false);
203
208
  await (0, collectTreeDependencies_1.collectTreeDependencies)(client, enrichedRoot);
204
209
  const payload = {
@@ -1 +1 @@
1
- {"version":3,"file":"buildPackageBackupTree.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/buildPackageBackupTree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,UAAU,CAAC;AAI/D,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAiCzB"}
1
+ {"version":3,"file":"buildPackageBackupTree.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/buildPackageBackupTree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAiC,MAAM,UAAU,CAAC;AAI9E,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAmCzB"}
@@ -13,6 +13,8 @@ async function buildPackageBackupTree(client, packageName) {
13
13
  .getPackageHierarchy(packageNameUpper);
14
14
  const rootTree = {
15
15
  ...hierarchy,
16
+ type: hierarchy.type,
17
+ children: hierarchy.children,
16
18
  restoreStatus: 'not-implemented',
17
19
  };
18
20
  (0, logVerbose_1.logVerbose)(1, `Enriching objects for ${packageNameUpper}`);
@@ -1 +1 @@
1
- {"version":3,"file":"enrichTreeNode.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/enrichTreeNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAU/C,wBAAsB,cAAc,CAClC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,OAAO,EACpB,uBAAuB,CAAC,EAAE,MAAM,GAC/B,OAAO,CAAC,cAAc,CAAC,CAkGzB"}
1
+ {"version":3,"file":"enrichTreeNode.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/enrichTreeNode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAY/C,wBAAsB,cAAc,CAClC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,OAAO,EACpB,uBAAuB,CAAC,EAAE,MAAM,GAC/B,OAAO,CAAC,cAAc,CAAC,CAwKzB"}
@@ -8,11 +8,17 @@ const ensureDescription_1 = require("../utils/ensureDescription");
8
8
  const parseBdefSource_1 = require("../utils/parseBdefSource");
9
9
  const parseBehaviorDefinitionFromClass_1 = require("../utils/parseBehaviorDefinitionFromClass");
10
10
  const extractMetadata_1 = require("../xml/extractMetadata");
11
+ const parseAppendStructureSource_1 = require("../xml/parseAppendStructureSource");
12
+ const parseScalarFunctionImplementationConfig_1 = require("../xml/parseScalarFunctionImplementationConfig");
11
13
  const buildConfigForNode_1 = require("./buildConfigForNode");
12
14
  const isRestoreImplemented_1 = require("./isRestoreImplemented");
13
15
  const mapAdtTypeToSupported_1 = require("./mapAdtTypeToSupported");
14
16
  const readPayloadForType_1 = require("./readPayloadForType");
15
17
  async function enrichTreeNode(node, client, includeCode, parentFunctionGroupName) {
18
+ // TABL/DS is reported for BOTH plain structures and append structures; ADT does not
19
+ // distinguish them by type string or hierarchy metadata — only the source content does.
20
+ // We default to 'structure' here and reclassify to 'appendStructure' after fetching
21
+ // the payload (see post-payload block below).
16
22
  const mappedType = (0, mapAdtTypeToSupported_1.mapAdtTypeToSupported)(node.adtType);
17
23
  const functionGroupName = mappedType === 'functionGroup'
18
24
  ? node.name
@@ -72,11 +78,70 @@ async function enrichTreeNode(node, client, includeCode, parentFunctionGroupName
72
78
  };
73
79
  }
74
80
  }
81
+ // DSFI stores its descriptor as JSON in the source payload — not in metadata XML.
82
+ // Parse scalarFunctionName and engine here, after the payload has been fetched.
83
+ if (nextNode.type === 'scalarFunctionImplementation') {
84
+ const sfi = (0, parseScalarFunctionImplementationConfig_1.parseScalarFunctionImplementationConfig)(payload.payload);
85
+ if (!sfi.scalarFunctionName) {
86
+ (0, logVerbose_1.logVerbose)(1, ` [WARN] scalarFunctionImplementation:${node.name} — could not extract scalarFunctionName from source; excluded from restore`);
87
+ nextNode.restoreStatus = 'not-implemented';
88
+ }
89
+ nextNode.config = {
90
+ ...(nextNode.config || {}),
91
+ implementationName: node.name,
92
+ scalarFunctionName: sfi.scalarFunctionName,
93
+ engineValue: sfi.engineValue ?? 'sqlEngine',
94
+ };
95
+ }
96
+ // TABL/DS is used for BOTH plain structures and append structures; ADT does not
97
+ // distinguish them by type string or hierarchy metadata — only the source does.
98
+ // An append uses `extend type <BASE> with <NAME>`; a plain structure uses
99
+ // `define structure`. Reclassify here after the source has been fetched.
100
+ if (node.adtType === 'TABL/DS') {
101
+ const { baseObject } = (0, parseAppendStructureSource_1.parseAppendStructureSource)(payload.payload);
102
+ if (baseObject) {
103
+ nextNode.type = 'appendStructure';
104
+ nextNode.restoreStatus = (0, isRestoreImplemented_1.isRestoreImplemented)('appendStructure')
105
+ ? 'ok'
106
+ : 'not-implemented';
107
+ nextNode.config = {
108
+ ...(nextNode.config || {}),
109
+ appendStructureName: node.name,
110
+ baseObject,
111
+ };
112
+ }
113
+ }
114
+ }
115
+ }
116
+ // A function group's function modules (FUGR/FF) and includes (FUGR/I) are not
117
+ // returned by the package hierarchy — enumerate them and attach as children so
118
+ // their source is captured. Skip the generated `L<FUGR>UXX` collector (no
119
+ // developer content; regenerated on restore).
120
+ const childNodes = node.children ? [...node.children] : [];
121
+ if (mappedType === 'functionGroup' && includeCode) {
122
+ const utils = client.getUtils();
123
+ const [fmNames, includeNames] = await Promise.all([
124
+ utils.listFunctionModules(node.name),
125
+ utils.listFunctionGroupIncludes(node.name),
126
+ ]);
127
+ const generatedCollector = `L${node.name.toUpperCase()}UXX`;
128
+ const enumerated = [
129
+ ...fmNames.map((name) => ({ name, adtType: 'FUGR/FF' })),
130
+ ...includeNames
131
+ .filter((name) => name.toUpperCase() !== generatedCollector)
132
+ .map((name) => ({ name, adtType: 'FUGR/I' })),
133
+ ];
134
+ const present = new Set(childNodes.map((c) => c.name.toUpperCase()));
135
+ for (const child of enumerated) {
136
+ if (!present.has(child.name.toUpperCase())) {
137
+ childNodes.push(child);
138
+ }
75
139
  }
140
+ (0, logVerbose_1.logVerbose)(2, ` FUGR ${node.name}: +${fmNames.length} FM, +${enumerated.length - fmNames.length} include(s)`);
76
141
  }
77
- if (node.children && node.children.length > 0) {
142
+ if (childNodes.length > 0) {
78
143
  const children = [];
79
- for (const child of node.children) {
144
+ for (const child of childNodes) {
80
145
  children.push(await enrichTreeNode(child, client, includeCode, functionGroupName));
81
146
  }
82
147
  nextNode.children = children;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNodeFunctionGroupName = getNodeFunctionGroupName;
4
4
  function getNodeFunctionGroupName(node) {
5
- if (node.type !== 'functionModule') {
5
+ if (node.type !== 'functionModule' && node.type !== 'functionInclude') {
6
6
  return undefined;
7
7
  }
8
8
  const configGroup = node.config && typeof node.config.functionGroupName === 'string'
@@ -6,7 +6,7 @@ function getNodeObjectSpec(node) {
6
6
  if (!node.type) {
7
7
  return undefined;
8
8
  }
9
- if (node.type === 'functionModule') {
9
+ if (node.type === 'functionModule' || node.type === 'functionInclude') {
10
10
  const group = (0, getNodeFunctionGroupName_1.getNodeFunctionGroupName)(node);
11
11
  if (!group) {
12
12
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"isRestoreImplemented.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/isRestoreImplemented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CA0BlE"}
1
+ {"version":3,"file":"isRestoreImplemented.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/isRestoreImplemented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CA8BlE"}
@@ -9,9 +9,12 @@ function isRestoreImplemented(type) {
9
9
  case 'structure':
10
10
  case 'table':
11
11
  case 'tableType':
12
- case 'view':
12
+ case 'ddl':
13
+ case 'scalarFunction':
14
+ case 'scalarFunctionImplementation':
13
15
  case 'functionGroup':
14
16
  case 'functionModule':
17
+ case 'functionInclude':
15
18
  case 'interface':
16
19
  case 'class':
17
20
  case 'program':
@@ -23,6 +26,7 @@ function isRestoreImplemented(type) {
23
26
  case 'behaviorImplementation':
24
27
  case 'enhancement':
25
28
  case 'accessControl':
29
+ case 'appendStructure':
26
30
  return true;
27
31
  default:
28
32
  return false;
@@ -1,3 +1,5 @@
1
1
  import type { SupportedType } from '../types';
2
- export declare function mapAdtTypeToSupported(adtType?: string): SupportedType | undefined;
2
+ export declare function mapAdtTypeToSupported(adtType?: string, hints?: {
3
+ isAppend?: boolean;
4
+ }): SupportedType | undefined;
3
5
  //# sourceMappingURL=mapAdtTypeToSupported.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapAdtTypeToSupported.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/mapAdtTypeToSupported.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,qBAAqB,CACnC,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,GAAG,SAAS,CAmE3B"}
1
+ {"version":3,"file":"mapAdtTypeToSupported.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/mapAdtTypeToSupported.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,qBAAqB,CACnC,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,aAAa,GAAG,SAAS,CA8E3B"}
@@ -1,23 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mapAdtTypeToSupported = mapAdtTypeToSupported;
4
- function mapAdtTypeToSupported(adtType) {
4
+ function mapAdtTypeToSupported(adtType, hints) {
5
5
  if (!adtType) {
6
6
  return undefined;
7
7
  }
8
8
  const normalized = adtType.toUpperCase();
9
9
  // Exact matches
10
+ // Note: 'TABL/DS' maps to 'structure' by default; when hints.isAppend is set,
11
+ // the prefix rule below takes precedence (see guard on map lookup).
10
12
  const map = {
11
13
  'DEVC/K': 'package',
12
14
  'DOMA/DD': 'domain',
13
15
  'DTEL/DE': 'dataElement',
14
- 'TABL/DS': 'structure', // Note: ADT might return TABL/DS for structures sometimes
16
+ 'TABL/DS': 'structure', // default; overridden by hint below
15
17
  'STRU/DT': 'structure',
16
18
  'STRU/DS': 'structure',
17
19
  'TABL/DT': 'table',
18
20
  'TTYP/DF': 'tableType',
19
21
  'TTYP/TT': 'tableType',
20
- 'DDLS/DF': 'view',
22
+ 'DDLS/DF': 'ddl',
23
+ 'DSFD/SCF': 'scalarFunction',
24
+ 'DSFI/SFI': 'scalarFunctionImplementation',
21
25
  'DDLX/EX': 'metadataExtension',
22
26
  'CLAS/OC': 'class',
23
27
  'INTF/IF': 'interface',
@@ -26,6 +30,7 @@ function mapAdtTypeToSupported(adtType) {
26
30
  'XSLT/VT': 'transformation',
27
31
  'XSLT/ST': 'transformation',
28
32
  'FUGR/FF': 'functionModule',
33
+ 'FUGR/I': 'functionInclude',
29
34
  'FUGR/F': 'functionGroup',
30
35
  FUGR: 'functionGroup',
31
36
  'SRVD/SRV': 'serviceDefinition',
@@ -37,7 +42,9 @@ function mapAdtTypeToSupported(adtType) {
37
42
  'ENHO/ENH': 'enhancement',
38
43
  'DCLS/DL': 'accessControl',
39
44
  };
40
- if (map[normalized]) {
45
+ // Skip the exact-map entry for TABL/DS when the append hint is set,
46
+ // so the prefix rule below can return 'appendStructure'.
47
+ if (map[normalized] && !(normalized === 'TABL/DS' && hints?.isAppend)) {
41
48
  return map[normalized];
42
49
  }
43
50
  // Prefix matches
@@ -50,7 +57,11 @@ function mapAdtTypeToSupported(adtType) {
50
57
  if (normalized.startsWith('XSLT/'))
51
58
  return 'transformation';
52
59
  if (normalized.startsWith('DDLS/'))
53
- return 'view';
60
+ return 'ddl';
61
+ if (normalized.startsWith('DSFD/'))
62
+ return 'scalarFunction';
63
+ if (normalized.startsWith('DSFI/'))
64
+ return 'scalarFunctionImplementation';
54
65
  if (normalized.startsWith('DDLX/'))
55
66
  return 'metadataExtension';
56
67
  if (normalized.startsWith('SRVD/'))
@@ -61,7 +72,9 @@ function mapAdtTypeToSupported(adtType) {
61
72
  return 'domain';
62
73
  if (normalized.startsWith('DTEL/'))
63
74
  return 'dataElement';
64
- if (normalized.startsWith('TABL/DS') || normalized.startsWith('STRU/'))
75
+ if (normalized.startsWith('TABL/DS'))
76
+ return hints?.isAppend ? 'appendStructure' : 'structure';
77
+ if (normalized.startsWith('STRU/'))
65
78
  return 'structure';
66
79
  if (normalized.startsWith('TABL/DT'))
67
80
  return 'table';
@@ -69,6 +82,8 @@ function mapAdtTypeToSupported(adtType) {
69
82
  return 'tableType';
70
83
  if (normalized.startsWith('FUGR/FF'))
71
84
  return 'functionModule';
85
+ if (normalized.startsWith('FUGR/I'))
86
+ return 'functionInclude';
72
87
  if (normalized.startsWith('FUGR/'))
73
88
  return 'functionGroup';
74
89
  if (normalized.startsWith('DEVC/'))
@@ -1 +1 @@
1
- {"version":3,"file":"readPayloadForType.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/readPayloadForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CAAE,CAAC,CAwCtE"}
1
+ {"version":3,"file":"readPayloadForType.d.ts","sourceRoot":"","sources":["../../../src/lib/tree/readPayloadForType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CAAE,CAAC,CA4CtE"}
@@ -9,16 +9,20 @@ async function readPayloadForType(client, type, name, functionGroupName) {
9
9
  case 'interface':
10
10
  case 'program':
11
11
  case 'transformation':
12
- case 'view':
12
+ case 'ddl':
13
13
  case 'structure':
14
14
  case 'table':
15
15
  case 'functionModule':
16
+ case 'functionInclude':
16
17
  case 'serviceDefinition':
17
18
  case 'metadataExtension':
18
19
  case 'behaviorDefinition':
19
20
  case 'behaviorImplementation':
20
21
  case 'enhancement':
21
22
  case 'accessControl':
23
+ case 'scalarFunction':
24
+ case 'scalarFunctionImplementation':
25
+ case 'appendStructure':
22
26
  case 'tableType': {
23
27
  const payload = await (0, readSourceText_1.readSourceText)(client, {
24
28
  type,
@@ -1,4 +1,4 @@
1
- export type SupportedType = 'package' | 'domain' | 'dataElement' | 'structure' | 'table' | 'tableType' | 'view' | 'class' | 'interface' | 'program' | 'transformation' | 'functionGroup' | 'functionModule' | 'serviceDefinition' | 'serviceBinding' | 'metadataExtension' | 'behaviorDefinition' | 'behaviorImplementation' | 'enhancement' | 'accessControl' | 'unitTest' | 'cdsUnitTest';
1
+ export type SupportedType = 'package' | 'domain' | 'dataElement' | 'structure' | 'table' | 'tableType' | 'ddl' | 'scalarFunction' | 'scalarFunctionImplementation' | 'class' | 'interface' | 'program' | 'transformation' | 'functionGroup' | 'functionModule' | 'functionInclude' | 'serviceDefinition' | 'serviceBinding' | 'metadataExtension' | 'behaviorDefinition' | 'behaviorImplementation' | 'enhancement' | 'accessControl' | 'appendStructure' | 'unitTest' | 'cdsUnitTest';
2
2
  export type RestoreMode = 'create' | 'update' | 'upsert' | 'skip';
3
3
  export type BackupConfig = Record<string, unknown>;
4
4
  export interface ObjectSpec {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,QAAQ,GACR,aAAa,GACb,WAAW,GACX,OAAO,GACP,WAAW,GACX,MAAM,GACN,OAAO,GACP,WAAW,GACX,SAAS,GACT,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,mBAAmB,GACnB,oBAAoB,GACpB,wBAAwB,GACxB,aAAa,GACb,eAAe,GACf,UAAU,GACV,aAAa,CAAC;AAElB,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,CAAC,EAAE,IAAI,GAAG,iBAAiB,CAAC;IACzC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,SAAS,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,OAAO,EAAE,GACT,MAAM,GACN,MAAM,GACN,IAAI,CAAC;AACT,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"applyConfigName.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/applyConfigName.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,EAC1B,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,CAwEd"}
1
+ {"version":3,"file":"applyConfigName.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/applyConfigName.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,MAAM,EAC1B,MAAM,CAAC,EAAE,YAAY,GACpB,YAAY,CAqFd"}
@@ -22,8 +22,14 @@ function applyConfigName(type, name, functionGroupName, config) {
22
22
  case 'tableType':
23
23
  finalConfig.tableTypeName = name;
24
24
  break;
25
- case 'view':
26
- finalConfig.viewName = name;
25
+ case 'ddl':
26
+ finalConfig.ddlName = name;
27
+ break;
28
+ case 'scalarFunction':
29
+ finalConfig.scalarFunctionName = name;
30
+ break;
31
+ case 'scalarFunctionImplementation':
32
+ finalConfig.implementationName = name;
27
33
  break;
28
34
  case 'class':
29
35
  finalConfig.className = name;
@@ -44,6 +50,10 @@ function applyConfigName(type, name, functionGroupName, config) {
44
50
  finalConfig.functionModuleName = name;
45
51
  finalConfig.functionGroupName = functionGroupName;
46
52
  break;
53
+ case 'functionInclude':
54
+ finalConfig.includeName = name;
55
+ finalConfig.functionGroupName = functionGroupName;
56
+ break;
47
57
  case 'serviceDefinition':
48
58
  finalConfig.serviceDefinitionName = name;
49
59
  break;
@@ -65,6 +75,9 @@ function applyConfigName(type, name, functionGroupName, config) {
65
75
  case 'accessControl':
66
76
  finalConfig.accessControlName = name;
67
77
  break;
78
+ case 'appendStructure':
79
+ finalConfig.appendStructureName = name;
80
+ break;
68
81
  case 'unitTest':
69
82
  finalConfig.className = name;
70
83
  break;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatObjectSpec = formatObjectSpec;
4
4
  function formatObjectSpec(spec) {
5
- if (spec.type === 'functionModule') {
5
+ if (spec.type === 'functionModule' || spec.type === 'functionInclude') {
6
6
  return `${spec.type}:${spec.functionGroupName}|${spec.name}`;
7
7
  }
8
8
  return `${spec.type}:${spec.name}`;
@@ -1 +1 @@
1
- {"version":3,"file":"normalizeType.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/normalizeType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CA6C5D"}
1
+ {"version":3,"file":"normalizeType.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/normalizeType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAuD5D"}
@@ -10,10 +10,18 @@ function normalizeType(rawType) {
10
10
  'data-element': 'dataElement',
11
11
  data_element: 'dataElement',
12
12
  structure: 'structure',
13
+ appendstructure: 'appendStructure',
14
+ append_structure: 'appendStructure',
13
15
  table: 'table',
14
16
  tabletype: 'tableType',
15
17
  table_type: 'tableType',
16
- view: 'view',
18
+ ddl: 'ddl',
19
+ view: 'ddl',
20
+ cds: 'ddl',
21
+ scalarfunction: 'scalarFunction',
22
+ scalar_function: 'scalarFunction',
23
+ scalarfunctionimplementation: 'scalarFunctionImplementation',
24
+ scalar_function_implementation: 'scalarFunctionImplementation',
17
25
  class: 'class',
18
26
  interface: 'interface',
19
27
  program: 'program',
@@ -25,6 +33,8 @@ function normalizeType(rawType) {
25
33
  function_group: 'functionGroup',
26
34
  functionmodule: 'functionModule',
27
35
  function_module: 'functionModule',
36
+ functioninclude: 'functionInclude',
37
+ function_include: 'functionInclude',
28
38
  servicedefinition: 'serviceDefinition',
29
39
  service_definition: 'serviceDefinition',
30
40
  servicebinding: 'serviceBinding',
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.objectId = objectId;
4
4
  function objectId(spec) {
5
- if (spec.type === 'functionModule') {
5
+ if (spec.type === 'functionModule' || spec.type === 'functionInclude') {
6
6
  return `${spec.type}:${spec.functionGroupName}|${spec.name}`;
7
7
  }
8
8
  return `${spec.type}:${spec.name}`;
@@ -1 +1 @@
1
- {"version":3,"file":"parseObjectSpec.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/parseObjectSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA0BxD"}
1
+ {"version":3,"file":"parseObjectSpec.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/parseObjectSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAwBxD"}
@@ -12,10 +12,10 @@ function parseObjectSpec(spec) {
12
12
  if (!namePart) {
13
13
  throw new Error(`Missing name in object spec: ${spec}`);
14
14
  }
15
- if (type === 'functionModule') {
15
+ if (type === 'functionModule' || type === 'functionInclude') {
16
16
  const split = namePart.split(/[|/]/);
17
17
  if (split.length !== 2) {
18
- throw new Error(`Function module spec must be GROUP|NAME or GROUP/NAME: ${spec}`);
18
+ throw new Error(`${type} spec must be GROUP|NAME or GROUP/NAME: ${spec}`);
19
19
  }
20
20
  return {
21
21
  type,
@@ -1 +1 @@
1
- {"version":3,"file":"collectBackupNodes.d.ts","sourceRoot":"","sources":["../../../src/lib/verify/collectBackupNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,cAAc,EAAE,GACpB,IAAI,CASN"}
1
+ {"version":3,"file":"collectBackupNodes.d.ts","sourceRoot":"","sources":["../../../src/lib/verify/collectBackupNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,cAAc,EAAE,GACpB,IAAI,CAYN"}
@@ -2,7 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.collectBackupNodes = collectBackupNodes;
4
4
  function collectBackupNodes(node, out) {
5
- if (node.type) {
5
+ // Skip nodes the backup marked as not restorable (unsupported types, or objects
6
+ // missing a required config field). They are excluded from plan/restore, so verifying
7
+ // them would wrongly report them as missing/failed. Children are still traversed below.
8
+ if (node.type && node.restoreStatus !== 'not-implemented') {
6
9
  out.push(node);
7
10
  }
8
11
  if (node.children && node.children.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"findOtherType.d.ts","sourceRoot":"","sources":["../../../src/lib/verify/findOtherType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyB9C,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,aAAa,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAepC"}
1
+ {"version":3,"file":"findOtherType.d.ts","sourceRoot":"","sources":["../../../src/lib/verify/findOtherType.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA4B9C,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,aAAa,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAepC"}
@@ -9,7 +9,9 @@ const supportedTypes = [
9
9
  'structure',
10
10
  'table',
11
11
  'tableType',
12
- 'view',
12
+ 'ddl',
13
+ 'scalarFunction',
14
+ 'scalarFunctionImplementation',
13
15
  'class',
14
16
  'interface',
15
17
  'program',
@@ -21,6 +23,7 @@ const supportedTypes = [
21
23
  'behaviorDefinition',
22
24
  'behaviorImplementation',
23
25
  'enhancement',
26
+ 'appendStructure',
24
27
  'unitTest',
25
28
  'cdsUnitTest',
26
29
  ];
@@ -0,0 +1,4 @@
1
+ export declare function parseAppendStructureSource(source: string): {
2
+ baseObject?: string;
3
+ };
4
+ //# sourceMappingURL=parseAppendStructureSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseAppendStructureSource.d.ts","sourceRoot":"","sources":["../../../src/lib/xml/parseAppendStructureSource.ts"],"names":[],"mappings":"AAAA,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAGA"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseAppendStructureSource = parseAppendStructureSource;
4
+ function parseAppendStructureSource(source) {
5
+ const m = source.match(/extend\s+type\s+([A-Za-z0-9_/]+)\s+with\b/i);
6
+ return m ? { baseObject: m[1].toUpperCase() } : {};
7
+ }
@@ -0,0 +1,5 @@
1
+ export declare function parseScalarFunctionImplementationConfig(source: string): {
2
+ scalarFunctionName?: string;
3
+ engineValue?: 'sqlEngine' | 'amdpEngine';
4
+ };
5
+ //# sourceMappingURL=parseScalarFunctionImplementationConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseScalarFunctionImplementationConfig.d.ts","sourceRoot":"","sources":["../../../src/lib/xml/parseScalarFunctionImplementationConfig.ts"],"names":[],"mappings":"AAAA,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,MAAM,GAAG;IACvE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC;CAC1C,CAmBA"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseScalarFunctionImplementationConfig = parseScalarFunctionImplementationConfig;
4
+ function parseScalarFunctionImplementationConfig(source) {
5
+ try {
6
+ const parsed = JSON.parse(source);
7
+ const scalarFunctionName = typeof parsed.scalarFunctionName === 'string'
8
+ ? parsed.scalarFunctionName
9
+ : undefined;
10
+ const rawEngine = typeof parsed.engineValue === 'string'
11
+ ? parsed.engineValue
12
+ : typeof parsed.engine === 'string'
13
+ ? parsed.engine
14
+ : undefined;
15
+ const engineValue = rawEngine === 'amdpEngine' ? 'amdpEngine' : 'sqlEngine';
16
+ return { scalarFunctionName, engineValue };
17
+ }
18
+ catch {
19
+ return {};
20
+ }
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/adt-backup",
3
- "version": "1.3.0",
3
+ "version": "1.6.0",
4
4
  "description": "ADT backup CLI for SAP ABAP objects (recursive package backups and restores)",
5
5
  "main": "dist/bin/adt-backup.js",
6
6
  "types": "dist/bin/adt-backup.d.ts",
@@ -48,7 +48,7 @@
48
48
  "node": ">=20.0.0"
49
49
  },
50
50
  "dependencies": {
51
- "@mcp-abap-adt/adt-clients": "^5.4.1",
51
+ "@mcp-abap-adt/adt-clients": "^6.0.0",
52
52
  "@mcp-abap-adt/auth-broker": "^1.0.5",
53
53
  "@mcp-abap-adt/auth-providers": "^1.0.5",
54
54
  "@mcp-abap-adt/auth-stores": "^1.0.4",