@proofgeist/fmdapi
Version:
FileMaker Data API client
168 lines (149 loc) • 4.71 kB
text/typescript
import { program } from "commander";
import chalk from "chalk";
import fs from "fs-extra";
import path from "path";
import { config } from "dotenv";
import { pathToFileURL, fileURLToPath } from "url";
import type { GenerateSchemaOptions } from "./utils/typegen/types.js";
import { generateTypedClients } from "./utils/index.js";
import { upgradeConfig } from "./utils/ugprade.js";
const defaultConfigPaths = ["./fmschema.config.mjs", "./fmschema.config.js"];
type ConfigArgs = {
configLocation: string;
};
function init({ configLocation }: ConfigArgs) {
console.log();
if (fs.existsSync(configLocation)) {
console.log(
chalk.yellow(`⚠️ ${path.basename(configLocation)} already exists`),
);
} else {
const stubFile = fs.readFileSync(
path.resolve(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof __dirname !== "undefined"
? __dirname
: fileURLToPath(new URL(".", import.meta.url)),
"../stubs/fmschema.config.stub.mjs",
),
"utf8",
);
fs.writeFileSync(configLocation, stubFile, "utf8");
console.log(`✅ Created config file: ${path.basename(configLocation)}`);
}
}
async function getConfig(configLocation: string) {
if (!fs.existsSync(configLocation)) {
console.error(
chalk.red(
`Could not find ${path.basename(
configLocation,
)} at the root of your project.`,
),
);
console.log();
console.log("run `codegen --init` to create a new config file");
return process.exit(1);
}
await fs.access(configLocation, fs.constants.R_OK).catch(() => {
console.error(
chalk.red(
`You do not have read access to ${path.basename(
configLocation,
)} at the root of your project.`,
),
);
return process.exit(1);
});
let config;
console.log(`🔍 Reading config from ${configLocation}`);
if (configLocation.endsWith(".mjs")) {
const module: { config: GenerateSchemaOptions } = await import(
pathToFileURL(configLocation).toString()
);
config = module.config;
} else {
config = require(configLocation);
}
if (!config) {
console.error(
chalk.red(
`Error reading the config object from ${path.basename(
configLocation,
)}. Are you sure you have a "config" object exported?`,
),
);
}
return config;
}
async function runCodegen({ configLocation }: ConfigArgs) {
const config = await getConfig(configLocation);
await generateTypedClients(config).catch((err: unknown) => {
console.error(err);
return process.exit(1);
});
console.log(`✅ Generated schemas\n`);
}
program
.option("--init", "Add the configuration file to your project")
.option("--config <filename>", "optional config file name")
.option("--env-path <path>", "optional path to your .env file", ".env.local")
.option(
"--skip-env-check",
"Ignore loading environment variables from a file.",
false,
)
.action(async (options) => {
// check if options.config resolves to a file
const configPath = getConfigPath(options.config);
const configLocation = path.toNamespacedPath(
path.resolve(configPath ?? defaultConfigPaths[0] ?? ""),
);
if (options.init) return init({ configLocation });
if (!options.skipEnvCheck) {
const envRes = config({ path: options.envPath });
if (envRes.error)
return console.log(
chalk.red(
`Could not resolve your environment variables.\n${envRes.error.message}\n`,
),
);
}
// default command
await runCodegen({ configLocation });
});
program
.command("upgrade", { hidden: true })
.option("--config <filename>", "optional config file name")
.action(async (options) => {
const configPath = getConfigPath(options.config);
const configLocation = path.toNamespacedPath(
path.resolve(configPath ?? defaultConfigPaths[0] ?? ""),
);
const config = await getConfig(configLocation);
await upgradeConfig(config, configLocation);
});
program.parse();
function getConfigPath(configPath?: string): string | null {
if (configPath) {
// If a config path is specified, check if it exists
try {
fs.accessSync(configPath, fs.constants.F_OK);
return configPath;
} catch (e) {
// If it doesn't exist, continue to default paths
}
}
// Try default paths in order
for (const path of defaultConfigPaths) {
try {
fs.accessSync(path, fs.constants.F_OK);
return path;
} catch (e) {
// If path doesn't exist, try the next one
}
}
return null;
}