Refactored type definitions (#1119)
* Updated types generation script * Refactored api method definitions * Updated test - Removed old test code - Added tsd dev dependency - Rewritten test with tsd * Removed unused dependencies * Fixed definition * Updated test * Updated docs * Improved events type definitions * Updated test * Minor fixes in the type definitons * More type test * Improved Transport type definitions * Updated test * Addressed comments * Code generation * Use RequestBody, Response and Context everywhere, also default Context to unknown * Updated test * body -> hasBody * Fixed conflicts * Updated code generation * Improved request body type definition * Updated code generation * Use BodyType for both request and reponses generics - Use extends for defining the RequestBody generic to force the user following the same shape. - BodyType and NDBodyType now accepts a generics to allow injecting more specific types in the future * API generation * Updated test * Updated docs * Use BodyType also in ReponseError * Removed useless client generics * Renamed generics and types - prefixed all generics with a T - BodyType => RequestBody - NDBodyType => RequestNDBody - Added ResponseBody * Updated test * Updated docs * Test ResponseBody as well * Simplify overloads * API generation * Updated test * Updated error types
This commit is contained in:
committed by
GitHub
parent
a80f510a9a
commit
6c82a4967e
@ -58,7 +58,7 @@ function start (opts) {
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
|
||||
const { fn: factory, types } = genFactory(apiOutputFolder)
|
||||
const { fn: factory, types } = genFactory(apiOutputFolder, [apiFolder, xPackFolder])
|
||||
writeFileSync(
|
||||
mainOutputFile,
|
||||
factory,
|
||||
|
||||
@ -543,3 +543,4 @@ function intersect (first, ...rest) {
|
||||
}
|
||||
|
||||
module.exports = generate
|
||||
module.exports.ndjsonApi = ndjsonApi
|
||||
|
||||
@ -7,10 +7,20 @@
|
||||
'use strict'
|
||||
|
||||
const { readdirSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
const dedent = require('dedent')
|
||||
const deepmerge = require('deepmerge')
|
||||
const { ndjsonApi } = require('./generateApis')
|
||||
|
||||
function genFactory (folder) {
|
||||
const ndjsonApiKey = ndjsonApi
|
||||
.map(api => {
|
||||
return api
|
||||
.replace(/\.([a-z])/g, k => k[1].toUpperCase())
|
||||
.replace(/_([a-z])/g, k => k[1].toUpperCase())
|
||||
})
|
||||
.map(toPascalCase)
|
||||
|
||||
function genFactory (folder, paths) {
|
||||
// get all the API files
|
||||
const apiFiles = readdirSync(folder)
|
||||
const types = apiFiles
|
||||
@ -25,15 +35,18 @@ function genFactory (folder) {
|
||||
.split('.')
|
||||
.reverse()
|
||||
.reduce((acc, val) => {
|
||||
const obj = {
|
||||
[val]: acc === null
|
||||
? `ApiMethod<RequestParams.${name[0].toUpperCase() + name.slice(1)}>`
|
||||
: acc
|
||||
}
|
||||
if (isSnakeCased(val)) {
|
||||
obj[camelify(val)] = acc === null
|
||||
? `ApiMethod<RequestParams.${name[0].toUpperCase() + name.slice(1)}>`
|
||||
: acc
|
||||
const body = hasBody(paths, file.slice(0, -3))
|
||||
const methods = acc === null ? buildMethodDefinition(val, name, body) : null
|
||||
const obj = {}
|
||||
if (methods) {
|
||||
for (const m of methods) {
|
||||
obj[m.key] = m.val
|
||||
}
|
||||
} else {
|
||||
obj[val] = acc
|
||||
if (isSnakeCased(val)) {
|
||||
obj[camelify(val)] = acc
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}, null)
|
||||
@ -83,7 +96,7 @@ function genFactory (folder) {
|
||||
.join('\n')
|
||||
// remove useless quotes and commas
|
||||
.replace(/"/g, '')
|
||||
.replace(/,/g, '')
|
||||
.replace(/,$/gm, '')
|
||||
|
||||
const fn = dedent`
|
||||
// Licensed to Elasticsearch B.V under one or more agreements.
|
||||
@ -160,4 +173,64 @@ function isSnakeCased (str) {
|
||||
return !!~str.indexOf('_')
|
||||
}
|
||||
|
||||
function toPascalCase (str) {
|
||||
return str[0].toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
function buildMethodDefinition (api, name, hasBody) {
|
||||
const Name = toPascalCase(name)
|
||||
const bodyType = ndjsonApiKey.includes(Name) ? 'RequestNDBody' : 'RequestBody'
|
||||
|
||||
if (hasBody) {
|
||||
let methods = [
|
||||
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `Promise<ApiResponse<TResponse, TContext>>` },
|
||||
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
|
||||
]
|
||||
if (isSnakeCased(api)) {
|
||||
methods = methods.concat([
|
||||
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `Promise<ApiResponse<TResponse, TContext>>` },
|
||||
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
|
||||
])
|
||||
}
|
||||
return methods
|
||||
} else {
|
||||
let methods = [
|
||||
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `Promise<ApiResponse<TResponse, TContext>>` },
|
||||
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
|
||||
]
|
||||
if (isSnakeCased(api)) {
|
||||
methods = methods.concat([
|
||||
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `Promise<ApiResponse<TResponse, TContext>>` },
|
||||
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
|
||||
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
|
||||
])
|
||||
}
|
||||
return methods
|
||||
}
|
||||
}
|
||||
|
||||
function hasBody (paths, file) {
|
||||
const spec = readSpec()
|
||||
return !!spec[file].body
|
||||
|
||||
function readSpec () {
|
||||
try {
|
||||
return require(join(paths[0], file))
|
||||
} catch (err) {}
|
||||
|
||||
try {
|
||||
return require(join(paths[1], file))
|
||||
} catch (err) {}
|
||||
|
||||
throw new Error(`Cannot read spec file ${file}`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = genFactory
|
||||
|
||||
@ -6,6 +6,15 @@
|
||||
|
||||
const semver = require('semver')
|
||||
const deprecatedParameters = require('./patch.json')
|
||||
const { ndjsonApi } = require('./generateApis')
|
||||
|
||||
const ndjsonApiKey = ndjsonApi
|
||||
.map(api => {
|
||||
return api
|
||||
.replace(/\.([a-z])/g, k => k[1].toUpperCase())
|
||||
.replace(/_([a-z])/g, k => k[1].toUpperCase())
|
||||
})
|
||||
.map(toPascalCase)
|
||||
|
||||
function generate (version, api) {
|
||||
const release = semver.valid(version) ? semver.major(version) : version
|
||||
@ -13,6 +22,8 @@ function generate (version, api) {
|
||||
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
|
||||
// See the LICENSE file in the project root for more information
|
||||
|
||||
import { RequestBody, RequestNDBody } from '../lib/Transport'
|
||||
|
||||
export interface Generic {
|
||||
method?: string;
|
||||
ignore?: number | number[];
|
||||
@ -83,8 +94,10 @@ export interface Generic {
|
||||
return `${e.key}${optional}: ${getType(e.value.type, e.value.options)};`
|
||||
}
|
||||
|
||||
const bodyGeneric = ndjsonApiKey.includes(toPascalCase(name)) ? 'RequestNDBody' : 'RequestBody'
|
||||
|
||||
const code = `
|
||||
export interface ${name[0].toUpperCase() + name.slice(1)}${body ? '<T = any>' : ''} extends Generic {
|
||||
export interface ${toPascalCase(name)}${body ? `<T = ${bodyGeneric}>` : ''} extends Generic {
|
||||
${partsArr.map(genLine).join('\n ')}
|
||||
${paramsArr.map(genLine).join('\n ')}
|
||||
${body ? `body${body.required ? '' : '?'}: T;` : ''}
|
||||
@ -122,4 +135,8 @@ function intersect (first, ...rest) {
|
||||
}, first)
|
||||
}
|
||||
|
||||
function toPascalCase (str) {
|
||||
return str[0].toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
module.exports = generate
|
||||
|
||||
Reference in New Issue
Block a user