mirror of
https://github.com/Redocly/redoc.git
synced 2025-11-03 09:17:31 +03:00
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import * as Sampler from 'openapi-sampler';
|
|
import { OpenAPIExample, OpenAPISchema } from '../types';
|
|
import { Example } from '../types/example';
|
|
import { MergedOpenAPISchema, OpenAPIParser } from '../services';
|
|
|
|
const MAX_ITEM_DEPTH = 1;
|
|
|
|
interface CsvExampleProps {
|
|
parser: OpenAPIParser;
|
|
schema: OpenAPISchema;
|
|
sample: OpenAPIExample;
|
|
samplerOptions: object;
|
|
}
|
|
|
|
const getCsvRows = (sample: OpenAPIExample): string => {
|
|
const headers = Object.keys(sample?.[0] ?? sample).join(',');
|
|
// Ensure the schema has deterministic headers
|
|
const hasValidHeaders =
|
|
!Array.isArray(sample) ||
|
|
sample.every(row => Object.keys(row).every(key => headers.includes(key)));
|
|
if (!hasValidHeaders) return '';
|
|
|
|
let values;
|
|
|
|
if (Array.isArray(sample)) {
|
|
values = sample.map(row => Object.values(row)).join('\n');
|
|
} else {
|
|
values = Object.values(sample).join(',');
|
|
}
|
|
return headers + '\n' + values;
|
|
};
|
|
|
|
const cleanUpExamples = (examples: Example[]): Example[] =>
|
|
examples.filter(example => example.exampleValue !== '');
|
|
|
|
export const generateCsvExample = ({
|
|
parser,
|
|
schema,
|
|
sample,
|
|
samplerOptions,
|
|
}: CsvExampleProps): Example[] => {
|
|
let examples: Example[] = [];
|
|
let depthCount = 0;
|
|
let exampleCount = 1;
|
|
const isValidSample = (Array.isArray(sample) ? sample : [sample]).every(sampleItem =>
|
|
Object.values(sampleItem).every(
|
|
value => typeof value !== 'object' && typeof value !== 'undefined',
|
|
),
|
|
);
|
|
|
|
const processSamplesWithSchema = subSchema => {
|
|
if (subSchema) {
|
|
const subItems = subSchema.items as OpenAPISchema;
|
|
|
|
if (subSchema.type === 'array' && subItems && depthCount < MAX_ITEM_DEPTH) {
|
|
depthCount++;
|
|
processSamplesWithSchema(subItems);
|
|
}
|
|
|
|
const metadata = {
|
|
exampleDescription: subSchema.description || schema.description || '',
|
|
exampleSummary: subSchema.title || schema.title || 'Example CSV',
|
|
};
|
|
|
|
if (subSchema?.allOf) {
|
|
const resolved: OpenAPISchema = {
|
|
...schema,
|
|
items: parser.deref(subSchema.allOf as MergedOpenAPISchema).resolved,
|
|
};
|
|
const sampleData = Sampler.sample(
|
|
resolved as any,
|
|
samplerOptions,
|
|
parser.spec,
|
|
) as OpenAPIExample;
|
|
|
|
const csvRows = getCsvRows(sampleData);
|
|
examples.push({
|
|
exampleId: `Example ${exampleCount++}`,
|
|
exampleValue: csvRows,
|
|
...metadata,
|
|
});
|
|
} else if (subSchema.oneOf) {
|
|
const oneOfExamples = subSchema.oneOf.map(oneOfSchema => {
|
|
const { resolved } = parser.deref(oneOfSchema as MergedOpenAPISchema);
|
|
const sampleData = Sampler.sample(
|
|
resolved as any,
|
|
samplerOptions,
|
|
parser.spec,
|
|
) as OpenAPIExample;
|
|
const csvRows = getCsvRows(sampleData);
|
|
const currentMetadata = {
|
|
exampleDescription: oneOfSchema.description || metadata.exampleDescription,
|
|
exampleSummary: oneOfSchema.title || metadata.exampleSummary,
|
|
};
|
|
|
|
return {
|
|
exampleId: `Example ${exampleCount++}`,
|
|
exampleValue: csvRows,
|
|
...currentMetadata,
|
|
};
|
|
});
|
|
examples = [...examples, ...oneOfExamples];
|
|
} else if (subSchema.$ref) {
|
|
const csvRows = getCsvRows(sample);
|
|
examples.push({
|
|
exampleId: `Example ${exampleCount++}`,
|
|
exampleValue: csvRows,
|
|
...metadata,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
if (isValidSample) {
|
|
processSamplesWithSchema(schema);
|
|
}
|
|
|
|
return cleanUpExamples(examples);
|
|
};
|