UNPKG

@7nohe/openapi-react-query-codegen

Version:
149 lines (148 loc) 4.77 kB
import { stat } from "node:fs/promises"; import path from "node:path"; import { ArrowFunction, } from "ts-morph"; import ts from "typescript"; import { queriesOutputPath, requestsOutputPath } from "./constants.mjs"; 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 getVariableArrowFunctionParameters = (variable) => { const initializer = variable.getInitializer(); if (!initializer) { throw new Error("Initializer not found"); } if (!ArrowFunction.isArrowFunction(initializer)) { throw new Error("Initializer is not an arrow function"); } return initializer.getParameters(); }; export const getNameFromVariable = (variable) => { const variableName = variable.getName(); if (!variableName) { throw new Error("Variable name not found"); } return variableName; }; 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) { // `Number("")` is 0, which would silently turn a blank option such as // `--initialPageParam ""` into a numeric 0. Treat blank strings as NaN so // callers keep the original value. if (typeof value === "string" && value.trim() === "") { return Number.NaN; } 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() .filter((prop) => prop.getValueDeclaration()?.getType()) .map((prop) => { return { 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); }