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 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(filter?: string): AsyncResult<Package[]>;
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, types?: string[]): AsyncResult<SearchResult[]>;
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(filter?: string): AsyncResult<Package[]>;
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, types?: string[]): AsyncResult<SearchResult[]>;
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, filter = "*") {
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 packages = [];
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
- packages.push(pkg);
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, types) {
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, filter) {
2707
+ async function getPackages2(state, requestor, options) {
2544
2708
  if (!state.session) return err(new Error("Not logged in"));
2545
- return getPackages(requestor, filter);
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, types) {
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, types);
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(filter) {
2943
- return getPackages2(this.state, this.requestor, filter);
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, types) {
2966
- return search(this.state, this.requestor, query, types);
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);