catalyst-relay 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +39 -3
- package/dist/index.d.ts +39 -3
- package/dist/index.js +255 -88
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +255 -88
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -182,7 +182,7 @@ type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
|
|
|
182
182
|
/**
|
|
183
183
|
* Machine-readable error codes
|
|
184
184
|
*/
|
|
185
|
-
type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
|
|
185
|
+
type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
188
|
* Session management type definitions
|
|
@@ -308,6 +308,13 @@ interface ActivationMessage {
|
|
|
308
308
|
column?: number;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
interface CheckResult {
|
|
312
|
+
name: string;
|
|
313
|
+
extension: string;
|
|
314
|
+
status: 'success' | 'warning' | 'error';
|
|
315
|
+
messages: ActivationMessage[];
|
|
316
|
+
}
|
|
317
|
+
|
|
311
318
|
/**
|
|
312
319
|
* Tree types — Public and internal type definitions
|
|
313
320
|
*/
|
|
@@ -341,6 +348,21 @@ interface Package {
|
|
|
341
348
|
name: string;
|
|
342
349
|
description?: string;
|
|
343
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Get list of available packages
|
|
353
|
+
*
|
|
354
|
+
* Uses the ADT search API with DEVC/K object type to search for packages,
|
|
355
|
+
* then enriches results with descriptions from the virtualfolders API.
|
|
356
|
+
*
|
|
357
|
+
* @param client - ADT client
|
|
358
|
+
* @param filter - Package name filter pattern (default: '*' for all packages)
|
|
359
|
+
* Examples: 'Z*' for custom packages, '$TMP' for local, 'ZSNAP*' for specific prefix
|
|
360
|
+
* @returns Array of packages or error
|
|
361
|
+
*/
|
|
362
|
+
interface GetPackagesOptions {
|
|
363
|
+
filter?: string;
|
|
364
|
+
includeDescriptions?: boolean;
|
|
365
|
+
}
|
|
344
366
|
|
|
345
367
|
/**
|
|
346
368
|
* Transports — List transport requests for a package
|
|
@@ -446,11 +468,24 @@ interface DistinctResult {
|
|
|
446
468
|
*/
|
|
447
469
|
interface SearchResult {
|
|
448
470
|
name: string;
|
|
471
|
+
uri: string;
|
|
449
472
|
extension: string;
|
|
450
473
|
package: string;
|
|
451
474
|
description?: string;
|
|
452
475
|
objectType: string;
|
|
453
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Search for objects by name pattern
|
|
479
|
+
*
|
|
480
|
+
* @param client - ADT client
|
|
481
|
+
* @param query - Search pattern (supports wildcards)
|
|
482
|
+
* @param types - Optional array of object type filters
|
|
483
|
+
* @returns Array of matching objects or error
|
|
484
|
+
*/
|
|
485
|
+
interface SearchOptions {
|
|
486
|
+
types?: string[];
|
|
487
|
+
includePackages?: boolean;
|
|
488
|
+
}
|
|
454
489
|
|
|
455
490
|
/**
|
|
456
491
|
* Where-Used — Find object dependencies
|
|
@@ -543,8 +578,9 @@ interface ADTClient {
|
|
|
543
578
|
update(object: ObjectContent, transport?: string): AsyncResult<void>;
|
|
544
579
|
upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
|
|
545
580
|
activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
|
|
581
|
+
checkSyntax(objects: ObjectRef[]): AsyncResult<CheckResult[]>;
|
|
546
582
|
delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
|
|
547
|
-
getPackages(
|
|
583
|
+
getPackages(options?: GetPackagesOptions): AsyncResult<Package[]>;
|
|
548
584
|
getTree(query: TreeQuery): AsyncResult<TreeResponse>;
|
|
549
585
|
getPackageStats(packageName: string): AsyncResult<PackageNode>;
|
|
550
586
|
getPackageStats(packageNames: string[]): AsyncResult<PackageNode[]>;
|
|
@@ -552,7 +588,7 @@ interface ADTClient {
|
|
|
552
588
|
previewData(query: PreviewSQL): AsyncResult<DataFrame>;
|
|
553
589
|
getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
|
|
554
590
|
countRows(objectName: string, objectType: 'table' | 'view', parameters?: Parameter[]): AsyncResult<number>;
|
|
555
|
-
search(query: string,
|
|
591
|
+
search(query: string, options?: SearchOptions): AsyncResult<SearchResult[]>;
|
|
556
592
|
whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
|
|
557
593
|
createTransport(config: TransportConfig): AsyncResult<string>;
|
|
558
594
|
gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -182,7 +182,7 @@ type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
|
|
|
182
182
|
/**
|
|
183
183
|
* Machine-readable error codes
|
|
184
184
|
*/
|
|
185
|
-
type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
|
|
185
|
+
type ErrorCode = 'AUTH_FAILED' | 'SESSION_EXPIRED' | 'SESSION_NOT_FOUND' | 'CSRF_INVALID' | 'OBJECT_LOCKED' | 'OBJECT_NOT_FOUND' | 'TRANSPORT_REQUIRED' | 'ACTIVATION_FAILED' | 'CHECK_FAILED' | 'VALIDATION_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
188
|
* Session management type definitions
|
|
@@ -308,6 +308,13 @@ interface ActivationMessage {
|
|
|
308
308
|
column?: number;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
interface CheckResult {
|
|
312
|
+
name: string;
|
|
313
|
+
extension: string;
|
|
314
|
+
status: 'success' | 'warning' | 'error';
|
|
315
|
+
messages: ActivationMessage[];
|
|
316
|
+
}
|
|
317
|
+
|
|
311
318
|
/**
|
|
312
319
|
* Tree types — Public and internal type definitions
|
|
313
320
|
*/
|
|
@@ -341,6 +348,21 @@ interface Package {
|
|
|
341
348
|
name: string;
|
|
342
349
|
description?: string;
|
|
343
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Get list of available packages
|
|
353
|
+
*
|
|
354
|
+
* Uses the ADT search API with DEVC/K object type to search for packages,
|
|
355
|
+
* then enriches results with descriptions from the virtualfolders API.
|
|
356
|
+
*
|
|
357
|
+
* @param client - ADT client
|
|
358
|
+
* @param filter - Package name filter pattern (default: '*' for all packages)
|
|
359
|
+
* Examples: 'Z*' for custom packages, '$TMP' for local, 'ZSNAP*' for specific prefix
|
|
360
|
+
* @returns Array of packages or error
|
|
361
|
+
*/
|
|
362
|
+
interface GetPackagesOptions {
|
|
363
|
+
filter?: string;
|
|
364
|
+
includeDescriptions?: boolean;
|
|
365
|
+
}
|
|
344
366
|
|
|
345
367
|
/**
|
|
346
368
|
* Transports — List transport requests for a package
|
|
@@ -446,11 +468,24 @@ interface DistinctResult {
|
|
|
446
468
|
*/
|
|
447
469
|
interface SearchResult {
|
|
448
470
|
name: string;
|
|
471
|
+
uri: string;
|
|
449
472
|
extension: string;
|
|
450
473
|
package: string;
|
|
451
474
|
description?: string;
|
|
452
475
|
objectType: string;
|
|
453
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Search for objects by name pattern
|
|
479
|
+
*
|
|
480
|
+
* @param client - ADT client
|
|
481
|
+
* @param query - Search pattern (supports wildcards)
|
|
482
|
+
* @param types - Optional array of object type filters
|
|
483
|
+
* @returns Array of matching objects or error
|
|
484
|
+
*/
|
|
485
|
+
interface SearchOptions {
|
|
486
|
+
types?: string[];
|
|
487
|
+
includePackages?: boolean;
|
|
488
|
+
}
|
|
454
489
|
|
|
455
490
|
/**
|
|
456
491
|
* Where-Used — Find object dependencies
|
|
@@ -543,8 +578,9 @@ interface ADTClient {
|
|
|
543
578
|
update(object: ObjectContent, transport?: string): AsyncResult<void>;
|
|
544
579
|
upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
|
|
545
580
|
activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
|
|
581
|
+
checkSyntax(objects: ObjectRef[]): AsyncResult<CheckResult[]>;
|
|
546
582
|
delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;
|
|
547
|
-
getPackages(
|
|
583
|
+
getPackages(options?: GetPackagesOptions): AsyncResult<Package[]>;
|
|
548
584
|
getTree(query: TreeQuery): AsyncResult<TreeResponse>;
|
|
549
585
|
getPackageStats(packageName: string): AsyncResult<PackageNode>;
|
|
550
586
|
getPackageStats(packageNames: string[]): AsyncResult<PackageNode[]>;
|
|
@@ -552,7 +588,7 @@ interface ADTClient {
|
|
|
552
588
|
previewData(query: PreviewSQL): AsyncResult<DataFrame>;
|
|
553
589
|
getDistinctValues(objectName: string, parameters: Parameter[], column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;
|
|
554
590
|
countRows(objectName: string, objectType: 'table' | 'view', parameters?: Parameter[]): AsyncResult<number>;
|
|
555
|
-
search(query: string,
|
|
591
|
+
search(query: string, options?: SearchOptions): AsyncResult<SearchResult[]>;
|
|
556
592
|
whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;
|
|
557
593
|
createTransport(config: TransportConfig): AsyncResult<string>;
|
|
558
594
|
gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]>;
|
package/dist/index.js
CHANGED
|
@@ -1535,8 +1535,201 @@ function extractActivationErrors(objects, xml, _extension) {
|
|
|
1535
1535
|
return ok(results);
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
|
+
// src/core/adt/craud/syntaxCheck.ts
|
|
1539
|
+
async function checkSyntax(client, objects) {
|
|
1540
|
+
if (objects.length === 0) {
|
|
1541
|
+
return ok([]);
|
|
1542
|
+
}
|
|
1543
|
+
const extension = objects[0].extension;
|
|
1544
|
+
const config = getConfigByExtension(extension);
|
|
1545
|
+
if (!config) return err(new Error(`Unsupported extension: ${extension}`));
|
|
1546
|
+
for (const obj of objects) {
|
|
1547
|
+
if (obj.extension !== extension) {
|
|
1548
|
+
return err(new Error("All objects must have the same extension for batch syntax check"));
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
const sources = /* @__PURE__ */ new Map();
|
|
1552
|
+
for (const obj of objects) {
|
|
1553
|
+
const [result, readErr] = await readObject(client, obj);
|
|
1554
|
+
if (readErr) return err(new Error(`Failed to read ${obj.name}: ${readErr.message}`));
|
|
1555
|
+
sources.set(obj.name.toLowerCase(), result.content);
|
|
1556
|
+
}
|
|
1557
|
+
const objectRefs = objects.map((obj) => {
|
|
1558
|
+
const uri = `/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}`;
|
|
1559
|
+
const sourceUri = `${uri}/source/main`;
|
|
1560
|
+
const content = sources.get(obj.name.toLowerCase()) ?? "";
|
|
1561
|
+
const encoded = Buffer.from(content).toString("base64");
|
|
1562
|
+
return `<chkrun:checkObject adtcore:uri="${uri}" chkrun:version="active">
|
|
1563
|
+
<chkrun:artifacts>
|
|
1564
|
+
<chkrun:artifact chkrun:contentType="text/plain; charset=utf-8" chkrun:uri="${sourceUri}">
|
|
1565
|
+
<chkrun:content>${encoded}</chkrun:content>
|
|
1566
|
+
</chkrun:artifact>
|
|
1567
|
+
</chkrun:artifacts>
|
|
1568
|
+
</chkrun:checkObject>`;
|
|
1569
|
+
}).join("\n ");
|
|
1570
|
+
const body = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1571
|
+
<chkrun:checkObjectList xmlns:chkrun="http://www.sap.com/adt/checkrun"
|
|
1572
|
+
xmlns:adtcore="http://www.sap.com/adt/core">
|
|
1573
|
+
${objectRefs}
|
|
1574
|
+
</chkrun:checkObjectList>`;
|
|
1575
|
+
const [response, requestErr] = await client.request({
|
|
1576
|
+
method: "POST",
|
|
1577
|
+
path: "/sap/bc/adt/checkruns",
|
|
1578
|
+
params: {
|
|
1579
|
+
"reporters": "abapCheckRun"
|
|
1580
|
+
},
|
|
1581
|
+
headers: {
|
|
1582
|
+
"Content-Type": "application/vnd.sap.adt.checkobjects+xml",
|
|
1583
|
+
"Accept": "application/vnd.sap.adt.checkmessages+xml"
|
|
1584
|
+
},
|
|
1585
|
+
body
|
|
1586
|
+
});
|
|
1587
|
+
if (requestErr) {
|
|
1588
|
+
return err(requestErr);
|
|
1589
|
+
}
|
|
1590
|
+
const text = await response.text();
|
|
1591
|
+
debug(`Syntax check response status: ${response.status}`);
|
|
1592
|
+
debug(`Syntax check response: ${text.substring(0, 500)}`);
|
|
1593
|
+
if (!response.ok) {
|
|
1594
|
+
const errorMsg = extractError(text);
|
|
1595
|
+
return err(new Error(`Syntax check failed: ${errorMsg}`));
|
|
1596
|
+
}
|
|
1597
|
+
const [results, parseErr] = extractCheckMessages(objects, text);
|
|
1598
|
+
if (parseErr) {
|
|
1599
|
+
return err(parseErr);
|
|
1600
|
+
}
|
|
1601
|
+
return ok(results);
|
|
1602
|
+
}
|
|
1603
|
+
function extractCheckMessages(objects, xml) {
|
|
1604
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
1605
|
+
if (parseErr) {
|
|
1606
|
+
return err(parseErr);
|
|
1607
|
+
}
|
|
1608
|
+
const messageMap = /* @__PURE__ */ new Map();
|
|
1609
|
+
objects.forEach((obj) => messageMap.set(obj.name.toLowerCase(), []));
|
|
1610
|
+
let msgElements = doc.getElementsByTagName("chkrun:checkMessage");
|
|
1611
|
+
if (msgElements.length === 0) {
|
|
1612
|
+
msgElements = doc.getElementsByTagName("checkMessage");
|
|
1613
|
+
}
|
|
1614
|
+
const startRegex = /#start=(\d+),(\d+)/;
|
|
1615
|
+
for (let i = 0; i < msgElements.length; i++) {
|
|
1616
|
+
const msg = msgElements[i];
|
|
1617
|
+
if (!msg) continue;
|
|
1618
|
+
const type = msg.getAttribute("chkrun:type") ?? msg.getAttribute("type");
|
|
1619
|
+
if (!type) continue;
|
|
1620
|
+
const uri = msg.getAttribute("chkrun:uri") ?? msg.getAttribute("uri") ?? "";
|
|
1621
|
+
let line;
|
|
1622
|
+
let column;
|
|
1623
|
+
const match = startRegex.exec(uri);
|
|
1624
|
+
if (match && match[1] && match[2]) {
|
|
1625
|
+
line = parseInt(match[1], 10);
|
|
1626
|
+
column = parseInt(match[2], 10);
|
|
1627
|
+
}
|
|
1628
|
+
const matchingObj = objects.find(
|
|
1629
|
+
(obj) => uri.toLowerCase().includes(obj.name.toLowerCase())
|
|
1630
|
+
);
|
|
1631
|
+
if (!matchingObj) continue;
|
|
1632
|
+
const text = msg.getAttribute("chkrun:shortText") ?? msg.getAttribute("shortText");
|
|
1633
|
+
if (!text) continue;
|
|
1634
|
+
const message = {
|
|
1635
|
+
severity: type === "E" ? "error" : type === "W" ? "warning" : "info",
|
|
1636
|
+
text,
|
|
1637
|
+
...line !== void 0 && { line },
|
|
1638
|
+
...column !== void 0 && { column }
|
|
1639
|
+
};
|
|
1640
|
+
const messages = messageMap.get(matchingObj.name.toLowerCase()) || [];
|
|
1641
|
+
messages.push(message);
|
|
1642
|
+
messageMap.set(matchingObj.name.toLowerCase(), messages);
|
|
1643
|
+
}
|
|
1644
|
+
const results = objects.map((obj) => {
|
|
1645
|
+
const messages = messageMap.get(obj.name.toLowerCase()) || [];
|
|
1646
|
+
const hasErrors = messages.some((m) => m.severity === "error");
|
|
1647
|
+
return {
|
|
1648
|
+
name: obj.name,
|
|
1649
|
+
extension: obj.extension,
|
|
1650
|
+
status: hasErrors ? "error" : messages.length > 0 ? "warning" : "success",
|
|
1651
|
+
messages
|
|
1652
|
+
};
|
|
1653
|
+
});
|
|
1654
|
+
return ok(results);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
// src/core/adt/discovery/tree/packageStats.ts
|
|
1658
|
+
function constructPackageStatsBody(packageNames) {
|
|
1659
|
+
const names = packageNames.length === 1 ? [...packageNames, "SRIS_TEST_DATA_VFS_EMPTY"] : packageNames;
|
|
1660
|
+
const values = names.map((name) => ` <vfs:value>${name}</vfs:value>`).join("\n");
|
|
1661
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1662
|
+
<vfs:virtualFoldersRequest xmlns:vfs="http://www.sap.com/adt/ris/virtualFolders" objectSearchPattern="*">
|
|
1663
|
+
<vfs:preselection facet="package">
|
|
1664
|
+
${values}
|
|
1665
|
+
</vfs:preselection>
|
|
1666
|
+
<vfs:facetorder>
|
|
1667
|
+
<vfs:facet>package</vfs:facet>
|
|
1668
|
+
<vfs:facet>group</vfs:facet>
|
|
1669
|
+
<vfs:facet>type</vfs:facet>
|
|
1670
|
+
</vfs:facetorder>
|
|
1671
|
+
</vfs:virtualFoldersRequest>`;
|
|
1672
|
+
}
|
|
1673
|
+
function parsePackageStats(xml) {
|
|
1674
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
1675
|
+
if (parseErr) return [];
|
|
1676
|
+
const packages = [];
|
|
1677
|
+
const virtualFolders = doc.getElementsByTagName("vfs:virtualFolder");
|
|
1678
|
+
for (let i = 0; i < virtualFolders.length; i++) {
|
|
1679
|
+
const vf = virtualFolders[i];
|
|
1680
|
+
if (!vf) continue;
|
|
1681
|
+
const facet = vf.getAttribute("facet")?.toUpperCase();
|
|
1682
|
+
if (facet !== "PACKAGE") continue;
|
|
1683
|
+
const name = vf.getAttribute("name");
|
|
1684
|
+
if (!name) continue;
|
|
1685
|
+
const countAttr = vf.getAttribute("counter");
|
|
1686
|
+
const count = countAttr ? parseInt(countAttr, 10) : 0;
|
|
1687
|
+
const description = vf.getAttribute("text");
|
|
1688
|
+
const pkg = {
|
|
1689
|
+
name,
|
|
1690
|
+
numContents: count
|
|
1691
|
+
};
|
|
1692
|
+
if (description) pkg.description = description;
|
|
1693
|
+
packages.push(pkg);
|
|
1694
|
+
}
|
|
1695
|
+
return packages;
|
|
1696
|
+
}
|
|
1697
|
+
async function getPackageStats(client, packageNames) {
|
|
1698
|
+
const isSingle = typeof packageNames === "string";
|
|
1699
|
+
const names = isSingle ? [packageNames] : packageNames;
|
|
1700
|
+
if (names.length === 0) {
|
|
1701
|
+
return ok([]);
|
|
1702
|
+
}
|
|
1703
|
+
const body = constructPackageStatsBody(names);
|
|
1704
|
+
const [response, requestErr] = await client.request({
|
|
1705
|
+
method: "POST",
|
|
1706
|
+
path: "/sap/bc/adt/repository/informationsystem/virtualfolders/contents",
|
|
1707
|
+
headers: {
|
|
1708
|
+
"Content-Type": "application/vnd.sap.adt.repository.virtualfolders.request.v1+xml",
|
|
1709
|
+
"Accept": "application/vnd.sap.adt.repository.virtualfolders.result.v1+xml"
|
|
1710
|
+
},
|
|
1711
|
+
body
|
|
1712
|
+
});
|
|
1713
|
+
if (requestErr) return err(requestErr);
|
|
1714
|
+
if (!response.ok) {
|
|
1715
|
+
const text = await response.text();
|
|
1716
|
+
const errorMsg = extractError(text);
|
|
1717
|
+
return err(new Error(`Package stats fetch failed: ${errorMsg}`));
|
|
1718
|
+
}
|
|
1719
|
+
const xml = await response.text();
|
|
1720
|
+
const packages = parsePackageStats(xml).filter((pkg) => pkg.name !== "SRIS_TEST_DATA_VFS_EMPTY");
|
|
1721
|
+
if (isSingle) {
|
|
1722
|
+
if (packages.length === 0) {
|
|
1723
|
+
return err(new Error(`Package ${packageNames} not found`));
|
|
1724
|
+
}
|
|
1725
|
+
return ok(packages[0]);
|
|
1726
|
+
}
|
|
1727
|
+
return ok(packages);
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1538
1730
|
// src/core/adt/discovery/packages.ts
|
|
1539
|
-
async function getPackages(client,
|
|
1731
|
+
async function getPackages(client, options = {}) {
|
|
1732
|
+
const { filter = "*", includeDescriptions = false } = options;
|
|
1540
1733
|
const params = new URLSearchParams([
|
|
1541
1734
|
["operation", "quickSearch"],
|
|
1542
1735
|
["query", filter],
|
|
@@ -1560,18 +1753,31 @@ async function getPackages(client, filter = "*") {
|
|
|
1560
1753
|
if (parseErr) {
|
|
1561
1754
|
return err(parseErr);
|
|
1562
1755
|
}
|
|
1563
|
-
const
|
|
1756
|
+
const packageNames = [];
|
|
1564
1757
|
const objectRefs = doc.getElementsByTagNameNS("http://www.sap.com/adt/core", "objectReference");
|
|
1565
1758
|
for (let i = 0; i < objectRefs.length; i++) {
|
|
1566
1759
|
const obj = objectRefs[i];
|
|
1567
1760
|
if (!obj) return err(new Error("Invalid object reference in package search results"));
|
|
1568
1761
|
const name = obj.getAttributeNS("http://www.sap.com/adt/core", "name") || obj.getAttribute("adtcore:name");
|
|
1569
|
-
const description = obj.getAttributeNS("http://www.sap.com/adt/core", "description") || obj.getAttribute("adtcore:description");
|
|
1570
1762
|
if (!name) return err(new Error("Package name missing in object reference"));
|
|
1763
|
+
packageNames.push(name);
|
|
1764
|
+
}
|
|
1765
|
+
if (packageNames.length === 0) return ok([]);
|
|
1766
|
+
if (!includeDescriptions) return ok(packageNames.map((name) => ({ name })));
|
|
1767
|
+
const [stats, statsErr] = await getPackageStats(client, packageNames);
|
|
1768
|
+
if (statsErr) {
|
|
1769
|
+
return ok(packageNames.map((name) => ({ name })));
|
|
1770
|
+
}
|
|
1771
|
+
const descriptionMap = /* @__PURE__ */ new Map();
|
|
1772
|
+
for (const stat2 of stats) {
|
|
1773
|
+
if (stat2.description) descriptionMap.set(stat2.name, stat2.description);
|
|
1774
|
+
}
|
|
1775
|
+
const packages = packageNames.map((name) => {
|
|
1571
1776
|
const pkg = { name };
|
|
1777
|
+
const description = descriptionMap.get(name);
|
|
1572
1778
|
if (description) pkg.description = description;
|
|
1573
|
-
|
|
1574
|
-
}
|
|
1779
|
+
return pkg;
|
|
1780
|
+
});
|
|
1575
1781
|
return ok(packages);
|
|
1576
1782
|
}
|
|
1577
1783
|
|
|
@@ -1811,79 +2017,6 @@ async function getTree(client, query = {}) {
|
|
|
1811
2017
|
return ok(result);
|
|
1812
2018
|
}
|
|
1813
2019
|
|
|
1814
|
-
// src/core/adt/discovery/tree/packageStats.ts
|
|
1815
|
-
function constructPackageStatsBody(packageNames) {
|
|
1816
|
-
const names = packageNames.length === 1 ? [...packageNames, "SRIS_TEST_DATA_VFS_EMPTY"] : packageNames;
|
|
1817
|
-
const values = names.map((name) => ` <vfs:value>${name}</vfs:value>`).join("\n");
|
|
1818
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1819
|
-
<vfs:virtualFoldersRequest xmlns:vfs="http://www.sap.com/adt/ris/virtualFolders" objectSearchPattern="*">
|
|
1820
|
-
<vfs:preselection facet="package">
|
|
1821
|
-
${values}
|
|
1822
|
-
</vfs:preselection>
|
|
1823
|
-
<vfs:facetorder>
|
|
1824
|
-
<vfs:facet>package</vfs:facet>
|
|
1825
|
-
<vfs:facet>group</vfs:facet>
|
|
1826
|
-
<vfs:facet>type</vfs:facet>
|
|
1827
|
-
</vfs:facetorder>
|
|
1828
|
-
</vfs:virtualFoldersRequest>`;
|
|
1829
|
-
}
|
|
1830
|
-
function parsePackageStats(xml) {
|
|
1831
|
-
const [doc, parseErr] = safeParseXml(xml);
|
|
1832
|
-
if (parseErr) return [];
|
|
1833
|
-
const packages = [];
|
|
1834
|
-
const virtualFolders = doc.getElementsByTagName("vfs:virtualFolder");
|
|
1835
|
-
for (let i = 0; i < virtualFolders.length; i++) {
|
|
1836
|
-
const vf = virtualFolders[i];
|
|
1837
|
-
if (!vf) continue;
|
|
1838
|
-
const facet = vf.getAttribute("facet")?.toUpperCase();
|
|
1839
|
-
if (facet !== "PACKAGE") continue;
|
|
1840
|
-
const name = vf.getAttribute("name");
|
|
1841
|
-
if (!name) continue;
|
|
1842
|
-
const countAttr = vf.getAttribute("counter");
|
|
1843
|
-
const count = countAttr ? parseInt(countAttr, 10) : 0;
|
|
1844
|
-
const description = vf.getAttribute("text");
|
|
1845
|
-
const pkg = {
|
|
1846
|
-
name,
|
|
1847
|
-
numContents: count
|
|
1848
|
-
};
|
|
1849
|
-
if (description) pkg.description = description;
|
|
1850
|
-
packages.push(pkg);
|
|
1851
|
-
}
|
|
1852
|
-
return packages;
|
|
1853
|
-
}
|
|
1854
|
-
async function getPackageStats(client, packageNames) {
|
|
1855
|
-
const isSingle = typeof packageNames === "string";
|
|
1856
|
-
const names = isSingle ? [packageNames] : packageNames;
|
|
1857
|
-
if (names.length === 0) {
|
|
1858
|
-
return ok([]);
|
|
1859
|
-
}
|
|
1860
|
-
const body = constructPackageStatsBody(names);
|
|
1861
|
-
const [response, requestErr] = await client.request({
|
|
1862
|
-
method: "POST",
|
|
1863
|
-
path: "/sap/bc/adt/repository/informationsystem/virtualfolders/contents",
|
|
1864
|
-
headers: {
|
|
1865
|
-
"Content-Type": "application/vnd.sap.adt.repository.virtualfolders.request.v1+xml",
|
|
1866
|
-
"Accept": "application/vnd.sap.adt.repository.virtualfolders.result.v1+xml"
|
|
1867
|
-
},
|
|
1868
|
-
body
|
|
1869
|
-
});
|
|
1870
|
-
if (requestErr) return err(requestErr);
|
|
1871
|
-
if (!response.ok) {
|
|
1872
|
-
const text = await response.text();
|
|
1873
|
-
const errorMsg = extractError(text);
|
|
1874
|
-
return err(new Error(`Package stats fetch failed: ${errorMsg}`));
|
|
1875
|
-
}
|
|
1876
|
-
const xml = await response.text();
|
|
1877
|
-
const packages = parsePackageStats(xml).filter((pkg) => pkg.name !== "SRIS_TEST_DATA_VFS_EMPTY");
|
|
1878
|
-
if (isSingle) {
|
|
1879
|
-
if (packages.length === 0) {
|
|
1880
|
-
return err(new Error(`Package ${packageNames} not found`));
|
|
1881
|
-
}
|
|
1882
|
-
return ok(packages[0]);
|
|
1883
|
-
}
|
|
1884
|
-
return ok(packages);
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
2020
|
// src/core/adt/transports/transports.ts
|
|
1888
2021
|
async function getTransports(client, packageName) {
|
|
1889
2022
|
const contentType = "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData";
|
|
@@ -2177,7 +2310,8 @@ async function countRows(client, objectName, _objectType, parameters = []) {
|
|
|
2177
2310
|
}
|
|
2178
2311
|
|
|
2179
2312
|
// src/core/adt/discovery/searchObjects.ts
|
|
2180
|
-
async function searchObjects(client, query,
|
|
2313
|
+
async function searchObjects(client, query, options) {
|
|
2314
|
+
const { types, includePackages = true } = options ?? {};
|
|
2181
2315
|
const searchPattern = query || "*";
|
|
2182
2316
|
const objectTypes = types && types.length > 0 ? types : getAllTypes();
|
|
2183
2317
|
const params = [
|
|
@@ -2209,8 +2343,30 @@ async function searchObjects(client, query, types) {
|
|
|
2209
2343
|
if (parseErr) {
|
|
2210
2344
|
return err(parseErr);
|
|
2211
2345
|
}
|
|
2346
|
+
if (includePackages) await enrichWithPackages(client, results);
|
|
2212
2347
|
return ok(results);
|
|
2213
2348
|
}
|
|
2349
|
+
async function enrichWithPackages(client, results) {
|
|
2350
|
+
const needsPackage = results.filter((r) => !r.package);
|
|
2351
|
+
if (needsPackage.length === 0) return;
|
|
2352
|
+
const promises = needsPackage.map(async (result) => {
|
|
2353
|
+
const encodedUri = encodeURIComponent(result.uri);
|
|
2354
|
+
const [response, reqErr] = await client.request({
|
|
2355
|
+
method: "GET",
|
|
2356
|
+
path: `/sap/bc/adt/repository/informationsystem/objectproperties/values?uri=${encodedUri}&facet=package`
|
|
2357
|
+
});
|
|
2358
|
+
if (reqErr || !response.ok) return;
|
|
2359
|
+
const text = await response.text();
|
|
2360
|
+
const [doc, parseErr] = safeParseXml(text);
|
|
2361
|
+
if (parseErr) return;
|
|
2362
|
+
const oprNs = "http://www.sap.com/adt/ris/objectProperties";
|
|
2363
|
+
const objEl = doc.getElementsByTagNameNS(oprNs, "object")[0];
|
|
2364
|
+
if (!objEl) return;
|
|
2365
|
+
const pkg = objEl.getAttribute("package");
|
|
2366
|
+
if (pkg) result.package = pkg;
|
|
2367
|
+
});
|
|
2368
|
+
await Promise.all(promises);
|
|
2369
|
+
}
|
|
2214
2370
|
function parseSearchResults(xml) {
|
|
2215
2371
|
const [doc, parseErr] = safeParseXml(xml);
|
|
2216
2372
|
if (parseErr) {
|
|
@@ -2223,14 +2379,16 @@ function parseSearchResults(xml) {
|
|
|
2223
2379
|
if (!obj) continue;
|
|
2224
2380
|
const name = obj.getAttributeNS("http://www.sap.com/adt/core", "name") || obj.getAttribute("adtcore:name");
|
|
2225
2381
|
const type = obj.getAttributeNS("http://www.sap.com/adt/core", "type") || obj.getAttribute("adtcore:type");
|
|
2382
|
+
const uri = obj.getAttributeNS("http://www.sap.com/adt/core", "uri") || obj.getAttribute("adtcore:uri");
|
|
2226
2383
|
const description = obj.getAttributeNS("http://www.sap.com/adt/core", "description") || obj.getAttribute("adtcore:description");
|
|
2227
|
-
if (!name || !type) continue;
|
|
2384
|
+
if (!name || !type || !uri) continue;
|
|
2228
2385
|
const config = getConfigByType(type);
|
|
2229
2386
|
if (!config) continue;
|
|
2230
2387
|
const packageRef = obj.getElementsByTagNameNS("http://www.sap.com/adt/core", "packageRef")[0];
|
|
2231
2388
|
const packageName = packageRef ? packageRef.getAttributeNS("http://www.sap.com/adt/core", "name") || packageRef.getAttribute("adtcore:name") : "";
|
|
2232
2389
|
const result = {
|
|
2233
2390
|
name,
|
|
2391
|
+
uri,
|
|
2234
2392
|
extension: config.extension,
|
|
2235
2393
|
package: packageName || "",
|
|
2236
2394
|
objectType: config.label
|
|
@@ -2539,10 +2697,16 @@ async function deleteObjects(state, requestor, objects, transport) {
|
|
|
2539
2697
|
return ok(void 0);
|
|
2540
2698
|
}
|
|
2541
2699
|
|
|
2700
|
+
// src/client/methods/craud/checkSyntax.ts
|
|
2701
|
+
async function checkSyntax2(state, requestor, objects) {
|
|
2702
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
2703
|
+
return checkSyntax(requestor, objects);
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2542
2706
|
// src/client/methods/discovery/getPackages.ts
|
|
2543
|
-
async function getPackages2(state, requestor,
|
|
2707
|
+
async function getPackages2(state, requestor, options) {
|
|
2544
2708
|
if (!state.session) return err(new Error("Not logged in"));
|
|
2545
|
-
return getPackages(requestor,
|
|
2709
|
+
return getPackages(requestor, options);
|
|
2546
2710
|
}
|
|
2547
2711
|
|
|
2548
2712
|
// src/client/methods/discovery/getTree.ts
|
|
@@ -2582,9 +2746,9 @@ async function countRows2(state, requestor, objectName, objectType, parameters =
|
|
|
2582
2746
|
}
|
|
2583
2747
|
|
|
2584
2748
|
// src/client/methods/search/search.ts
|
|
2585
|
-
async function search(state, requestor, query,
|
|
2749
|
+
async function search(state, requestor, query, options) {
|
|
2586
2750
|
if (!state.session) return err(new Error("Not logged in"));
|
|
2587
|
-
return searchObjects(requestor, query,
|
|
2751
|
+
return searchObjects(requestor, query, options);
|
|
2588
2752
|
}
|
|
2589
2753
|
|
|
2590
2754
|
// src/client/methods/search/whereUsed.ts
|
|
@@ -2935,12 +3099,15 @@ var ADTClientImpl = class {
|
|
|
2935
3099
|
async activate(objects) {
|
|
2936
3100
|
return activate(this.state, this.requestor, objects);
|
|
2937
3101
|
}
|
|
3102
|
+
async checkSyntax(objects) {
|
|
3103
|
+
return checkSyntax2(this.state, this.requestor, objects);
|
|
3104
|
+
}
|
|
2938
3105
|
async delete(objects, transport) {
|
|
2939
3106
|
return deleteObjects(this.state, this.requestor, objects, transport);
|
|
2940
3107
|
}
|
|
2941
3108
|
// --- Discovery ---
|
|
2942
|
-
async getPackages(
|
|
2943
|
-
return getPackages2(this.state, this.requestor,
|
|
3109
|
+
async getPackages(options) {
|
|
3110
|
+
return getPackages2(this.state, this.requestor, options);
|
|
2944
3111
|
}
|
|
2945
3112
|
async getTree(query) {
|
|
2946
3113
|
return getTree2(this.state, this.requestor, query);
|
|
@@ -2962,8 +3129,8 @@ var ADTClientImpl = class {
|
|
|
2962
3129
|
return countRows2(this.state, this.requestor, objectName, objectType, parameters);
|
|
2963
3130
|
}
|
|
2964
3131
|
// --- Search ---
|
|
2965
|
-
async search(query,
|
|
2966
|
-
return search(this.state, this.requestor, query,
|
|
3132
|
+
async search(query, options) {
|
|
3133
|
+
return search(this.state, this.requestor, query, options);
|
|
2967
3134
|
}
|
|
2968
3135
|
async whereUsed(object) {
|
|
2969
3136
|
return whereUsed(this.state, this.requestor, object);
|