-
Notifications
You must be signed in to change notification settings - Fork 109
Generate useMutate
components
#126
Changes from all commits
1a3e52b
f0b4171
17bd22e
ed78ff2
bc4df4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
declare module "ibm-openapi-validator" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sad that it's not TS. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we contribute this to @DefinitelyTyped? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 24 stars on github, I've tried but without a lot of hope 😅 I will contribute to definitelyTyped to add this later. |
||
interface OpenAPIError { | ||
path: string; | ||
message: string; | ||
} | ||
|
||
interface ValidatorResults { | ||
errors: OpenAPIError[]; | ||
warnings: OpenAPIError[]; | ||
} | ||
|
||
/** | ||
* Returns a Promise with the validation results. | ||
* | ||
* @param openApiDoc An object that represents an OpenAPI document. | ||
* @param defaultMode If set to true, the validator will ignore the .validaterc file and will use the configuration defaults. | ||
*/ | ||
function validator(openApiDoc: any, defaultMode = false): Promise<ValidatorResults>; | ||
|
||
export default validator; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
import { pascal } from "case"; | ||
import chalk from "chalk"; | ||
import openApiValidator from "ibm-openapi-validator"; | ||
import get from "lodash/get"; | ||
import groupBy from "lodash/groupBy"; | ||
import isEmpty from "lodash/isEmpty"; | ||
|
@@ -318,16 +320,16 @@ export const generateRestfulComponent = ( | |
}` | ||
: `${needAResponseComponent ? componentName + "Response" : responseTypes}, ${errorTypes}, ${ | ||
queryParamsType ? componentName + "QueryParams" : "void" | ||
}, ${requestBodyTypes}`; | ||
}, ${verb === "delete" ? "string" : requestBodyTypes}`; | ||
|
||
const genericsTypesWithoutError = | ||
const genericsTypesForHooksProps = | ||
verb === "get" | ||
? `${needAResponseComponent ? componentName + "Response" : responseTypes}, ${ | ||
queryParamsType ? componentName + "QueryParams" : "void" | ||
}` | ||
: `${needAResponseComponent ? componentName + "Response" : responseTypes}, ${ | ||
queryParamsType ? componentName + "QueryParams" : "void" | ||
}, ${requestBodyTypes}`; | ||
}`; | ||
|
||
let output = `${ | ||
needAResponseComponent | ||
|
@@ -366,18 +368,18 @@ export const ${componentName} = (${ | |
`; | ||
|
||
// Hooks version | ||
if (verb === "get" /* TODO: Remove this condition after `useMutate` implementation */) { | ||
output += `export type Use${componentName}Props = Omit<Use${Component}Props<${genericsTypesWithoutError}>, "path"${ | ||
verb === "get" ? "" : ` | "verb"` | ||
}>${paramsInPath.length ? ` & {${paramsTypes}}` : ""}; | ||
output += `export type Use${componentName}Props = Omit<Use${Component}Props<${genericsTypesForHooksProps}>, "path"${ | ||
verb === "get" ? "" : ` | "verb"` | ||
}>${paramsInPath.length ? ` & {${paramsTypes}}` : ""}; | ||
|
||
${operation.summary ? "// " + operation.summary : ""} | ||
export const use${componentName} = (${ | ||
paramsInPath.length ? `{${paramsInPath.join(", ")}, ...props}` : "props" | ||
}: Use${componentName}Props) => use${Component}<${genericsTypes}>(\`${route}\`, props); | ||
paramsInPath.length ? `{${paramsInPath.join(", ")}, ...props}` : "props" | ||
}: Use${componentName}Props) => use${Component}<${genericsTypes}>(${ | ||
verb === "get" ? "" : `"${verb.toUpperCase()}", ` | ||
}\`${route}\`, props); | ||
|
||
`; | ||
} | ||
|
||
if (headerParams.map(({ name }) => name.toLocaleLowerCase()).includes("prefer")) { | ||
output += `export type Poll${componentName}Props = Omit<PollProps<${genericsTypes}>, "path">${ | ||
|
@@ -468,24 +470,76 @@ export interface ${pascal(name)}Response ${type}`; | |
); | ||
}; | ||
|
||
/** | ||
* Validate the spec with ibm-openapi-validator (with a custom pretty logger). | ||
* | ||
* @param schema openAPI spec | ||
*/ | ||
const validate = async (schema: OpenAPIObject) => { | ||
// tslint:disable:no-console | ||
const log = console.log; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe export this from that other place you do it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's more have only one |
||
|
||
// Catch the internal console.log to add some information if needed | ||
// because openApiValidator() calls console.log internally and | ||
// we want to add more context if it's used | ||
let wasConsoleLogCalledFromBlackBox = false; | ||
console.log = (...props: any) => { | ||
wasConsoleLogCalledFromBlackBox = true; | ||
log(...props); | ||
}; | ||
const { errors, warnings } = await openApiValidator(schema); | ||
console.log = log; // reset console.log because we're done with the black box | ||
|
||
if (wasConsoleLogCalledFromBlackBox) { | ||
log("More information: https://github.com/IBM/openapi-validator/#configuration"); | ||
} | ||
if (warnings.length) { | ||
log(chalk.yellow("(!) Warnings")); | ||
warnings.forEach(i => | ||
log( | ||
chalk.yellow(` | ||
Message : ${i.message} | ||
Path : ${i.path}`), | ||
), | ||
); | ||
} | ||
if (errors.length) { | ||
log(chalk.red("(!) Errors")); | ||
errors.forEach(i => | ||
log( | ||
chalk.red(` | ||
Message : ${i.message} | ||
Path : ${i.path}`), | ||
), | ||
); | ||
} | ||
// tslint:enable:no-console | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've disabled the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
}; | ||
|
||
/** | ||
* Main entry of the generator. Generate restful-react component from openAPI. | ||
* | ||
* @param data raw data of the spec | ||
* @param format format of the spec | ||
* @param transformer custom function to transform your spec | ||
* @param validation validate the spec with ibm-openapi-validator tool | ||
*/ | ||
const importOpenApi = async ( | ||
data: string, | ||
format: "yaml" | "json", | ||
transformer?: (schema: OpenAPIObject) => OpenAPIObject, | ||
validation = false, | ||
) => { | ||
const operationIds: string[] = []; | ||
let schema = await importSpecs(data, format); | ||
if (transformer) { | ||
schema = transformer(schema); | ||
} | ||
|
||
if (validation) { | ||
await validate(schema); | ||
} | ||
|
||
let output = ""; | ||
|
||
output += generateSchemasDefinition(schema.components && schema.components.schemas); | ||
|
@@ -507,7 +561,7 @@ const importOpenApi = async ( | |
imports.push("Get", "GetProps", "useGet", "UseGetProps"); | ||
} | ||
if (haveMutate) { | ||
imports.push("Mutate", "MutateProps"); | ||
imports.push("Mutate", "MutateProps", "useMutate", "UseMutateProps"); | ||
} | ||
if (havePoll) { | ||
imports.push("Poll", "PollProps"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data
is not anymore optional, so we can definestring
for DELETE operation.This is to have a bit more type safety,
mutate()
is not possible anymore if a body is required.