@aloma.io/integration-sdk 3.8.62 → 3.8.63

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.
@@ -38,15 +38,18 @@ export class OpenAPIToConnector {
38
38
  if (!this.options.nestedPaths) {
39
39
  return this.generateMethodName({ method: httpMethod, path: urlPath, operationId });
40
40
  }
41
- const VERSION_RE = /^v\d+$/;
41
+ const VERSION_RE = /^v\d+$|^\d{4}-\d{2}$/;
42
42
  const STRIP = new Set(['objects', 'items']);
43
+ // Convert hyphenated segment to camelCase identifier
44
+ const toCamel = (s) => s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
43
45
  // Build namespace parts from the URL path
44
46
  const parts = urlPath
45
47
  .replace(/\{[^}]+\}/g, '')
46
48
  .split('/')
47
49
  .filter(Boolean)
48
50
  .filter((p) => !VERSION_RE.test(p))
49
- .filter((p) => !STRIP.has(p));
51
+ .filter((p) => !STRIP.has(p))
52
+ .map(toCamel);
50
53
  // Extract the leaf action from operationId suffix
51
54
  let suffix = operationId.includes('_')
52
55
  ? operationId.split('_').pop()
@@ -59,10 +62,13 @@ export class OpenAPIToConnector {
59
62
  .split('/')
60
63
  .filter(Boolean)
61
64
  .filter((p) => !VERSION_RE.test(p))
62
- .filter((p) => !STRIP.has(p));
63
- // Use the last meaningful segment from the URL-like suffix, or fall back to HTTP method
65
+ .filter((p) => !STRIP.has(p))
66
+ .map(toCamel);
64
67
  suffix = suffixParts.length > 0 ? suffixParts[suffixParts.length - 1] : httpMethod.toLowerCase();
65
68
  }
69
+ else {
70
+ suffix = toCamel(suffix);
71
+ }
66
72
  // Dedup: if suffix equals last path segment, don't repeat it
67
73
  const last = parts[parts.length - 1];
68
74
  if (suffix === last)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aloma.io/integration-sdk",
3
- "version": "3.8.62",
3
+ "version": "3.8.63",
4
4
  "description": "",
5
5
  "author": "aloma.io",
6
6
  "license": "Apache-2.0",
@@ -62,16 +62,21 @@ export class OpenAPIToConnector {
62
62
  return this.generateMethodName({method: httpMethod, path: urlPath, operationId});
63
63
  }
64
64
 
65
- const VERSION_RE = /^v\d+$/;
65
+ const VERSION_RE = /^v\d+$|^\d{4}-\d{2}$/;
66
66
  const STRIP = new Set(['objects', 'items']);
67
67
 
68
+ // Convert hyphenated segment to camelCase identifier
69
+ const toCamel = (s: string): string =>
70
+ s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
71
+
68
72
  // Build namespace parts from the URL path
69
73
  const parts = urlPath
70
74
  .replace(/\{[^}]+\}/g, '')
71
75
  .split('/')
72
76
  .filter(Boolean)
73
77
  .filter((p) => !VERSION_RE.test(p))
74
- .filter((p) => !STRIP.has(p));
78
+ .filter((p) => !STRIP.has(p))
79
+ .map(toCamel);
75
80
 
76
81
  // Extract the leaf action from operationId suffix
77
82
  let suffix = operationId.includes('_')
@@ -86,9 +91,11 @@ export class OpenAPIToConnector {
86
91
  .split('/')
87
92
  .filter(Boolean)
88
93
  .filter((p) => !VERSION_RE.test(p))
89
- .filter((p) => !STRIP.has(p));
90
- // Use the last meaningful segment from the URL-like suffix, or fall back to HTTP method
94
+ .filter((p) => !STRIP.has(p))
95
+ .map(toCamel);
91
96
  suffix = suffixParts.length > 0 ? suffixParts[suffixParts.length - 1] : httpMethod.toLowerCase();
97
+ } else {
98
+ suffix = toCamel(suffix);
92
99
  }
93
100
 
94
101
  // Dedup: if suffix equals last path segment, don't repeat it
@@ -0,0 +1,69 @@
1
+ import assert from 'assert';
2
+
3
+ const { OpenAPIToConnector } = await import('../build/openapi-to-connector.mjs');
4
+
5
+ let passed = 0;
6
+ let failed = 0;
7
+
8
+ function test(name, fn) {
9
+ try { fn(); console.log(`✓ PASS: ${name}`); passed++; }
10
+ catch(e) { console.log(`✗ FAIL: ${name} — ${e.message}`); failed++; }
11
+ }
12
+
13
+ const minimalSpec = { openapi: '3.0.0', info: { title: 'Test', version: '1.0' }, paths: {} };
14
+ const gen = new OpenAPIToConnector(minimalSpec, 'test', { nestedPaths: true });
15
+
16
+ // Bug 4: hyphenated path segment must not appear in dotted method path
17
+ test('hyphenated path segment sanitised in nested method path', () => {
18
+ const path = gen.deriveMethodPath('PUT',
19
+ '/crm/lists/2025-09/{listId}/memberships/add-and-remove',
20
+ 'put-/crm/lists/2025-09/{listId}/memberships/add-and-remove_addAndRemove');
21
+ const segments = path.split('.');
22
+ segments.forEach(seg => {
23
+ assert(!seg.includes('-'), `Method path segment contains hyphen: "${seg}" in "${path}"`);
24
+ });
25
+ });
26
+
27
+ // Bug 4: path with object-type-id (hyphenated) must produce clean segments
28
+ test('object-type-id hyphenated path sanitised to camelCase', () => {
29
+ const path = gen.deriveMethodPath('GET',
30
+ '/crm/lists/2025-09/object-type-id/{objectTypeId}/name/{listName}',
31
+ 'get-/crm/lists/2025-09/object-type-id/{objectTypeId}/name/{listName}_getByName');
32
+ const segments = path.split('.');
33
+ segments.forEach(seg => {
34
+ assert(!seg.includes('-'), `Method path segment contains hyphen: "${seg}" in "${path}"`);
35
+ });
36
+ });
37
+
38
+ // Bug 5: operationId suffix that IS a raw URL path must not duplicate the full path
39
+ test('raw URL suffix does not produce duplicated path in method name', () => {
40
+ const path = gen.deriveMethodPath('GET',
41
+ '/crm/lists/2025-09',
42
+ 'get-/crm/lists/2025-09_/crm/lists/2025-09');
43
+ // Should be short and clean, not a duplicated path
44
+ assert(path.length < 40, `Path too long (duplication): "${path}" (${path.length} chars)`);
45
+ assert(!path.includes('_'), `Path contains underscores (non-nested fallback used): "${path}"`);
46
+ });
47
+
48
+ // Bug 5: same duplication test for the batch/read endpoint
49
+ test('batch/read raw URL suffix does not produce duplicated path', () => {
50
+ const path = gen.deriveMethodPath('POST',
51
+ '/crm/lists/2025-09/records/memberships/batch/read',
52
+ 'post-/crm/lists/2025-09/records/memberships/batch/read_/crm/lists/2025-09/records/memberships/batch/read');
53
+ assert(path.length < 60, `Path too long (duplication): "${path}" (${path.length} chars)`);
54
+ assert(!path.includes('_'), `Path contains underscores (non-nested fallback used): "${path}"`);
55
+ });
56
+
57
+ // Bug 4: generateMethodName fallback (no operationId) must sanitise hyphens
58
+ test('generateMethodName fallback sanitises hyphens to camelCase', () => {
59
+ const name = gen.generateMethodName({
60
+ method: 'PUT',
61
+ path: '/crm/lists/2025-09/folders/move-list',
62
+ operationId: undefined
63
+ });
64
+ assert(!name.includes('-'), `Fallback name contains hyphen: "${name}"`);
65
+ assert(/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name), `Not a valid identifier: "${name}"`);
66
+ });
67
+
68
+ console.log(`\n${passed} passing / ${failed} failing`);
69
+ if (failed > 0) process.exit(1);