UNPKG

@seamapi/blueprint

Version:

Build tools for the Seam API using this blueprint.

217 lines (216 loc) 9.1 kB
import { pascalCase } from 'change-case'; const defaultGoPackageName = 'api'; const goPackageBasePath = 'github.com/seamapi/go'; export const createGoRequest = ({ request }, _context) => { const isReqWithParams = Object.keys(request.parameters).length !== 0; const goPackageName = getGoPackageName(request.path); const goSdkImports = generateImports({ goPackageName, isReqWithParams, }); const requestStructName = getRequestStructName(request.path); const formattedArgs = formatGoRequestArgs(request.parameters, { goPackageName, requestStructName, }); const goSdkRequestArgs = `context.Background()${isReqWithParams ? `,\n${goPackageName}.${requestStructName}{\n${formattedArgs},\n}` : ''}`; const pathParts = request.path.split('/'); return `package main ${goSdkImports} func main() { client${pathParts.map((p) => pascalCase(p)).join('.')}(${isReqWithParams ? '\n' : ''}${goSdkRequestArgs},\n) } `.trim(); }; const getGoPackageName = (path) => { if (!isPathNested(path)) { return defaultGoPackageName; } const firstPathPart = path.split('/').slice(1)[1]; if (firstPathPart == null) { throw new Error(`Invalid path: missing second part in "${path}"`); } return firstPathPart.replace(/_/g, ''); }; const isPathNested = (path) => path.split('/').slice(1).length > 2; const generateImports = ({ goPackageName, isReqWithParams, }) => { const imports = []; if (isReqWithParams) { const defaultPackageImport = `import ${defaultGoPackageName} "${goPackageBasePath}"`; imports.push(defaultPackageImport); } if (goPackageName !== defaultGoPackageName && isReqWithParams) { const nestedPackageImport = `import ${goPackageName} "${goPackageBasePath}/${goPackageName}"`; imports.push(nestedPackageImport); } return imports.join('\n'); }; const getRequestStructName = (path) => { const requestStructNameSuffix = 'Request'; return isPathNested(path) ? `${pascalCase(removeUntilSecondSlash(path))}${requestStructNameSuffix}` : `${pascalCase(path)}${requestStructNameSuffix}`; }; const removeUntilSecondSlash = (str) => str.replace(/^\/[^/]*/, ''); const formatGoRequestArgs = (jsonParams, context) => Object.entries(jsonParams) .map(([paramKey, paramValue]) => { const formattedValue = formatGoRequestArgValue(paramKey, paramValue, context); return `${pascalCase(paramKey)}: ${formattedValue}`; }) .join(',\n'); const formatGoRequestArgValue = (key, value, context) => { if (value == null) return 'nil'; if (typeof value === 'string') { return `${defaultGoPackageName}.String("${value}")`; } if (typeof value === 'boolean') { return `${defaultGoPackageName}.Bool(${value})`; } if (typeof value === 'number') { return `${defaultGoPackageName}.Float64(${value})`; } if (Array.isArray(value)) { return formatGoRequestArrayValue(key, value, context); } if (typeof value === 'object') { return formatGoRequestObjectValue(key, value, context); } throw new Error(`Unsupported type: ${typeof value}`); }; const formatGoRequestArrayValue = (key, value, context) => { if (value.length === 0) { // in Go there's no way define an empty array without specifying type // and code samples definitions don't include the type annotations return 'nil'; } const formattedItems = value.map((v) => formatGoRequestArgValue(key, v, context)); const item = value[0]; if (item == null) { throw new Error(`Null value in response array for '${key}'`); } const { goPackageName, requestStructName } = context; const arrayType = isPrimitiveValue(item) ? getPrimitiveTypeName(item) : `${goPackageName}.${pascalCase(`${requestStructName} ${key}`)}Item`; return `[${value.length}]${arrayType}{${formattedItems.join(', ')}}`; }; const isPrimitiveValue = (value) => typeof value !== 'object' && value !== null; const getPrimitiveTypeName = (value) => { switch (typeof value) { case 'string': return 'string'; case 'number': return 'float64'; case 'boolean': return 'bool'; } }; const formatGoRequestObjectValue = (key, value, context) => { if (Object.keys(value).length === 0) { return 'struct{}{}'; } const formattedEntries = Object.entries(value) .map(([objKey, val]) => `${pascalCase(objKey)}: ${formatGoRequestArgValue(objKey, val, context)}`) .join(', '); const { goPackageName, requestStructName } = context; return `${goPackageName}.${pascalCase(`${requestStructName} ${key}`)}{${formattedEntries}}`; }; export const createGoResponse = ({ response, title }, context) => { const { endpoint } = context; if (endpoint.response.responseType === 'void') return 'nil'; const { responseKey, resourceType } = endpoint.response; const responseValue = response?.body?.[responseKey]; if (responseValue == null) { throw new Error(`Missing ${responseKey} for '${title}'`); } const responseResourceGoStructName = pascalCase(resourceType); return Array.isArray(responseValue) ? formatGoArrayResponse(responseValue, responseResourceGoStructName, title) : formatGoResponse(responseValue, responseResourceGoStructName); }; const formatGoArrayResponse = (responseArray, responseResourceGoStructName, title) => { const formattedItems = responseArray .map((v) => { if (v == null) { throw new Error(`Null value in response array for '${title}'`); } return formatGoResponse(v, responseResourceGoStructName); }) .join(', '); return `[]${defaultGoPackageName}.${responseResourceGoStructName}{${formattedItems}}`; }; const formatGoResponse = (responseParams, responseResourceGoStructName) => { const params = formatGoResponseParams(responseParams, responseResourceGoStructName); return `${defaultGoPackageName}.${responseResourceGoStructName}{${params}}`; }; const formatGoResponseParams = (jsonParams, responseResourceGoStructName) => Object.entries(jsonParams) .map(([paramKey, paramValue]) => { const formattedValue = formatGoResponseParamValue({ key: paramKey, value: paramValue, propertyChain: [], }, responseResourceGoStructName); return `${pascalCase(paramKey)}: ${formattedValue}`; }) .join(', '); const formatGoResponseParamValue = ({ key, value, propertyChain, }, responseResourceGoStructName) => { if (value === null) return 'nil'; if (typeof value === 'boolean') return value.toString(); if (typeof value === 'number') return value.toString(); if (typeof value === 'string') return `"${value}"`; if (Array.isArray(value)) { return formatGoResponseArrayValue({ key, value, propertyChain }, responseResourceGoStructName); } if (typeof value === 'object') { return formatGoResponseObjectValue({ key, value, propertyChain }, responseResourceGoStructName); } throw new Error(`Unsupported type: ${typeof value}`); }; const formatGoResponseArrayValue = ({ key, value, propertyChain, }, responseResourceGoStructName) => { if (value.length === 0) { return 'nil'; } const rawItem = value[0]; if (rawItem == null) { throw new Error(`Null value in response array for '${key}'`); } const updatedPropertyChain = [...propertyChain, key]; const formattedItems = value.map((v) => formatGoResponseParamValue({ key, value: v, propertyChain: updatedPropertyChain }, responseResourceGoStructName)); if (isPrimitiveValue(rawItem)) { const arrayType = getPrimitiveTypeName(rawItem); return `[]${arrayType}{${formattedItems.join(', ')}}`; } else { const structName = getStructName(updatedPropertyChain, responseResourceGoStructName); return `[]${structName}{${formattedItems.join(', ')}}`; } }; const formatGoResponseObjectValue = ({ key, value, propertyChain, }, responseResourceGoStructName) => { if (Object.keys(value).length === 0) { return 'struct{}{}'; } const updatedPropertyChain = [...propertyChain, key]; const structName = getStructName(updatedPropertyChain, responseResourceGoStructName); const formattedEntries = Object.entries(value) .map(([objKey, val]) => { const formattedValue = formatGoResponseParamValue({ key: objKey, value: val, propertyChain: updatedPropertyChain, }, responseResourceGoStructName); return `${pascalCase(objKey)}: ${formattedValue}`; }) .join(', '); return `${defaultGoPackageName}.${structName}{${formattedEntries}}`; }; const getStructName = (propertyChain, responseResourceGoStructName) => { const fullPropertyChain = [responseResourceGoStructName, ...propertyChain]; return pascalCase(fullPropertyChain.join('_')); }; //# sourceMappingURL=go.js.map