Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mongoose-tsgen

Package Overview
Dependencies
Maintainers
1
Versions
148
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mongoose-tsgen - npm Package Compare versions

Comparing version 8.1.1 to 8.2.0

6

CHANGELOG.md
# CHANGELOG
## 8.2.0 / 2021-05-19
* Added `mongoose.Query.populate` overload to narrow query typings & `--no-populate-overload` flag to disable the behaviour
* Added new population helper types and type guards `PopulatedDocument`, `IsPopulated`
* Update to Mongoose 5.12.10
## 8.1.0 / 2021-05-17

@@ -4,0 +10,0 @@

2

lib/helpers/parser.d.ts

@@ -38,2 +38,4 @@ import mongoose from "mongoose";

export declare const loadSchemas: (modelsPaths: string[]) => LoadedSchemas;
export declare const addPopulateHelpers: (sourceFile: SourceFile) => void;
export declare const overloadQueryPopulate: (sourceFile: SourceFile) => void;
export declare const createSourceFile: (genPath: string) => SourceFile;

@@ -40,0 +42,0 @@ export declare const generateTypes: ({ sourceFile, schemas, imports, noMongoose }: {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.saveFile = exports.generateTypes = exports.createSourceFile = exports.loadSchemas = exports.registerUserTs = exports.getParseKeyFn = exports.parseSchema = exports.replaceModelTypes = void 0;
exports.saveFile = exports.generateTypes = exports.createSourceFile = exports.overloadQueryPopulate = exports.addPopulateHelpers = exports.loadSchemas = exports.registerUserTs = exports.getParseKeyFn = exports.parseSchema = exports.replaceModelTypes = void 0;
const tslib_1 = require("tslib");

@@ -15,2 +15,49 @@ const mongoose_1 = tslib_1.__importDefault(require("mongoose"));

const MONGOOSE_IMPORT = `import mongoose from "mongoose";`;
const POPULATE_HELPERS = `/**
* Populate properties on a document type:
* \`\`\`
* import { PopulatedDocument } from "../interfaces/mongoose.gen.ts"
*
* function example(user: PopulatedDocument<UserDocument, "bestFriend">) {
* console.log(user.bestFriend._id) // typescript knows this is populated
* }
* \`\`\`
*/
export type PopulatedDocument<DocType extends mongoose.Document, T> = T extends keyof DocType ? Omit<DocType, T> & { [ref in T]: Exclude<DocType[T], mongoose.Types.ObjectId> } : DocType;
/**
* Check if a property on a document is populated:
* \`\`\`
* import { IsPopulated } from "../interfaces/mongoose.gen.ts"
*
* if (IsPopulated<UserDocument["bestFriend"]>) { ... }
* \`\`\`
*/
export function IsPopulated<T>(doc: T | mongoose.Types.ObjectId): doc is T {
return doc instanceof mongoose.Document;
}`;
const QUERY_POPULATE = `/**
* Helper types used by the populate overloads
*/
type Unarray<T> = T extends Array<infer U> ? U : T;
type Modify<T, R> = Omit<T, keyof R> & R;
/**
* Augment mongoose with Query.populate overloads
*/
declare module "mongoose" {
interface Query<ResultType, DocType extends Document, THelpers = {}> {
populate<T extends keyof DocType>(path: T, select?: string | any, model?: string | Model<any, THelpers>, match?: any): Query<
ResultType extends Array<DocType> ? Array<PopulatedDocument<Unarray<ResultType>, T>> : (ResultType extends DocType ? PopulatedDocument<Unarray<ResultType>, T> : ResultType),
DocType,
THelpers
> & THelpers;
populate<T extends keyof DocType>(options: Modify<PopulateOptions, { path: T }> | Array<PopulateOptions>): Query<
ResultType extends Array<DocType> ? Array<PopulatedDocument<Unarray<ResultType>, T>> : (ResultType extends DocType ? PopulatedDocument<Unarray<ResultType>, T> : ResultType),
DocType,
THelpers
> & THelpers;
}
}`;
const getObjectDocs = (modelName) => `/**

@@ -613,2 +660,8 @@ * Lean version of ${modelName}Document (type alias of \`${modelName}\`)

};
exports.addPopulateHelpers = (sourceFile) => {
sourceFile.addStatements("\n" + POPULATE_HELPERS);
};
exports.overloadQueryPopulate = (sourceFile) => {
sourceFile.addStatements("\n" + QUERY_POPULATE);
};
exports.createSourceFile = (genPath) => {

@@ -615,0 +668,0 @@ const project = new ts_morph_1.Project();

@@ -14,2 +14,3 @@ import { Command, flags } from "@oclif/command";

"no-mongoose": import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
"no-populate-overload": import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
};

@@ -16,0 +17,0 @@ static args: {

@@ -53,2 +53,6 @@ "use strict";

}
await parser.addPopulateHelpers(sourceFile);
if (!flags["no-populate-overload"]) {
await parser.overloadQueryPopulate(sourceFile);
}
cleanupTs === null || cleanupTs === void 0 ? void 0 : cleanupTs();

@@ -95,3 +99,3 @@ cli_ux_1.default.action.stop();

char: "o",
description: "[default: ./src/interfaces] Path of output file containing generated typings. If a folder path is passed, the generator will default to creating a `mongoose.gen.ts` file in the specified folder."
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."
}),

@@ -107,2 +111,5 @@ project: command_1.flags.string({

description: "Don't generate types that reference mongoose (i.e. documents). Replace ObjectId with string."
}),
"no-populate-overload": command_1.flags.boolean({
description: "Disable augmenting mongoose with Query.populate overloads (the overloads narrow the return type of populated documents queries)."
})

@@ -109,0 +116,0 @@ };

4

package.json
{
"name": "mongoose-tsgen",
"description": "A Typescript interface generator for Mongoose that works out of the box.",
"version": "8.1.1",
"version": "8.2.0",
"author": "Francesco Virga @francescov1",

@@ -24,3 +24,3 @@ "bin": {

"mkdirp": "^1.0.4",
"mongoose": "^5.12.6",
"mongoose": "^5.12.10",
"prettier": "^2.1.2",

@@ -27,0 +27,0 @@ "strip-json-comments": "^3.1.1",

@@ -131,25 +131,28 @@ # mongoose-tsgen

OPTIONS
-c, --config=config [default: ./] Path of `mtgen.config.json` or its root folder. CLI flag
options will take precendence over settings in `mtgen.config.json`.
-c, --config=config [default: ./] Path of `mtgen.config.json` or its root folder. CLI flag
options will take precendence over settings in `mtgen.config.json`.
-d, --dry-run Print output rather than writing to file.
-d, --dry-run Print output rather than writing to file.
-h, --help Show CLI help
-h, --help Show CLI help
-i, --imports=import 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.
-i, --imports=imports 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.
-o, --output=output [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.
-o, --output=output [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.
-p, --project=project [default: ./] Path of `tsconfig.json` or its root folder.
-p, --project=project [default: ./] Path of `tsconfig.json` or its root folder.
--debug Print debug information if anything isn't working
--debug Print debug information if anything isn't working
--no-format Disable formatting generated files with prettier.
--no-format Disable formatting generated files with prettier.
--no-mongoose Don't generate types that reference mongoose (i.e. documents). Replace ObjectId with
string.
--no-mongoose Don't generate types that reference mongoose (i.e. documents). Replace ObjectId with
string.
--no-populate-overload Disable augmenting mongoose with Query.populate overloads (the overloads narrow
the return type of populated documents queries).
```

@@ -178,26 +181,27 @@

Any field with a `ref` property will be typed as `RefDocument["_id"] | RefDocument`. This allows you to use the same type whether you populate a field or not. When populating a field, you will need to use [Typeguards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types) or [Type Assertion](https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions) to tell Typescript that the field is populated:
Any field with a `ref` property will be typed as `RefDocument["_id"] | RefDocument`. As part of the generated file, mongoose will be augmented with `Query.populate` overloads to narrow return types of populated queries (this can be disabled using the `--no-populate-overload` flag). A helper type `IsPopulated` and a type guard function `PopulatedDocument` will also be generated to help with handling populated documents, see usage below:
```typescript
// fetch user with bestFriend populated
const user = await User.findById(uid).populate("bestFriend").exec()
import { IsPopulated, PopulatedDocument } from "../interfaces/mongoose.gen.ts";
// typescript won't allow this, since `bestFriend` is typed as `UserDocument["_id"] | UserDocument`
console.log(user.bestFriend._id)
// instead use type assertion
const bestFriend = user.bestFriend as UserDocument;
console.log(bestFriend._id);
// or use typeguards
function isPopulated<T>(doc: T | mongoose.Types.ObjectId): doc is T {
return doc instanceof mongoose.Document;
// UserDocument["bestFriend"] = mongoose.Types.ObjectId | UserDocument
function unsafeType(user: UserDocument) {
// type guard
if (IsPopulated(user.bestFriend))) {
// user.bestFriend is confirmed to be populated, typescript will allow accessing its properties now
console.log(user.bestFriend._id)
}
}
if (isPopulated<UserDocument>(user.bestFriend)) {
// user.bestFriend is a UserDocument
// `user` is typed as a UserDocument with `bestFriend` populated
function safeType(user: PopulatedDocument<UserDocument, "bestFriend">) {
console.log(user.bestFriend._id)
}
// due to the `Query.populate` overload, `user` will be typed as `PopulatedDocument<UserDocument, "bestFriend">`
// rather than the usual `UserDocument`
const user = await User.findById(uid).populate("bestFriend").exec()
// completely typesafe
safeType(user)
```

@@ -349,4 +353,2 @@

- [ ] Stronger/automatic [populate](https://mongoosejs.com/docs/populate.html) typing (see [Query Population](#query-population)).
- [ ] Add CLI option to type `_id` fields as a string rather than an ObjectId on lean version of documents (see [#7](https://github.com/francescov1/mongoose-tsgen/issues/7)).
- [ ] Cut down node_modules by using peer dependencies (i.e. mongoose) and stripping oclif.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc