From 636369181b9d6cebbcb4e5233f1ce45490f7fd42 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Wed, 9 May 2018 12:01:16 +0200 Subject: [PATCH] Bring back basic api documentation --- config/jsdoc/api/conf.json | 64 ++++++------ config/jsdoc/api/plugins/api.js | 7 ++ config/jsdoc/api/plugins/default-export.js | 85 ++++++++++++++++ config/jsdoc/api/plugins/inheritdoc.js | 109 --------------------- package.json | 3 +- 5 files changed, 125 insertions(+), 143 deletions(-) create mode 100644 config/jsdoc/api/plugins/default-export.js delete mode 100644 config/jsdoc/api/plugins/inheritdoc.js diff --git a/config/jsdoc/api/conf.json b/config/jsdoc/api/conf.json index 0a0cfb601f..13cf7460f1 100644 --- a/config/jsdoc/api/conf.json +++ b/config/jsdoc/api/conf.json @@ -1,36 +1,34 @@ { - "opts": { - "recurse": true, - "template": "config/jsdoc/api/template" + "opts": { + "recurse": true + }, + "tags": { + "allowUnknownTags": true + }, + "source": { + "includePattern": ".+\\.js(doc)?$", + "excludePattern": "(^|\\/|\\\\)_", + "include": [ + "src" + ] + }, + "plugins": [ + "plugins/markdown", + "config/jsdoc/api/plugins/default-export", + "config/jsdoc/api/plugins/events", + "config/jsdoc/api/plugins/observable", + "config/jsdoc/api/plugins/api" + ], + "markdown": { + "parser": "gfm" + }, + "templates": { + "cleverLinks": true, + "monospaceLinks": true, + "default": { + "outputSourceFiles": false }, - "tags": { - "allowUnknownTags": true - }, - "source": { - "includePattern": ".+\\.js(doc)?$", - "excludePattern": "(^|\\/|\\\\)_", - "include": [ - "src" - ] - }, - "plugins": [ - "plugins/markdown", - "config/jsdoc/api/plugins/inheritdoc", - "config/jsdoc/api/plugins/typedefs", - "config/jsdoc/api/plugins/events", - "config/jsdoc/api/plugins/observable", - "config/jsdoc/api/plugins/api" - ], - "markdown": { - "parser": "gfm" - }, - "templates": { - "cleverLinks": true, - "monospaceLinks": true, - "default": { - "outputSourceFiles": false - }, - "applicationName": "OpenLayers" - }, - "jsVersion": 180 + "applicationName": "OpenLayers" + }, + "jsVersion": 180 } diff --git a/config/jsdoc/api/plugins/api.js b/config/jsdoc/api/plugins/api.js index 4f2204a21f..b7d9390548 100644 --- a/config/jsdoc/api/plugins/api.js +++ b/config/jsdoc/api/plugins/api.js @@ -24,6 +24,7 @@ exports.defineTags = function(dictionary) { const api = []; const classes = {}; const types = {}; +const modules = {}; function hasApiMembers(doclet) { return doclet.longname.split('#')[0] == this.longname; @@ -68,6 +69,7 @@ function extractTypes(item) { item.type.names.forEach(function(type) { const match = type.match(/^(.*<)?([^>]*)>?$/); if (match) { + modules[match[2]] = true; types[match[2]] = true; } }); @@ -93,6 +95,7 @@ exports.handlers = { newDoclet: function(e) { const doclet = e.doclet; if (doclet.stability) { + modules[doclet.longname.split('~').shift()] = true; api.push(doclet); } // Mark explicity defined namespaces - needed in parseComplete to keep @@ -101,6 +104,7 @@ exports.handlers = { doclet.namespace_ = true; } if (doclet.kind == 'class') { + modules[doclet.longname.split('~').shift()] = true; classes[doclet.longname] = doclet; } }, @@ -126,6 +130,9 @@ exports.handlers = { // Always document namespaces and items with stability annotation continue; } + if (doclet.kind == 'module' && doclet.longname in modules) { + continue; + } if (doclet.kind == 'class' && api.some(hasApiMembers, doclet)) { // Mark undocumented classes with documented members as unexported. // This is used in ../template/tmpl/container.tmpl to hide the diff --git a/config/jsdoc/api/plugins/default-export.js b/config/jsdoc/api/plugins/default-export.js new file mode 100644 index 0000000000..e85d0941f7 --- /dev/null +++ b/config/jsdoc/api/plugins/default-export.js @@ -0,0 +1,85 @@ +/** + * @filedesc + * Expands module path type to point to default export when no name is given + */ + +const fs = require('fs'); +const path = require('path'); + +let moduleRoot; + +function addDefaultExportPath(obj) { + if (!Array.isArray(obj)) { + obj = obj.names; + } + obj.forEach((name, index) => { + const matches = name.match(/module\:([^>|),\.<]|)+/g); + if (matches) { + matches.forEach(module => { + if (!/[~\.]/.test(module)) { + const checkFile = path.resolve(moduleRoot, module.replace(/^module\:/, '')); + const file = fs.readFileSync(require.resolve(checkFile), 'utf-8'); + const lines = file.split('\n'); + let hasDefaultExport = false; + for (let i = 0, ii = lines.length; i < ii; ++i) { + hasDefaultExport = hasDefaultExport || lines[i].indexOf('export default ') == 0; + const match = lines[i].match(/^export default ([A-Za-z_$][A-Za-z0-9_$]+);$/); + if (match) { + // Use variable name if default export is assigned to a variable. + obj[index] = name.replace(module, `${module}~${match[1]}`); + return; + } + } + if (hasDefaultExport) { + // Duplicate last part if default export is not assigned to a variable. + obj[index] = name.replace(module, `${module}~${module.split('/').pop()}`); + } + } + }); + } + }); +} + +exports.handlers = { + + /** + * Adds default export to module path types without name + * @param {Object} e Event object. + */ + newDoclet: function(e) { + const doclet = e.doclet; + if (doclet.kind == 'module') { + const levelsUp = doclet.longname.replace(/^module\:/, '').split('/'); + if (doclet.meta.filename != 'index.js') { + levelsUp.pop(); + } + const pathArgs = [doclet.meta.path].concat(levelsUp.map(() => '../')); + moduleRoot = path.resolve.apply(null, pathArgs); + } else { + if (doclet.augments) { + addDefaultExportPath(doclet.augments); + } + if (doclet.params) { + doclet.params.forEach(p => addDefaultExportPath(p.type)); + } + if (doclet.returns) { + doclet.returns.forEach(r => addDefaultExportPath(r.type)); + } + if (doclet.properties) { + doclet.properties.forEach(p => addDefaultExportPath(p.type)); + } + if (doclet.type) { + addDefaultExportPath(doclet.type); + } + } + }, + + /** + * Adds `options.*` params for options that match the longname of one of the + * collected typedefs. + * @param {Object} e Event object. + */ + parseComplete: function(e) { + } + +}; diff --git a/config/jsdoc/api/plugins/inheritdoc.js b/config/jsdoc/api/plugins/inheritdoc.js deleted file mode 100644 index e252269bcc..0000000000 --- a/config/jsdoc/api/plugins/inheritdoc.js +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This is a hack to prevent inheritDoc tags from entirely removing - * documentation of the method that inherits the documentation. - * - * TODO: Remove this hack when https://github.com/jsdoc3/jsdoc/issues/53 - * is addressed. - */ - - -exports.defineTags = function(dictionary) { - dictionary.defineTag('inheritDoc', { - mustHaveValue: false, - canHaveType: false, - canHaveName: false, - onTagged: function(doclet, tag) { - doclet.inheritdoc = true; - } - }); -}; - - -const lookup = {}; -const incompleteByClass = {}; -const keepKeys = ['comment', 'meta', 'name', 'memberof', 'longname', 'augment', - 'stability']; - -exports.handlers = { - - newDoclet: function(e) { - const doclet = e.doclet; - let incompletes; - if (!(doclet.longname in lookup)) { - lookup[doclet.longname] = []; - } - lookup[doclet.longname].push(doclet); - if (doclet.inheritdoc) { - if (!(doclet.memberof in incompleteByClass)) { - incompleteByClass[doclet.memberof] = []; - } - incompletes = incompleteByClass[doclet.memberof]; - if (incompletes.indexOf(doclet.name) == -1) { - incompletes.push(doclet.name); - } - } - }, - - parseComplete: function(e) { - let ancestors, candidate, candidates, doclet, i, j, k, l, key; - let incompleteDoclet, stability, incomplete, incompletes; - const doclets = e.doclets; - for (i = doclets.length - 1; i >= 0; --i) { - doclet = doclets[i]; - if (doclet.augments) { - ancestors = [].concat(doclet.augments); - } - incompletes = incompleteByClass[doclet.longname]; - if (ancestors && incompletes) { - // collect ancestors from the whole hierarchy - for (j = 0; j < ancestors.length; ++j) { - candidates = lookup[ancestors[j]]; - if (candidates) { - for (k = candidates.length - 1; k >= 0; --k) { - candidate = candidates[k]; - if (candidate.augments) { - ancestors = ancestors.concat(candidate.augments); - } - } - } - } - // walk through all inheritDoc members - for (j = incompletes.length - 1; j >= 0; --j) { - incomplete = incompletes[j]; - candidates = lookup[doclet.longname + '#' + incomplete]; - if (candidates) { - // get the incomplete doclet that needs to be augmented - for (k = candidates.length - 1; k >= 0; --k) { - incompleteDoclet = candidates[k]; - if (incompleteDoclet.inheritdoc) { - break; - } - } - } - // find the documented ancestor - for (k = ancestors.length - 1; k >= 0; --k) { - candidates = lookup[ancestors[k] + '#' + incomplete]; - if (candidates) { - for (l = candidates.length - 1; l >= 0; --l) { - candidate = candidates[l]; - if (candidate && !candidate.inheritdoc) { - stability = candidate.stability || incompleteDoclet.stability; - if (stability) { - incompleteDoclet.stability = stability; - for (key in candidate) { - if (candidate.hasOwnProperty(key) && - keepKeys.indexOf(key) == -1) { - incompleteDoclet[key] = candidate[key]; - } - } - } - } - } - } - } - } - } - } - } - -}; diff --git a/package.json b/package.json index 58a5b63dfe..da1723c508 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "presrc-closure": "npm run prebuild", "src-closure": "babel -q --out-dir build/src-closure src/", "pretypecheck": "npm run src-closure", - "typecheck": "node tasks/typecheck" + "typecheck": "node tasks/typecheck", + "apidoc": "jsdoc -c config/jsdoc/api/conf.json -d build/apidoc" }, "main": "src/ol/index.js", "repository": {