Skip to content

Commit 364ba09

Browse files
committed
chore: extend respect event
1 parent 02ff999 commit 364ba09

5 files changed

Lines changed: 240 additions & 17 deletions

File tree

packages/cli/src/__tests__/utils/telemetry.test.ts

Lines changed: 132 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import {
88
collectXSecurityAuthTypes,
99
cacheAnonymousId,
1010
getCachedAnonymousId,
11+
collectSourceDescriptionTypes,
12+
collectCriterionObjectTypes,
1113
} from '../../utils/telemetry.js';
1214

1315
describe('collectXSecurityAuthTypes', () => {
1416
it('should collect X-Security Auth types and schemeNames', () => {
15-
const respectXSecurityAuthTypesAndSchemeName: string[] = [];
17+
const respectXSecurityAuthTypesAndSchemeName = new Set<string>();
1618
const arazzoDocument = {
1719
workflows: [
1820
{
@@ -86,7 +88,7 @@ describe('collectXSecurityAuthTypes', () => {
8688
],
8789
} as Partial<ArazzoDefinition>;
8890
collectXSecurityAuthTypes(arazzoDocument, respectXSecurityAuthTypesAndSchemeName);
89-
expect(respectXSecurityAuthTypesAndSchemeName).toEqual([
91+
expect([...respectXSecurityAuthTypesAndSchemeName]).toEqual([
9092
'basic',
9193
'apiKey',
9294
'bearer',
@@ -96,14 +98,14 @@ describe('collectXSecurityAuthTypes', () => {
9698
});
9799

98100
it('should handle documents with no workflows', () => {
99-
const respectXSecurityAuthTypesAndSchemeName: string[] = [];
101+
const respectXSecurityAuthTypesAndSchemeName = new Set<string>();
100102
const arazzoDocument = {} as Partial<ArazzoDefinition>;
101103
collectXSecurityAuthTypes(arazzoDocument, respectXSecurityAuthTypesAndSchemeName);
102-
expect(respectXSecurityAuthTypesAndSchemeName).toEqual([]);
104+
expect([...respectXSecurityAuthTypesAndSchemeName]).toEqual([]);
103105
});
104106

105107
it('should handle workflows with no x-security', () => {
106-
const respectXSecurityAuthTypesAndSchemeName: string[] = [];
108+
const respectXSecurityAuthTypesAndSchemeName = new Set<string>();
107109
const arazzoDocument = {
108110
workflows: [
109111
{
@@ -113,7 +115,131 @@ describe('collectXSecurityAuthTypes', () => {
113115
],
114116
} as Partial<ArazzoDefinition>;
115117
collectXSecurityAuthTypes(arazzoDocument, respectXSecurityAuthTypesAndSchemeName);
116-
expect(respectXSecurityAuthTypesAndSchemeName).toEqual([]);
118+
expect([...respectXSecurityAuthTypesAndSchemeName]).toEqual([]);
119+
});
120+
});
121+
122+
describe('collectSourceDescriptionTypes', () => {
123+
it('should collect source description types', () => {
124+
const respectSourceDescriptionTypes = new Set<string>();
125+
const arazzoDocument = {
126+
sourceDescriptions: [
127+
{
128+
type: 'openapi',
129+
url: 'https://example.com/openapi.yaml',
130+
},
131+
{
132+
type: 'arazzo',
133+
url: 'https://example.com/arazzo.yaml',
134+
},
135+
{
136+
type: 'asyncapi',
137+
url: 'https://example.com/asyncapi.yaml',
138+
},
139+
],
140+
} as Partial<ArazzoDefinition>;
141+
collectSourceDescriptionTypes(arazzoDocument, respectSourceDescriptionTypes);
142+
expect([...respectSourceDescriptionTypes]).toEqual(['openapi', 'arazzo', 'asyncapi']);
143+
});
144+
145+
it('should handle documents with no source descriptions', () => {
146+
const respectSourceDescriptionTypes = new Set<string>();
147+
const arazzoDocument = {} as Partial<ArazzoDefinition>;
148+
collectSourceDescriptionTypes(arazzoDocument, respectSourceDescriptionTypes);
149+
expect([...respectSourceDescriptionTypes]).toEqual([]);
150+
});
151+
});
152+
153+
describe('collectCriterionObjectTypes', () => {
154+
it('should collect criterion object types from all criteria locations', () => {
155+
const respectCriterionObjectTypes = new Set<string>();
156+
const arazzoDocument = {
157+
workflows: [
158+
{
159+
workflowId: 'workflow1',
160+
successActions: [
161+
{
162+
name: 'workflow-success',
163+
type: 'end',
164+
criteria: [{ condition: '$response.body.id', type: 'jsonpath' }],
165+
},
166+
],
167+
failureActions: [
168+
{
169+
name: 'workflow-failure',
170+
type: 'end',
171+
criteria: [{ condition: 'Problem', type: 'regex' }],
172+
},
173+
],
174+
steps: [
175+
{
176+
stepId: 'step1',
177+
operationId: 'operation1',
178+
successCriteria: [{ condition: '$statusCode == 200', type: 'simple' }],
179+
onSuccess: [
180+
{
181+
name: 'step-success',
182+
type: 'end',
183+
criteria: [
184+
{
185+
condition: '$.data',
186+
context: '$response.body',
187+
type: {
188+
type: 'jsonpath',
189+
version: 'draft-goessner-dispatch-jsonpath-00',
190+
},
191+
},
192+
],
193+
},
194+
],
195+
onFailure: [
196+
{
197+
name: 'step-failure',
198+
type: 'end',
199+
criteria: [
200+
{
201+
condition: '//error',
202+
context: '$response.body',
203+
type: {
204+
type: 'xpath',
205+
version: 'xpath-30',
206+
},
207+
},
208+
],
209+
},
210+
],
211+
},
212+
],
213+
},
214+
],
215+
components: {
216+
successActions: {
217+
ReusableSuccess: {
218+
name: 'reusable-success',
219+
type: 'end',
220+
criteria: [{ condition: '$statusCode == 201' }],
221+
},
222+
},
223+
failureActions: {
224+
ReusableFailure: {
225+
name: 'reusable-failure',
226+
type: 'end',
227+
criteria: [{ condition: '$statusCode == 500', type: 'regex' }],
228+
},
229+
},
230+
},
231+
} as Partial<ArazzoDefinition>;
232+
233+
collectCriterionObjectTypes(arazzoDocument, respectCriterionObjectTypes);
234+
235+
expect([...respectCriterionObjectTypes]).toEqual(['jsonpath', 'regex', 'simple', 'xpath']);
236+
});
237+
238+
it('should handle documents with no criterion objects', () => {
239+
const respectCriterionObjectTypes = new Set<string>();
240+
const arazzoDocument = {} as Partial<ArazzoDefinition>;
241+
collectCriterionObjectTypes(arazzoDocument, respectCriterionObjectTypes);
242+
expect([...respectCriterionObjectTypes]).toEqual([]);
117243
});
118244
});
119245

packages/cli/src/__tests__/wrapper.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ describe('commandWrapper', () => {
5757
spec_keyword: 'openapi',
5858
spec_full_version: '3.1.0',
5959
respect_x_security_auth_types: [],
60+
respect_source_description_types: [],
61+
respect_criterion_object_types: [],
6062
})
6163
);
6264
});
@@ -88,6 +90,8 @@ describe('commandWrapper', () => {
8890
spec_keyword: undefined,
8991
spec_full_version: undefined,
9092
respect_x_security_auth_types: [],
93+
respect_source_description_types: [],
94+
respect_criterion_object_types: [],
9195
})
9296
);
9397
});

packages/cli/src/utils/__tests__/telemetry.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ it('sendTelemetry calls all telemetry functions', async () => {
2727
spec_keyword: 'openapi',
2828
spec_full_version: '3.1.0',
2929
respect_x_security_auth_types: undefined,
30+
respect_source_description_types: undefined,
31+
respect_criterion_object_types: undefined,
3032
});
3133

3234
expect(respondWithinMs).toHaveBeenCalled();

packages/cli/src/utils/telemetry.ts

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@ import type { ExtendedSecurity } from 'respect-core/src/types.js';
1616
import { ulid } from 'ulid';
1717
import type { Arguments } from 'yargs';
1818

19+
import type { CriterionObject } from '../../../core/src/typings/arazzo.js';
1920
import { getReuniteUrl } from '../reunite/api/index.js';
2021
import type { CommandArgv } from '../types.js';
2122
import { ANONYMOUS_ID_CACHE_FILE } from './constants.js';
2223
import type { ExitCode } from './miscellaneous.js';
2324
import { respondWithinMs } from './network-check.js';
2425
import { version } from './package.js';
2526

27+
type ArazzoWorkflow = NonNullable<ArazzoDefinition['workflows']>[number];
28+
type ArazzoStep = ArazzoWorkflow['steps'][number];
29+
type ArazzoSuccessAction = NonNullable<ArazzoWorkflow['successActions']>[number];
30+
type ArazzoFailureAction = NonNullable<ArazzoWorkflow['failureActions']>[number];
31+
2632
const SECRET_REPLACEMENT = '***';
2733

2834
export async function sendTelemetry({
@@ -34,6 +40,8 @@ export async function sendTelemetry({
3440
spec_keyword,
3541
spec_full_version,
3642
respect_x_security_auth_types,
43+
respect_source_description_types,
44+
respect_criterion_object_types,
3745
}: {
3846
config: Config | undefined;
3947
argv: Arguments<CommandArgv> | undefined;
@@ -43,6 +51,8 @@ export async function sendTelemetry({
4351
spec_keyword: string | undefined;
4452
spec_full_version: string | undefined;
4553
respect_x_security_auth_types: string[] | undefined;
54+
respect_source_description_types: string[] | undefined;
55+
respect_criterion_object_types: string[] | undefined;
4656
}): Promise<void> {
4757
try {
4858
if (!argv) {
@@ -93,6 +103,14 @@ export async function sendTelemetry({
93103
spec_version === 'arazzo1' && respect_x_security_auth_types?.length
94104
? JSON.stringify(respect_x_security_auth_types)
95105
: undefined,
106+
respect_source_description_types:
107+
spec_version === 'arazzo1' && respect_source_description_types?.length
108+
? JSON.stringify(respect_source_description_types)
109+
: undefined,
110+
respect_criterion_object_types:
111+
spec_version === 'arazzo1' && respect_criterion_object_types?.length
112+
? JSON.stringify(respect_criterion_object_types)
113+
: undefined,
96114
},
97115
];
98116

@@ -117,18 +135,79 @@ export async function sendTelemetry({
117135
}
118136
}
119137

138+
export function collectSourceDescriptionTypes(
139+
document: Partial<ArazzoDefinition>,
140+
respectSourceDescriptionTypes: Set<string>
141+
) {
142+
for (const sourceDescription of document.sourceDescriptions ?? []) {
143+
if (sourceDescription.type) {
144+
respectSourceDescriptionTypes.add(sourceDescription.type);
145+
}
146+
}
147+
}
148+
149+
export function collectCriterionObjectTypes(
150+
document: Partial<ArazzoDefinition>,
151+
respectCriterionObjectTypes: Set<string>
152+
) {
153+
for (const criterionObject of getCriterionObjects(document)) {
154+
const type = getCriterionObjectType(criterionObject);
155+
if (type) {
156+
respectCriterionObjectTypes.add(type);
157+
}
158+
}
159+
}
160+
161+
function getCriterionObjects(document: Partial<ArazzoDefinition>) {
162+
const criterionObjects: CriterionObject[] = [];
163+
164+
for (const workflow of document.workflows ?? []) {
165+
collectActionCriteria(workflow.successActions, criterionObjects);
166+
collectActionCriteria(workflow.failureActions, criterionObjects);
167+
168+
for (const step of workflow.steps ?? []) {
169+
collectStepCriteria(step, criterionObjects);
170+
}
171+
}
172+
173+
collectActionCriteria(Object.values(document.components?.successActions ?? {}), criterionObjects);
174+
collectActionCriteria(Object.values(document.components?.failureActions ?? {}), criterionObjects);
175+
176+
return criterionObjects;
177+
}
178+
179+
function collectStepCriteria(step: ArazzoStep, criterionObjects: CriterionObject[]) {
180+
criterionObjects.push(...(step.successCriteria ?? []));
181+
collectActionCriteria(step.onSuccess, criterionObjects);
182+
collectActionCriteria(step.onFailure, criterionObjects);
183+
}
184+
185+
function collectActionCriteria(
186+
actions: readonly (ArazzoSuccessAction | ArazzoFailureAction)[] | undefined,
187+
criterionObjects: CriterionObject[]
188+
) {
189+
criterionObjects.push(...(actions ?? []).flatMap((action) => action.criteria ?? []));
190+
}
191+
192+
function getCriterionObjectType(criterionObject: CriterionObject) {
193+
const type = criterionObject.type;
194+
return typeof type === 'string'
195+
? type
196+
: type?.type || (criterionObject.condition ? 'simple' : undefined);
197+
}
198+
120199
export function collectXSecurityAuthTypes(
121200
document: Partial<ArazzoDefinition>,
122-
respectXSecurityAuthTypesAndSchemeName: string[]
201+
respectXSecurityAuthTypesAndSchemeName: Set<string>
123202
) {
124203
for (const workflow of document.workflows ?? []) {
125204
// Collect auth types from workflow-level x-security
126205
for (const security of workflow['x-security'] ?? []) {
127206
const scheme = (security as ExtendedSecurity).scheme;
128207
if (scheme?.type) {
129208
const authType = scheme.type === 'http' ? scheme.scheme : scheme.type;
130-
if (authType && !respectXSecurityAuthTypesAndSchemeName.includes(authType)) {
131-
respectXSecurityAuthTypesAndSchemeName.push(authType);
209+
if (authType) {
210+
respectXSecurityAuthTypesAndSchemeName.add(authType);
132211
}
133212
}
134213
}
@@ -140,15 +219,15 @@ export function collectXSecurityAuthTypes(
140219
const scheme = (security as ExtendedSecurity).scheme;
141220
if (scheme?.type) {
142221
const authType = scheme.type === 'http' ? scheme.scheme : scheme.type;
143-
if (authType && !respectXSecurityAuthTypesAndSchemeName.includes(authType)) {
144-
respectXSecurityAuthTypesAndSchemeName.push(authType);
222+
if (authType) {
223+
respectXSecurityAuthTypesAndSchemeName.add(authType);
145224
}
146225
}
147226

148227
// Handle schemeName case
149228
const schemeName = (security as ExtendedSecurity).schemeName;
150-
if (schemeName && !respectXSecurityAuthTypesAndSchemeName.includes(schemeName)) {
151-
respectXSecurityAuthTypesAndSchemeName.push(schemeName);
229+
if (schemeName) {
230+
respectXSecurityAuthTypesAndSchemeName.add(schemeName);
152231
}
153232
}
154233
}

0 commit comments

Comments
 (0)