Skip to content

Commit d80a2ee

Browse files
authored
Merge pull request #12024 from hasezoey/updateDox
Update `dox` to latest version and fix some documentation issues
2 parents 51ea808 + 1cc2293 commit d80a2ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+338
-248
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,8 @@ docs/tutorials/*.html
4949
docs/typescript/*.html
5050
docs/api/*.html
5151
index.html
52+
53+
# yarn package-lock
54+
yarn.lock
55+
5256
examples/ecommerce-netlify-functions/.netlify/state.json

docs/source/api.js

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,35 @@ const out = module.exports.docs;
5050

5151
const combinedFiles = [];
5252
for (const file of files) {
53-
const comments = dox.parseComments(fs.readFileSync(`./${file}`, 'utf8'), { raw: true });
54-
comments.file = file;
55-
combinedFiles.push(comments);
53+
try {
54+
const comments = dox.parseComments(fs.readFileSync(`./${file}`, 'utf8'), { raw: true });
55+
comments.file = file;
56+
combinedFiles.push(comments);
57+
} catch (err) {
58+
// show log of which file has thrown a error for easier debugging
59+
console.error("Error while trying to parseComments for ", file);
60+
throw err;
61+
}
5662
}
5763

5864
parse();
5965

66+
/**
67+
* @typedef {Object} PropContext
68+
* @property {boolean} [isStatic] Defines wheter the current property is a static property (not mutually exlusive with "isInstance")
69+
* @property {boolean} [isInstance] Defines wheter the current property is a instance property (not mutually exlusive with "isStatic")
70+
* @property {boolean} [isFunction] Defines wheter the current property is meant to be a function
71+
* @property {string} [constructor] Defines the Constructor (or rather path) the current property is on
72+
* @property {boolean} [constructorWasUndefined] Defined wheter the "constructor" property was defined by "dox", but was set to "undefined"
73+
* @property {string} [type] Defines the type the property is meant to be
74+
* @property {string} [name] Defines the current Properties name
75+
* @property {Object} [return] The full object for a "@return" jsdoc tag
76+
* @property {string} [string] Defines the full string the property will be listed as
77+
* @property {string} [anchorId] Defines the Anchor ID to be used for linking
78+
* @property {string} [description] Defines the Description the property will be listed with
79+
* @property {string} [deprecated] Defines wheter the current Property is signaled as deprecated
80+
*/
81+
6082
function parse() {
6183
for (const props of combinedFiles) {
6284
let name = props.file.
@@ -88,43 +110,67 @@ function parse() {
88110
if (prop.ignore || prop.isPrivate) {
89111
continue;
90112
}
91-
113+
114+
/** @type {PropContext} */
92115
const ctx = prop.ctx || {};
116+
117+
// somehow in "dox", it is named "receiver" sometimes, not "constructor"
118+
// this is used as a fall-back if the handling below does not overwrite it
119+
if ("receiver" in ctx) {
120+
ctx.constructor = ctx.receiver;
121+
delete ctx.receiver;
122+
}
123+
124+
// in some cases "dox" has "ctx.constructor" defined but set to "undefined", which will later be used for setting "ctx.string"
125+
if ("constructor" in ctx && ctx.constructor === undefined) {
126+
ctx.constructorWasUndefined = true;
127+
}
128+
93129
for (const tag of prop.tags) {
94130
switch (tag.type) {
95131
case 'receiver':
96132
ctx.constructor = tag.string;
97133
break;
98134
case 'property':
99135
ctx.type = 'property';
136+
137+
// somewhere since 6.0 the "string" property came back, which was gone with 4.5
100138
let str = tag.string;
139+
101140
const match = str.match(/^{\w+}/);
102141
if (match != null) {
103142
ctx.type = match[0].substring(1, match[0].length - 1);
104143
str = str.replace(/^{\w+}\s*/, '');
105144
}
106145
ctx.name = str;
107-
ctx.string = `${ctx.constructor}.prototype.${ctx.name}`;
108146
break;
109147
case 'type':
110148
ctx.type = Array.isArray(tag.types) ? tag.types.join('|') : tag.types;
111149
break;
112150
case 'static':
113151
ctx.type = 'property';
114-
ctx.static = true;
115-
ctx.name = tag.string;
116-
ctx.string = `${data.name}.${ctx.name}`;
152+
ctx.isStatic = true;
153+
// dont take "string" as "name" from here, because jsdoc definitions of "static" do not have parameters, also its defined elsewhere anyway
154+
// ctx.name = tag.string;
117155
break;
118156
case 'function':
119157
ctx.type = 'function';
120-
ctx.static = true;
158+
ctx.isStatic = true;
121159
ctx.name = tag.string;
122-
ctx.string = `${data.name}.${ctx.name}()`;
160+
// extra parameter to make function definitions independant of where "@function" is defined
161+
// like "@static" could have overwritten "ctx.string" again if defined after "@function"
162+
ctx.isFunction = true;
123163
break;
124164
case 'return':
125-
tag.return = tag.description ?
126-
md.parse(tag.description).replace(/^<p>/, '').replace(/<\/p>$/, '') :
165+
tag.description = tag.description ?
166+
md.parse(tag.description).replace(/^<p>/, '').replace(/<\/p>\n?$/, '') :
127167
'';
168+
169+
// dox does not add "void" / "undefined" to types, so in the documentation it would result in a empty "«»"
170+
if (tag.string.includes('void') || tag.string.includes('undefined')) {
171+
tag.types.push("void");
172+
}
173+
128174
ctx.return = tag;
129175
break;
130176
case 'inherits':
@@ -133,6 +179,10 @@ function parse() {
133179
case 'event':
134180
case 'param':
135181
ctx[tag.type] = (ctx[tag.type] || []);
182+
// the following is required, because in newer "dox" version "null" is not included in "types" anymore, but a seperate property
183+
if (tag.nullable) {
184+
tag.types.push('null');
185+
}
136186
if (tag.types) {
137187
tag.types = tag.types.join('|');
138188
}
@@ -147,26 +197,49 @@ function parse() {
147197
case 'method':
148198
ctx.type = 'method';
149199
ctx.name = tag.string;
150-
ctx.string = `${ctx.constructor}.prototype.${ctx.name}()`;
200+
ctx.isFunction = true;
151201
break;
152202
case 'memberOf':
153203
ctx.constructor = tag.parent;
154-
ctx.string = `${ctx.constructor}.prototype.${ctx.name}`;
155-
if (ctx.type === 'method') {
156-
ctx.string += '()';
157-
}
158204
break;
159205
case 'constructor':
160-
ctx.string = tag.string + '()';
206+
ctx.string = tag.string;
161207
ctx.name = tag.string;
208+
ctx.isFunction = true;
209+
break;
210+
case 'instance':
211+
ctx.isInstance = true;
212+
break;
213+
case 'deprecated':
214+
ctx.deprecated = true;
215+
break;
162216
}
163217
}
164218

219+
if (ctx.isInstance && ctx.isStatic) {
220+
console.warn(`Property "${ctx.name}" in "${ctx.constructor}" has both instance and static JSDOC markings (most likely both @instance and @static)! (File: "${props.file}")`);
221+
}
222+
223+
// the following if-else-if statement is in this order, because there are more "instance" methods thans static
224+
// the following condition will be true if "isInstance = true" or if "isInstance = false && isStatic = false" AND "ctx.string" are empty or not defined
225+
// if "isStatic" and "isInstance" are falsy and "ctx.string" is not falsy, then rely on the "ctx.string" set by "dox"
226+
if (ctx.isInstance || (!ctx.isStatic && !ctx.isInstance && (!ctx.string || ctx.constructorWasUndefined))) {
227+
ctx.string = `${ctx.constructor}.prototype.${ctx.name}`;
228+
} else if (ctx.isStatic) {
229+
ctx.string = `${ctx.constructor}.${ctx.name}`;
230+
}
231+
232+
// add "()" to the end of the string if function
233+
if ((ctx.isFunction || ctx.type === "method") && !ctx.string.endsWith("()")) {
234+
ctx.string = ctx.string + "()";
235+
}
236+
237+
// fixing up "something.prototypemissingdot" to "something.prototype.missingdot"
165238
if (/\.prototype[^.]/.test(ctx.string)) {
166239
ctx.string = `${ctx.constructor}.prototype.${ctx.name}`;
167240
}
168241

169-
// Backwards compat
242+
// Backwards compat anchors
170243
if (typeof ctx.constructor === 'string') {
171244
ctx.anchorId = `${ctx.constructor.toLowerCase()}_${ctx.constructor}-${ctx.name}`;
172245
} else if (typeof ctx.receiver === 'string') {
@@ -178,9 +251,6 @@ function parse() {
178251
ctx.description = prop.description.full.
179252
replace(/<br \/>/ig, ' ').
180253
replace(/&gt;/ig, '>');
181-
if (ctx.description.includes('function capitalize')) {
182-
console.log('\n\n-------\n\n', ctx);
183-
}
184254
ctx.description = md.parse(ctx.description);
185255

186256
data.props.push(ctx);

lib/aggregate.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ Aggregate.prototype.sortByCount = function(arg) {
481481
*
482482
* @see $lookup https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/#pipe._S_lookup
483483
* @param {Object} options to $lookup as described in the above link
484-
* @return {Aggregate}* @api public
484+
* @return {Aggregate}
485+
* @api public
485486
*/
486487

487488
Aggregate.prototype.lookup = function(options) {
@@ -1051,7 +1052,7 @@ Aggregate.prototype.catch = function(reject) {
10511052
* You do not need to call this function explicitly, the JavaScript runtime
10521053
* will call it for you.
10531054
*
1054-
* #### Example
1055+
* #### Example:
10551056
*
10561057
* const agg = Model.aggregate([{ $match: { age: { $gte: 25 } } }]);
10571058
* for await (const doc of agg) {

lib/connection.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Connection.prototype.__proto__ = EventEmitter.prototype;
9393
*
9494
* Each state change emits its associated event name.
9595
*
96-
* #### Example
96+
* #### Example:
9797
*
9898
* conn.on('connected', callback);
9999
* conn.on('disconnected', callback);
@@ -193,7 +193,7 @@ Connection.prototype.collections;
193193
/**
194194
* The name of the database this connection points to.
195195
*
196-
* #### Example
196+
* #### Example:
197197
*
198198
* mongoose.createConnection('mongodb://localhost:27017/mydb').name; // "mydb"
199199
*
@@ -210,7 +210,7 @@ Connection.prototype.name;
210210
* a map from model names to models. Contains all models that have been
211211
* added to this connection using [`Connection#model()`](/docs/api/connection.html#connection_Connection-model).
212212
*
213-
* #### Example
213+
* #### Example:
214214
*
215215
* const conn = mongoose.createConnection();
216216
* const Test = conn.model('Test', mongoose.Schema({ name: String }));
@@ -230,7 +230,7 @@ Connection.prototype.models;
230230
* A number identifier for this connection. Used for debugging when
231231
* you have [multiple connections](/docs/connections.html#multiple_connections).
232232
*
233-
* #### Example
233+
* #### Example:
234234
*
235235
* // The default connection has `id = 0`
236236
* mongoose.connection.id; // 0
@@ -274,7 +274,7 @@ Object.defineProperty(Connection.prototype, 'plugins', {
274274
* The host name portion of the URI. If multiple hosts, such as a replica set,
275275
* this will contain the first host name in the URI
276276
*
277-
* #### Example
277+
* #### Example:
278278
*
279279
* mongoose.createConnection('mongodb://localhost:27017/mydb').host; // "localhost"
280280
*
@@ -294,7 +294,7 @@ Object.defineProperty(Connection.prototype, 'host', {
294294
* The port portion of the URI. If multiple hosts, such as a replica set,
295295
* this will contain the port from the first host name in the URI.
296296
*
297-
* #### Example
297+
* #### Example:
298298
*
299299
* mongoose.createConnection('mongodb://localhost:27017/mydb').port; // 27017
300300
*
@@ -313,7 +313,7 @@ Object.defineProperty(Connection.prototype, 'port', {
313313
/**
314314
* The username specified in the URI
315315
*
316-
* #### Example
316+
* #### Example:
317317
*
318318
* mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').user; // "val"
319319
*
@@ -332,7 +332,7 @@ Object.defineProperty(Connection.prototype, 'user', {
332332
/**
333333
* The password specified in the URI
334334
*
335-
* #### Example
335+
* #### Example:
336336
*
337337
* mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').pass; // "psw"
338338
*
@@ -1452,7 +1452,7 @@ Connection.prototype.setClient = function setClient(client) {
14521452
*
14531453
* @param {Object} options
14541454
* @param {Boolean} options.continueOnError `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.
1455-
* @returns
1455+
* @return {Promise} Returns a Promise, when the Promise resolves the value is a list of the dropped indexes.
14561456
*/
14571457
Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
14581458
const result = {};

lib/cursor/AggregationCursor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ if (Symbol.asyncIterator != null) {
107107
* Registers a transform function which subsequently maps documents retrieved
108108
* via the streams interface or `.next()`
109109
*
110-
* #### Example
110+
* #### Example:
111111
*
112112
* // Map documents returned by `data` events
113113
* Thing.
@@ -132,6 +132,7 @@ if (Symbol.asyncIterator != null) {
132132
*
133133
* @param {Function} fn
134134
* @return {AggregationCursor}
135+
* @memberOf AggregationCursor
135136
* @api public
136137
* @method map
137138
*/
@@ -226,7 +227,7 @@ AggregationCursor.prototype.eachAsync = function(fn, opts, callback) {
226227
* You do not need to call this function explicitly, the JavaScript runtime
227228
* will call it for you.
228229
*
229-
* #### Example
230+
* #### Example:
230231
*
231232
* // Async iterator without explicitly calling `cursor()`. Mongoose still
232233
* // creates an AggregationCursor instance internally.

lib/cursor/QueryCursor.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ QueryCursor.prototype._read = function() {
112112
* Registers a transform function which subsequently maps documents retrieved
113113
* via the streams interface or `.next()`
114114
*
115-
* #### Example
115+
* #### Example:
116116
*
117117
* // Map documents returned by `data` events
118118
* Thing.
@@ -137,6 +137,7 @@ QueryCursor.prototype._read = function() {
137137
*
138138
* @param {Function} fn
139139
* @return {QueryCursor}
140+
* @memberOf QueryCursor
140141
* @api public
141142
* @method map
142143
*/
@@ -211,7 +212,7 @@ QueryCursor.prototype.next = function(callback) {
211212
* will wait for the promise to resolve before iterating on to the next one.
212213
* Returns a promise that resolves when done.
213214
*
214-
* #### Example
215+
* #### Example:
215216
*
216217
* // Iterate over documents asynchronously
217218
* Thing.
@@ -300,7 +301,7 @@ QueryCursor.prototype._transformForAsyncIterator = function() {
300301
* You do not need to call this function explicitly, the JavaScript runtime
301302
* will call it for you.
302303
*
303-
* #### Example
304+
* #### Example:
304305
*
305306
* // Works without using `cursor()`
306307
* for await (const doc of Model.find([{ $sort: { name: 1 } }])) {
@@ -320,7 +321,7 @@ QueryCursor.prototype._transformForAsyncIterator = function() {
320321
* support async iterators.
321322
*
322323
* @method Symbol.asyncIterator
323-
* @memberOf Query
324+
* @memberOf QueryCursor
324325
* @instance
325326
* @api public
326327
*/

0 commit comments

Comments
 (0)