From b462c3cc325a63889ce1e047a82386278ffa916a Mon Sep 17 00:00:00 2001 From: Zack Hall Date: Wed, 17 Apr 2019 14:12:05 -0400 Subject: [PATCH 1/2] Add initial commit of gatsby-source-lodash plugin. --- gatsby-config.js | 9 + plugins/gatsby-source-lodash/README.md | 25 + plugins/gatsby-source-lodash/gatsby-node.js | 99 +++ plugins/gatsby-source-lodash/lib/alias.js | 259 ++++++++ plugins/gatsby-source-lodash/lib/entry.js | 575 ++++++++++++++++++ plugins/gatsby-source-lodash/lib/util.js | 96 +++ .../gatsby-source-lodash/package-lock.json | 31 + plugins/gatsby-source-lodash/package.json | 20 + 8 files changed, 1114 insertions(+) create mode 100644 plugins/gatsby-source-lodash/README.md create mode 100644 plugins/gatsby-source-lodash/gatsby-node.js create mode 100644 plugins/gatsby-source-lodash/lib/alias.js create mode 100644 plugins/gatsby-source-lodash/lib/entry.js create mode 100644 plugins/gatsby-source-lodash/lib/util.js create mode 100644 plugins/gatsby-source-lodash/package-lock.json create mode 100644 plugins/gatsby-source-lodash/package.json diff --git a/gatsby-config.js b/gatsby-config.js index 6979a3f2..27d8eec5 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -19,6 +19,15 @@ module.exports = { path: `${__dirname}/src/images`, }, }, + { + resolve: "gatsby-source-lodash", + options: { + versions: [{ + version: '4.17.11', + url: 'https://raw.githubusercontent.com/lodash/lodash/4.17.11-npm/lodash.js', + }] + }, + }, `gatsby-plugin-react-svg`, `gatsby-transformer-sharp`, `gatsby-plugin-sharp`, diff --git a/plugins/gatsby-source-lodash/README.md b/plugins/gatsby-source-lodash/README.md new file mode 100644 index 00000000..09872cd2 --- /dev/null +++ b/plugins/gatsby-source-lodash/README.md @@ -0,0 +1,25 @@ +# Gatsby Source Lodash + +A simple Gatsby Source Plugin to grab method metadata from Lodash. + +## Usage + +In the `gatsby-config.js` file, add `gatsby-source-lodash` to the `module.exports`. + +```js +module.exports = { + plugins: [ + ... + { + resolve: "gatsby-source-lodash", + options: { + versions: [{ + version: '4.17.11', + url: 'https://raw.githubusercontent.com/lodash/lodash/4.17.11-npm/lodash.js', + }] + }, + }, + ... + ] +} +``` \ No newline at end of file diff --git a/plugins/gatsby-source-lodash/gatsby-node.js b/plugins/gatsby-source-lodash/gatsby-node.js new file mode 100644 index 00000000..60d2f40f --- /dev/null +++ b/plugins/gatsby-source-lodash/gatsby-node.js @@ -0,0 +1,99 @@ +'use strict'; + +const fetch = require("node-fetch"), + _ = require("lodash"), + Entry = require('./lib/entry.js'), + getEntries = Entry.getEntries; + +exports.sourceNodes = ( + { actions, createNodeId, createContentDigest }, + configOptions +) => { + const { createNode } = actions + + // Gatsby adds a configOption that's not needed for this plugin, delete it + delete configOptions.plugins + + // TODO: Extend this to include multiple versions + const url = configOptions.versions[0].url, + version = configOptions.versions[0].version; + + const processEntry = entry => { + try { + // Exit early if the entry is private or has no name + if (!entry || !entry.getName() || entry.isPrivate()) { + return; + } + } catch (err) { + // Some of the non-lodash methods were throwing a hard to trace error + // from the lib code. Rather than trace back, it was easier to catch + // since they aren't part of lodash. + return; + } + + // Special handling of aliases to get call names. Without this, there are + // circular JS object references. + const aliases = entry.getAliases().map(alias => { + const member = entry.getMembers(0) || '', + name = alias.getName(); + return `${member}.${name}`; + }) + + const params = entry.getParams().map( + ([type, name, desc]) => ({ type, name, desc })); + + const entryData = { + aliases, + version, + params, + call: entry.getCall(), + category: entry.getCategory(), + desc: entry.getDesc(), + example: entry.getExample(), + hash: entry.getHash(), + lineNumber: entry.getLineNumber(), + members: entry.getMembers(), + name: entry.getName(), + related: entry.getRelated(), + returns: entry.getReturns(), + since: entry.getSince(), + type: entry.getType(), + isAlias: entry.isAlias(), + isCtor: entry.isCtor(), + isFunction: entry.isFunction(), + isLicense: entry.isLicense(), + isPlugin: entry.isPlugin(), + isStatic: entry.isStatic(), + } + + const nodeData = _.assign({}, entryData, { + id: createNodeId(`lodash_method_${version}_${entryData.hash}_${entryData.lineNumber}`), + parent: null, + children: [], + internal: { + type: 'LodashMethod', + content: JSON.stringify(entryData), + contentDigest: createContentDigest(JSON.stringify(entryData)), + } + }); + + return nodeData; + } + + return ( + fetch(url) + .then(res => res.text()) + .then(body => { + const entries = getEntries(body); + + // For each entry, create node. + _.each(entries, entry => { + entry = new Entry(entry, body); + const nodeData = processEntry(entry); + if (nodeData) { + createNode(nodeData); + } + }) + }) + ) +} \ No newline at end of file diff --git a/plugins/gatsby-source-lodash/lib/alias.js b/plugins/gatsby-source-lodash/lib/alias.js new file mode 100644 index 00000000..34bcca22 --- /dev/null +++ b/plugins/gatsby-source-lodash/lib/alias.js @@ -0,0 +1,259 @@ +'use strict'; + +var _ = require('lodash'); + +/*----------------------------------------------------------------------------*/ + +/** + * The Alias constructor. + * + * @constructor + * @param {string} name The alias name. + * @param {Object} owner The alias owner. + */ +function Alias(name, owner) { + this._owner = owner; + this._name = name; +} + +/** + * Extracts the entry's `alias` objects. + * + * @memberOf Alias + * @param {number} [index] The index of the array value to return. + * @returns {Array|string} Returns the entry's `alias` objects. + */ +function getAliases(index) { + return index == null ? [] : undefined; +} + +/** + * Extracts the function call from the owner entry. + * + * @memberOf Alias + * @returns {string} Returns the function call. + */ +function getCall() { + return this._owner.getCall(); +} + +/** + * Extracts the owner entry's `category` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `category` data. + */ +function getCategory() { + return this._owner.getCategory(); +} + +/** + * Extracts the owner entry's description. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's description. + */ +function getDesc() { + return this._owner.getDesc(); +} + +/** + * Extracts the owner entry's `example` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `example` data. + */ +function getExample() { + return this._owner.getExample(); +} + +/** + * Extracts the entry's hash value for permalinking. + * + * @memberOf Alias + * @param {string} [style] The hash style. + * @returns {string} Returns the entry's hash value (without a hash itself). + */ +function getHash(style) { + return this._owner.getHash(style); +} + +/** + * Resolves the owner entry's line number. + * + * @memberOf Alias + * @returns {number} Returns the owner entry's line number. + */ +function getLineNumber() { + return this._owner.getLineNumber(); +} + +/** + * Extracts the owner entry's `member` data. + * + * @memberOf Alias + * @param {number} [index] The index of the array value to return. + * @returns {Array|string} Returns the owner entry's `member` data. + */ +function getMembers(index) { + return this._owner.getMembers(index); +} + +/** + * Extracts the owner entry's `name` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `name` data. + */ +function getName() { + return this._name; +} + +/** + * Gets the owner entry object. + * + * @memberOf Alias + * @returns {Object} Returns the owner entry. + */ +function getOwner() { + return this._owner; +} + +/** + * Extracts the owner entry's `param` data. + * + * @memberOf Alias + * @param {number} [index] The index of the array value to return. + * @returns {Array} Returns the owner entry's `param` data. + */ +function getParams(index) { + return this._owner.getParams(index); +} + +/** + * Extracts the owner entry's `returns` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `returns` data. + */ +function getReturns() { + return this._owner.getReturns(); +} + +/** + * Extracts the owner entry's `since` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `since` data. + */ +function getSince() { + return this._owner.getSince(); +} + +/** + * Extracts the owner entry's `type` data. + * + * @memberOf Alias + * @returns {string} Returns the owner entry's `type` data. + */ +function getType() { + return this._owner.getType(); +} + +/** + * Checks if the entry is an alias. + * + * @memberOf Alias + * @returns {boolean} Returns `true`. + */ +function isAlias() { + return true; +} + +/** + * Checks if the owner entry is a constructor. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if a constructor, else `false`. + */ +function isCtor() { + return this._owner.isCtor(); +} + +/** + * Checks if the entry is a function reference. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if the entry is a function reference, else `false`. + */ +function isFunction() { + return this._owner.isFunction(); +} + +/** + * Checks if the owner entry is a license. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if a license, else `false`. + */ +function isLicense() { + return this._owner.isLicense(); +} + +/** + * Checks if the owner entry *is* assigned to a prototype. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if assigned to a prototype, else `false`. + */ +function isPlugin() { + return this._owner.isPlugin(); +} + +/** + * Checks if the owner entry is private. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if private, else `false`. + */ +function isPrivate() { + return this._owner.isPrivate(); +} + +/** + * Checks if the owner entry is *not* assigned to a prototype. + * + * @memberOf Alias + * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`. + */ +function isStatic() { + return this._owner.isStatic(); +} + +/*----------------------------------------------------------------------------*/ + +_.assign(Alias.prototype, { + 'getAliases': getAliases, + 'getCall': getCall, + 'getCategory': getCategory, + 'getDesc': getDesc, + 'getExample': getExample, + 'getHash': getHash, + 'getLineNumber': getLineNumber, + 'getMembers': getMembers, + 'getName': getName, + 'getOwner': getOwner, + 'getParams': getParams, + 'getReturns': getReturns, + 'getSince': getSince, + 'getType': getType, + 'isAlias': isAlias, + 'isCtor': isCtor, + 'isFunction': isFunction, + 'isLicense': isLicense, + 'isPlugin': isPlugin, + 'isPrivate': isPrivate, + 'isStatic': isStatic, +}); + +module.exports = Alias; diff --git a/plugins/gatsby-source-lodash/lib/entry.js b/plugins/gatsby-source-lodash/lib/entry.js new file mode 100644 index 00000000..943ad4fe --- /dev/null +++ b/plugins/gatsby-source-lodash/lib/entry.js @@ -0,0 +1,575 @@ +'use strict'; + +var _ = require('lodash'), + fp = require('lodash/fp'), + os = require('os'), + Alias = require('./alias.js'), + util = require('./util.js'); + +/*----------------------------------------------------------------------------*/ + +/** + * Gets the param type of `tag`. + * + * @private + * @param {Object} tag The param tag to inspect. + * @returns {string} Returns the param type. + */ +function getParamType(tag) { + var expression = tag.expression, + result = '', + type = tag.type; + + switch (type) { + case 'AllLiteral': + result = '*'; + break; + + case 'NameExpression': + result = _.toString(tag.name); + break; + + case 'RestType': + result = '...' + result; + break; + + case 'TypeApplication': + expression = undefined; + result = _(tag) + .chain() + .get('applications') + .map(_.flow(getParamType, fp.add(fp, '[]'))) + .sort(util.compareNatural) + .join('|') + .value(); + break; + + case 'UnionType': + result = _(tag) + .chain() + .get('elements') + .map(getParamType) + .sort(util.compareNatural) + .join('|') + .value(); + } + if (expression) { + result += getParamType(expression); + } + return type == 'UnionType' + ? ('(' + result + ')') + : result; +} + +/** + * Gets an `entry` tag by `tagName`. + * + * @private + * @param {Object} entry The entry to inspect. + * @param {string} tagName The name of the tag. + * @returns {null|Object} Returns the tag. + */ +function getTag(entry, tagName) { + var parsed = entry.parsed; + return _.find(parsed.tags, ['title', tagName]) || null; +} + +/** + * Gets an `entry` tag value by `tagName`. + * + * @private + * @param {Object} entry The entry to inspect. + * @param {string} tagName The name of the tag. + * @returns {string} Returns the tag value. + */ +function getValue(entry, tagName) { + var parsed = entry.parsed, + result = parsed.description, + tag = getTag(entry, tagName); + + if (tagName == 'alias') { + result = _.get(tag, 'name') ; + + // Doctrine can't parse alias tags containing multiple values so extract + // them from the error message. + var error = _.first(_.get(tag, 'errors')); + if (error) { + result += error.replace(/^[^']*'|'[^']*$/g, ''); + } + } + else if (tagName == 'type') { + result = _.get(tag, 'type.name'); + } + else if (tagName != 'description') { + result = _.get(tag, 'name') || _.get(tag, 'description'); + } + return tagName == 'example' + ? _.toString(result) + : util.format(result); +} + +/** + * Checks if `entry` has a tag of `tagName`. + * + * @private + * @param {Object} entry The entry to inspect. + * @param {string} tagName The name of the tag. + * @returns {boolean} Returns `true` if the tag is found, else `false`. + */ +function hasTag(entry, tagName) { + return getTag(entry, tagName) !== null; +} + +/** + * Converts CR+LF line endings to LF. + * + * @private + * @param {string} string The string to convert. + * @returns {string} Returns the converted string. + */ +function normalizeEOL(string) { + return string.replace(/\r\n/g, '\n'); +} + +/*----------------------------------------------------------------------------*/ + +/** + * The Entry constructor. + * + * @constructor + * @param {string} entry The documentation entry to analyse. + * @param {string} source The source code. + * @param {string} [lang='js'] The language highlighter used for code examples. + */ +function Entry(entry, source, lang) { + entry = normalizeEOL(entry); + + this.entry = entry; + this.lang = lang == null ? 'js' : lang; + this.parsed = util.parse(entry.replace(/(\*)\/\s*.+$/, '*')); + this.source = normalizeEOL(source); + this.getCall = _.memoize(this.getCall); + this.getCategory = _.memoize(this.getCategory); + this.getDesc = _.memoize(this.getDesc); + this.getExample = _.memoize(this.getExample); + this.getHash = _.memoize(this.getHash); + this.getLineNumber = _.memoize(this.getLineNumber); + this.getName = _.memoize(this.getName); + this.getRelated = _.memoize(this.getRelated); + this.getReturns = _.memoize(this.getReturns); + this.getSince = _.memoize(this.getSince); + this.getType = _.memoize(this.getType); + this.isAlias = _.memoize(this.isAlias); + this.isCtor = _.memoize(this.isCtor); + this.isFunction = _.memoize(this.isFunction); + this.isLicense = _.memoize(this.isLicense); + this.isPlugin = _.memoize(this.isPlugin); + this.isPrivate = _.memoize(this.isPrivate); + this.isStatic = _.memoize(this.isStatic); + this._aliases = this._members = this._params = undefined; +} + +/** + * Extracts the documentation entries from source code. + * + * @static + * @memberOf Entry + * @param {string} source The source code. + * @returns {Array} Returns the array of entries. + */ +function getEntries(source) { + return _.toString(source).match(/\/\*\*(?![-!])[\s\S]*?\*\/\s*.+/g) || []; +} + +/** + * Extracts the entry's `alias` objects. + * + * @memberOf Entry + * @param {number} index The index of the array value to return. + * @returns {Array|string} Returns the entry's `alias` objects. + */ +function getAliases(index) { + if (this._aliases === undefined) { + var owner = this; + this._aliases = _(getValue(this, 'alias')) + .split(/,\s*/) + .compact() + .sort(util.compareNatural) + .map(function(value) { return new Alias(value, owner); }) + .value(); + } + var result = this._aliases; + return index === undefined ? result : result[index]; +} + +/** + * Extracts the function call from the entry. + * + * @memberOf Entry + * @returns {string} Returns the function call. + */ +function getCall() { + var result = _.trim(_.get(/\*\/\s*(?:function\s+)?([^\s(]+)\s*\(/.exec(this.entry), 1)); + if (!result) { + result = _.trim(_.get(/\*\/\s*(.*?)[:=,]/.exec(this.entry), 1)); + result = /['"]$/.test(result) + ? _.trim(result, '"\'') + : result.split('.').pop().split(/^(?:const|let|var) /).pop(); + } + var name = getValue(this, 'name') || result; + if (!this.isFunction()) { + return name; + } + var params = this.getParams(); + result = _.castArray(result); + + // Compile the function call syntax. + _.each(params, function(param) { + var paramValue = param[1], + parentParam = _.get(/\w+(?=\.[\w.]+)/.exec(paramValue), 0); + + var parentIndex = parentParam == null ? -1 : _.findIndex(params, function(param) { + return _.trim(param[1], '[]').split(/\s*=/)[0] == parentParam; + }); + + // Skip params that are properties of other params (e.g. `options.leading`). + if (_.get(params[parentIndex], 0) != 'Object') { + result.push(paramValue); + } + }); + + // Format the function call. + return name + '(' + result.slice(1).join(', ') + ')'; +} + +/** + * Extracts the entry's `category` data. + * + * @memberOf Entry + * @returns {string} Returns the entry's `category` data. + */ +function getCategory() { + var result = getValue(this, 'category'); + return result || (this.getType() == 'Function' ? 'Methods' : 'Properties'); +} + +/** + * Extracts the entry's description. + * + * @memberOf Entry + * @returns {string} Returns the entry's description. + */ +function getDesc() { + var type = this.getType(), + result = getValue(this, 'description'); + + return (!result || type == 'Function' || type == 'unknown') + ? result + : ('(' + _.trim(type.replace(/\|/g, ', '), '()') + '): ' + result); +} + +/** + * Extracts the entry's `example` data. + * + * @memberOf Entry + * @returns {string} Returns the entry's `example` data. + */ +function getExample() { + var result = getValue(this, 'example'); + return result && ('```' + this.lang + '\n' + result + '\n```'); +} + +/** + * Extracts the entry's hash value for permalinking. + * + * @memberOf Entry + * @param {string} [style] The hash style. + * @returns {string} Returns the entry's hash value (without a hash itself). + */ +function getHash(style) { + var result = _.toString(this.getMembers(0)); + if (style == 'github') { + if (result) { + result += this.isPlugin() ? 'prototype' : ''; + } + result += this.getCall(); + return result + .replace(/[\\.=|'"(){}\[\]\t ]/g, '') + .replace(/[#,]+/g, '-') + .toLowerCase(); + } + if (result) { + result += '-' + (this.isPlugin() ? 'prototype-' : ''); + } + result += this.isAlias() ? this.getOwner().getName() : this.getName(); + return result + .replace(/\./g, '-') + .replace(/^_-/, ''); +} + +/** + * Resolves the entry's line number. + * + * @memberOf Entry + * @returns {number} Returns the entry's line number. + */ +function getLineNumber() { + var lines = this.source + .slice(0, this.source.indexOf(this.entry) + this.entry.length) + .match(/\n/g) + .slice(1); + + // Offset by 2 because the first line number is before a line break and the + // last line doesn't include a line break. + return lines.length + 2; +} + +/** + * Extracts the entry's `member` data. + * + * @memberOf Entry + * @param {number} [index] The index of the array value to return. + * @returns {Array|string} Returns the entry's `member` data. + */ +function getMembers(index) { + if (this._members === undefined) { + this._members = _(getValue(this, 'member') || getValue(this, 'memberOf')) + .split(/,\s*/) + .compact() + .sort(util.compareNatural) + .value(); + } + var result = this._members; + return index === undefined ? result : result[index]; +} + +/** + * Extracts the entry's `name` data. + * + * @memberOf Entry + * @returns {string} Returns the entry's `name` data. + */ +function getName() { + return hasTag(this, 'name') + ? getValue(this, 'name') + : _.toString(_.first(this.getCall().split('('))); +} + +/** + * Extracts the entry's `param` data. + * + * @memberOf Entry + * @param {number} [index] The index of the array value to return. + * @returns {Array} Returns the entry's `param` data. + */ +function getParams(index) { + if (this._params === undefined) { + this._params = _(this.parsed.tags) + .filter(['title', 'param']) + .filter('name') + .map(function(tag) { + var defaultValue = tag['default'], + desc = util.format(tag.description), + name = _.toString(tag.name), + type = getParamType(tag.type); + + if (defaultValue != null) { + name += '=' + defaultValue; + } + if (_.get(tag, 'type.type') == 'OptionalType') { + name = '[' + name + ']'; + } + return [type, name, desc]; + }) + .value(); + } + var result = this._params; + return index === undefined ? result : result[index]; +} + +/** + * Extracts the entry's `see` data. + * + * @memberOf Entry + * @returns {array} Returns the entry's `see` data as links. + */ +function getRelated() { + var relatedValues = getValue(this, 'see'); + if (relatedValues && relatedValues.trim().length > 0) { + var relatedItems = relatedValues.split(',').map((relatedItem) => relatedItem.trim()); + return relatedItems.map((relatedItem) => '[' + relatedItem + '](#' + relatedItem + ')'); + } else { + return []; + } +} + +/** + * Extracts the entry's `returns` data. + * + * @memberOf Entry + * @returns {array} Returns the entry's `returns` data. + */ +function getReturns() { + var tag = getTag(this, 'returns'), + desc = _.toString(_.get(tag, 'description')), + type = _.toString(_.get(tag, 'type.name')) || '*'; + + return tag ? [type, desc] : []; +} + +/** + * Extracts the entry's `since` data. + * + * @memberOf Entry + * @returns {string} Returns the entry's `since` data. + */ +function getSince() { + return getValue(this, 'since'); +} + +/** + * Extracts the entry's `type` data. + * + * @memberOf Entry + * @returns {string} Returns the entry's `type` data. + */ +function getType() { + var result = getValue(this, 'type'); + if (!result) { + return this.isFunction() ? 'Function' : 'unknown'; + } + return /^(?:array|function|object|regexp)$/.test(result) + ? _.capitalize(result) + : result; +} + +/** + * Checks if the entry is an alias. + * + * @memberOf Entry + * @type {Function} + * @returns {boolean} Returns `false`. + */ +var isAlias = _.constant(false); + +/** + * Checks if the entry is a constructor. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if a constructor, else `false`. + */ +function isCtor() { + return hasTag(this, 'constructor'); +} + +/** + * Checks if the entry is a function reference. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if the entry is a function reference, else `false`. + */ +function isFunction() { + return !!( + this.isCtor() || + _.size(this.getParams()) || + _.size(this.getReturns()) || + hasTag(this, 'function') || + /\*\/\s*(?:function\s+)?[^\s(]+\s*\(/.test(this.entry) + ); +} + +/** + * Checks if the entry is a license. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if a license, else `false`. + */ +function isLicense() { + return hasTag(this, 'license'); +} + +/** + * Checks if the entry *is* assigned to a prototype. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if assigned to a prototype, else `false`. + */ +function isPlugin() { + return ( + !this.isCtor() && + !this.isPrivate() && + !this.isStatic() + ); +} + +/** + * Checks if the entry is private. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if private, else `false`. + */ +function isPrivate() { + return ( + this.isLicense() || + hasTag(this, 'private') || + _.isEmpty(this.parsed.tags) + ); +} + +/** + * Checks if the entry is *not* assigned to a prototype. + * + * @memberOf Entry + * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`. + */ +function isStatic() { + var isPublic = !this.isPrivate(), + result = isPublic && hasTag(this, 'static'); + + // Get the result in cases where it isn't explicitly stated. + if (isPublic && !result) { + var parent = _.last(_.toString(this.getMembers(0)).split(/[#.]/)); + if (!parent) { + return true; + } + var source = this.source; + _.each(getEntries(source), function(entry) { + entry = new Entry(entry, source); + if (entry.getName() == parent) { + result = !entry.isCtor(); + return false; + } + }); + } + return result; +} + +/*----------------------------------------------------------------------------*/ + +Entry.getEntries = getEntries; + +_.assign(Entry.prototype, { + 'getAliases': getAliases, + 'getCall': getCall, + 'getCategory': getCategory, + 'getDesc': getDesc, + 'getExample': getExample, + 'getHash': getHash, + 'getLineNumber': getLineNumber, + 'getMembers': getMembers, + 'getName': getName, + 'getParams': getParams, + 'getRelated': getRelated, + 'getReturns': getReturns, + 'getSince': getSince, + 'getType': getType, + 'isAlias': isAlias, + 'isCtor': isCtor, + 'isFunction': isFunction, + 'isLicense': isLicense, + 'isPlugin': isPlugin, + 'isPrivate': isPrivate, + 'isStatic': isStatic +}); + +module.exports = Entry; diff --git a/plugins/gatsby-source-lodash/lib/util.js b/plugins/gatsby-source-lodash/lib/util.js new file mode 100644 index 00000000..7a6c3b8b --- /dev/null +++ b/plugins/gatsby-source-lodash/lib/util.js @@ -0,0 +1,96 @@ +'use strict'; + +var _ = require('lodash'), + doctrine = require('doctrine'); + +var reCode = /`.*?`/g, + reToken = /@@token@@/g, + split = String.prototype.split, + token = '@@token@@'; + +/*----------------------------------------------------------------------------*/ + +/** + * The `Array#sort` comparator to produce a + * [natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order). + * + * @memberOf util + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ +function compareNatural(value, other) { + var index = -1, + valParts = split.call(value, '.'), + valLength = valParts.length, + othParts = split.call(other, '.'), + othLength = othParts.length, + length = Math.min(valLength, othLength); + + while (++index < length) { + var valPart = valParts[index], + othPart = othParts[index]; + + if (valPart > othPart && othPart != 'prototype') { + return 1; + } else if (valPart < othPart && valPart != 'prototype') { + return -1; + } + } + return valLength > othLength ? 1 : (valLength < othLength ? -1 : 0); +} + +/** + * Performs common string formatting operations. + * + * @memberOf util + * @param {string} string The string to format. + * @returns {string} Returns the formatted string. + */ +function format(string) { + string = _.toString(string); + + // Replace all code snippets with a token. + var snippets = []; + string = string.replace(reCode, function(match) { + snippets.push(match); + return token; + }); + + return string + // Add line breaks. + .replace(/:\n(?=[\t ]*\S)/g, ':
\n') + .replace(/\n( *)[-*](?=[\t ]+\S)/g, '\n
\n$1*') + .replace(/^[\t ]*\n/gm, '
\n
\n') + // Normalize whitespace. + .replace(/\n +/g, ' ') + // Italicize parentheses. + .replace(/(^|\s)(\(.+\))/g, '$1*$2*') + // Mark numbers as inline code. + .replace(/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/g, ' `$1`') + // Replace all tokens with code snippets. + .replace(reToken, function(match) { + return snippets.shift(); + }) + .trim(); +} + +/** + * Parses the JSDoc `comment` into an object. + * + * @memberOf util + * @param {string} comment The comment to parse. + * @returns {Object} Returns the parsed object. + */ +var parse = _.partial(doctrine.parse, _, { + 'lineNumbers': true, + 'recoverable': true, + 'sloppy': true, + 'unwrap': true +}); + +module.exports = { + 'compareNatural': compareNatural, + 'format': format, + 'parse': parse +}; diff --git a/plugins/gatsby-source-lodash/package-lock.json b/plugins/gatsby-source-lodash/package-lock.json new file mode 100644 index 00000000..08f8f3e1 --- /dev/null +++ b/plugins/gatsby-source-lodash/package-lock.json @@ -0,0 +1,31 @@ +{ + "name": "gatsby-source-lodash", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "node-fetch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", + "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" + } + } +} diff --git a/plugins/gatsby-source-lodash/package.json b/plugins/gatsby-source-lodash/package.json new file mode 100644 index 00000000..5152ab02 --- /dev/null +++ b/plugins/gatsby-source-lodash/package.json @@ -0,0 +1,20 @@ +{ + "name": "gatsby-source-lodash", + "version": "0.1.0", + "description": "Gatsby Source Plugin to grab method metadata from Lodash.", + "main": "gatsby-node.js", + "scripts": {}, + "keywords": [], + "author": "Zack Hall ", + "contributors": [ + "John-David Dalton ", + "Mathias Bynens ", + "Zack Hall " + ], + "license": "MIT", + "dependencies": { + "doctrine": "^3.0.0", + "lodash": "^4.17.11", + "node-fetch": "^2.3.0" + } +} From 535d306ebff8423357f860d27ff1792c6eb3c2ee Mon Sep 17 00:00:00 2001 From: Zack Hall Date: Thu, 18 Apr 2019 11:24:38 -0400 Subject: [PATCH 2/2] Update code format & match prettier/tslint rules. --- plugins/gatsby-source-lodash/README.md | 2 +- plugins/gatsby-source-lodash/gatsby-node.js | 94 ++--- plugins/gatsby-source-lodash/lib/alias.js | 96 ++--- plugins/gatsby-source-lodash/lib/entry.js | 424 ++++++++++---------- plugins/gatsby-source-lodash/lib/util.js | 110 ++--- 5 files changed, 368 insertions(+), 358 deletions(-) diff --git a/plugins/gatsby-source-lodash/README.md b/plugins/gatsby-source-lodash/README.md index 09872cd2..f5c640e5 100644 --- a/plugins/gatsby-source-lodash/README.md +++ b/plugins/gatsby-source-lodash/README.md @@ -22,4 +22,4 @@ module.exports = { ... ] } -``` \ No newline at end of file +``` diff --git a/plugins/gatsby-source-lodash/gatsby-node.js b/plugins/gatsby-source-lodash/gatsby-node.js index 60d2f40f..eca7a5cf 100644 --- a/plugins/gatsby-source-lodash/gatsby-node.js +++ b/plugins/gatsby-source-lodash/gatsby-node.js @@ -1,9 +1,9 @@ -'use strict'; +"use strict" -const fetch = require("node-fetch"), - _ = require("lodash"), - Entry = require('./lib/entry.js'), - getEntries = Entry.getEntries; +const fetch = require("node-fetch") +const _ = require("lodash") +const Entry = require("./lib/entry.js") +const getEntries = Entry.getEntries exports.sourceNodes = ( { actions, createNodeId, createContentDigest }, @@ -15,85 +15,87 @@ exports.sourceNodes = ( delete configOptions.plugins // TODO: Extend this to include multiple versions - const url = configOptions.versions[0].url, - version = configOptions.versions[0].version; + const url = configOptions.versions[0].url + const version = configOptions.versions[0].version const processEntry = entry => { try { // Exit early if the entry is private or has no name if (!entry || !entry.getName() || entry.isPrivate()) { - return; - } + return + } } catch (err) { // Some of the non-lodash methods were throwing a hard to trace error - // from the lib code. Rather than trace back, it was easier to catch + // from the lib code. Rather than trace back, it was easier to catch // since they aren't part of lodash. - return; + return } // Special handling of aliases to get call names. Without this, there are // circular JS object references. const aliases = entry.getAliases().map(alias => { - const member = entry.getMembers(0) || '', - name = alias.getName(); - return `${member}.${name}`; + const member = entry.getMembers(0) || "" + const name = alias.getName() + return `${member}.${name}` }) - const params = entry.getParams().map( - ([type, name, desc]) => ({ type, name, desc })); + const params = entry + .getParams() + .map(([type, name, desc]) => ({ type, name, desc })) const entryData = { aliases, - version, - params, call: entry.getCall(), category: entry.getCategory(), desc: entry.getDesc(), example: entry.getExample(), hash: entry.getHash(), + isAlias: entry.isAlias(), + isCtor: entry.isCtor(), + isFunction: entry.isFunction(), + isLicense: entry.isLicense(), + isPlugin: entry.isPlugin(), + isStatic: entry.isStatic(), lineNumber: entry.getLineNumber(), members: entry.getMembers(), name: entry.getName(), + params, related: entry.getRelated(), returns: entry.getReturns(), since: entry.getSince(), type: entry.getType(), - isAlias: entry.isAlias(), - isCtor: entry.isCtor(), - isFunction: entry.isFunction(), - isLicense: entry.isLicense(), - isPlugin: entry.isPlugin(), - isStatic: entry.isStatic(), + version, } - const nodeData = _.assign({}, entryData, { - id: createNodeId(`lodash_method_${version}_${entryData.hash}_${entryData.lineNumber}`), - parent: null, + const nodeData = { + ...entryData, children: [], + id: createNodeId( + `lodash_method_${version}_${entryData.hash}_${entryData.lineNumber}` + ), internal: { - type: 'LodashMethod', content: JSON.stringify(entryData), contentDigest: createContentDigest(JSON.stringify(entryData)), - } - }); + type: "LodashMethod", + }, + parent: null, + } - return nodeData; + return nodeData } - return ( - fetch(url) - .then(res => res.text()) - .then(body => { - const entries = getEntries(body); + return fetch(url) + .then(res => res.text()) + .then(body => { + const entries = getEntries(body) - // For each entry, create node. - _.each(entries, entry => { - entry = new Entry(entry, body); - const nodeData = processEntry(entry); - if (nodeData) { - createNode(nodeData); - } - }) + // For each entry, create node. + _.each(entries, entry => { + entry = new Entry(entry, body) + const nodeData = processEntry(entry) + if (nodeData) { + createNode(nodeData) + } }) - ) -} \ No newline at end of file + }) +} diff --git a/plugins/gatsby-source-lodash/lib/alias.js b/plugins/gatsby-source-lodash/lib/alias.js index 34bcca22..df3c7e72 100644 --- a/plugins/gatsby-source-lodash/lib/alias.js +++ b/plugins/gatsby-source-lodash/lib/alias.js @@ -1,6 +1,6 @@ -'use strict'; +"use strict" -var _ = require('lodash'); +const _ = require("lodash") /*----------------------------------------------------------------------------*/ @@ -12,8 +12,8 @@ var _ = require('lodash'); * @param {Object} owner The alias owner. */ function Alias(name, owner) { - this._owner = owner; - this._name = name; + this._owner = owner + this._name = name } /** @@ -24,7 +24,7 @@ function Alias(name, owner) { * @returns {Array|string} Returns the entry's `alias` objects. */ function getAliases(index) { - return index == null ? [] : undefined; + return index == null ? [] : undefined } /** @@ -34,7 +34,7 @@ function getAliases(index) { * @returns {string} Returns the function call. */ function getCall() { - return this._owner.getCall(); + return this._owner.getCall() } /** @@ -44,7 +44,7 @@ function getCall() { * @returns {string} Returns the owner entry's `category` data. */ function getCategory() { - return this._owner.getCategory(); + return this._owner.getCategory() } /** @@ -54,7 +54,7 @@ function getCategory() { * @returns {string} Returns the owner entry's description. */ function getDesc() { - return this._owner.getDesc(); + return this._owner.getDesc() } /** @@ -64,7 +64,7 @@ function getDesc() { * @returns {string} Returns the owner entry's `example` data. */ function getExample() { - return this._owner.getExample(); + return this._owner.getExample() } /** @@ -75,7 +75,7 @@ function getExample() { * @returns {string} Returns the entry's hash value (without a hash itself). */ function getHash(style) { - return this._owner.getHash(style); + return this._owner.getHash(style) } /** @@ -85,7 +85,7 @@ function getHash(style) { * @returns {number} Returns the owner entry's line number. */ function getLineNumber() { - return this._owner.getLineNumber(); + return this._owner.getLineNumber() } /** @@ -96,7 +96,7 @@ function getLineNumber() { * @returns {Array|string} Returns the owner entry's `member` data. */ function getMembers(index) { - return this._owner.getMembers(index); + return this._owner.getMembers(index) } /** @@ -106,7 +106,7 @@ function getMembers(index) { * @returns {string} Returns the owner entry's `name` data. */ function getName() { - return this._name; + return this._name } /** @@ -116,7 +116,7 @@ function getName() { * @returns {Object} Returns the owner entry. */ function getOwner() { - return this._owner; + return this._owner } /** @@ -127,7 +127,7 @@ function getOwner() { * @returns {Array} Returns the owner entry's `param` data. */ function getParams(index) { - return this._owner.getParams(index); + return this._owner.getParams(index) } /** @@ -137,7 +137,7 @@ function getParams(index) { * @returns {string} Returns the owner entry's `returns` data. */ function getReturns() { - return this._owner.getReturns(); + return this._owner.getReturns() } /** @@ -147,7 +147,7 @@ function getReturns() { * @returns {string} Returns the owner entry's `since` data. */ function getSince() { - return this._owner.getSince(); + return this._owner.getSince() } /** @@ -157,7 +157,7 @@ function getSince() { * @returns {string} Returns the owner entry's `type` data. */ function getType() { - return this._owner.getType(); + return this._owner.getType() } /** @@ -167,7 +167,7 @@ function getType() { * @returns {boolean} Returns `true`. */ function isAlias() { - return true; + return true } /** @@ -177,7 +177,7 @@ function isAlias() { * @returns {boolean} Returns `true` if a constructor, else `false`. */ function isCtor() { - return this._owner.isCtor(); + return this._owner.isCtor() } /** @@ -187,7 +187,7 @@ function isCtor() { * @returns {boolean} Returns `true` if the entry is a function reference, else `false`. */ function isFunction() { - return this._owner.isFunction(); + return this._owner.isFunction() } /** @@ -197,7 +197,7 @@ function isFunction() { * @returns {boolean} Returns `true` if a license, else `false`. */ function isLicense() { - return this._owner.isLicense(); + return this._owner.isLicense() } /** @@ -207,7 +207,7 @@ function isLicense() { * @returns {boolean} Returns `true` if assigned to a prototype, else `false`. */ function isPlugin() { - return this._owner.isPlugin(); + return this._owner.isPlugin() } /** @@ -217,7 +217,7 @@ function isPlugin() { * @returns {boolean} Returns `true` if private, else `false`. */ function isPrivate() { - return this._owner.isPrivate(); + return this._owner.isPrivate() } /** @@ -227,33 +227,33 @@ function isPrivate() { * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`. */ function isStatic() { - return this._owner.isStatic(); + return this._owner.isStatic() } /*----------------------------------------------------------------------------*/ _.assign(Alias.prototype, { - 'getAliases': getAliases, - 'getCall': getCall, - 'getCategory': getCategory, - 'getDesc': getDesc, - 'getExample': getExample, - 'getHash': getHash, - 'getLineNumber': getLineNumber, - 'getMembers': getMembers, - 'getName': getName, - 'getOwner': getOwner, - 'getParams': getParams, - 'getReturns': getReturns, - 'getSince': getSince, - 'getType': getType, - 'isAlias': isAlias, - 'isCtor': isCtor, - 'isFunction': isFunction, - 'isLicense': isLicense, - 'isPlugin': isPlugin, - 'isPrivate': isPrivate, - 'isStatic': isStatic, -}); + getAliases, + getCall, + getCategory, + getDesc, + getExample, + getHash, + getLineNumber, + getMembers, + getName, + getOwner, + getParams, + getReturns, + getSince, + getType, + isAlias, + isCtor, + isFunction, + isLicense, + isPlugin, + isPrivate, + isStatic, +}) -module.exports = Alias; +module.exports = Alias diff --git a/plugins/gatsby-source-lodash/lib/entry.js b/plugins/gatsby-source-lodash/lib/entry.js index 943ad4fe..93201661 100644 --- a/plugins/gatsby-source-lodash/lib/entry.js +++ b/plugins/gatsby-source-lodash/lib/entry.js @@ -1,10 +1,10 @@ -'use strict'; +"use strict" -var _ = require('lodash'), - fp = require('lodash/fp'), - os = require('os'), - Alias = require('./alias.js'), - util = require('./util.js'); +const _ = require("lodash") +const fp = require("lodash/fp") +const os = require("os") +const Alias = require("./alias.js") +const util = require("./util.js") /*----------------------------------------------------------------------------*/ @@ -16,49 +16,52 @@ var _ = require('lodash'), * @returns {string} Returns the param type. */ function getParamType(tag) { - var expression = tag.expression, - result = '', - type = tag.type; + let expression = tag.expression + let result = "" + const type = tag.type switch (type) { - case 'AllLiteral': - result = '*'; - break; + case "AllLiteral": + result = "*" + break - case 'NameExpression': - result = _.toString(tag.name); - break; + case "NameExpression": + result = _.toString(tag.name) + break - case 'RestType': - result = '...' + result; - break; + case "RestType": + result = "..." + result + break - case 'TypeApplication': - expression = undefined; + case "TypeApplication": + expression = undefined result = _(tag) .chain() - .get('applications') - .map(_.flow(getParamType, fp.add(fp, '[]'))) + .get("applications") + .map( + _.flow( + getParamType, + fp.add(fp, "[]") + ) + ) .sort(util.compareNatural) - .join('|') - .value(); - break; + .join("|") + .value() + break - case 'UnionType': + case "UnionType": result = _(tag) .chain() - .get('elements') + .get("elements") .map(getParamType) .sort(util.compareNatural) - .join('|') - .value(); + .join("|") + .value() } if (expression) { - result += getParamType(expression); + result += getParamType(expression) } - return type == 'UnionType' - ? ('(' + result + ')') - : result; + return type === "UnionType" ? "(" + result + ")" : result } /** @@ -70,8 +73,8 @@ function getParamType(tag) { * @returns {null|Object} Returns the tag. */ function getTag(entry, tagName) { - var parsed = entry.parsed; - return _.find(parsed.tags, ['title', tagName]) || null; + const parsed = entry.parsed + return _.find(parsed.tags, ["title", tagName]) || null } /** @@ -83,29 +86,25 @@ function getTag(entry, tagName) { * @returns {string} Returns the tag value. */ function getValue(entry, tagName) { - var parsed = entry.parsed, - result = parsed.description, - tag = getTag(entry, tagName); + const parsed = entry.parsed + let result = parsed.description + const tag = getTag(entry, tagName) - if (tagName == 'alias') { - result = _.get(tag, 'name') ; + if (tagName === "alias") { + result = _.get(tag, "name") // Doctrine can't parse alias tags containing multiple values so extract // them from the error message. - var error = _.first(_.get(tag, 'errors')); + const error = _.first(_.get(tag, "errors")) if (error) { - result += error.replace(/^[^']*'|'[^']*$/g, ''); + result += error.replace(/^[^']*'|'[^']*$/g, "") } + } else if (tagName === "type") { + result = _.get(tag, "type.name") + } else if (tagName !== "description") { + result = _.get(tag, "name") || _.get(tag, "description") } - else if (tagName == 'type') { - result = _.get(tag, 'type.name'); - } - else if (tagName != 'description') { - result = _.get(tag, 'name') || _.get(tag, 'description'); - } - return tagName == 'example' - ? _.toString(result) - : util.format(result); + return tagName === "example" ? _.toString(result) : util.format(result) } /** @@ -117,18 +116,18 @@ function getValue(entry, tagName) { * @returns {boolean} Returns `true` if the tag is found, else `false`. */ function hasTag(entry, tagName) { - return getTag(entry, tagName) !== null; + return getTag(entry, tagName) !== null } /** * Converts CR+LF line endings to LF. * * @private - * @param {string} string The string to convert. + * @param {string} str The string to convert. * @returns {string} Returns the converted string. */ -function normalizeEOL(string) { - return string.replace(/\r\n/g, '\n'); +function normalizeEOL(str) { + return str.replace(/\r\n/g, "\n") } /*----------------------------------------------------------------------------*/ @@ -142,31 +141,31 @@ function normalizeEOL(string) { * @param {string} [lang='js'] The language highlighter used for code examples. */ function Entry(entry, source, lang) { - entry = normalizeEOL(entry); - - this.entry = entry; - this.lang = lang == null ? 'js' : lang; - this.parsed = util.parse(entry.replace(/(\*)\/\s*.+$/, '*')); - this.source = normalizeEOL(source); - this.getCall = _.memoize(this.getCall); - this.getCategory = _.memoize(this.getCategory); - this.getDesc = _.memoize(this.getDesc); - this.getExample = _.memoize(this.getExample); - this.getHash = _.memoize(this.getHash); - this.getLineNumber = _.memoize(this.getLineNumber); - this.getName = _.memoize(this.getName); - this.getRelated = _.memoize(this.getRelated); - this.getReturns = _.memoize(this.getReturns); - this.getSince = _.memoize(this.getSince); - this.getType = _.memoize(this.getType); - this.isAlias = _.memoize(this.isAlias); - this.isCtor = _.memoize(this.isCtor); - this.isFunction = _.memoize(this.isFunction); - this.isLicense = _.memoize(this.isLicense); - this.isPlugin = _.memoize(this.isPlugin); - this.isPrivate = _.memoize(this.isPrivate); - this.isStatic = _.memoize(this.isStatic); - this._aliases = this._members = this._params = undefined; + const normalizedEntry = normalizeEOL(entry) + + this.entry = normalizedEntry + this.lang = lang == null ? "js" : lang + this.parsed = util.parse(normalizedEntry.replace(/(\*)\/\s*.+$/, "*")) + this.source = normalizeEOL(source) + this.getCall = _.memoize(this.getCall) + this.getCategory = _.memoize(this.getCategory) + this.getDesc = _.memoize(this.getDesc) + this.getExample = _.memoize(this.getExample) + this.getHash = _.memoize(this.getHash) + this.getLineNumber = _.memoize(this.getLineNumber) + this.getName = _.memoize(this.getName) + this.getRelated = _.memoize(this.getRelated) + this.getReturns = _.memoize(this.getReturns) + this.getSince = _.memoize(this.getSince) + this.getType = _.memoize(this.getType) + this.isAlias = _.memoize(this.isAlias) + this.isCtor = _.memoize(this.isCtor) + this.isFunction = _.memoize(this.isFunction) + this.isLicense = _.memoize(this.isLicense) + this.isPlugin = _.memoize(this.isPlugin) + this.isPrivate = _.memoize(this.isPrivate) + this.isStatic = _.memoize(this.isStatic) + this._aliases = this._members = this._params = undefined } /** @@ -178,7 +177,7 @@ function Entry(entry, source, lang) { * @returns {Array} Returns the array of entries. */ function getEntries(source) { - return _.toString(source).match(/\/\*\*(?![-!])[\s\S]*?\*\/\s*.+/g) || []; + return _.toString(source).match(/\/\*\*(?![-!])[\s\S]*?\*\/\s*.+/g) || [] } /** @@ -190,16 +189,18 @@ function getEntries(source) { */ function getAliases(index) { if (this._aliases === undefined) { - var owner = this; - this._aliases = _(getValue(this, 'alias')) + const owner = this + this._aliases = _(getValue(this, "alias")) .split(/,\s*/) .compact() .sort(util.compareNatural) - .map(function(value) { return new Alias(value, owner); }) - .value(); + .map(function(value) { + return new Alias(value, owner) + }) + .value() } - var result = this._aliases; - return index === undefined ? result : result[index]; + const result = this._aliases + return index === undefined ? result : result[index] } /** @@ -209,37 +210,46 @@ function getAliases(index) { * @returns {string} Returns the function call. */ function getCall() { - var result = _.trim(_.get(/\*\/\s*(?:function\s+)?([^\s(]+)\s*\(/.exec(this.entry), 1)); + let result = _.trim( + _.get(/\*\/\s*(?:function\s+)?([^\s(]+)\s*\(/.exec(this.entry), 1) + ) if (!result) { - result = _.trim(_.get(/\*\/\s*(.*?)[:=,]/.exec(this.entry), 1)); + result = _.trim(_.get(/\*\/\s*(.*?)[:=,]/.exec(this.entry), 1)) result = /['"]$/.test(result) - ? _.trim(result, '"\'') - : result.split('.').pop().split(/^(?:const|let|var) /).pop(); + ? _.trim(result, "\"'") + : result + .split(".") + .pop() + .split(/^(?:const|let|var) /) + .pop() } - var name = getValue(this, 'name') || result; + const name = getValue(this, "name") || result if (!this.isFunction()) { - return name; + return name } - var params = this.getParams(); - result = _.castArray(result); + const params = this.getParams() + result = _.castArray(result) // Compile the function call syntax. _.each(params, function(param) { - var paramValue = param[1], - parentParam = _.get(/\w+(?=\.[\w.]+)/.exec(paramValue), 0); + const paramValue = param[1] + const parentParam = _.get(/\w+(?=\.[\w.]+)/.exec(paramValue), 0) - var parentIndex = parentParam == null ? -1 : _.findIndex(params, function(param) { - return _.trim(param[1], '[]').split(/\s*=/)[0] == parentParam; - }); + const parentIndex = + parentParam === null + ? -1 + : _.findIndex(params, function(parameter) { + return _.trim(parameter[1], "[]").split(/\s*=/)[0] === parentParam + }) // Skip params that are properties of other params (e.g. `options.leading`). - if (_.get(params[parentIndex], 0) != 'Object') { - result.push(paramValue); + if (_.get(params[parentIndex], 0) !== "Object") { + result.push(paramValue) } - }); + }) // Format the function call. - return name + '(' + result.slice(1).join(', ') + ')'; + return name + "(" + result.slice(1).join(", ") + ")" } /** @@ -249,8 +259,8 @@ function getCall() { * @returns {string} Returns the entry's `category` data. */ function getCategory() { - var result = getValue(this, 'category'); - return result || (this.getType() == 'Function' ? 'Methods' : 'Properties'); + const result = getValue(this, "category") + return result || (this.getType() === "Function" ? "Methods" : "Properties") } /** @@ -260,12 +270,12 @@ function getCategory() { * @returns {string} Returns the entry's description. */ function getDesc() { - var type = this.getType(), - result = getValue(this, 'description'); + const type = this.getType() + const result = getValue(this, "description") - return (!result || type == 'Function' || type == 'unknown') + return !result || type === "Function" || type === "unknown" ? result - : ('(' + _.trim(type.replace(/\|/g, ', '), '()') + '): ' + result); + : "(" + _.trim(type.replace(/\|/g, ", "), "()") + "): " + result } /** @@ -275,8 +285,8 @@ function getDesc() { * @returns {string} Returns the entry's `example` data. */ function getExample() { - var result = getValue(this, 'example'); - return result && ('```' + this.lang + '\n' + result + '\n```'); + const result = getValue(this, "example") + return result && "```" + this.lang + "\n" + result + "\n```" } /** @@ -287,24 +297,22 @@ function getExample() { * @returns {string} Returns the entry's hash value (without a hash itself). */ function getHash(style) { - var result = _.toString(this.getMembers(0)); - if (style == 'github') { + let result = _.toString(this.getMembers(0)) + if (style === "github") { if (result) { - result += this.isPlugin() ? 'prototype' : ''; + result += this.isPlugin() ? "prototype" : "" } - result += this.getCall(); + result += this.getCall() return result - .replace(/[\\.=|'"(){}\[\]\t ]/g, '') - .replace(/[#,]+/g, '-') - .toLowerCase(); + .replace(/[\\.=|'"(){}\[\]\t ]/g, "") + .replace(/[#,]+/g, "-") + .toLowerCase() } if (result) { - result += '-' + (this.isPlugin() ? 'prototype-' : ''); + result += "-" + (this.isPlugin() ? "prototype-" : "") } - result += this.isAlias() ? this.getOwner().getName() : this.getName(); - return result - .replace(/\./g, '-') - .replace(/^_-/, ''); + result += this.isAlias() ? this.getOwner().getName() : this.getName() + return result.replace(/\./g, "-").replace(/^_-/, "") } /** @@ -314,14 +322,14 @@ function getHash(style) { * @returns {number} Returns the entry's line number. */ function getLineNumber() { - var lines = this.source + const lines = this.source .slice(0, this.source.indexOf(this.entry) + this.entry.length) .match(/\n/g) - .slice(1); + .slice(1) // Offset by 2 because the first line number is before a line break and the // last line doesn't include a line break. - return lines.length + 2; + return lines.length + 2 } /** @@ -333,14 +341,14 @@ function getLineNumber() { */ function getMembers(index) { if (this._members === undefined) { - this._members = _(getValue(this, 'member') || getValue(this, 'memberOf')) + this._members = _(getValue(this, "member") || getValue(this, "memberOf")) .split(/,\s*/) .compact() .sort(util.compareNatural) - .value(); + .value() } - var result = this._members; - return index === undefined ? result : result[index]; + const result = this._members + return index === undefined ? result : result[index] } /** @@ -350,9 +358,9 @@ function getMembers(index) { * @returns {string} Returns the entry's `name` data. */ function getName() { - return hasTag(this, 'name') - ? getValue(this, 'name') - : _.toString(_.first(this.getCall().split('('))); + return hasTag(this, "name") + ? getValue(this, "name") + : _.toString(_.first(this.getCall().split("("))) } /** @@ -365,26 +373,26 @@ function getName() { function getParams(index) { if (this._params === undefined) { this._params = _(this.parsed.tags) - .filter(['title', 'param']) - .filter('name') + .filter(["title", "param"]) + .filter("name") .map(function(tag) { - var defaultValue = tag['default'], - desc = util.format(tag.description), - name = _.toString(tag.name), - type = getParamType(tag.type); + const defaultValue = tag["default"] + const desc = util.format(tag.description) + let name = _.toString(tag.name) + const type = getParamType(tag.type) if (defaultValue != null) { - name += '=' + defaultValue; + name += "=" + defaultValue } - if (_.get(tag, 'type.type') == 'OptionalType') { - name = '[' + name + ']'; + if (_.get(tag, "type.type") === "OptionalType") { + name = "[" + name + "]" } - return [type, name, desc]; + return [type, name, desc] }) - .value(); + .value() } - var result = this._params; - return index === undefined ? result : result[index]; + const result = this._params + return index === undefined ? result : result[index] } /** @@ -394,12 +402,16 @@ function getParams(index) { * @returns {array} Returns the entry's `see` data as links. */ function getRelated() { - var relatedValues = getValue(this, 'see'); + const relatedValues = getValue(this, "see") if (relatedValues && relatedValues.trim().length > 0) { - var relatedItems = relatedValues.split(',').map((relatedItem) => relatedItem.trim()); - return relatedItems.map((relatedItem) => '[' + relatedItem + '](#' + relatedItem + ')'); + const relatedItems = relatedValues + .split(",") + .map(relatedItem => relatedItem.trim()) + return relatedItems.map( + relatedItem => "[" + relatedItem + "](#" + relatedItem + ")" + ) } else { - return []; + return [] } } @@ -410,11 +422,11 @@ function getRelated() { * @returns {array} Returns the entry's `returns` data. */ function getReturns() { - var tag = getTag(this, 'returns'), - desc = _.toString(_.get(tag, 'description')), - type = _.toString(_.get(tag, 'type.name')) || '*'; + const tag = getTag(this, "returns") + const desc = _.toString(_.get(tag, "description")) + const type = _.toString(_.get(tag, "type.name")) || "*" - return tag ? [type, desc] : []; + return tag ? [type, desc] : [] } /** @@ -424,7 +436,7 @@ function getReturns() { * @returns {string} Returns the entry's `since` data. */ function getSince() { - return getValue(this, 'since'); + return getValue(this, "since") } /** @@ -434,13 +446,13 @@ function getSince() { * @returns {string} Returns the entry's `type` data. */ function getType() { - var result = getValue(this, 'type'); + const result = getValue(this, "type") if (!result) { - return this.isFunction() ? 'Function' : 'unknown'; + return this.isFunction() ? "Function" : "unknown" } return /^(?:array|function|object|regexp)$/.test(result) ? _.capitalize(result) - : result; + : result } /** @@ -450,7 +462,7 @@ function getType() { * @type {Function} * @returns {boolean} Returns `false`. */ -var isAlias = _.constant(false); +const isAlias = _.constant(false) /** * Checks if the entry is a constructor. @@ -459,7 +471,7 @@ var isAlias = _.constant(false); * @returns {boolean} Returns `true` if a constructor, else `false`. */ function isCtor() { - return hasTag(this, 'constructor'); + return hasTag(this, "constructor") } /** @@ -473,9 +485,9 @@ function isFunction() { this.isCtor() || _.size(this.getParams()) || _.size(this.getReturns()) || - hasTag(this, 'function') || + hasTag(this, "function") || /\*\/\s*(?:function\s+)?[^\s(]+\s*\(/.test(this.entry) - ); + ) } /** @@ -485,7 +497,7 @@ function isFunction() { * @returns {boolean} Returns `true` if a license, else `false`. */ function isLicense() { - return hasTag(this, 'license'); + return hasTag(this, "license") } /** @@ -495,11 +507,7 @@ function isLicense() { * @returns {boolean} Returns `true` if assigned to a prototype, else `false`. */ function isPlugin() { - return ( - !this.isCtor() && - !this.isPrivate() && - !this.isStatic() - ); + return !this.isCtor() && !this.isPrivate() && !this.isStatic() } /** @@ -510,10 +518,8 @@ function isPlugin() { */ function isPrivate() { return ( - this.isLicense() || - hasTag(this, 'private') || - _.isEmpty(this.parsed.tags) - ); + this.isLicense() || hasTag(this, "private") || _.isEmpty(this.parsed.tags) + ) } /** @@ -523,53 +529,53 @@ function isPrivate() { * @returns {boolean} Returns `true` if not assigned to a prototype, else `false`. */ function isStatic() { - var isPublic = !this.isPrivate(), - result = isPublic && hasTag(this, 'static'); + const isPublic = !this.isPrivate() + let result = isPublic && hasTag(this, "static") // Get the result in cases where it isn't explicitly stated. if (isPublic && !result) { - var parent = _.last(_.toString(this.getMembers(0)).split(/[#.]/)); + const parent = _.last(_.toString(this.getMembers(0)).split(/[#.]/)) if (!parent) { - return true; + return true } - var source = this.source; + const source = this.source _.each(getEntries(source), function(entry) { - entry = new Entry(entry, source); - if (entry.getName() == parent) { - result = !entry.isCtor(); - return false; + entry = new Entry(entry, source) + if (entry.getName() === parent) { + result = !entry.isCtor() + return false } - }); + }) } - return result; + return result } /*----------------------------------------------------------------------------*/ -Entry.getEntries = getEntries; +Entry.getEntries = getEntries _.assign(Entry.prototype, { - 'getAliases': getAliases, - 'getCall': getCall, - 'getCategory': getCategory, - 'getDesc': getDesc, - 'getExample': getExample, - 'getHash': getHash, - 'getLineNumber': getLineNumber, - 'getMembers': getMembers, - 'getName': getName, - 'getParams': getParams, - 'getRelated': getRelated, - 'getReturns': getReturns, - 'getSince': getSince, - 'getType': getType, - 'isAlias': isAlias, - 'isCtor': isCtor, - 'isFunction': isFunction, - 'isLicense': isLicense, - 'isPlugin': isPlugin, - 'isPrivate': isPrivate, - 'isStatic': isStatic -}); - -module.exports = Entry; + getAliases, + getCall, + getCategory, + getDesc, + getExample, + getHash, + getLineNumber, + getMembers, + getName, + getParams, + getRelated, + getReturns, + getSince, + getType, + isAlias, + isCtor, + isFunction, + isLicense, + isPlugin, + isPrivate, + isStatic, +}) + +module.exports = Entry diff --git a/plugins/gatsby-source-lodash/lib/util.js b/plugins/gatsby-source-lodash/lib/util.js index 7a6c3b8b..d731ee35 100644 --- a/plugins/gatsby-source-lodash/lib/util.js +++ b/plugins/gatsby-source-lodash/lib/util.js @@ -1,12 +1,12 @@ -'use strict'; +"use strict" -var _ = require('lodash'), - doctrine = require('doctrine'); +const _ = require("lodash") +const doctrine = require("doctrine") -var reCode = /`.*?`/g, - reToken = /@@token@@/g, - split = String.prototype.split, - token = '@@token@@'; +const reCode = /`.*?`/g +const reToken = /@@token@@/g +const split = String.prototype.split +const token = "@@token@@" /*----------------------------------------------------------------------------*/ @@ -20,59 +20,61 @@ var reCode = /`.*?`/g, * @returns {number} Returns the sort order indicator for `value`. */ function compareNatural(value, other) { - var index = -1, - valParts = split.call(value, '.'), - valLength = valParts.length, - othParts = split.call(other, '.'), - othLength = othParts.length, - length = Math.min(valLength, othLength); + let index = -1 + const valParts = split.call(value, ".") + const valLength = valParts.length + const othParts = split.call(other, ".") + const othLength = othParts.length + const length = Math.min(valLength, othLength) while (++index < length) { - var valPart = valParts[index], - othPart = othParts[index]; + const valPart = valParts[index] + const othPart = othParts[index] - if (valPart > othPart && othPart != 'prototype') { - return 1; - } else if (valPart < othPart && valPart != 'prototype') { - return -1; + if (valPart > othPart && othPart !== "prototype") { + return 1 + } else if (valPart < othPart && valPart !== "prototype") { + return -1 } } - return valLength > othLength ? 1 : (valLength < othLength ? -1 : 0); + return valLength > othLength ? 1 : valLength < othLength ? -1 : 0 } /** * Performs common string formatting operations. * * @memberOf util - * @param {string} string The string to format. + * @param {string} str The string to format. * @returns {string} Returns the formatted string. */ -function format(string) { - string = _.toString(string); +function format(str) { + let copy = _.toString(str) // Replace all code snippets with a token. - var snippets = []; - string = string.replace(reCode, function(match) { - snippets.push(match); - return token; - }); + let snippets = [] + copy = copy.replace(reCode, function(match) { + snippets.push(match) + return token + }) - return string - // Add line breaks. - .replace(/:\n(?=[\t ]*\S)/g, ':
\n') - .replace(/\n( *)[-*](?=[\t ]+\S)/g, '\n
\n$1*') - .replace(/^[\t ]*\n/gm, '
\n
\n') - // Normalize whitespace. - .replace(/\n +/g, ' ') - // Italicize parentheses. - .replace(/(^|\s)(\(.+\))/g, '$1*$2*') - // Mark numbers as inline code. - .replace(/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/g, ' `$1`') - // Replace all tokens with code snippets. - .replace(reToken, function(match) { - return snippets.shift(); - }) - .trim(); + return ( + copy + // Add line breaks. + .replace(/:\n(?=[\t ]*\S)/g, ":
\n") + .replace(/\n( *)[-*](?=[\t ]+\S)/g, "\n
\n$1*") + .replace(/^[\t ]*\n/gm, "
\n
\n") + // Normalize whitespace. + .replace(/\n +/g, " ") + // Italicize parentheses. + .replace(/(^|\s)(\(.+\))/g, "$1*$2*") + // Mark numbers as inline code. + .replace(/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/g, " `$1`") + // Replace all tokens with code snippets. + .replace(reToken, function(match) { + return snippets.shift() + }) + .trim() + ) } /** @@ -82,15 +84,15 @@ function format(string) { * @param {string} comment The comment to parse. * @returns {Object} Returns the parsed object. */ -var parse = _.partial(doctrine.parse, _, { - 'lineNumbers': true, - 'recoverable': true, - 'sloppy': true, - 'unwrap': true -}); +const parse = _.partial(doctrine.parse, _, { + lineNumbers: true, + recoverable: true, + sloppy: true, + unwrap: true, +}) module.exports = { - 'compareNatural': compareNatural, - 'format': format, - 'parse': parse -}; + compareNatural, + format, + parse, +}