API Docs for: 5.0.0
Show:

File: esnext/lib/fellow.js

/**
A fellow with similarties to other people

@class Fellow
@constructor
*/
export default class Fellow {

    // -----------------------------------
    // Static Helpers

    /**
    Create a new Fellow instance with the value, however if the value is already a fellow instance, then just return it
    @static
    @method create
    @param {Mixed} value
    @return {Fellow} The new fellow instance
    */
    static create (value) {
        return value instanceof this ? value : new this(value)
    }

    /**
    A singleton array attached to the class object that stores it's people objects
    @static
    @property list
    */
    static get list () {
        if ( this._list == null )  this._list = []
        return this._list
    }

    /**
    An array of fields that will denote if the user is the same user or not when using ensure
    @protected
    @static
    @property ensureFields
    @type Array
    */
    static get ensureFields () {
        if ( this._ensureFields == null )  this._ensureFields = ['email', 'homepage', 'githubUsername']
        return this._ensureFields
    }

    /**
    With the value, see if an existing fellow exists in our singleton list property with the value, otherwise create a new fellow instance with the value and add them to our singleton list
    @static
    @method ensure
    @param {Mixed} value  The value to create a new fellow instance or find the existing fellow instance with
    @return {Fellow} The new or existing fellow instance
    */
    static ensure (value, add = true) {
        const newFellow = this.create(value)
        const fields = this.ensureFields
        const people = this.list
        for ( const existingFellow of people ) {
            for ( const field of fields ) {
                if ( newFellow[field] && newFellow[field] === existingFellow[field] ) {
                    return existingFellow.setValue(value)
                }
            }
        }
        if ( add ) {
            people.push(newFellow)
            return newFellow
        }
        else {
            return null
        }
    }

    /**
    Get a fellow from the singleton list
    @static
    @method get
    @param {Mixed} value The value to fetch the value with
    @return {Fellow|Null} The fetched fellow, if they exist with that value
    */
    static get (value) {
        return this.ensure(value, false)
    }

    /**
    Add a fellow or a series of people, denoted by the value, to the singleton list
    @static
    @method add
    @param {Mixed} value The fellow or people to add
    @return {Array} An array of the fellow objects for the passed people
    */
    static add (value) {
        if ( value instanceof this ) {
            return [this.ensure(value)]
        }
        else if ( typeof value === 'string' ) {
            return value.split(/, +/).map((fellow) => {
                return this.ensure(fellow)
            })
        }
        else if ( Array.isArray(value) ) {
            return value.map((value) => {
                return this.ensure(value)
            })
        }
        else if ( value ) {
            return [this.ensure(value)]
        }
        else {
            return []
        }
    }

    // -----------------------------------
    // Properties

    /**
    @property name
    @type String
    */
    set name (value) {
        const match = (/^((?:[0-9]+[\-\+]?)+)?(.+)$/).exec(value)
        if ( match ) {
            this.years = String(match[1] || '').trim()
            this._name = (match[2] || '').trim()
        }
    }

    get name () {
        return this._name
    }

    /**
    If the name is prefixed with a series of numbers, that is considered the year
    E.g. In `2015+ Bevry Pty Ltd` then `2015+` is the years
    E.g. In `2013-2015 Bevry Pty Ltd` then `2013-2015` is the years
    @property years
    @type String
    */

    /**
    @property email
    @type String
    */

    /**
    If this is a github URL, then `githubUrl` and `githubUsername` are extracted and this is not yet
    If this is not a github URL, then it is set to `homepage`
    When fetched, it will return `homepage || githubUrl || null`
    @property url
    @type String
    */
    set url (value) {
        const githubMatch = (/^.+github.com\/([^\/]+)\/?$/).exec(value)
        if ( githubMatch ) {
            this.githubUsername = githubMatch[1]
            this.githubUrl = 'https://github.com/' + this.githubUsername
        }
        else {
            this.homepage = value
        }
    }
    get url () {
        return this.homepage || this.githubUrl
    }

    /**
    @property homepage
    @type String
    */

    /**
    @property githubUrl
    @type String
    */

    /**
    @property githubUsername
    @type String
    */

    // -----------------------------------
    // Methods

    /**
    Construct our fellow instance with the value
    @method constructor
    @property {Mixed} value The value used to set the properties of the fellow, forwarded to setValue
    */
    constructor (value) {
        this.setValue(value)
    }

    /**
    Update our fellow with the passed value
    @property {String|Object} fellow A string in the format of "Benjamin Lupton <b@lupton.cc> (https://balupton.com)" or an object with properties
    @chainable
    */
    setValue (fellow) {
        // String format
        // Benjamin Lupton <b@lupton.cc> (https://balupton.com)
        if ( typeof fellow === 'string' ) {
            const match = (/^([^<(]+)\s*(?:<(.+?)>)?\s*(?:\((.+?)\))?$/).exec(fellow)
            if ( !match ) {
                throw new Error('Invalid fellow string')
            }
            this.name = (match[1] || '').trim() || null
            this.email = (match[2] || '').trim() || null
            this.url = (match[3] || '').trim() || null
        }

        // Object Format
        else if ( typeof fellow === 'object' ) {
            const urlFields = ['url', 'homepage', 'web', 'githubUrl']
            Object.keys(fellow).forEach((key) => {
                if ( key[0] === '_' )  return  // skip if private
                const value = fellow[key] || null
                if ( urlFields.indexOf(key) === -1 ) {
                    this[key] = value
                }
                else {
                    this.url = value
                }
            })
            this.name = fellow.name || null
            this.email = fellow.email || null
        }

        else {
            throw new Error('Invalid fellow input')
        }

        return this
    }


    // -----------------------------------
    // Repos

    /**
    Ensures that the github repository exists on the class
    @private
    @method ensureGithubRepository
    @param {String} slug Github repository slug (e.g. "bevry/projectz")
    @return {Object} The repository object
    */
    ensureGithubRepository (slug) {
        if ( this._githubRepositories == null )  this._githubRepositories = {}
        if ( this._githubRepositories[slug] == null )  this._githubRepositories[slug] = {contributes: false, maintains: false, authors: false}
        return this._githubRepositories[slug]
    }

    /**
    Get all added github repository slugs that this fellow contributes to
    @property contributedGithubRepositories
    @type Array
    */
    get contributedGithubRepositories () {
        const result = []
        Object.keys(this._githubRepositories || {}).filter((slug) => {
            const repo = this._githubRepositories[slug]
            if ( repo && repo.contributes ) {
                result.push(slug)
            }
        })
        return result
    }

    /**
    Make note that this fellow contributes to this repository slug
    @method contributesToGithubRepository
    @param {String} slug The github repository slug that this user contributes to
    @chainable
    */
    contributesToGithubRepository (slug) {
        this.ensureGithubRepository(slug).contributes = true
        return this
    }

    /**
    Get all added github repository slugs that this fellow maintains
    @property maintainedGithubRepositories
    @type Array
    */
    get maintainedGithubRepositories () {
        const result = []
        Object.keys(this._githubRepositories || {}).filter((slug) => {
            const repo = this._githubRepositories[slug]
            if ( repo && repo.maintains ) {
                result.push(slug)
            }
        })
        return result
    }

    /**
    Make note that this fellow maintains this repository slug
    @method maintainsGithubRepository
    @param {String} slug The github repository slug that this user maintains
    @chainable
    */
    maintainsGithubRepository (slug) {
        this.ensureGithubRepository(slug).maintains = true
        return this
    }

    /**
    Get all added github repository slugs that this fellow authors
    @property authoredGithubRepositories
    @type Array
    */
    get authoredGithubRepositories () {
        const result = []
        Object.keys(this._githubRepositories || {}).filter((slug) => {
            const repo = this._githubRepositories[slug]
            if ( repo && repo.authors ) {
                result.push(slug)
            }
        })
        return result
    }

    /**
    Make note that this fellow authors this repository slug
    @method authorsGithubRepository
    @param {String} slug The github repository slug that this user authors
    @chainable
    */
    authorsGithubRepository (slug) {
        this.ensureGithubRepository(slug).authors = true
        return this
    }
}