Skip to content

Commit 830bf73

Browse files
committed
Merge branch '8.x'
2 parents f631093 + 46996b6 commit 830bf73

File tree

8 files changed

+482
-13
lines changed

8 files changed

+482
-13
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
8.20.1 / 2025-11-20
2+
===================
3+
* types: correct Model.schema type and fix unknown check for this param type in schema.methods #15750 #15693
4+
* docs: add detailed loadClass() TypeScript usage guide #15731 #12813 [Necro-Rohan](https://github.com/Necro-Rohan)
5+
* docs: update version support documentation for Mongoose #15761 [ManmathX](https://github.com/ManmathX)
6+
* docs: add copy-to-clipboard feature for code blocks in docs #15759 [vedansha07](https://github.com/vedansha07)
7+
18
9.0.0-rc1 / 2025-11-19
29
======================
310
* fix(populate): correctly populate embedded discriminators on subdocuments #15774

docs/css/copy-code.css

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* Base button placement & visibility */
2+
.copy-btn {
3+
position: absolute;
4+
top: 6px;
5+
right: 6px;
6+
background: transparent;
7+
border: none;
8+
padding: 4px;
9+
cursor: pointer;
10+
11+
opacity: 0;
12+
transform: translateY(-3px);
13+
transition: opacity 0.18s ease, transform 0.18s ease, color 0.2s ease;
14+
15+
display: flex;
16+
align-items: center;
17+
justify-content: center;
18+
19+
color: #666; /* default icon color */
20+
}
21+
22+
/* Show button only when the code block is hovered */
23+
pre:hover .copy-btn {
24+
opacity: 1;
25+
transform: translateY(0);
26+
}
27+
28+
/* Hover state always forces black — applies to both icons */
29+
.copy-btn:hover {
30+
color: #000 !important;
31+
}
32+
33+
/* Tick icon uses the same neutral grey so hover can override cleanly */
34+
.copy-btn.copied {
35+
color: #666;
36+
}
37+
38+
/* Icon sizing + smooth color transition */
39+
.copy-btn svg {
40+
width: 20px;
41+
height: 20px;
42+
transition: color 0.2s ease;
43+
}

docs/js/copy-code.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
// Attach copy-button logic only after the full DOM is loaded
4+
document.addEventListener('DOMContentLoaded', () => {
5+
// Inline SVG icons so no external asset load is required
6+
const copyIcon = `
7+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
8+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
9+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
10+
</svg>
11+
`;
12+
13+
const checkIcon = `
14+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
15+
<path d="M20 6L9 17l-5-5"></path>
16+
</svg>
17+
`;
18+
19+
// Inject a copy button into each <pre><code> block used in docs
20+
document.querySelectorAll('pre code').forEach(block => {
21+
const wrapper = block.parentElement;
22+
wrapper.style.position = 'relative'; // ensures button can be positioned correctly
23+
24+
const btn = document.createElement('button');
25+
btn.className = 'copy-btn';
26+
btn.setAttribute('aria-label', 'Copy code to clipboard'); // accessibility support
27+
btn.innerHTML = copyIcon; // initial icon state
28+
29+
// Handle the copy-to-clipboard action
30+
btn.onclick = async() => {
31+
if (btn.dataset.locked) return; // prevents multiple fast clicks
32+
btn.dataset.locked = '1';
33+
34+
// Uses Clipboard API to copy code block text
35+
await navigator.clipboard.writeText(block.textContent);
36+
37+
// Show success tick briefly
38+
btn.innerHTML = checkIcon;
39+
btn.classList.add('copied');
40+
41+
// Restore original icon after delay
42+
setTimeout(() => {
43+
btn.innerHTML = copyIcon;
44+
btn.classList.remove('copied');
45+
btn.dataset.locked = '';
46+
}, 1200);
47+
};
48+
49+
wrapper.appendChild(btn); // attach button to code block
50+
});
51+
});

docs/layout.pug

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ html(lang='en')
1313
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/github.css`)
1414
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/mongoose5.css`)
1515
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/carbonads.css`)
16+
link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/copy-code.css`)
17+
1618

1719
meta(name='msapplication-TileColor', content='#ffffff')
1820
meta(name='msapplication-TileImage', content=`${versions.versionedPath}/docs/images/favicon/ms-icon-144x144.png`)
@@ -172,3 +174,6 @@ html(lang='en')
172174

173175
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/navbar-search.js`)
174176
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/mobile-navbar-toggle.js`)
177+
178+
script(type="text/javascript" src=`${versions.versionedPath}/docs/js/copy-code.js`)
179+

docs/typescript/statics-and-methods.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,173 @@ const doc = new User({ name: 'test' });
8080
// Compiles correctly
8181
doc.updateName('foo');
8282
```
83+
84+
## Using `loadClass()` with TypeScript
85+
86+
Mongoose supports applying ES6 classes to a schema using [`schema.loadClass()`](../api/schema.html#Schema.prototype.loadClass()) as an alternative to defining statics and methods in your schema.
87+
When using TypeScript, there are a few important typing details to understand.
88+
89+
### Basic Usage
90+
91+
`loadClass()` copies static methods, instance methods, and ES getters/setters from the class onto the schema.
92+
93+
```ts
94+
class MyClass {
95+
myMethod() {
96+
return 42;
97+
}
98+
99+
static myStatic() {
100+
return 42;
101+
}
102+
103+
get myVirtual() {
104+
return 42;
105+
}
106+
}
107+
108+
const schema = new Schema({ property1: String });
109+
schema.loadClass(MyClass);
110+
```
111+
112+
Mongoose does not automatically update TypeScript types for class members. To get full type support, you must manually define types using Mongoose's [Model](../api/model.html) and [HydratedDocument](../typescript.html) generics.
113+
114+
```ts
115+
// 1. Define an interface for the raw document data
116+
interface RawDocType {
117+
property1: string;
118+
}
119+
120+
// 2. Define the Model type
121+
// This includes the raw data, query helpers, instance methods, virtuals, and statics.
122+
type MyCombinedModel = Model<
123+
RawDocType,
124+
{},
125+
Pick<MyClass, 'myMethod'>,
126+
Pick<MyClass, 'myVirtual'>
127+
> & Pick<typeof MyClass, 'myStatic'>;
128+
129+
// 3. Define the Document type
130+
type MyCombinedDocument = HydratedDocument<
131+
RawDocType,
132+
Pick<MyClass, 'myMethod'>,
133+
{},
134+
Pick<MyClass, 'myVirtual'>
135+
>;
136+
137+
// 4. Create the Mongoose model
138+
const MyModel = model<RawDocType, MyCombinedModel>(
139+
'MyClass',
140+
schema
141+
);
142+
143+
MyModel.myStatic();
144+
const doc = new MyModel();
145+
doc.myMethod();
146+
doc.myVirtual;
147+
doc.property1;
148+
```
149+
150+
### Typing `this` Inside Methods
151+
152+
You can annotate `this` in methods to enable full safety, using the [Model](../api/model.html) and [HydratedDocument](../typescript.html) types you defined.
153+
Note that this must be done for **each method individually**; it is not possible to set a `this` type for the entire class at once.
154+
155+
```ts
156+
class MyClass {
157+
// Instance method typed with correct `this` type
158+
myMethod(this: MyCombinedDocument) {
159+
return this.property1;
160+
}
161+
162+
// Static method typed with correct `this` type
163+
static myStatic(this: MyCombinedModel) {
164+
return 42;
165+
}
166+
}
167+
```
168+
169+
### Getters / Setters Limitation
170+
171+
TypeScript currently does **not** allow `this` parameters on getters/setters:
172+
173+
```ts
174+
class MyClass {
175+
// error TS2784: 'this' parameters are not allowed in getters
176+
get myVirtual(this: MyCombinedDocument) {
177+
return this.property1;
178+
}
179+
}
180+
```
181+
182+
This is a TypeScript limitation. See: [TypeScript issue #52923](https://github.com/microsoft/TypeScript/issues/52923)
183+
184+
As a workaround, you can cast `this` to the document type inside your getter:
185+
186+
```ts
187+
get myVirtual() {
188+
// Workaround: cast 'this' to your document type
189+
const self = this as MyCombinedDocument;
190+
return `Name: ${self.property1}`;
191+
}
192+
```
193+
194+
### Full Example Code
195+
196+
```ts
197+
import { Model, Schema, model, HydratedDocument } from 'mongoose';
198+
199+
interface RawDocType {
200+
property1: string;
201+
}
202+
203+
class MyClass {
204+
myMethod(this: MyCombinedDocument) {
205+
return this.property1;
206+
}
207+
208+
static myStatic(this: MyCombinedModel) {
209+
return 42;
210+
}
211+
212+
get myVirtual() {
213+
const self = this as MyCombinedDocument;
214+
return `Hello ${self.property1}`;
215+
}
216+
}
217+
218+
const schema = new Schema<RawDocType>({ property1: String });
219+
schema.loadClass(MyClass);
220+
221+
type MyCombinedModel = Model<
222+
RawDocType,
223+
{},
224+
Pick<MyClass, 'myMethod'>,
225+
Pick<MyClass, 'myVirtual'>
226+
> & Pick<typeof MyClass, 'myStatic'>;
227+
228+
type MyCombinedDocument = HydratedDocument<
229+
RawDocType,
230+
Pick<MyClass, 'myMethod'>,
231+
{},
232+
Pick<MyClass, 'myVirtual'>
233+
>;
234+
235+
const MyModel = model<RawDocType, MyCombinedModel>(
236+
'MyClass',
237+
schema
238+
);
239+
240+
const doc = new MyModel({ property1: 'world' });
241+
doc.myMethod();
242+
MyModel.myStatic();
243+
console.log(doc.myVirtual);
244+
```
245+
246+
### When Should I Use `loadClass()`?
247+
248+
`loadClass()` is useful for defining methods and statics in classes.
249+
If you have a strong preference for classes, you can use `loadClass()`; however, we recommend defining `statics` and `methods` in schema options as described in the first section.
250+
251+
The major downside of `loadClass()` in TypeScript is that it requires manual TypeScript types.
252+
If you want better type inference, you can use schema options [`methods`](../guide.html#methods) and [`statics`](../guide.html#statics).

docs/version-support.md

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
11
# Version Support
22

3-
Mongoose 8.x (released October 31, 2023) is the current Mongoose major version.
4-
We ship all new bug fixes and features to 8.x.
3+
## Mongoose 8 (Current Version)
54

6-
## Mongoose 7
5+
Released on **October 31, 2023**, Mongoose 8 is the latest major version.
6+
All new features, improvements, and bug fixes are delivered to 8.x—so if you want the best experience, this is the version to use.
77

8-
Mongoose 7.x (released February 27, 2023) is currently in legacy support.
9-
We ship all new bug fixes and features to 7.x.
8+
* **Latest release:** [8.20.0](https://mongoosejs.com/docs/index.html)
9+
* **Docs:** https://mongoosejs.com/docs/8.x/
1010

11-
## Mongoose 6
11+
## Mongoose 7 (Legacy)
1212

13-
Mongoose 6.x (released August 24, 2021) is currently only receiving security fixes and requested bug fixes as of August 24, 2023.
14-
Please open a [bug report on GitHub](https://github.com/Automattic/mongoose/issues/new?assignees=&labels=&template=bug.yml) to request backporting a fix to Mongoose 6.
13+
Mongoose 7.x was released on **February 27, 2023** and is now in **legacy support**.
14+
It still receives important fixes when needed, but it’s no longer the primary development focus.
1515

16-
Mongoose 6.x end of life (EOL) is January 1, 2025.
17-
Mongoose 6.x will no longer receive any updates, security or otherwise, after that date.
16+
* **Latest release:** [7.8.7](https://mongoosejs.com/docs/7.x/docs/guide.html)
17+
* **Docs:** https://mongoosejs.com/docs/7.x/
1818

19-
## Mongoose 5
19+
## Mongoose 6 (Limited Maintenance)
2020

21-
Mongoose 5.x (released January 17, 2018) is End-of-Life (EOL) since March 1, 2024. Mongoose 5.x will no longer receive any updates, security or otherwise.
21+
Released on **August 24, 2021**, Mongoose 6.x now only receives **security patches** and **requested bug fixes**.
22+
If you find an issue that needs to be backported, you can open a request on GitHub.
23+
24+
* **Latest release:** [6.13.8](https://mongoosejs.com/docs/6.x/docs/guide.html)
25+
* **Docs:** https://mongoosejs.com/docs/6.x/
26+
27+
**End of Life:** January 1, 2025
28+
After this date, Mongoose 6 will no longer receive any updates—not even security fixes.
29+
30+
## Mongoose 5 (End of Life)
31+
32+
Mongoose 5.x, released **January 17, 2018**, reached **End-of-Life** on **March 1, 2024**.
33+
It’s no longer maintained or updated.
34+
35+
* **Latest release:** [5.13.23](https://mongoosejs.com/docs/5.x/index.html)
36+
* **Docs:** https://mongoosejs.com/docs/6.x/

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"lodash.isequal": "4.5.0",
4747
"lodash.isequalwith": "4.4.0",
4848
"markdownlint-cli2": "^0.18.1",
49-
"marked": "16.4.1",
49+
"marked": "15.x",
5050
"mkdirp": "^3.0.1",
5151
"mocha": "11.7.4",
5252
"moment": "2.30.1",
@@ -81,6 +81,7 @@
8181
"docs:prepare:publish:5x": "git checkout 5.x && git merge 5.x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && git checkout gh-pages && npm run docs:copy:tmp:5x",
8282
"docs:prepare:publish:6x": "git checkout 6.x && git merge 6.x && npm run docs:clean:stable && env DOCS_DEPLOY=true npm run docs:generate && mv ./docs/6.x ./tmp && git checkout gh-pages && npm run docs:copy:tmp:6x",
8383
"docs:prepare:publish:7x": "env DOCS_DEPLOY=true npm run docs:generate && git checkout gh-pages && rimraf ./docs/7.x && mv ./tmp ./docs/7.x",
84+
"docs:prepare:publish:8x": "git checkout gh-pages && git merge 8.x && npm run docs:generate",
8485
"docs:check-links": "blc http://127.0.0.1:8089 -ro",
8586
"lint": "eslint .",
8687
"lint-js": "eslint . --ext .js --ext .cjs",

0 commit comments

Comments
 (0)