Skip to content

Commit

Permalink
refactor into smaller functions
Browse files Browse the repository at this point in the history
  • Loading branch information
kainpets committed Jul 3, 2024
1 parent dbe009a commit bb3201c
Show file tree
Hide file tree
Showing 2 changed files with 257 additions and 132 deletions.
317 changes: 212 additions & 105 deletions src/lib/blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,95 +121,138 @@ export interface TypesModule {
openapi: Openapi
}

export const createBlueprint = ({
openapi,
}: {
openapi: Openapi
}): Blueprint => {
const blueprint: Blueprint = {
name: openapi.info.title,
routes: [],
resources: {},
}

export const createBlueprint = (openapi: Openapi): Blueprint => {
const isFakeData = openapi.info.title === 'Foo'
const targetPath = '/acs/systems/list'
const targetSchema = 'acs_system'

const isFakeData = openapi.info.title === 'Foo'

for (const [path, pathItem] of Object.entries(openapi.paths)) {
if (!isFakeData && path !== targetPath) continue

const route: Route = {
path,
namespace: { path: '/acs' },
endpoints: [],
subroutes: [],
}

for (const [method, operation] of Object.entries(pathItem as Record<string, unknown>)) {
if (typeof operation !== 'object' || operation === null) continue

const endpoint: Endpoint = {
name: 'operationId' in operation && typeof operation.operationId === 'string'
? operation.operationId
: `${method}${path.replace(/\//g, '_')}`,
path,
methods: [method.toUpperCase() as Method],
semanticMethod: method.toUpperCase() as Method,
preferredMethod: method.toUpperCase() as Method,
description: 'summary' in operation && typeof operation.summary === 'string'
? operation.summary
: '',
isUndocumented: false,
isDeprecated: false,
deprecationMessage: '',
parameters: [],
request: {
methods: [method.toUpperCase() as Method],
semanticMethod: method.toUpperCase() as Method,
preferredMethod: method.toUpperCase() as Method,
parameters: [],
},
response: createResponse('responses' in operation ? operation.responses : {}),
}

if ('parameters' in operation && Array.isArray(operation.parameters)) {
for (const param of operation.parameters) {
if (typeof param === 'object' && param !== null) {
const parameter: Parameter = {
name: 'name' in param && typeof param.name === 'string' ? param.name : '',
isRequired: 'required' in param && typeof param.required === 'boolean' ? param.required : false,
isUndocumented: false,
isDeprecated: false,
deprecationMessage: '',
description: 'description' in param && typeof param.description === 'string' ? param.description : '',
}
endpoint.parameters.push(parameter)
endpoint.request.parameters.push(parameter)
}
}
}

route.endpoints.push(endpoint)
}

blueprint.routes.push(route)
return {
name: openapi.info.title,
routes: createRoutes(openapi.paths, isFakeData, targetPath),
resources: createResources(
openapi.components.schemas,
isFakeData,
targetSchema,
),
}
}

for (const [schemaName, schema] of Object.entries(openapi.components.schemas)) {
if (!isFakeData && schemaName !== targetSchema) continue

if (typeof schema === 'object' && schema !== null && 'properties' in schema && typeof schema.properties === 'object' && schema.properties !== null) {
blueprint.resources[schemaName] = {
resourceType: schemaName,
properties: createProperties(schema.properties as Record<string, unknown>),
const createRoutes = (
paths: Openapi['paths'],
isFakeData: boolean,
targetPath: string,
): Route[] =>
Object.entries(paths)
.filter(([path]) => isFakeData || path === targetPath)
.map(([path, pathItem]) => createRoute(path, pathItem))

const createRoute = (
path: string,
pathItem: Record<string, unknown>,
): Route => ({
path,
namespace: { path: '/acs' },
endpoints: createEndpoints(path, pathItem),
subroutes: [],
})

const createEndpoints = (
path: string,
pathItem: Record<string, unknown>,
): Endpoint[] =>
Object.entries(pathItem)
.filter(
([, operation]) => typeof operation === 'object' && operation !== null,
)
.map(([method, operation]) =>
createEndpoint(method, operation as Record<string, unknown>, path),
)

const createEndpoint = (
method: string,
operation: Record<string, unknown>,
path: string,
): Endpoint => ({
name:
'operationId' in operation && typeof operation['operationId'] === 'string'
? operation['operationId']
: `${method}${path.replace(/\//g, '_')}`,
path,
methods: [method.toUpperCase() as Method],
semanticMethod: method.toUpperCase() as Method,
preferredMethod: method.toUpperCase() as Method,
description:
'summary' in operation && typeof operation['summary'] === 'string'
? operation['summary']
: '',
isUndocumented: false,
isDeprecated: false,
deprecationMessage: '',
parameters: createParameters(operation),
request: createRequest(method, operation),
response: createResponse(
'responses' in operation ? operation['responses'] : {},
),
})

const createParameters = (operation: Record<string, unknown>): Parameter[] =>
'parameters' in operation && Array.isArray(operation['parameters'])
? operation['parameters']
.filter(
(param): param is Record<string, unknown> =>
typeof param === 'object' && param !== null,
)
.map(createParameter)
: []

const createParameter = (param: Record<string, unknown>): Parameter => ({
name:
'name' in param && typeof param['name'] === 'string' ? param['name'] : '',
isRequired:
'required' in param && typeof param['required'] === 'boolean'
? param['required']
: false,
isUndocumented: false,
isDeprecated: false,
deprecationMessage: '',
description:
'description' in param && typeof param['description'] === 'string'
? param['description']
: '',
})

const createRequest = (
method: string,
operation: Record<string, unknown>,
): Request => ({
methods: [method.toUpperCase() as Method],
semanticMethod: method.toUpperCase() as Method,
preferredMethod: method.toUpperCase() as Method,
parameters: createParameters(operation),
})

const createResources = (
schemas: Openapi['components']['schemas'],
isFakeData: boolean,
targetSchema: string,
): Record<string, Resource> =>
Object.entries(schemas)
.filter(([schemaName]) => isFakeData || schemaName === targetSchema)
.reduce<Record<string, Resource>>((acc, [schemaName, schema]) => {
if (
typeof schema === 'object' &&
schema !== null &&
'properties' in schema &&
typeof schema.properties === 'object' &&
schema.properties !== null
) {
acc[schemaName] = {
resourceType: schemaName,
properties: createProperties(schema.properties),
}
}
}
}

return blueprint
}
return acc
}, {})

function createResponse(responses: unknown): Response {
if (typeof responses !== 'object' || responses === null) {
Expand All @@ -223,61 +266,122 @@ function createResponse(responses: unknown): Response {

const content = 'content' in okResponse ? okResponse.content : null
if (typeof content !== 'object' || content === null) {
return { responseType: 'void', description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '' }
return {
responseType: 'void',
description:
'description' in okResponse &&
typeof okResponse.description === 'string'
? okResponse.description
: '',
}
}

const jsonContent = 'application/json' in content ? content['application/json'] : null
const jsonContent =
'application/json' in content ? content['application/json'] : null
if (typeof jsonContent !== 'object' || jsonContent === null) {
return { responseType: 'void', description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '' }
return {
responseType: 'void',
description:
'description' in okResponse &&
typeof okResponse.description === 'string'
? okResponse.description
: '',
}
}

const schema = 'schema' in jsonContent ? jsonContent.schema : null
if (typeof schema !== 'object' || schema === null) {
return { responseType: 'void', description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '' }
return {
responseType: 'void',
description:
'description' in okResponse &&
typeof okResponse.description === 'string'
? okResponse.description
: '',
}
}

if ('type' in schema && 'properties' in schema) {
if (schema.type === 'array' && 'items' in schema && typeof schema.items === 'object' && schema.items !== null) {
if (
schema.type === 'array' &&
'items' in schema &&
typeof schema.items === 'object' &&
schema.items !== null
) {
const refString = '$ref' in schema.items ? schema.items.$ref : null
return {
responseType: 'resource_list',
responseKey: 'items',
resourceType: typeof refString === 'string' && refString.length > 0 ? refString.split('/').pop() ?? 'unknown' : 'unknown',
description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '',
resourceType:
typeof refString === 'string' && refString.length > 0
? refString.split('/').pop() ?? 'unknown'
: 'unknown',
description:
'description' in okResponse &&
typeof okResponse.description === 'string'
? okResponse.description
: '',
}
} else if (schema.type === 'object' && typeof schema.properties === 'object' && schema.properties !== null) {
} else if (
schema.type === 'object' &&
typeof schema.properties === 'object' &&
schema.properties !== null
) {
const properties = schema.properties as Record<string, unknown>
const refKey = Object.keys(properties).find(
(key) => typeof properties[key] === 'object' &&
(key) =>
typeof properties[key] === 'object' &&
properties[key] !== null &&
'$ref' in (properties[key] as Record<string, unknown>)
'$ref' in (properties[key] as Record<string, unknown>),
)
if (refKey != null) {
const refString = '$ref' in (properties[refKey] as Record<string, unknown>)
? (properties[refKey] as Record<string, unknown>)['$ref']
: null
const refString =
'$ref' in (properties[refKey] as Record<string, unknown>)
? (properties[refKey] as Record<string, unknown>)['$ref']
: null
return {
responseType: 'resource',
responseKey: refKey,
resourceType: typeof refString === 'string' && refString.length > 0 ? refString.split('/').pop() ?? 'unknown' : 'unknown',
description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '',
resourceType:
typeof refString === 'string' && refString.length > 0
? refString.split('/').pop() ?? 'unknown'
: 'unknown',
description:
'description' in okResponse &&
typeof okResponse.description === 'string'
? okResponse.description
: '',
}
}
}
}

return { responseType: 'void', description: 'description' in okResponse && typeof okResponse.description === 'string' ? okResponse.description : '' }
return {
responseType: 'void',
description:
'description' in okResponse && typeof okResponse.description === 'string'
? okResponse.description
: '',
}
}

function createProperties(properties: Record<string, unknown>): Property[] {
return Object.entries(properties).map(([name, prop]): Property => {
if (typeof prop !== 'object' || prop === null) {
return { name, type: 'string', isDeprecated: false, deprecationMessage: '' }
return {
name,
type: 'string',
isDeprecated: false,
deprecationMessage: '',
}
}

const baseProperty = {
name,
description: 'description' in prop && typeof prop.description === 'string' ? prop.description : '',
description:
'description' in prop && typeof prop.description === 'string'
? prop.description
: '',
isDeprecated: false,
deprecationMessage: '',
}
Expand All @@ -290,9 +394,12 @@ function createProperties(properties: Record<string, unknown>): Property[] {
return {
...baseProperty,
type: 'object',
properties: 'properties' in prop && typeof prop.properties === 'object' && prop.properties !== null
? createProperties(prop.properties as Record<string, unknown>)
: [],
properties:
'properties' in prop &&
typeof prop.properties === 'object' &&
prop.properties !== null
? createProperties(prop.properties as Record<string, unknown>)
: [],
}
case 'array':
return { ...baseProperty, type: 'list' }
Expand All @@ -303,4 +410,4 @@ function createProperties(properties: Record<string, unknown>): Property[] {

return { ...baseProperty, type: 'string' }
})
}
}
Loading

0 comments on commit bb3201c

Please sign in to comment.