javascript-value-locator

    1.4.7 • Public • Published

    Javascript Value Locator

    unstable

    Branch : release version npm version

    Build Status Coverage Status

    Dependency Status devDependency Status

    Load javascript values from multiples sources and using multiple protocols

    Introduction

    This module provide a minimalist api to load (asynchronously only) javascript values from different sources, using javascript value locators - JVL. A JVL is an object or a string (matching a specific format), which represent a way to load a javascript value. It's composed both of a protocol and a target.

    // this is a jvl object
    {
        protocol: 'protocol-name',
        target: 'full/path/to/module/exporting/the/targeted/value'
    }
     
    // this is the equivalent jvl string
    'protocol-name:full/path/to/module/exporting/the/targeted/value'

    You can see this module as a kind of webpack at the run time, where protocols are loaders, and where instead of doing this :

    require.ensure([], require => {
        const value = require('module/path');
     
        // do something with the value
    })

    You do this :

    const jvl = require('javascript-value-locator');
     
    jvl.load('require:module/path').then(value => {
        // do something with the value
    })

    And for example, if you want to load a yaml, you could use a specific protocol, as you would have used a yaml-loader in webpack

    const jvl = require('javascript-value-locator');
     
    /**
     * Assuming that a "require-yaml" protocol was defined in the first place
     * (which is currently not the case)
     */
    jvl.load('require-yaml:module/path.yaml').then(value => {
        // do something with the value
    })

    Note that the comparison with webpack is only here for explanatory purpose, this module doesn't aim the same use cases.

    Purpose and use cases

    The previous examples are here only for the sake of explaining the module basic usage. If you want to require a module in node.js, you should more than probably just do a require (unless you want to load it asynchronously). The following use case is the one for what the module was created in the first place.

    • Use the JVL string format to "require" a module in a cli command option

    Assuming you want to provide a command with an option which can be a javascript value. If the option is a number, it's ok to do that :

    cli command input --javascript-value-option=5
    

    But if the option is a complex/dynamic object, using JVL allow you to do that :

    cli command input --javascript-value-option=require:full/path/to/module
    

    The cli users have in that way a more fine control over the module he wants use to do some task. A logger module is a good example. Imagine you implement a cli command which only log the input, you could have something like :

    // ./load-override.js
    // create a custom load function
     
    const path = require('path');
    const {load, setLocatorDefaultProtocol, defaultProtocols} = require('javascript-value-locator');
     
    module.exports = function customLoad(locator, options){
        // if the locator is an object and doesn't have protocol property, 
        // or if it's a string without protocol ahead, the 'custom-protocol' will be used
     
        return load(setLocatorDefaultProtocol(locator, 'custom-protocol'), options, {
            protocols: Object.assign({}, defaultProtocols, {
                ['custom-protocol'](resolve, reject, target){
                    
                    // define a way to "require" the javascript value targeted
                    // for instance, require the path from a custom directory
                    // It will allow to provide some built-in log functions
     
                    defaultProtocols.require(resolve, reject,
                        path.join(__dirname, '../custom/directory/path', target)
                    );
                }
            })
        })
    }
    // ./log-command.js
    // then use the custom load function in your log command implementation
     
    const load = require('./load-override');
     
    module.exports = async function logCommand(
        input,
        log = (...logs) => console.log(...logs) // provide a default logger
    ){
        // enable silent mode
        if(log === false){
            log = ()=>{};
        }
     
        // enable the user to directly use a function as log option
        if(typeof log !== 'function'){
            log = await load(log);
        }
     
        assert(typeof log === 'function');
     
        return log(input);
    }

    Make the cli implementation which will call this async function, then your users can do :

    • this will use a simple console.log

      cli log "hello world"

    • this will not log anything

      cli log "hello world" --log=false

    • this will use a built-in logger defined in custom/directory/path

      cli log "hello world" --log=custom-protocol:log-one

    • this will use an other built-in logger defined in custom/directory/path

      cli log "hello world" --log=log-two

    • this will use a logger defined by the user

      cli log "hello world" --log=require:path/to/a/custom/logger

    Speculative use cases

    The module wasn't thinked in order to do that, but it may could be used to accomplish some of these things :

    • Create and use some custom protocols able to load javascript from the cloud

    • Use in the browser to load assets (still with custom protocols)

    • And probably more...

    Get started

    Install

    • using npm

      npm install --save javascript-value-locator

    • or using yarn

      yarn add javascript-value-locator

    Load one or more values from JVL

    TO DO - see the load function documentation for now

    Available protocols

    Currently, the only implemented protocol is the require. If needed, add others and eventually open a issue or event better, a PR.

    Use custom protocols

    You can use the inject.protocols option of the load function. Look here for concrete example.

    Load a value synchronously

    JVL is not aimed to do that.

    About the documentation

    The following documentation was generated using documentation.js.

    Naming conventions

    • CapitalizedCamelCasedNames are used for types

    • dashified-case-names are used for filenames

    • camelCasedNames are used for methods and properties

    Documentation

    Table of Contents

    JavascriptValueLocator

    A JavascriptValueLocator (JVL) is a string or an object which describe a way to access to a javascript value. It must provide at least:

    Type: (JavascriptValueLocatorString | JavascriptValueLocatorObject)

    JavascriptValueLocatorString

    A JavascriptValueLocatorString (JVL string) is a string which describe a way to access to a javascript value. It must matches the following format:

    Type: string

    Examples

    // Those are valid JVL strings
    "require:/path/to/file"
    "any-defined-protocol-name:any-target-name_case is-NotImportant"
     
    // Those are unvalid JVL strings
    ":target-name" // Missing protocol
    "protocol-name" // Missing target

    JavascriptValueLocatorObject

    A JavascriptValueLocatorObject is an object which describe a way to access to a javascript value.

    Type: object

    Properties

    JavascriptValueLocatorProtocol

    A JavascriptValueLocatorProtocol is a function which take the following arguments (resolve, reject, target, options) and resolve the targeted javascript value or reject an error

    Type: function

    Parameters

    • resolve function A resolve function which will be called with the targeted javascript value as single argument
    • reject function A reject function which will be called with a error as single argument if the javascript value load failed
    • target string The target to load and resolve. A target must be a unique identifier/path (or maybe other things depending on the used protocol) to the requested javascript value. You must use it to know which value is requested
    • options object The options passed to the protocol.

    javascript-value-locator

    The JVL API is an object providing the following properties:

    Examples

    // require the public API
    const JVL = require('javascript-value-locator')
    // then use a method of the API
    JVL.load('npm:string-humanize@1.0.0').then(_ => console.log(_('hello-world'))) // Hello world

    load

    This function loads a javascript value in a async way

    Parameters

    • locator (JavascriptValueLocator | Array<JavascriptValueLocator>) A javascript value locator as an object or a string which follow the JVL format. Can also be an Array of locators.
    • options object? The javascript options object which will be passed to the locator protocol function. If locator is an object, it can provide directly an options object which will be merged with the options parameter. (optional, default {})
    • inject object? A javascript object containing the load function dependencies. (optional, default {})
      • inject.protocols object A Dictionnary where keys are the names of the protocols and value are the protocols functions. If locator is an object, it can provide directly a protocols key which will be merged with the inject.protocols parameter. (optional, default defaultProtocols)

    Returns Promise A promise resolving the javascript value targeted by the locator. If locator was an Array, the promise resolve an Array containing all the targeted values in the same order as defined.

    setLocatorDefaultProtocol

    This function returns a locator with the specified default protocol if the input locator doesn't provide one.

    Parameters

    • locator ((string | object) | Array<(string | object)>) A potential JVL which must at least provide a target. It will be transformed in a valid JVL. If it's an Array, the function will return an Array of valid JVL. The output JVl will keep the type of the original input locator.
    • defaultProtocol string If no protocol is found in the locator, then the default protocol will be setted as the current locator protocol. Note that you can't provide a protocol as a function using the setLocatorDefaultProtocol function.

    Returns (JavascriptValueLocator | Array<JavascriptValueLocator>) The corresponding locator as an object.

    parse

    This function returns a locator object from a JVL string.

    Parameters

    Returns JavascriptValueLocatorObject The corresponding locator as an object.

    stringify

    This function transforms a locator object to a JVL string.

    Parameters

    Returns JavascriptValueLocatorString The corresponding JVL string.

    defaultProtocols

    This object contains the defaults protocols defined by the javascript-value-locator package :

    You can use it, for example, in order to create a new load functions with new custom protocols.

    Examples

    //import the load function and the default-protocols
    const {load, defaultProtocols} = require('javascript-value-locator')
     
    //define some custom protocols
    const customProtocols = {
        newProtocol: function(resolve, reject, target, options){
            resolve(getTheValueUsingTheTargetAndOptions)
            //or
            reject()
        }
    }
     
    //create and export a function which call the original function,
    //but passing to it a new protocols object dependency
    module.exports = function customLoad(locator, options){
        return load(locator, options, {
            protocols: Object.assign({}, defaultProtocols, customProtocols)
        })
    }

    require

    This function is a JavascriptValueLocatorProtocol that use the node require function to load the target.

    Parameters

    • resolve function A resolve function which will be called with the targeted javascript value as single argument.
    • reject function A reject function which will be called with a error as single argument if the javascript value load failed.
    • target string The target to load and resolve. It must be a path to a valid node module.
    • options object? A javascript object containing the require protocol options. (optional, default {})
      • options.cwd string The current working directory to use if the target path is not absolute. (optional, default process.cwd())

    Returns undefined

    License

    javascript-value-locator is released under MIT. Copyright (c) 2017-present Alexis Tessier

    Install

    npm i javascript-value-locator

    DownloadsWeekly Downloads

    55

    Version

    1.4.7

    License

    MIT

    Last publish

    Collaborators

    • alexistessier