| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 | /** * The Overload Helper plugin automatically adds a signature-like string to the longnames of * overloaded functions and methods. In JSDoc, this string is known as a _variation_. (The longnames * of overloaded constructor functions are _not_ updated, so that JSDoc can identify the class' * members correctly.) * * Using this plugin allows you to link to overloaded functions without manually adding `@variation` * tags to your documentation. * * For example, suppose your code includes a function named `foo` that you can call in the * following ways: * * + `foo()` * + `foo(bar)` * + `foo(bar, baz)` (where `baz` is repeatable) * * This plugin assigns the following variations and longnames to each version of `foo`: * * + `foo()` gets the variation `()` and the longname `foo()`. * + `foo(bar)` gets the variation `(bar)` and the longname `foo(bar)`. * + `foo(bar, baz)` (where `baz` is repeatable) gets the variation `(bar, ...baz)` and the longname * `foo(bar, ...baz)`. * * You can then link to these functions with `{@link foo()}`, `{@link foo(bar)}`, and * `{@link foo(bar, ...baz)`. Note that the variation is based on the names of the function * parameters, _not_ their types. * * If you prefer to manually assign variations to certain functions, you can still do so with the * `@variation` tag. This plugin will not change these variations or add more variations for that * function, as long as the variations you've defined result in unique longnames. * * If an overloaded function includes multiple signatures with the same parameter names, the plugin * will assign numeric variations instead, starting at `(1)` and counting upwards. * * @module plugins/overloadHelper */// lookup table of function doclets by longnamelet functionDoclets;function hasUniqueValues(obj) {    let isUnique = true;    const seen = [];    Object.keys(obj).forEach(key => {        if (seen.includes(obj[key])) {            isUnique = false;        }        seen.push(obj[key]);    });    return isUnique;}function getParamNames(params) {    const names = [];    params.forEach(param => {        let name = param.name || '';        if (param.variable) {            name = `...${name}`;        }        if (name !== '') {            names.push(name);        }    });    return names.length ? names.join(', ') : '';}function getParamVariation({params}) {    return getParamNames(params || []);}function getUniqueVariations(doclets) {    let counter = 0;    const variations = {};    const docletKeys = Object.keys(doclets);    function getUniqueNumbers() {        docletKeys.forEach(doclet => {            let newLongname;            while (true) {                counter++;                variations[doclet] = String(counter);                // is this longname + variation unique?                newLongname = `${doclets[doclet].longname}(${variations[doclet]})`;                if ( !functionDoclets[newLongname] ) {                    break;                }            }        });    }    function getUniqueNames() {        // start by trying to preserve existing variations        docletKeys.forEach(doclet => {            variations[doclet] = doclets[doclet].variation || getParamVariation(doclets[doclet]);        });        // if they're identical, try again, without preserving existing variations        if ( !hasUniqueValues(variations) ) {            docletKeys.forEach(doclet => {                variations[doclet] = getParamVariation(doclets[doclet]);            });            // if they're STILL identical, switch to numeric variations            if ( !hasUniqueValues(variations) ) {                getUniqueNumbers();            }        }    }    // are we already using numeric variations? if so, keep doing that    if (functionDoclets[`${doclets.newDoclet.longname}(1)`]) {        getUniqueNumbers();    }    else {        getUniqueNames();    }    return variations;}function ensureUniqueLongname(newDoclet) {    const doclets = {        oldDoclet: functionDoclets[newDoclet.longname],        newDoclet: newDoclet    };    const docletKeys = Object.keys(doclets);    let oldDocletLongname;    let variations = {};    if (doclets.oldDoclet) {        oldDocletLongname = doclets.oldDoclet.longname;        // if the shared longname has a variation, like MyClass#myLongname(variation),        // remove the variation        if (doclets.oldDoclet.variation || doclets.oldDoclet.variation === '') {            docletKeys.forEach(doclet => {                doclets[doclet].longname = doclets[doclet].longname.replace(/\([\s\S]*\)$/, '');                doclets[doclet].variation = null;            });        }        variations = getUniqueVariations(doclets);        // update the longnames/variations        docletKeys.forEach(doclet => {            doclets[doclet].longname += `(${variations[doclet]})`;            doclets[doclet].variation = variations[doclet];        });        // update the old doclet in the lookup table        functionDoclets[oldDocletLongname] = null;        functionDoclets[doclets.oldDoclet.longname] = doclets.oldDoclet;    }    // always store the new doclet in the lookup table    functionDoclets[doclets.newDoclet.longname] = doclets.newDoclet;    return doclets.newDoclet;}exports.handlers = {    parseBegin() {        functionDoclets = {};    },    newDoclet(e) {        if (e.doclet.kind === 'function') {            e.doclet = ensureUniqueLongname(e.doclet);        }    },    parseComplete() {        functionDoclets = null;    }};
 |