node package manager
Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

yamdo

YAMDO

Yet Another Module Definition Loader Build Status

Repository: http://github.com/brianmhunt/yamdo.git

Purpose

YAMDO compiles a set of javascript files into one optimized script, which should work sensibly with any AMD loader in a browser, such as almond.js, Curl.js and RequireJS.

YAMDO aims to do optimization well.

It is an alternative to, or in some case a compliment of, a number of existing packages, such as,

It is intended to be a compliment to client-side package management such as bower and client-side AMD loaders such as almond.js.

This project is not intended as a long-term solution to the nightmare of modules in browsers. That's what we hope ES-Harmony:modules shall solve. In lieu thereof, YAMDO is a way to make sure scripts can be compiled and work intelligently in an AMD-like framework.

Installation

Since YAMDO runs on node.js, you will need to install npm.

Armed with npm, install YAMDO with:

npm install yamdo

or install the command line interface globally with

npm install -g yamdo

Usage

YAMDO can be imported into a script that is being interpreted by node, or run from the command line.

Examples

In node run:

yamdo = require('yamdo')

Optimize a single script file:

yamdo.optimize_file("module-name", "./file_name.js")

yamdo.optimize_file("./file_name.js") # module is 'file_name'

Optimize a given script (i.e. ensure it is AMD-friendly):

yamdo.optimize_source("module-name", "var x = 123; console.log("hey");")

Optimize a number of scripts, in order, returning a list of optimized scripts:

yamdo.optimize_map([
  {
    file: "./lodash.js",
    module: "lodash"
  },
  {
    source: 'function () { console.log("There are 4 lights!") }',
    module: "picard"
  },
  { 
    file: "jquery.js"
    // module is basename without .js i.e. jquery
  }
]);

Or individually:

yamdo.optimize({
    file: "./lodash.js",
    module: "lodash"
  });

Or from a config file (see Config Files below):

yamdo.from_config("yamdo.yaml", callback)

API

YAMDO exposes the following functions

  • optimize(options, [config,] callback)

  • optimize_file([module,] script_file, [config,] callback)

  • optimize_source(module, source, [config,] callback)

  • optimize_map(options_array, [config,] callback)

  • from_config(config_file, [config,], callback)

The arguments are:

options: An object containing one or more of the following options that is used to identify the code to be optimized:

  • file: The filename to be found
  • module: The name of the module
  • depends: a string or array of strings of modules this depends on
  • provides: a string or array of strings of modules provided by this file
  • strategy: the name or string of names of the Strategy subclass to use
  • source: a string containing inline javascript source code
  • ignore_dependencies: if true, this module will not try to load any of its dependencies
  • ignore_missing: if true, the script will not fail if this module is missing any dependencies

The options_array passed to optimmize_map is an array of options objects. The order of the results is not necessarily preserved.

config: An object that may contain the following

  • path: a string (":" separated) or array of paths to search for modules
  • verbose: print more logging output
  • quiet: print less logging output
  • before_modules: an array of raw scripts to include before the modules (bear in mind that module output is unordered)
  • ignore_dependencies: same as options, but for all modules
  • ignore_missing: same as for options, but for all modules

callback: A function that is called when YAMBO completes, receiving a string containing the optimized code.

The functions optimize_file and optimize_source are essentially shorthands for optimize({ file: ... }) and optimize({ source: ... }), respectively, for the file and source arguments given.

Command line

From the command line (use -h for options):

$ yamdo my_script.js

$ yamdo my_module::my_script.js

$ yamdo script_config.yaml

For the command line to work you will need to be using a shell that respects the shebang.

Config files

All of the above can be performed by passing a yaml config file to YAMDO with the -c option. Here is a sample config, which we can call yamdo.yaml:

# all paths are searched for each module requested
path:

 # our compiled components
 - ../compiled

 # bower components
 - components/

 # contributions not from bower
 - contrib/

# the following file is inserted into our output stream before any compiled
# modules
before_modules:

  # raw text is inserted
  - Copyright (C) 2012 Brian M Hunt 

  # if the text starts with "file:" and there are no newlines, then YAMDO will
  # attempt to read the file and insert its content without any
  # interpretation
  - file: almond/almond.js
  # (note that the 'file:' above turns this argument into an object by the
  # yaml parser; you can do that however you may wish)

# NOTE: there is no guarantee about the order of the installed modules being
# placed into the output

modules:
  # the following is a list that defines the modules that will be included
  # and defined

  # Exports
  # ~~~~~~~
  # Equivalent to a stub for a module named 'exports', inserting
  #
  #    define('exports', [], function () { /* source */ });
  #
  # 'source' can be any javascript one wishes to insert; it will be parsed
  # over by the strategies.
  - module: exports
    source: ''

  # jQuery
  # ~~~~~~
  # jQuery has a `define` call so the 'stub' strategy is not called i.e.
  # no `define` call is injected to wrap the jquery.
  #
  # However, the 'idem' strategy below may be called to change the identity
  # of the jquery module being loaded.
  #
  # Note: .js is automatically added to the module name (as is .coffee and .txt,
  # and they are # processed as if they had cs! and text! in the module
  # name). As well, if the name given is a directory, YAMDO will look for 
  # name/index.js
  - jquery/jquery

  # bootstrap
  # ~~~~~~~~~
  # One can specify the name of the module, its files and its dependencies.
  #
  # The following will have something like:
  # define('bootstrap', function () {
  #    /* transition */
  #    /* tab */
  #    /* typeahead */
  # });
  - module: bootstrap

    # One can explicitly specify dependencies
    depends: jquery

    # The order of the following files is preserved
    file:
      - bootstrap/js/bootstrap-transition
      - bootstrap/js/bootstrap-tab
      - bootstrap/js/bootstrap-typeahead

  # knockout
  # ~~~~~~~~
  # Sometimes we have to go deep into the bowels of a bower component to
  # get the file we want to include in the browser
  - module: knockout
    file: knockout/build/output/knockout-latest.debug

  # komapping
  # ~~~~~~~~~
  # The following will define something like
  #
  #     define('komapping', ['knockout'], function () {/*  */});
  #
  - module: komapping
    depends: knockout
    file: knockout-mapping/build/output/knockout.mapping-latest.debug

  # lodash
  # ~~~~~~
  # Every project needs a splash of lodash
  - lodash/lodash

  # mocha
  # ~~~~~
  # Some scripts like mocha have a lot of `require` statements that the
  # parser picks up, but they refer to modules used only when running in
  # e.g. node.js; in cases such as this we sometimes want to just 
  # ignore all the dependencies.
  #
  # A more granular alternative is to add stub modules such as 'exports'
  # above.
  - file: mocha/mocha
    ignore_dependencies: true

  # jquery.timeago
  # ~~~~~~~~~~~~~~
  # One can explicitly provide dependencies
  - file: jquery-timeago/jquery.timeago
    depends: jquery
    
  # expandingTextarea
  # ~~~~~~~~~~~~~~~~~
  # The following is typical of a jquery module.
  - module: expandingTextarea
    depends: jquery
    file: jquery.expanding

---
# Document separators: 
# One can separate our loading into separate YAML documents, to change the
# configuration options such as the path or stub modules. This can be
# helpful if there is a module with a large number of dependencies that we
# want to stub. The dependencies are not preserved across documents.
# 
path:
  - ../legacy

modules:
  # One can explicitly specify a module name for a given file
  - module: jquery-1.7

    # the following file is the same as the jquery above, but the path is
    # different
    file: jquery/jquery

  # Although dependencies are not preserved across documents, YAMDO
  # will not insert duplicate scripts. For example, if the `lodash` module
  # here loads the exact same text as in the prior part of the config, it
  # will nevertheless be inserted only once
  - module: lodash
    file: components/lodash # lodash/index.js will be loaded

Now we can run yamdo yambo.yaml and it will compile all of the above into what should be a format acceptable to AMD.

What's it actually doing?

It does a number of things, pursuant to a set of strategies. In essence it parses the given script files and if they are not AMD compliant it makes changes that ought to make the files confirm.

For example, among other things:

  • if a file does not contain a define call, the StubStrategy will wrap the entire file in a define call.

  • if the file only contains anonymous define calls, the AnonStrategy adds as a first parameter to those calls a string with the identity of the module (which identity may be specified or automatically determined from the file).

  • if the file depends on other files, based on calls to define([DEPS],... or require([DEPS], ...) or require('DEP'), it will attempt to include them (unless the --ignore-dependencies option is true), based on the DependencyStrategy

  • it determines what a module provides, given the ProvidesStrategy, so that files may contain several (possibly already optimized) modules with define('id', ...)

  • where a script file does have a define call that has a string literal that identifies the module, the IdemStrategy changes the id to an explicitly defined module (but not one automatically generated by the filename). In this way one can include different versions of scripts.

LICENSE

MIT

Not to be confused with

Being an acronym, it's easy to confuse yamdo with lots of other words. Yando. Yambo. Yanbo. Bambi. Here are some tips:

  • Yamdo is a potato that gets things done. [YAM](http://en.wikipedia.org/wiki/Yam_(vegetable) – DO.

  • it's philosophically rhetorical: Y AMD? O.

  • it is non-violent:

    • it does not end with a .

    • although the rhotatic may pronounce it the same, yamdo is not Rambo.

  • If googling is any indication, "Yan" doesn't really mean anything in English.