@7nohe/openapi-react-query-codegen
Version:
OpenAPI React Query Codegen
138 lines (137 loc) • 4.56 kB
JavaScript
import { stat } from "node:fs/promises";
import path from "node:path";
import ts from "typescript";
import { queriesOutputPath, requestsOutputPath } from "./constants.mjs";
export const TData = ts.factory.createIdentifier("TData");
export const TError = ts.factory.createIdentifier("TError");
export const TContext = ts.factory.createIdentifier("TContext");
export const EqualsOrGreaterThanToken = ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken);
export const QuestionToken = ts.factory.createToken(ts.SyntaxKind.QuestionToken);
export const queryKeyGenericType = ts.factory.createTypeReferenceNode("TQueryKey");
export const queryKeyConstraint = ts.factory.createTypeReferenceNode("Array", [
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
]);
export const capitalizeFirstLetter = (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
};
export const lowercaseFirstLetter = (str) => {
return str.charAt(0).toLowerCase() + str.slice(1);
};
export const getNameFromMethod = (method) => {
const methodName = method.getName();
if (!methodName) {
throw new Error("Method name not found");
}
return methodName;
};
export async function exists(f) {
try {
await stat(f);
return true;
}
catch {
return false;
}
}
const Common = "Common";
/**
* Build a common type name by prepending the Common namespace.
*/
export function BuildCommonTypeName(name) {
if (typeof name === "string") {
return ts.factory.createIdentifier(`${Common}.${name}`);
}
return ts.factory.createIdentifier(`${Common}.${name.text}`);
}
/**
* Safely parse a value into a number. Checks for NaN and Infinity.
* Returns NaN if the string is not a valid number.
* @param value The value to parse.
* @returns The parsed number or NaN if the value is not a valid number.
*/
export function safeParseNumber(value) {
const parsed = Number(value);
if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {
return parsed;
}
return Number.NaN;
}
export function extractPropertiesFromObjectParam(param) {
const referenced = param.findReferences()[0];
const def = referenced.getDefinition();
const paramNodes = def
.getNode()
.getType()
.getProperties()
.map((prop) => ({
name: prop.getName(),
optional: prop.isOptional(),
type: prop.getValueDeclaration()?.getType(),
}));
return paramNodes;
}
/**
* Replace the import("...") surrounding the type if there is one.
* This can happen when the type is imported from another file, but
* we are already importing all the types from that file.
*
* https://regex101.com/r/3DyHaQ/1
*
* TODO: Replace with a more robust solution.
*/
export function getShortType(type) {
return type.replaceAll(/import\(".*?"\)\./g, "");
}
export function getClassesFromService(node) {
const klasses = node.getClasses();
if (!klasses.length) {
throw new Error("No classes found");
}
return klasses.map((klass) => {
const className = klass.getName();
if (!className) {
throw new Error("Class name not found");
}
return {
className,
klass,
};
});
}
export function getClassNameFromClassNode(klass) {
const className = klass.getName();
if (!className) {
throw new Error("Class name not found");
}
return className;
}
export function formatOptions(options) {
// loop through properties on the options object
// if the property is a string of number then convert it to a number
// if the property is a string of boolean then convert it to a boolean
const formattedOptions = Object.entries(options).reduce((acc, [key, value]) => {
const typedKey = key;
const typedValue = value;
const parsedNumber = safeParseNumber(typedValue);
if (value === "true" || value === true) {
acc[typedKey] = true;
}
else if (value === "false" || value === false) {
acc[typedKey] = false;
}
else if (!Number.isNaN(parsedNumber)) {
acc[typedKey] = parsedNumber;
}
else {
acc[typedKey] = typedValue;
}
return acc;
}, options);
return formattedOptions;
}
export function buildRequestsOutputPath(outputPath) {
return path.join(outputPath, requestsOutputPath);
}
export function buildQueriesOutputPath(outputPath) {
return path.join(outputPath, queriesOutputPath);
}