@sdk-it/spec 0.21.0 → 0.22.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.
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2629 -2
- package/dist/index.js.map +4 -4
- package/dist/lib/find-polymorphic-varients.d.ts +15 -0
- package/dist/lib/find-polymorphic-varients.d.ts.map +1 -0
- package/dist/lib/find-polymorphic-varients.test.d.ts +2 -0
- package/dist/lib/find-polymorphic-varients.test.d.ts.map +1 -0
- package/dist/lib/find-unique-schema-name.d.ts +3 -0
- package/dist/lib/find-unique-schema-name.d.ts.map +1 -0
- package/dist/lib/format-name.d.ts +2 -0
- package/dist/lib/format-name.d.ts.map +1 -0
- package/dist/lib/get-ref-usage.d.ts +3 -0
- package/dist/lib/get-ref-usage.d.ts.map +1 -0
- package/dist/lib/is-primitive-schema.d.ts +3 -0
- package/dist/lib/is-primitive-schema.d.ts.map +1 -0
- package/dist/lib/loaders/load-spec.d.ts.map +1 -1
- package/dist/lib/loaders/postman/postman-converter.d.ts.map +1 -1
- package/dist/lib/metadata.d.ts +22 -0
- package/dist/lib/metadata.d.ts.map +1 -0
- package/dist/lib/operation.d.ts +62 -18
- package/dist/lib/operation.d.ts.map +1 -1
- package/dist/lib/pagination/pagination-result.d.ts.map +1 -1
- package/dist/lib/pagination/pagination.d.ts +1 -1
- package/dist/lib/pagination/pagination.d.ts.map +1 -1
- package/dist/lib/security.d.ts +10 -0
- package/dist/lib/security.d.ts.map +1 -0
- package/dist/lib/sidebar.d.ts +2 -2
- package/dist/lib/sidebar.d.ts.map +1 -1
- package/dist/lib/tune.d.ts +11 -0
- package/dist/lib/tune.d.ts.map +1 -0
- package/dist/lib/tune.test.d.ts +2 -0
- package/dist/lib/tune.test.d.ts.map +1 -0
- package/package.json +8 -4
- package/dist/lib/loaders/load-spec.js +0 -27
- package/dist/lib/loaders/load-spec.js.map +0 -7
- package/dist/lib/loaders/local-loader.js +0 -20
- package/dist/lib/loaders/local-loader.js.map +0 -7
- package/dist/lib/loaders/postman/postman-converter.js +0 -486
- package/dist/lib/loaders/postman/postman-converter.js.map +0 -7
- package/dist/lib/loaders/postman/spec-types.js +0 -1
- package/dist/lib/loaders/postman/spec-types.js.map +0 -7
- package/dist/lib/loaders/remote-loader.js +0 -29
- package/dist/lib/loaders/remote-loader.js.map +0 -7
- package/dist/lib/operation.js +0 -425
- package/dist/lib/operation.js.map +0 -7
- package/dist/lib/operation.test.js +0 -261
- package/dist/lib/operation.test.js.map +0 -7
- package/dist/lib/pagination/pagination-result.js +0 -237
- package/dist/lib/pagination/pagination-result.js.map +0 -7
- package/dist/lib/pagination/pagination-result.test.js +0 -548
- package/dist/lib/pagination/pagination-result.test.js.map +0 -7
- package/dist/lib/pagination/pagination.js +0 -199
- package/dist/lib/pagination/pagination.js.map +0 -7
- package/dist/lib/pagination/pagination.test.js +0 -380
- package/dist/lib/pagination/pagination.test.js.map +0 -7
- package/dist/lib/sidebar.js +0 -81
- package/dist/lib/sidebar.js.map +0 -7
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { describe, test } from "node:test";
|
|
3
|
-
import { determineGenericTag } from "./operation.ts";
|
|
4
|
-
const mockOperation = (operationId = "") => ({ operationId });
|
|
5
|
-
describe("determineGenericTag", () => {
|
|
6
|
-
describe("Heuristic 1: Path-Based Tag Determination", () => {
|
|
7
|
-
test("should use the last non-parameter, non-version, non-@ segment", () => {
|
|
8
|
-
assert.strictEqual(
|
|
9
|
-
determineGenericTag("/users", mockOperation()),
|
|
10
|
-
"users"
|
|
11
|
-
);
|
|
12
|
-
assert.strictEqual(
|
|
13
|
-
determineGenericTag("/users/{userId}/orders", mockOperation()),
|
|
14
|
-
"orders"
|
|
15
|
-
);
|
|
16
|
-
assert.strictEqual(
|
|
17
|
-
determineGenericTag("/admin/system/logs", mockOperation()),
|
|
18
|
-
"logs"
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
test("should ignore path parameters", () => {
|
|
22
|
-
assert.strictEqual(
|
|
23
|
-
determineGenericTag("/users/{userId}", mockOperation()),
|
|
24
|
-
"users"
|
|
25
|
-
);
|
|
26
|
-
assert.strictEqual(
|
|
27
|
-
determineGenericTag("/items/{itemId}", mockOperation()),
|
|
28
|
-
"items"
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
test("should ignore version segments", () => {
|
|
32
|
-
assert.strictEqual(
|
|
33
|
-
determineGenericTag("/v1/products", mockOperation()),
|
|
34
|
-
"products"
|
|
35
|
-
);
|
|
36
|
-
assert.strictEqual(
|
|
37
|
-
determineGenericTag("/api/V2/items/{itemId}/details", mockOperation()),
|
|
38
|
-
"details"
|
|
39
|
-
);
|
|
40
|
-
assert.strictEqual(
|
|
41
|
-
determineGenericTag("/api/resource/v2", mockOperation()),
|
|
42
|
-
"resource"
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
test("should ignore segments starting with @", () => {
|
|
46
|
-
assert.strictEqual(
|
|
47
|
-
determineGenericTag("/users/@me", mockOperation()),
|
|
48
|
-
"users"
|
|
49
|
-
);
|
|
50
|
-
assert.strictEqual(
|
|
51
|
-
determineGenericTag("/users/@me/guilds", mockOperation()),
|
|
52
|
-
"guilds"
|
|
53
|
-
);
|
|
54
|
-
assert.strictEqual(
|
|
55
|
-
determineGenericTag(
|
|
56
|
-
"/webhooks/{webhookId}/messages/@original",
|
|
57
|
-
mockOperation()
|
|
58
|
-
),
|
|
59
|
-
"messages"
|
|
60
|
-
);
|
|
61
|
-
assert.strictEqual(
|
|
62
|
-
determineGenericTag("/@admin/users/{userId}", mockOperation()),
|
|
63
|
-
"users"
|
|
64
|
-
);
|
|
65
|
-
assert.strictEqual(
|
|
66
|
-
determineGenericTag(
|
|
67
|
-
"/guilds/{guild_id}/@audit-log/users/@me/settings",
|
|
68
|
-
mockOperation()
|
|
69
|
-
),
|
|
70
|
-
"settings"
|
|
71
|
-
);
|
|
72
|
-
assert.strictEqual(
|
|
73
|
-
determineGenericTag("/system/tasks/@scheduled-jobs", mockOperation()),
|
|
74
|
-
"tasks"
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
test("should sanitize results matching reserved keywords", () => {
|
|
78
|
-
assert.strictEqual(
|
|
79
|
-
determineGenericTag("/api/v1/public", mockOperation()),
|
|
80
|
-
"public_"
|
|
81
|
-
);
|
|
82
|
-
assert.strictEqual(
|
|
83
|
-
determineGenericTag("/api/case/{id}", mockOperation()),
|
|
84
|
-
"case_"
|
|
85
|
-
);
|
|
86
|
-
assert.strictEqual(
|
|
87
|
-
determineGenericTag("/permissions/check", mockOperation()),
|
|
88
|
-
"check_"
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
test("should sanitize results starting with numbers", () => {
|
|
92
|
-
assert.strictEqual(
|
|
93
|
-
determineGenericTag("/api/2fa/enable", mockOperation()),
|
|
94
|
-
"enable"
|
|
95
|
-
);
|
|
96
|
-
});
|
|
97
|
-
test("should handle mixed separators via camelcase", () => {
|
|
98
|
-
assert.strictEqual(
|
|
99
|
-
determineGenericTag("/user-profiles/{id}", mockOperation()),
|
|
100
|
-
"userProfiles"
|
|
101
|
-
);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe("Heuristic 2: OperationId Fallback", () => {
|
|
105
|
-
test("should be used when path has no valid segments (root)", () => {
|
|
106
|
-
assert.strictEqual(
|
|
107
|
-
determineGenericTag("/", mockOperation("getRootResource")),
|
|
108
|
-
"rootResource"
|
|
109
|
-
);
|
|
110
|
-
assert.strictEqual(
|
|
111
|
-
determineGenericTag("/", mockOperation("healthCheck")),
|
|
112
|
-
"healthCheck"
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
test("should be used when path has only params/version segments", () => {
|
|
116
|
-
assert.strictEqual(
|
|
117
|
-
determineGenericTag("/v3/{tenantId}/", mockOperation("getTenantRoot")),
|
|
118
|
-
"tenantRoot"
|
|
119
|
-
);
|
|
120
|
-
assert.strictEqual(
|
|
121
|
-
determineGenericTag("/v1/{userId}/", mockOperation("listUserItems")),
|
|
122
|
-
"userItems"
|
|
123
|
-
);
|
|
124
|
-
});
|
|
125
|
-
test("should extract nouns after common verb prefixes", () => {
|
|
126
|
-
assert.strictEqual(
|
|
127
|
-
determineGenericTag("/v1/", mockOperation("postUserPreferences")),
|
|
128
|
-
"userPreferences"
|
|
129
|
-
);
|
|
130
|
-
assert.strictEqual(
|
|
131
|
-
determineGenericTag("/v1/", mockOperation("doFoo")),
|
|
132
|
-
"foo"
|
|
133
|
-
);
|
|
134
|
-
assert.strictEqual(
|
|
135
|
-
determineGenericTag("/v1/", mockOperation("addUser")),
|
|
136
|
-
"user"
|
|
137
|
-
);
|
|
138
|
-
assert.strictEqual(
|
|
139
|
-
determineGenericTag("/v1/", mockOperation("makePublic")),
|
|
140
|
-
"public_"
|
|
141
|
-
);
|
|
142
|
-
});
|
|
143
|
-
test("should use the full operationId if no common verb prefix", () => {
|
|
144
|
-
assert.strictEqual(
|
|
145
|
-
determineGenericTag("/v1/", mockOperation("metrics")),
|
|
146
|
-
"metrics"
|
|
147
|
-
);
|
|
148
|
-
assert.strictEqual(
|
|
149
|
-
determineGenericTag("/v1/", mockOperation("tenantAdminSettings")),
|
|
150
|
-
"tenantAdminSettings"
|
|
151
|
-
);
|
|
152
|
-
});
|
|
153
|
-
test("should handle numbers within the operationId correctly", () => {
|
|
154
|
-
assert.strictEqual(
|
|
155
|
-
determineGenericTag("/v1/", mockOperation("getUser2FAStatus")),
|
|
156
|
-
"user2FAStatus"
|
|
157
|
-
);
|
|
158
|
-
assert.strictEqual(
|
|
159
|
-
determineGenericTag("/api/", mockOperation("get2FAStatus")),
|
|
160
|
-
"api"
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
test("should sanitize results matching reserved keywords", () => {
|
|
164
|
-
assert.strictEqual(
|
|
165
|
-
determineGenericTag("/v1/{id}", mockOperation("delete")),
|
|
166
|
-
"delete_"
|
|
167
|
-
);
|
|
168
|
-
assert.strictEqual(
|
|
169
|
-
determineGenericTag("/v1/{id}", mockOperation("createCase")),
|
|
170
|
-
"case_"
|
|
171
|
-
);
|
|
172
|
-
assert.strictEqual(
|
|
173
|
-
determineGenericTag("/v1/{id}", mockOperation("get")),
|
|
174
|
-
"get_"
|
|
175
|
-
);
|
|
176
|
-
});
|
|
177
|
-
test("should use verb if it is the only part and no path fallback", () => {
|
|
178
|
-
assert.strictEqual(
|
|
179
|
-
determineGenericTag("/v1/", mockOperation("get")),
|
|
180
|
-
"get_"
|
|
181
|
-
);
|
|
182
|
-
assert.strictEqual(
|
|
183
|
-
determineGenericTag("/v1/{id}", mockOperation("list")),
|
|
184
|
-
"list_"
|
|
185
|
-
);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
describe("Heuristic 3: First Path Segment Fallback", () => {
|
|
189
|
-
test("should be used when path only has @ segments and no suitable opId", () => {
|
|
190
|
-
assert.strictEqual(
|
|
191
|
-
determineGenericTag("/@system/@status", mockOperation()),
|
|
192
|
-
"system"
|
|
193
|
-
);
|
|
194
|
-
assert.strictEqual(
|
|
195
|
-
determineGenericTag("/@audit-log/@entries", mockOperation()),
|
|
196
|
-
"auditLog"
|
|
197
|
-
);
|
|
198
|
-
});
|
|
199
|
-
test("should be used when opId fallback yields only a common verb", () => {
|
|
200
|
-
assert.strictEqual(
|
|
201
|
-
determineGenericTag("/@system/@status", mockOperation("get")),
|
|
202
|
-
"system"
|
|
203
|
-
);
|
|
204
|
-
});
|
|
205
|
-
test("should strip leading @ before using segment", () => {
|
|
206
|
-
assert.strictEqual(
|
|
207
|
-
determineGenericTag("/@system/@status", mockOperation()),
|
|
208
|
-
"system"
|
|
209
|
-
);
|
|
210
|
-
});
|
|
211
|
-
test("should sanitize results matching reserved keywords", () => {
|
|
212
|
-
assert.strictEqual(
|
|
213
|
-
determineGenericTag("/@public/@data", mockOperation()),
|
|
214
|
-
"public_"
|
|
215
|
-
);
|
|
216
|
-
});
|
|
217
|
-
test("should sanitize results starting with numbers", () => {
|
|
218
|
-
assert.strictEqual(
|
|
219
|
-
determineGenericTag("/@2fa/@status", mockOperation()),
|
|
220
|
-
"_2fa"
|
|
221
|
-
);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
describe("Heuristic Priority", () => {
|
|
225
|
-
test("Path (Heuristic 1) should take priority over OperationId (Heuristic 2)", () => {
|
|
226
|
-
const tag = determineGenericTag(
|
|
227
|
-
"/users/{id}/permissions/check",
|
|
228
|
-
// Path -> 'check' -> sanitized 'check_'
|
|
229
|
-
mockOperation("verifyPermissions")
|
|
230
|
-
// opId -> 'permissions'
|
|
231
|
-
);
|
|
232
|
-
assert.strictEqual(tag, "check_");
|
|
233
|
-
});
|
|
234
|
-
test("OperationId (Heuristic 2) should take priority over First Path Segment (Heuristic 3)", () => {
|
|
235
|
-
const tag = determineGenericTag(
|
|
236
|
-
"/@system/@status",
|
|
237
|
-
mockOperation("getSystemStatus")
|
|
238
|
-
);
|
|
239
|
-
assert.strictEqual(tag, "systemStatus");
|
|
240
|
-
});
|
|
241
|
-
test("First Path Segment (Heuristic 3) is used if OperationId is skipped (verb-only)", () => {
|
|
242
|
-
const tag = determineGenericTag("/@system/@status", mockOperation("get"));
|
|
243
|
-
assert.strictEqual(tag, "system");
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
describe("Heuristic 4: Unknown Fallback", () => {
|
|
247
|
-
test('should return "unknown" when no path segments and no operationId', () => {
|
|
248
|
-
assert.strictEqual(determineGenericTag("/", mockOperation()), "unknown");
|
|
249
|
-
});
|
|
250
|
-
test('should return "unknown" when path has only params/version and no operationId', () => {
|
|
251
|
-
assert.strictEqual(
|
|
252
|
-
determineGenericTag("/v3/{tenantId}/", mockOperation()),
|
|
253
|
-
"unknown"
|
|
254
|
-
);
|
|
255
|
-
});
|
|
256
|
-
test('should return "unknown" for empty path string', () => {
|
|
257
|
-
assert.strictEqual(determineGenericTag("", mockOperation()), "unknown");
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
//# sourceMappingURL=operation.test.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/lib/operation.test.ts"],
|
|
4
|
-
"sourcesContent": ["import assert from 'node:assert/strict';\nimport { describe, test } from 'node:test';\nimport type { OperationObject } from 'openapi3-ts/oas31';\n\nimport { determineGenericTag } from './operation.ts';\n\nconst mockOperation = (operationId = ''): OperationObject => ({ operationId });\n\ndescribe('determineGenericTag', () => {\n describe('Heuristic 1: Path-Based Tag Determination', () => {\n test('should use the last non-parameter, non-version, non-@ segment', () => {\n assert.strictEqual(\n determineGenericTag('/users', mockOperation()),\n 'users',\n );\n assert.strictEqual(\n determineGenericTag('/users/{userId}/orders', mockOperation()),\n 'orders',\n );\n assert.strictEqual(\n determineGenericTag('/admin/system/logs', mockOperation()),\n 'logs',\n );\n });\n\n test('should ignore path parameters', () => {\n assert.strictEqual(\n determineGenericTag('/users/{userId}', mockOperation()),\n 'users',\n );\n assert.strictEqual(\n determineGenericTag('/items/{itemId}', mockOperation()),\n 'items',\n );\n });\n\n test('should ignore version segments', () => {\n assert.strictEqual(\n determineGenericTag('/v1/products', mockOperation()),\n 'products',\n );\n assert.strictEqual(\n determineGenericTag('/api/V2/items/{itemId}/details', mockOperation()),\n 'details',\n );\n assert.strictEqual(\n determineGenericTag('/api/resource/v2', mockOperation()),\n 'resource',\n );\n });\n\n test('should ignore segments starting with @', () => {\n assert.strictEqual(\n determineGenericTag('/users/@me', mockOperation()),\n 'users',\n );\n assert.strictEqual(\n determineGenericTag('/users/@me/guilds', mockOperation()),\n 'guilds',\n );\n assert.strictEqual(\n determineGenericTag(\n '/webhooks/{webhookId}/messages/@original',\n mockOperation(),\n ),\n 'messages',\n );\n assert.strictEqual(\n determineGenericTag('/@admin/users/{userId}', mockOperation()),\n 'users',\n );\n assert.strictEqual(\n determineGenericTag(\n '/guilds/{guild_id}/@audit-log/users/@me/settings',\n mockOperation(),\n ),\n 'settings',\n );\n assert.strictEqual(\n determineGenericTag('/system/tasks/@scheduled-jobs', mockOperation()),\n 'tasks',\n );\n });\n\n test('should sanitize results matching reserved keywords', () => {\n assert.strictEqual(\n determineGenericTag('/api/v1/public', mockOperation()),\n 'public_',\n );\n assert.strictEqual(\n determineGenericTag('/api/case/{id}', mockOperation()),\n 'case_',\n );\n assert.strictEqual(\n determineGenericTag('/permissions/check', mockOperation()),\n 'check_',\n );\n });\n\n test('should sanitize results starting with numbers', () => {\n // FIX: Expectation changed - last valid segment is 'enable'\n assert.strictEqual(\n determineGenericTag('/api/2fa/enable', mockOperation()),\n 'enable',\n );\n });\n\n test('should handle mixed separators via camelcase', () => {\n assert.strictEqual(\n determineGenericTag('/user-profiles/{id}', mockOperation()),\n 'userProfiles',\n );\n });\n });\n\n describe('Heuristic 2: OperationId Fallback', () => {\n test('should be used when path has no valid segments (root)', () => {\n assert.strictEqual(\n determineGenericTag('/', mockOperation('getRootResource')),\n 'rootResource',\n );\n // FIX: Expectation changed - 'healthCheck' is not reserved\n assert.strictEqual(\n determineGenericTag('/', mockOperation('healthCheck')),\n 'healthCheck',\n );\n });\n\n test('should be used when path has only params/version segments', () => {\n assert.strictEqual(\n determineGenericTag('/v3/{tenantId}/', mockOperation('getTenantRoot')),\n 'tenantRoot',\n );\n assert.strictEqual(\n determineGenericTag('/v1/{userId}/', mockOperation('listUserItems')),\n 'userItems',\n );\n });\n\n test('should extract nouns after common verb prefixes', () => {\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('postUserPreferences')),\n 'userPreferences',\n );\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('doFoo')),\n 'foo',\n );\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('addUser')),\n 'user',\n );\n // FIX: Added 'make' to commonVerbs\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('makePublic')),\n 'public_',\n );\n });\n\n test('should use the full operationId if no common verb prefix', () => {\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('metrics')),\n 'metrics',\n );\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('tenantAdminSettings')),\n 'tenantAdminSettings',\n );\n });\n\n test('should handle numbers within the operationId correctly', () => {\n // FIX: Expectation aligned with stringcase behavior\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('getUser2FAStatus')),\n 'user2FAStatus',\n );\n assert.strictEqual(\n determineGenericTag('/api/', mockOperation('get2FAStatus')),\n 'api',\n ); // Sanitized (starts with number after verb removal)\n });\n\n test('should sanitize results matching reserved keywords', () => {\n assert.strictEqual(\n determineGenericTag('/v1/{id}', mockOperation('delete')),\n 'delete_',\n );\n assert.strictEqual(\n determineGenericTag('/v1/{id}', mockOperation('createCase')),\n 'case_',\n );\n assert.strictEqual(\n determineGenericTag('/v1/{id}', mockOperation('get')),\n 'get_',\n );\n });\n\n test('should use verb if it is the only part and no path fallback', () => {\n assert.strictEqual(\n determineGenericTag('/v1/', mockOperation('get')),\n 'get_',\n );\n assert.strictEqual(\n determineGenericTag('/v1/{id}', mockOperation('list')),\n 'list_',\n );\n });\n });\n\n describe('Heuristic 3: First Path Segment Fallback', () => {\n test('should be used when path only has @ segments and no suitable opId', () => {\n assert.strictEqual(\n determineGenericTag('/@system/@status', mockOperation()),\n 'system',\n );\n assert.strictEqual(\n determineGenericTag('/@audit-log/@entries', mockOperation()),\n 'auditLog',\n );\n });\n\n test('should be used when opId fallback yields only a common verb', () => {\n assert.strictEqual(\n determineGenericTag('/@system/@status', mockOperation('get')),\n 'system',\n );\n });\n\n test('should strip leading @ before using segment', () => {\n assert.strictEqual(\n determineGenericTag('/@system/@status', mockOperation()),\n 'system',\n );\n });\n\n test('should sanitize results matching reserved keywords', () => {\n assert.strictEqual(\n determineGenericTag('/@public/@data', mockOperation()),\n 'public_',\n );\n });\n\n test('should sanitize results starting with numbers', () => {\n assert.strictEqual(\n determineGenericTag('/@2fa/@status', mockOperation()),\n '_2fa',\n );\n });\n });\n\n describe('Heuristic Priority', () => {\n test('Path (Heuristic 1) should take priority over OperationId (Heuristic 2)', () => {\n const tag = determineGenericTag(\n '/users/{id}/permissions/check', // Path -> 'check' -> sanitized 'check_'\n mockOperation('verifyPermissions'), // opId -> 'permissions'\n );\n assert.strictEqual(tag, 'check_');\n });\n\n test('OperationId (Heuristic 2) should take priority over First Path Segment (Heuristic 3)', () => {\n const tag = determineGenericTag(\n '/@system/@status',\n mockOperation('getSystemStatus'),\n );\n assert.strictEqual(tag, 'systemStatus');\n });\n\n test('First Path Segment (Heuristic 3) is used if OperationId is skipped (verb-only)', () => {\n const tag = determineGenericTag('/@system/@status', mockOperation('get'));\n assert.strictEqual(tag, 'system');\n });\n });\n\n describe('Heuristic 4: Unknown Fallback', () => {\n test('should return \"unknown\" when no path segments and no operationId', () => {\n assert.strictEqual(determineGenericTag('/', mockOperation()), 'unknown');\n });\n\n test('should return \"unknown\" when path has only params/version and no operationId', () => {\n assert.strictEqual(\n determineGenericTag('/v3/{tenantId}/', mockOperation()),\n 'unknown',\n );\n });\n\n test('should return \"unknown\" for empty path string', () => {\n assert.strictEqual(determineGenericTag('', mockOperation()), 'unknown');\n });\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import pluralize from "pluralize";
|
|
2
|
-
const PRIMARY_TOP_TIER_KEYWORDS = [
|
|
3
|
-
"data",
|
|
4
|
-
"items",
|
|
5
|
-
"results",
|
|
6
|
-
"value"
|
|
7
|
-
];
|
|
8
|
-
const PRIMARY_OTHER_KEYWORDS = [
|
|
9
|
-
"records",
|
|
10
|
-
"content",
|
|
11
|
-
"list",
|
|
12
|
-
"payload",
|
|
13
|
-
"entities",
|
|
14
|
-
"collection",
|
|
15
|
-
"users",
|
|
16
|
-
"products",
|
|
17
|
-
"orders",
|
|
18
|
-
"bookings",
|
|
19
|
-
"articles",
|
|
20
|
-
"posts",
|
|
21
|
-
"documents",
|
|
22
|
-
"events"
|
|
23
|
-
];
|
|
24
|
-
const SECONDARY_KEYWORDS = ["entries", "rows", "elements"];
|
|
25
|
-
const PLURAL_DEPRIORITIZE_LIST = [
|
|
26
|
-
"status",
|
|
27
|
-
"success",
|
|
28
|
-
"address",
|
|
29
|
-
"details",
|
|
30
|
-
"properties",
|
|
31
|
-
"params",
|
|
32
|
-
"headers",
|
|
33
|
-
"cookies",
|
|
34
|
-
"series",
|
|
35
|
-
"links",
|
|
36
|
-
"meta",
|
|
37
|
-
"metadata",
|
|
38
|
-
"statistics",
|
|
39
|
-
"settings",
|
|
40
|
-
"options",
|
|
41
|
-
"permissions",
|
|
42
|
-
"credentials",
|
|
43
|
-
"diagnostics",
|
|
44
|
-
"warnings",
|
|
45
|
-
"errors",
|
|
46
|
-
"actions",
|
|
47
|
-
"attributes",
|
|
48
|
-
"categories",
|
|
49
|
-
"features",
|
|
50
|
-
"includes",
|
|
51
|
-
"tags"
|
|
52
|
-
];
|
|
53
|
-
const HAS_MORE_PRIMARY_POSITIVE_EXACT = [
|
|
54
|
-
"hasmore",
|
|
55
|
-
"hasnext",
|
|
56
|
-
"hasnextpage",
|
|
57
|
-
"moreitems",
|
|
58
|
-
"moreitemsavailable",
|
|
59
|
-
"nextpage",
|
|
60
|
-
"nextpageexists",
|
|
61
|
-
"nextpageavailable",
|
|
62
|
-
"hasadditionalresults",
|
|
63
|
-
"moreresultsavailable",
|
|
64
|
-
"canloadmore",
|
|
65
|
-
"hasadditional",
|
|
66
|
-
"additionalitems",
|
|
67
|
-
"fetchmore"
|
|
68
|
-
];
|
|
69
|
-
const HAS_MORE_SECONDARY_POSITIVE_EXACT = ["more", "next"];
|
|
70
|
-
const HAS_MORE_PRIMARY_INVERTED_EXACT = [
|
|
71
|
-
"islast",
|
|
72
|
-
"lastpage",
|
|
73
|
-
"endofresults",
|
|
74
|
-
"endoflist",
|
|
75
|
-
"nomoreitems",
|
|
76
|
-
"nomoredata",
|
|
77
|
-
"allitemsloaded",
|
|
78
|
-
"iscomplete",
|
|
79
|
-
"completed"
|
|
80
|
-
];
|
|
81
|
-
const HAS_MORE_POSITIVE_REGEX_PATTERNS = [
|
|
82
|
-
"\\bhas_?more\\b",
|
|
83
|
-
"\\bhas_?next\\b",
|
|
84
|
-
// e.g., itemsHasNext, items_has_next
|
|
85
|
-
"\\bmore_?items\\b",
|
|
86
|
-
"\\bnext_?page\\b",
|
|
87
|
-
// e.g., userNextPageFlag
|
|
88
|
-
"\\badditional\\b",
|
|
89
|
-
// e.g., hasAdditionalData, additional_results_exist
|
|
90
|
-
"\\bcontinuation\\b",
|
|
91
|
-
// e.g., continuationAvailable, has_continuation_token
|
|
92
|
-
"\\bmore_?results\\b",
|
|
93
|
-
"\\bpage_?available\\b",
|
|
94
|
-
"\\bnext(?:_?(page))?\\b"
|
|
95
|
-
];
|
|
96
|
-
const COMPILED_HAS_MORE_POSITIVE_REGEXES = HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
|
|
97
|
-
const HAS_MORE_INVERTED_REGEX_PATTERNS = [
|
|
98
|
-
"\\bis_?last\\b",
|
|
99
|
-
// e.g., pageIsLast
|
|
100
|
-
"\\blast_?page\\b",
|
|
101
|
-
// e.g., resultsAreLastPage
|
|
102
|
-
"\\bend_?of_?(data|results|list|items|stream)\\b",
|
|
103
|
-
"\\bno_?more_?(items|data|results)?\\b",
|
|
104
|
-
"\\ball_?(items_?)?loaded\\b",
|
|
105
|
-
"\\bis_?complete\\b"
|
|
106
|
-
];
|
|
107
|
-
const COMPILED_HAS_MORE_INVERTED_REGEXES = HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
|
|
108
|
-
function getItemsName(properties) {
|
|
109
|
-
const arrayPropertyNames = [];
|
|
110
|
-
for (const propName in properties) {
|
|
111
|
-
if (propName in properties) {
|
|
112
|
-
const propSchema = properties[propName];
|
|
113
|
-
if (propSchema && propSchema.type === "array") {
|
|
114
|
-
arrayPropertyNames.push(propName);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (arrayPropertyNames.length === 0) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
if (arrayPropertyNames.length === 1) {
|
|
122
|
-
return arrayPropertyNames[0];
|
|
123
|
-
}
|
|
124
|
-
let bestCandidate = null;
|
|
125
|
-
let candidateRank = Infinity;
|
|
126
|
-
const updateCandidate = (propName, rank) => {
|
|
127
|
-
if (rank < candidateRank) {
|
|
128
|
-
bestCandidate = propName;
|
|
129
|
-
candidateRank = rank;
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
for (const propName of arrayPropertyNames) {
|
|
133
|
-
const lowerPropName = propName.toLowerCase();
|
|
134
|
-
if (PRIMARY_TOP_TIER_KEYWORDS.includes(lowerPropName)) {
|
|
135
|
-
updateCandidate(propName, 2);
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (candidateRank > 3 && PRIMARY_OTHER_KEYWORDS.includes(lowerPropName)) {
|
|
139
|
-
updateCandidate(propName, 3);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
if (candidateRank > 4 && SECONDARY_KEYWORDS.includes(lowerPropName)) {
|
|
143
|
-
updateCandidate(propName, 4);
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
if (candidateRank > 5 && pluralize.isPlural(propName) && !PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
|
|
147
|
-
updateCandidate(propName, 5);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
if (candidateRank > 6 && pluralize.isPlural(propName) && PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
|
|
151
|
-
updateCandidate(propName, 6);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (bestCandidate) {
|
|
156
|
-
return bestCandidate;
|
|
157
|
-
}
|
|
158
|
-
return arrayPropertyNames[0];
|
|
159
|
-
}
|
|
160
|
-
function guess(properties) {
|
|
161
|
-
const booleanPropertyNames = [];
|
|
162
|
-
for (const propName in properties) {
|
|
163
|
-
if (Object.prototype.hasOwnProperty.call(properties, propName)) {
|
|
164
|
-
const propSchema = properties[propName];
|
|
165
|
-
if (propSchema && propSchema.type === "boolean" || propSchema.type === "integer") {
|
|
166
|
-
booleanPropertyNames.push(propName);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (booleanPropertyNames.length === 0) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
if (booleanPropertyNames.length === 1) {
|
|
174
|
-
return booleanPropertyNames[0];
|
|
175
|
-
}
|
|
176
|
-
let bestCandidate = null;
|
|
177
|
-
let candidateRank = Infinity;
|
|
178
|
-
const updateCandidate = (propName, rank) => {
|
|
179
|
-
if (rank < candidateRank) {
|
|
180
|
-
bestCandidate = propName;
|
|
181
|
-
candidateRank = rank;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
for (const propName of booleanPropertyNames) {
|
|
185
|
-
const normalizedForExactMatch = propName.toLowerCase().replace(/[-_]/g, "");
|
|
186
|
-
let currentPropRank = Infinity;
|
|
187
|
-
if (HAS_MORE_PRIMARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
|
|
188
|
-
currentPropRank = 1;
|
|
189
|
-
} else if (HAS_MORE_SECONDARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
|
|
190
|
-
currentPropRank = 2;
|
|
191
|
-
} else {
|
|
192
|
-
let foundPositiveRegex = false;
|
|
193
|
-
for (const regex of COMPILED_HAS_MORE_POSITIVE_REGEXES) {
|
|
194
|
-
if (regex.test(propName)) {
|
|
195
|
-
currentPropRank = 3;
|
|
196
|
-
foundPositiveRegex = true;
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (!foundPositiveRegex) {
|
|
201
|
-
if (HAS_MORE_PRIMARY_INVERTED_EXACT.includes(normalizedForExactMatch)) {
|
|
202
|
-
currentPropRank = 4;
|
|
203
|
-
} else {
|
|
204
|
-
for (const regex of COMPILED_HAS_MORE_INVERTED_REGEXES) {
|
|
205
|
-
if (regex.test(propName)) {
|
|
206
|
-
currentPropRank = 5;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
updateCandidate(propName, currentPropRank);
|
|
214
|
-
}
|
|
215
|
-
return bestCandidate;
|
|
216
|
-
}
|
|
217
|
-
function getHasMoreName(properties) {
|
|
218
|
-
const rootGuess = guess(properties);
|
|
219
|
-
if (rootGuess) {
|
|
220
|
-
return rootGuess;
|
|
221
|
-
}
|
|
222
|
-
for (const propName in properties) {
|
|
223
|
-
const propSchema = properties[propName];
|
|
224
|
-
if (propSchema.type === "object" && propSchema.properties) {
|
|
225
|
-
const nested = getHasMoreName(propSchema.properties);
|
|
226
|
-
if (nested) {
|
|
227
|
-
return propName + "." + nested;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
export {
|
|
234
|
-
getHasMoreName,
|
|
235
|
-
getItemsName
|
|
236
|
-
};
|
|
237
|
-
//# sourceMappingURL=pagination-result.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/lib/pagination/pagination-result.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SchemaObject, SchemasObject } from 'openapi3-ts/oas31';\nimport pluralize from 'pluralize';\n\nconst PRIMARY_TOP_TIER_KEYWORDS: string[] = [\n 'data',\n 'items',\n 'results',\n 'value',\n];\nconst PRIMARY_OTHER_KEYWORDS: string[] = [\n 'records',\n 'content',\n 'list',\n 'payload',\n 'entities',\n 'collection',\n 'users',\n 'products',\n 'orders',\n 'bookings',\n 'articles',\n 'posts',\n 'documents',\n 'events',\n];\nconst SECONDARY_KEYWORDS: string[] = ['entries', 'rows', 'elements'];\n\nconst PLURAL_DEPRIORITIZE_LIST: string[] = [\n 'status',\n 'success',\n 'address',\n 'details',\n 'properties',\n 'params',\n 'headers',\n 'cookies',\n 'series',\n 'links',\n 'meta',\n 'metadata',\n 'statistics',\n 'settings',\n 'options',\n 'permissions',\n 'credentials',\n 'diagnostics',\n 'warnings',\n 'errors',\n 'actions',\n 'attributes',\n 'categories',\n 'features',\n 'includes',\n 'tags',\n];\n\n// For exact matches (normalized: lowercase, no underscores/hyphens)\nconst HAS_MORE_PRIMARY_POSITIVE_EXACT: string[] = [\n 'hasmore',\n 'hasnext',\n 'hasnextpage',\n 'moreitems',\n 'moreitemsavailable',\n 'nextpage',\n 'nextpageexists',\n 'nextpageavailable',\n 'hasadditionalresults',\n 'moreresultsavailable',\n 'canloadmore',\n 'hasadditional',\n 'additionalitems',\n 'fetchmore',\n];\n\nconst HAS_MORE_SECONDARY_POSITIVE_EXACT: string[] = ['more', 'next'];\n\nconst HAS_MORE_PRIMARY_INVERTED_EXACT: string[] = [\n 'islast',\n 'lastpage',\n 'endofresults',\n 'endoflist',\n 'nomoreitems',\n 'nomoredata',\n 'allitemsloaded',\n 'iscomplete',\n 'completed',\n];\n\n// For regex-based sub-phrase matching (tested against original propName, case-insensitive)\n// These regexes look for meaningful phrases, often using word boundaries (\\b)\n// and allowing for optional underscores.\nconst HAS_MORE_POSITIVE_REGEX_PATTERNS: string[] = [\n '\\\\bhas_?more\\\\b',\n '\\\\bhas_?next\\\\b', // e.g., itemsHasNext, items_has_next\n '\\\\bmore_?items\\\\b',\n '\\\\bnext_?page\\\\b', // e.g., userNextPageFlag\n '\\\\badditional\\\\b', // e.g., hasAdditionalData, additional_results_exist\n '\\\\bcontinuation\\\\b', // e.g., continuationAvailable, has_continuation_token\n '\\\\bmore_?results\\\\b',\n '\\\\bpage_?available\\\\b',\n '\\\\bnext(?:_?(page))?\\\\b',\n];\nconst COMPILED_HAS_MORE_POSITIVE_REGEXES: RegExp[] =\n HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, 'i'));\n\nconst HAS_MORE_INVERTED_REGEX_PATTERNS: string[] = [\n '\\\\bis_?last\\\\b', // e.g., pageIsLast\n '\\\\blast_?page\\\\b', // e.g., resultsAreLastPage\n '\\\\bend_?of_?(data|results|list|items|stream)\\\\b',\n '\\\\bno_?more_?(items|data|results)?\\\\b',\n '\\\\ball_?(items_?)?loaded\\\\b',\n '\\\\bis_?complete\\\\b',\n];\nconst COMPILED_HAS_MORE_INVERTED_REGEXES: RegExp[] =\n HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, 'i'));\n\n/**\n * Tries to guess the name of the property that holds the main list of items\n * within an object schema using a series of heuristics.\n *\n * @param schema The OpenAPI SchemaObject, expected to be of type 'object'.\n * @returns The name of the most likely property containing the items array,\n * or null if no array properties are found in the schema.\n */\nexport function getItemsName(\n properties: Record<string, SchemaObject>,\n): string | null {\n const arrayPropertyNames: string[] = [];\n for (const propName in properties) {\n if (propName in properties) {\n const propSchema = properties[propName] as SchemaObject;\n if (propSchema && propSchema.type === 'array') {\n arrayPropertyNames.push(propName);\n }\n }\n }\n\n // Heuristic 0: No array properties at all.\n if (arrayPropertyNames.length === 0) {\n return null;\n }\n\n // Heuristic 1: Exactly one array property. This is the strongest signal.\n if (arrayPropertyNames.length === 1) {\n return arrayPropertyNames[0];\n }\n\n // Multiple array properties exist. Apply ranked heuristics:\n let bestCandidate: string | null = null;\n let candidateRank = Infinity; // Lower is better\n\n const updateCandidate = (propName: string, rank: number) => {\n if (rank < candidateRank) {\n bestCandidate = propName;\n candidateRank = rank;\n }\n };\n\n for (const propName of arrayPropertyNames) {\n const lowerPropName = propName.toLowerCase();\n\n // Heuristic 2: Top-tier primary keywords (e.g., \"data\", \"items\")\n if (PRIMARY_TOP_TIER_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 2);\n continue; // Move to next property, this is a strong match for this prop\n }\n\n // Heuristic 3: Other primary keywords\n if (candidateRank > 3 && PRIMARY_OTHER_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 3);\n continue;\n }\n\n // Heuristic 4: Secondary keywords\n if (candidateRank > 4 && SECONDARY_KEYWORDS.includes(lowerPropName)) {\n updateCandidate(propName, 4);\n continue;\n }\n\n // Heuristic 5: Pluralized name, not on the deprioritize list\n if (\n candidateRank > 5 &&\n pluralize.isPlural(propName) &&\n !PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)\n ) {\n updateCandidate(propName, 5);\n continue;\n }\n\n // Heuristic 6: Pluralized name, IS on the deprioritize list (less preferred plural)\n if (\n candidateRank > 6 &&\n pluralize.isPlural(propName) &&\n PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)\n ) {\n updateCandidate(propName, 6);\n continue;\n }\n }\n\n // If any of the above heuristics found a candidate, return it.\n if (bestCandidate) {\n return bestCandidate;\n }\n\n // Heuristic 7: Fallback - If no keywords or clear plurals,\n // and multiple arrays exist, return the first array property encountered.\n // This ensures we always return a name if arrays are present.\n return arrayPropertyNames[0];\n}\n\nfunction guess(properties: Record<string, SchemaObject>) {\n const booleanPropertyNames: string[] = [];\n for (const propName in properties) {\n if (Object.prototype.hasOwnProperty.call(properties, propName)) {\n const propSchema = properties[propName] as SchemaObject;\n if (\n (propSchema && propSchema.type === 'boolean') ||\n propSchema.type === 'integer'\n ) {\n booleanPropertyNames.push(propName);\n }\n }\n }\n\n if (booleanPropertyNames.length === 0) {\n return null;\n }\n\n if (booleanPropertyNames.length === 1) {\n return booleanPropertyNames[0];\n }\n\n let bestCandidate: string | null = null;\n let candidateRank = Infinity;\n\n const updateCandidate = (propName: string, rank: number) => {\n if (rank < candidateRank) {\n bestCandidate = propName;\n candidateRank = rank;\n }\n };\n\n for (const propName of booleanPropertyNames) {\n const normalizedForExactMatch = propName.toLowerCase().replace(/[-_]/g, '');\n let currentPropRank = Infinity;\n\n // Rank 1: Primary Exact Positive Match\n if (HAS_MORE_PRIMARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {\n currentPropRank = 1;\n }\n // Rank 2: Secondary Exact Positive Match\n else if (\n HAS_MORE_SECONDARY_POSITIVE_EXACT.includes(normalizedForExactMatch)\n ) {\n currentPropRank = 2;\n }\n // Rank 3: Positive Regex Match (sub-phrase)\n else {\n let foundPositiveRegex = false;\n for (const regex of COMPILED_HAS_MORE_POSITIVE_REGEXES) {\n if (regex.test(propName)) {\n // Test against original propName\n currentPropRank = 3;\n foundPositiveRegex = true;\n break;\n }\n }\n\n // Only proceed to inverted matches if no positive match of any kind (Rank 1, 2, or 3) was found\n if (!foundPositiveRegex) {\n // Rank 4: Primary Exact Inverted Match\n if (HAS_MORE_PRIMARY_INVERTED_EXACT.includes(normalizedForExactMatch)) {\n currentPropRank = 4;\n }\n // Rank 5: Inverted Regex Match (sub-phrase)\n else {\n for (const regex of COMPILED_HAS_MORE_INVERTED_REGEXES) {\n if (regex.test(propName)) {\n // Test against original propName\n currentPropRank = 5;\n break;\n }\n }\n }\n }\n }\n\n updateCandidate(propName, currentPropRank);\n }\n return bestCandidate;\n}\n\n/**\n * Tries to guess the name of a boolean property that indicates if there are more items\n * to fetch (e.g., for pagination).\n *\n * @param schema The OpenAPI SchemaObject, expected to be of type 'object'.\n * @returns The name of the most likely boolean property indicating \"has more\",\n * or null if no suitable boolean property is found.\n */\nexport function getHasMoreName(properties: SchemasObject): string | null {\n const rootGuess = guess(properties);\n if (rootGuess) {\n return rootGuess;\n }\n for (const propName in properties) {\n const propSchema = properties[propName];\n if (propSchema.type === 'object' && propSchema.properties) {\n const nested = getHasMoreName(propSchema.properties as SchemasObject);\n if (nested) {\n return propName + '.' + nested;\n }\n }\n }\n return null;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|