@aloma.io/integration-sdk 3.8.62 → 3.8.64
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
|
-
|
|
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)
|
|
@@ -152,7 +158,9 @@ export class OpenAPIToConnector {
|
|
|
152
158
|
// Extract the last part after underscore if it exists
|
|
153
159
|
const parts = cleaned.split('_');
|
|
154
160
|
if (parts.length > 1) {
|
|
155
|
-
|
|
161
|
+
let lastPart = parts[parts.length - 1];
|
|
162
|
+
// Convert hyphens to camelCase before testing
|
|
163
|
+
lastPart = lastPart.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
156
164
|
// If the last part looks like a method name (camelCase), use it
|
|
157
165
|
if (lastPart && /^[a-z][a-zA-Z0-9]*$/.test(lastPart)) {
|
|
158
166
|
cleaned = lastPart;
|
|
@@ -192,7 +200,7 @@ export class OpenAPIToConnector {
|
|
|
192
200
|
.filter((p) => p.toLowerCase() !== baseName.toLowerCase());
|
|
193
201
|
// Use the last path segment before the method name as a distinguishing prefix
|
|
194
202
|
if (pathParts.length > 0) {
|
|
195
|
-
const prefix = pathParts[pathParts.length - 1];
|
|
203
|
+
const prefix = pathParts[pathParts.length - 1].replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
196
204
|
const capitalizedBase = baseName.charAt(0).toUpperCase() + baseName.slice(1);
|
|
197
205
|
return `${prefix}${capitalizedBase}`;
|
|
198
206
|
}
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
|
@@ -190,7 +197,9 @@ export class OpenAPIToConnector {
|
|
|
190
197
|
// Extract the last part after underscore if it exists
|
|
191
198
|
const parts = cleaned.split('_');
|
|
192
199
|
if (parts.length > 1) {
|
|
193
|
-
|
|
200
|
+
let lastPart = parts[parts.length - 1];
|
|
201
|
+
// Convert hyphens to camelCase before testing
|
|
202
|
+
lastPart = lastPart.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
194
203
|
// If the last part looks like a method name (camelCase), use it
|
|
195
204
|
if (lastPart && /^[a-z][a-zA-Z0-9]*$/.test(lastPart)) {
|
|
196
205
|
cleaned = lastPart;
|
|
@@ -237,7 +246,7 @@ export class OpenAPIToConnector {
|
|
|
237
246
|
|
|
238
247
|
// Use the last path segment before the method name as a distinguishing prefix
|
|
239
248
|
if (pathParts.length > 0) {
|
|
240
|
-
const prefix = pathParts[pathParts.length - 1];
|
|
249
|
+
const prefix = pathParts[pathParts.length - 1].replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
241
250
|
const capitalizedBase = baseName.charAt(0).toUpperCase() + baseName.slice(1);
|
|
242
251
|
return `${prefix}${capitalizedBase}`;
|
|
243
252
|
}
|
|
@@ -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);
|