mongoose-tsgen
Version:
A Typescript interface generator for Mongoose that works out of the box.
142 lines (141 loc) • 6.85 kB
JavaScript
;
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const tsReader = (0, tslib_1.__importStar)(require("./helpers/tsReader"));
const paths = (0, tslib_1.__importStar)(require("./helpers/paths"));
const formatter = (0, tslib_1.__importStar)(require("./helpers/formatter"));
const generator = (0, tslib_1.__importStar)(require("./helpers/generator"));
const cli = (0, tslib_1.__importStar)(require("./helpers/cli"));
const utils_1 = require("./parser/utils");
class MongooseTsgen extends core_1.Command {
constructor(argv = [], config = new core_1.Config({ root: __dirname })) {
super(argv, config);
}
async getConfig(customConfig) {
var _a, _b, _c, _d;
const configFileFlags = paths.getConfigFromFile(customConfig.flags.config);
return {
flags: {
...configFileFlags,
...customConfig.flags,
// We dont need the config field anymore now that we've merged the config file here
config: undefined,
// we cant set flags as `default` using the official oclif method since the defaults would overwrite flags provided in the config file.
// instead, well just set "output" and "project" as default manually if theyre still missing after merge with configFile.
output: (_b = (_a = configFileFlags === null || configFileFlags === void 0 ? void 0 : configFileFlags.output) !== null && _a !== void 0 ? _a : customConfig.flags.output) !== null && _b !== void 0 ? _b : "./src/interfaces",
project: (_d = (_c = configFileFlags === null || configFileFlags === void 0 ? void 0 : configFileFlags.project) !== null && _c !== void 0 ? _c : customConfig.flags.project) !== null && _d !== void 0 ? _d : "./"
},
args: {
...configFileFlags,
...customConfig.args
}
};
}
async run() {
const customConfig = await this.parse(MongooseTsgen);
try {
await this.generateDefinitions(customConfig);
}
catch (error) {
this.error(error, { exit: 1 });
}
}
async generateDefinitions(customConfig) {
core_1.ux.action.start("Generating mongoose typescript definitions");
const { flags, args } = await this.getConfig(customConfig);
if (flags.debug) {
this.log("Debug mode enabled");
process.env.DEBUG = "1";
}
const modelsPaths = paths.getModelsPaths(args.model_path);
const cleanupTs = tsReader.registerUserTs(flags.project);
const generatedFilePath = paths.cleanOutputPath(flags.output);
let sourceFile = generator.createSourceFile(generatedFilePath);
const noMongoose = flags["no-mongoose"];
const datesAsStrings = flags["dates-as-strings"];
sourceFile = generator.generateTypes({
modelsPaths,
sourceFile,
imports: flags.imports,
noMongoose,
datesAsStrings
});
const modelTypes = tsReader.getModelTypes(modelsPaths);
const models = (0, utils_1.loadModels)(modelsPaths);
generator.replaceModelTypes(sourceFile, modelTypes, models);
// only get model types (methods, statics, queries & virtuals) if user does not specify `noMongoose`,
if (noMongoose) {
this.log("Skipping TS model parsing and sourceFile model type replacement");
}
else {
// add populate helpers
await generator.addPopulateHelpers(sourceFile);
// add mongoose.Query.populate overloads
if (!flags["no-populate-overload"]) {
await generator.overloadQueryPopulate(sourceFile);
}
}
cleanupTs === null || cleanupTs === void 0 ? void 0 : cleanupTs();
if (flags["dry-run"]) {
this.log("Dry run detected, generated interfaces will be printed to console:\n");
this.log(sourceFile.getFullText());
}
else {
this.log(`Writing interfaces to ${generatedFilePath}`);
generator.saveFile({ generatedFilePath, sourceFile });
if (!flags["no-format"])
await formatter.format([generatedFilePath]);
this.log("Writing complete 🐒");
}
core_1.ux.action.stop();
return { generatedFilePath, sourceFile };
}
}
MongooseTsgen.id = ".";
MongooseTsgen.description = "Generate a Typescript file containing Mongoose Schema typings.\nSpecify the directory of your Mongoose model definitions using `MODEL_PATH`. If left blank, all sub-directories will be searched for `models/*.ts` (ignores `index.ts` files). Files found are expected to export a Mongoose model.";
MongooseTsgen.flags = {
config: core_1.Flags.string({
char: "c",
description: "[default: ./] Path of `mtgen.config.json` or its root folder. CLI flag options will take precendence over settings in `mtgen.config.json`."
}),
"dry-run": core_1.Flags.boolean({
char: "d",
description: "Print output rather than writing to file."
}),
help: cli.helpFlag({
char: "h"
}),
imports: core_1.Flags.string({
char: "i",
description: "Custom import statements to add to the output file. Useful if you use third-party types in your mongoose schema definitions. For multiple imports, specify this flag more than once.",
multiple: true
}),
"no-format": core_1.Flags.boolean({
description: "Disable formatting generated files with prettier."
}),
output: core_1.Flags.string({
char: "o",
description: "[default: ./src/interfaces] Path of output file to write generated typings. If a folder path is passed, the generator will create a `mongoose.gen.ts` file in the specified folder."
}),
project: core_1.Flags.string({
char: "p",
description: "[default: ./] Path of `tsconfig.json` or its root folder."
}),
debug: core_1.Flags.boolean({
description: "Print debug information if anything isn't working"
}),
"no-mongoose": core_1.Flags.boolean({
description: "Don't generate types that reference mongoose (i.e. documents). Replace ObjectId with string."
}),
"dates-as-strings": core_1.Flags.boolean({
description: "Dates will be typed as strings. Useful for types returned to a frontend by API requests."
}),
"no-populate-overload": core_1.Flags.boolean({
description: "Disable augmenting mongoose with Query.populate overloads (the overloads narrow the return type of populated documents queries)."
})
};
// path of mongoose models folder
MongooseTsgen.args = {
model_path: core_1.Args.string()
};
module.exports = MongooseTsgen;