fixes #64, make yang-js to support windows platform. (#82)

Awesome, thanks @quantang!

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema') if process.env.DEBUG?
    fs     = require 'fs'
    path   = require 'path'
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'
    XPath = require './xpath'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg unless schema.arg is false

        schema = (new this kind, tag).extends schema.substmts.map (x) => @parse x, compile: false
        # perform final scoped constraint validation
        for kind, constraint of schema.scope when constraint in [ '1', '1..n' ]
          unless schema.hasOwnProperty kind
            throw schema.error "constraint violation for required '#{kind}' = #{constraint}"
        schema.compile() if opts.compile
        return schema

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug? "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

### resolve (from..., name)

This call is internally used by [import](#import-name-opts) to perform
a search within the local filesystem to locate a given YANG schema
module by `name`. It will first check the calling code's local
[package.json](../package.json) to look for a `yang: { resolve: {} }`
configuration section to identify where the target module can be
found. If there is an entry defined, it will then follow that
reference - which may be a JS file, YANG schema text file, or another
NPM module. If it is not found within the `yang: { resolve: {} }`
configuration block or it fails to load the referenced dependency, it
will then fallback to attempt to locate a YANG schema text file in the
same folder that the `resolve` request was made: `#{name}.yang`.

      @resolve: (from..., name) ->
        return null unless typeof name is 'string'
        dir = from = switch
          when from.length then from[0]
          else path.resolve()
        while not found? and dir != path.dirname dir
          target = path.resolve dir, "package.json"
          debug? "[resolve] #{name} in #{target}"
          try
            pkginfo = require(target)
            found = pkginfo.yang?.resolve?[name] ? pkginfo.models[name]
          if found?
            dir = path.dirname require.resolve(target)
            debug? "[resolve] #{name} check #{found} in #{dir}"
            unless !!path.extname found
              from = switch
                when found of pkginfo.dependencies
                  path.resolve dir, 'node_modules', found
                else path.resolve dir, found
              if fs.existsSync from
                return @resolve from, name
              else
                found = @resolve found, name
          if not found? and pkginfo?.name is name
            found = path.dirname require.resolve(target)
          dir = path.dirname dir unless found?
        file = switch
          when not found? then path.resolve from, "#{name}.yang"
          else path.resolve dir, found
        debug? "[resolve] checking if #{file} exists"
        return if fs.existsSync file then file else null

### import (name [, opts={}])

This call provides a convenience mechanism for dealing with YANG
schema module dependencies. It performs parsing of the YANG schema
content from the specified `name` and saves the generated `Yang`
expression inside the internal registry. The `name` can be a YANG
module name or a *filename* to the actual schema content (JS or YANG).

Once a given YANG module has been saved inside the registry,
subsequent [parse](#parse-schema) of YANG schema that *import* the
saved module will successfully resolve.

Typical usage scenario for this pattern is to internally define common
modules such as `ietf-yang-types` which can then be *imported* by
other schemas.

It will also return the new `Yang` expression instance (to do with as
you please).

      @import: (name, opts={}) ->
        return unless name?
        opts.basedir ?= ''
        extname  = path.extname name
        filename = path.resolve opts.basedir, name
        basedir  = path.dirname filename

        unless !!extname
          return (Yang::match.call this, 'module', name) ? @import (@resolve name), opts

        unless extname is '.yang'
          res = require filename
          unless res instanceof Yang
            throw @error "unable to import '#{name}' from '#{filename}' (not Yang expression)", res
          return res

        try return @use (@parse (fs.readFileSync filename, 'utf-8'), opts)
        catch e
          debug? e
          unless opts.compile and e.name is 'ExpressionError' and e.context.kind in [ 'include', 'import' ]
            console.error "unable to parse '#{name}' YANG module from '#{filename}'"
            throw e
          if e.context.kind is 'include'
            opts = Object.assign {}, opts
            opts.compile = false

          # try to find the dependency module for import
          dependency = @import (@resolve basedir, e.context.tag), opts
          unless dependency?
            e.message = "unable to auto-resolve '#{e.context.tag}' dependency module"
            throw e
          unless dependency.tag is e.context.tag
            e.message = "found mismatching module '#{dependency.tag}' while resolving '#{e.context.tag}'"
            throw e

          # retry the original request
          debug? "retrying import(#{name})"
          return @import arguments...

Please note that this method will look for the `name` in current
working directory of the script execution if the `name` is a relative
path. It utilizes the [resolve](#resolve-from-name) method and will
attempt to **recursively** resolve any failed `import` dependencies.

While this is a convenient abstraction, it is **recommended** to
directly use the Node.js built-in `require` mechanism (if
available). Using native `require` instead of `Yang.import` will
allow package bundlers such as `browserify` to capture the
dependencies as part of the produced bundle.  It also allows you to
directly load YANG schema files from other NPM modules.

By default, loading the [yang-js](./main.coffee) module will attempt
to associate `.yang` extension inside `require` facility. If
available, it will allow you to `require('./some-dependency.yang')`
and get back a parsed `Yang expression` instance.

## Main constructor

This method can be called directly without the use of `new` keyword
and will internally parse the provided schema and return a `bound
function` which will invoke [eval](#eval-data-opts) when called.

      constructor: (kind, tag, extension) ->
        unless this instanceof Yang
          [ schema, bindings ] = arguments
          schema = Yang.parse schema unless schema instanceof Yang
          return schema.bind bindings

        extension ?= (@lookup 'extension', kind)
        self = super kind, tag, extension
        unless extension instanceof Expression
          @debug "defer processing of custom extension #{kind}"
          @once 'compile:before', (->
            @debug "processing deferred extension #{kind}"
            extension = (@lookup 'extension', kind)
            unless extension instanceof Yang
              throw @error "encountered unknown extension '#{kind}'"
            { @source, @argument } = extension
          ).bind self
        return self

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module' then "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          else @tag ? @kind

      @property 'datapath',
        get: -> switch
          when @parent not instanceof Yang then ''
          when @node then @parent.datapath + "/#{@datakey}"
          else @parent.datapath + "/#{@kind}(#{@datakey})"

      error: (msg, context) -> super "[#{@trail}] #{msg}", context

      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      # bind() is inherited from Expression

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### validate (data, opts={})

Perform schema correctness validation for the passed in `data`.  This
differs from [eval](#eval-data-opts) in that the final data returned
is not infused as dynamic data model using Property instances. It
should be used to perform a sanity check on the data if it will not
be programmatically modified.

For example, [Property](./property.litcoffee) instance uses `validate`
when dealing with non-configurable data nodes `config false`.

      validate: (data, ctx={}) ->
        # XXX - for now, we just do the full apply...
        return @apply data, ctx

        @compile() unless @resolved
        debug? "[#{@trail}] validating data to schema"

        try @predicate?.call this, data
        catch e
          throw @error "predicate validation error: #{e}", data

        if @kind is 'list' and Array.isArray data
          data = data.map (item) =>
            if Array.isArray item
              throw @error "list item cannot be another array"
            @validate item
        else
          # TODO: consider appending '..' property here?
          data[node.datakey] = node.validate data[node.datakey] for node in @nodes when data?

        unless @nodes.length
          data = this.apply data, ctx
        else
          data = attr.apply data, ctx for attr in @attrs

        return data

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)(?:\[.+\])?$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        res = XPath.split(ypath).map(normalizeEntry).join('/')
        res = '/' + res if /^\//.test ypath
        return res

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super unless kind? and tag? and typeof tag is 'string'
        res = super
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        debug? "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        debug? "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        debug? "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module.match kind, arg

        debug? "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          debug? "[match] checking #{m.module.tag}"
          return m.module.match kind, arg

        debug? "[match] check if one of available modules"
        module = @lookup 'module', prefix
        return module.match kind, arg if module?

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @source.argument?
          s += ' ' + switch @source.argument
            when 'value' then "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @elements
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @source.argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang

# Yang - evaluable schema expression

This module provides support for basic set of YANG schema modeling
language by using the built-in *extension* syntax to define additional
schema language constructs. The actual YANG language [RFC
6020](http://tools.ietf.org/html/rfc6020) specifications are loaded
inside the [main module](./main.coffee).

This module is the **primary interface** for consumers of this
library.

## Dependencies

    debug  = require('debug')('yang:schema') if process.env.DEBUG?
    fs     = require 'fs'
    path   = require 'path'
    parser = require 'yang-parser'
    indent = require 'indent-string'

    Expression = require './expression'
    XPath = require './xpath'

## Class Yang

    class Yang extends Expression
      @scope:
        extension: '0..n'
        typedef:   '0..n'
        module:    '0..n'
        submodule: '0..n'

## Class-level methods

      @clear: ->
        @module.splice(0,@module.length) if @module?
        @submodule.splice(0,@submodule.length) if @submodule?

### parse (schema)

This class-level routine performs recursive parsing of passed in
statement and sub-statements. It provides syntactic, semantic and
contextual validations on the provided schema and returns the final JS
object tree structure as hierarchical Yang expression instances.

If any validation errors are encountered, it will throw the
appropriate error along with the context information regarding the
error.

      @parse: (schema, opts={}) ->
        opts.compile ?= true
        try
          schema = parser.parse schema if typeof schema is 'string'
        catch e
          e.offset = 50 unless e.offset > 50
          offender = schema.slice e.offset-50, e.offset+50
          offender = offender.replace /\s\s+/g, ' '
          throw @error "invalid YANG syntax detected around: '#{offender}'", offender

        unless schema instanceof Object
          throw @error "must pass in valid YANG schema", schema

        kind = switch
          when !!schema.prf then "#{schema.prf}:#{schema.kw}"
          else schema.kw
        tag = schema.arg unless schema.arg is false

        schema = (new this kind, tag).extends schema.substmts.map (x) => @parse x, compile: false
        # perform final scoped constraint validation
        for kind, constraint of schema.scope when constraint in [ '1', '1..n' ]
          unless schema.hasOwnProperty kind
            throw schema.error "constraint violation for required '#{kind}' = #{constraint}"
        schema.compile() if opts.compile
        return schema

For comprehensive overview on currently supported YANG statements,
please refer to
[Compliance Report](../test/yang-compliance-coverage.md) for the latest
[RFC 6020](http://tools.ietf.org/html/rfc6020) YANG specification
compliance.

### compose (data [, opts={}])

This call *accepts* any arbitrary JS object and it will attempt to
convert it into a structural `Yang` expression instance. It will
analyze the passed in JS data and perform best match mapping to an
appropriate YANG schema representation to describe the input
data. This method will not be able to determine conditionals or any
meta-data to further constrain the data, but it should provide a good
starting point with the resulting `Yang` expression instance.

      @compose: (data, opts={}) ->
        unless data?
          throw @error "must supply input 'data' to compose"

        # explict compose
        if opts.kind?
          ext = Yang::lookup.call this, 'extension', opts.kind
          unless ext instanceof Expression
            throw @error "unable to find requested '#{opts.kind}' extension"
          return ext.compose? data, opts

        # implicit compose (dynamic discovery)
        for ext in @extension when ext.compose instanceof Function
          debug? "checking data if #{ext.tag}"
          res = ext.compose data, opts
          return res if res instanceof Yang

This facility is a powerful construct to dynamically generate `Yang`
schema from ordinary JS objects. For additional usage examples, please
refer to [Dynamic Composition](../TUTORIAL.md#dynamic-composition)
section in the [Getting Started Guide](../TUTORIAL.md).

### resolve (from..., name)

This call is internally used by [import](#import-name-opts) to perform
a search within the local filesystem to locate a given YANG schema
module by `name`. It will first check the calling code's local
[package.json](../package.json) to look for a `yang: { resolve: {} }`
configuration section to identify where the target module can be
found. If there is an entry defined, it will then follow that
reference - which may be a JS file, YANG schema text file, or another
NPM module. If it is not found within the `yang: { resolve: {} }`
configuration block or it fails to load the referenced dependency, it
will then fallback to attempt to locate a YANG schema text file in the
same folder that the `resolve` request was made: `#{name}.yang`.

      @resolve: (from..., name) ->
        return null unless typeof name is 'string'
        dir = from = switch
          when from.length then from[0]
          else path.resolve()
        while not found? and dir not in [ '/', '.' ]
          target = "#{dir}/package.json"
          debug? "[resolve] #{name} in #{target}"
          try
            pkginfo = require(target)
            found = pkginfo.yang?.resolve?[name] ? pkginfo.models[name]
          if found?
            dir = path.dirname require.resolve(target)
            debug? "[resolve] #{name} check #{found} in #{dir}"
            unless !!path.extname found
              from = switch
                when found of pkginfo.dependencies
                  path.resolve dir, 'node_modules', found
                else path.resolve dir, found
              if fs.existsSync from
                return @resolve from, name
              else
                found = @resolve found, name
          if not found? and pkginfo?.name is name
            found = path.dirname require.resolve(target)
          dir = path.dirname dir unless found?
        file = switch
          when not found? then path.resolve from, "#{name}.yang"
          else path.resolve dir, found
        debug? "[resolve] checking if #{file} exists"
        return if fs.existsSync file then file else null

### import (name [, opts={}])

This call provides a convenience mechanism for dealing with YANG
schema module dependencies. It performs parsing of the YANG schema
content from the specified `name` and saves the generated `Yang`
expression inside the internal registry. The `name` can be a YANG
module name or a *filename* to the actual schema content (JS or YANG).

Once a given YANG module has been saved inside the registry,
subsequent [parse](#parse-schema) of YANG schema that *import* the
saved module will successfully resolve.

Typical usage scenario for this pattern is to internally define common
modules such as `ietf-yang-types` which can then be *imported* by
other schemas.

It will also return the new `Yang` expression instance (to do with as
you please).

      @import: (name, opts={}) ->
        return unless name?
        opts.basedir ?= ''
        extname  = path.extname name
        filename = path.resolve opts.basedir, name
        basedir  = path.dirname filename

        unless !!extname
          return (Yang::match.call this, 'module', name) ? @import (@resolve name), opts

        unless extname is '.yang'
          res = require filename
          unless res instanceof Yang
            throw @error "unable to import '#{name}' from '#{filename}' (not Yang expression)", res
          return res

        try return @use (@parse (fs.readFileSync filename, 'utf-8'), opts)
        catch e
          debug? e
          unless opts.compile and e.name is 'ExpressionError' and e.context.kind in [ 'include', 'import' ]
            console.error "unable to parse '#{name}' YANG module from '#{filename}'"
            throw e
          if e.context.kind is 'include'
            opts = Object.assign {}, opts
            opts.compile = false

          # try to find the dependency module for import
          dependency = @import (@resolve basedir, e.context.tag), opts
          unless dependency?
            e.message = "unable to auto-resolve '#{e.context.tag}' dependency module"
            throw e
          unless dependency.tag is e.context.tag
            e.message = "found mismatching module '#{dependency.tag}' while resolving '#{e.context.tag}'"
            throw e

          # retry the original request
          debug? "retrying import(#{name})"
          return @import arguments...

Please note that this method will look for the `name` in current
working directory of the script execution if the `name` is a relative
path. It utilizes the [resolve](#resolve-from-name) method and will
attempt to **recursively** resolve any failed `import` dependencies.

While this is a convenient abstraction, it is **recommended** to
directly use the Node.js built-in `require` mechanism (if
available). Using native `require` instead of `Yang.import` will
allow package bundlers such as `browserify` to capture the
dependencies as part of the produced bundle.  It also allows you to
directly load YANG schema files from other NPM modules.

By default, loading the [yang-js](./main.coffee) module will attempt
to associate `.yang` extension inside `require` facility. If
available, it will allow you to `require('./some-dependency.yang')`
and get back a parsed `Yang expression` instance.

## Main constructor

This method can be called directly without the use of `new` keyword
and will internally parse the provided schema and return a `bound
function` which will invoke [eval](#eval-data-opts) when called.

      constructor: (kind, tag, extension) ->
        unless this instanceof Yang
          [ schema, bindings ] = arguments
          schema = Yang.parse schema unless schema instanceof Yang
          return schema.bind bindings

        extension ?= (@lookup 'extension', kind)
        self = super kind, tag, extension
        unless extension instanceof Expression
          @debug "defer processing of custom extension #{kind}"
          @once 'compile:before', (->
            @debug "processing deferred extension #{kind}"
            extension = (@lookup 'extension', kind)
            unless extension instanceof Yang
              throw @error "encountered unknown extension '#{kind}'"
            { @source, @argument } = extension
          ).bind self
        return self

      @property 'datakey',
        get: -> switch
          when @parent instanceof Yang and @parent.kind is 'module' then "#{@parent.tag}:#{@tag}"
          when @parent instanceof Yang and @parent.kind is 'submodule'
            "#{@parent['belongs-to'].tag}:#{@tag}"
          else @tag ? @kind

      @property 'datapath',
        get: -> switch
          when @parent not instanceof Yang then ''
          when @node then @parent.datapath + "/#{@datakey}"
          else @parent.datapath + "/#{@kind}(#{@datakey})"

      error: (msg, context) -> super "[#{@trail}] #{msg}", context

      emit: (event, args...) ->
        @emitter.emit arguments...
        @root.emit event, this if event is 'change' and this isnt @root

## Instance-level methods

### bind (obj)

Every instance of `Yang` expression can be *bound* with control logic
which will be used during [eval](#eval-data-opts) to produce schema
infused **adaptive data object**. This routine is *inherited* from
[Class Expression](./expression.coffee).

This facility can be used to associate default behaviors for any
element in the configuration tree, as well as handler logic for
various YANG statements such as *rpc*, *feature*, etc.

This call will return the original `Yang` expression instance with the
new bindings registered within the `Yang` expression hierarchy.

      # bind() is inherited from Expression

Please refer to [Schema Binding](../TUTORIAL.md#schema-binding)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

### eval (data, opts={})

Every instance of `Yang` expression can be [eval](#eval-data-opts)
with arbitrary JS data input which will apply the schema against the
provided data and return a schema infused **adaptive** data object.

This is an extremely useful construct which brings out the true power
of YANG for defining and governing arbitrary JS data structures.

Basically, the input `data` will be YANG schema validated and
converted to a schema infused *adaptive data model* that dynamically
defines properties according to the schema expressions.

It currently supports the `opts.adaptive` parameter (default `false`)
which establishes a persistent binding relationship with the governing
`Yang` expression instance. This allows the generated model to
dynamically **adapt** to any changes to the governing `Yang`
expression instance. Refer to below [extends](#extends-schema) section
for additional info on how the schema can be programmatically
modified.

      eval: (data, opts={}) ->
        if opts.adaptive is true
          # TODO: this will break for 'module' which will return Model?
          @once 'change', arguments.callee.bind(this, data, opts)
        super

Please refer to [Working with Models](../TUTORIAL.md#working-with-models)
section of the [Getting Started Guide](../TUTORIAL.md) for special
usage examples for `module` schemas.

### validate (data, opts={})

Perform schema correctness validation for the passed in `data`.  This
differs from [eval](#eval-data-opts) in that the final data returned
is not infused as dynamic data model using Property instances. It
should be used to perform a sanity check on the data if it will not
be programmatically modified.

For example, [Property](./property.litcoffee) instance uses `validate`
when dealing with non-configurable data nodes `config false`.

      validate: (data, ctx={}) ->
        # XXX - for now, we just do the full apply...
        return @apply data, ctx

        @compile() unless @resolved
        debug? "[#{@trail}] validating data to schema"

        try @predicate?.call this, data
        catch e
          throw @error "predicate validation error: #{e}", data

        if @kind is 'list' and Array.isArray data
          data = data.map (item) =>
            if Array.isArray item
              throw @error "list item cannot be another array"
            @validate item
        else
          # TODO: consider appending '..' property here?
          data[node.datakey] = node.validate data[node.datakey] for node in @nodes when data?

        unless @nodes.length
          data = this.apply data, ctx
        else
          data = attr.apply data, ctx for attr in @attrs

        return data

### extends (schema...)

Every instance of `Yang` expression can be `extends` with additional
YANG schema string(s) and it will automatically perform
[parse](#parse-schema) of the provided schema text and update itself
accordingly.

This action also triggers an event emitter which will *retroactively*
adapt any previously [eval](#eval-data-opts) produced adaptive data
model instances to react accordingly to the newly changed underlying
schema expression(s).

      # extends() is inherited from Element

      merge: (elem) ->
        unless elem instanceof Yang
          throw @error "cannot merge invalid element into Yang", elem

        switch elem.kind
          when 'type'     then super elem, append: true
          when 'argument' then super elem, replace: true
          else super

Please refer to [Schema Extension](../TUTORIAL.md#schema-extension)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

      normalizePath: (ypath) ->
        lastPrefix = null
        prefix2module = (root, prefix) ->
          return unless root.kind is 'module'
          switch
            when root.tag is prefix then prefix
            when root.prefix.tag is prefix then root.tag
            else
              for m in root.import ? [] when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              modules = root.lookup 'module'
              for m in modules when m.tag is prefix or m.prefix.tag is prefix
                return m.tag
              return prefix # return as-is...

        normalizeEntry = (x) =>
          return x unless x? and !!x
          match = x.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)(?:\[.+\])?$/
          unless match?
            throw @error "invalid path expression '#{x}' found in #{ypath}"
          [ prefix, target ] = [ match[1], match[2] ]
          return switch
            when not prefix? then target
            when prefix is lastPrefix then target
            else
              lastPrefix = prefix
              mname = prefix2module @root, prefix
              "#{mname}:#{target}"
        ypath = ypath.replace /\s/g, ''
        res = XPath.split(ypath).map(normalizeEntry).join('/')
        res = '/' + res if /^\//.test ypath
        return res

### locate (ypath)

This is an internal helper facility used to locate a given schema node
within the `Yang` schema expression tree hierarchy. It supports a
limited version of XPATH-like expression to locate an explicit
element.

      locate: (ypath) ->
        # TODO: figure out how to eliminate duplicate code-block section
        # shared with Element
        return unless ypath?

        @debug "locate enter for '#{ypath}'"
        if typeof ypath is 'string'
          if (/^\//.test ypath) and this isnt @root
            return @root.locate ypath
          [ key, rest... ] = @normalizePath(ypath).split('/').filter (e) -> !!e
        else
          [ key, rest... ] = ypath
        return this unless key? and key isnt '.'

        if key is '..'
          return @parent?.locate rest

        match = key.match /^(?:([._-\w]+):)?([.{[<\w][.,+_\-}():>\]\w]*)$/
        [ prefix, target ] = [ match[1], match[2] ]
        if prefix? and this is @root
          search = [target].concat(rest)
          if (@tag is prefix) or (@lookup 'prefix', prefix)
            @debug "locate (local) '/#{prefix}:#{search.join('/')}'"
            return super search
          for m in @import ? [] when m.tag is prefix or m.prefix.tag is prefix
            @debug "locate (external) '/#{prefix}:#{search.join('/')}'"
            return m.module.locate search
          m = @lookup 'module', prefix
          return m?.locate search

        switch
          when /^{.+}$/.test(target)
            kind = 'grouping'
            tag  = target.replace /^{(.+)}$/, '$1'
          when /^\[.+\]$/.test(target)
            kind = 'feature'
            tag  = target.replace /^\[(.+)\]$/, '$1'
          when /^[^(]+\([^)]*\)$/.test(target)
            target = target.match /^([^(]+)\((.*)\)$/
            [ kind, tag ] = [ target[1], target[2] ]
            tag = undefined unless !!tag
          when /^\<.+\>$/.test(target)
            target = target.replace /^\<(.+)\>$/, '$1'
            [ kind..., tag ]  = target.split ':'
            [ tag, selector ] = tag.split '='
            kind = kind[0] if kind?.length
          else return super [key].concat rest

        match = @match kind, tag
        return switch
          when rest.length is 0 then match
          else match?.locate rest

### match (kind, tag)

This is an internal helper facility used by [locate](#locate-ypath) and
[lookup](./element.litcoffee#lookup-kind-tag) to test whether a given
entity exists in the local schema tree.

      # Yang Expression can support 'tag' with prefix to another module
      # (or itself).
      match: (kind, tag) ->
        return super unless kind? and tag? and typeof tag is 'string'
        res = super
        return res if res?

        [ prefix..., arg ] = tag.split ':'
        return unless prefix.length

        debug? "[match] with #{kind} #{tag}"

        prefix = prefix[0]
        debug? "[match] check if current module's prefix"
        if @root.tag is prefix or @root.prefix?.tag is prefix
          return @root.match kind, arg

        debug? "[match] checking if submodule's parent"
        ctx = @lookup 'belongs-to'
        if ctx?.prefix.tag is prefix
          return ctx.module.match kind, arg

        debug? "[match] check if one of current module's imports"
        imports = @root?.import ? []
        for m in imports when m.prefix.tag is prefix
          debug? "[match] checking #{m.module.tag}"
          return m.module.match kind, arg

        debug? "[match] check if one of available modules"
        module = @lookup 'module', prefix
        return module.match kind, arg if module?

### toString (opts={})

The current `Yang` expression will covert back to the equivalent YANG
schema text format.

At first glance, this may not seem like a useful facility since YANG
schema text is *generally known* before [parse](#parse-schema) but it
becomes highly relevant when you consider a given `Yang` expression
programatically changing via [extends](#extends-schema).

Currently it supports `space` parameter which can be used to specify
number of spaces to use for indenting YANG statement blocks.  It
defaults to **2** but when set to **0**, the generated output will
omit newlines and other spacing for a more compact YANG output.

      toString: (opts={ space: 2 }) ->
        s = @kind
        if @source.argument?
          s += ' ' + switch @source.argument
            when 'value' then "'#{@tag}'"
            when 'text'
              "\n" + (indent '"'+@tag+'"', ' ', opts.space)
            else @tag
        sub =
          @elements
            .filter (x) => x.parent is this
            .map (x) -> x.toString opts
            .join "\n"
        if !!sub
          s += " {\n" + (indent sub, ' ', opts.space) + "\n}"
        else
          s += ';'
        return s

### toJSON

The current `Yang` expression will convert into a simple JS object
format.

      # toJSON() is inherited from Element

### valueOf

The current 'Yang' expression will convert into a primitive form for
comparision purposes.

      valueOf: ->
        switch @source.argument
          when 'value','text' then @tag.valueOf()
          else this

Please refer to [Schema Conversion](../TUTORIAL.md#schema-conversion)
section of the [Getting Started Guide](../TUTORIAL.md) for usage
examples.

## Export Yang Class

    module.exports = Yang


Docs for LVar

Docs for LVar

We always start with the JavaScript-like magic scoping mojo!

    ((root) ->
      root = this
      _ = root._ || require 'underscore'
      F = {}

Non-determinism
---------------

Non-deterministic functions are functions that can have more (or less) than one result.  As known from logic, a binary relation xRy (where x ∈ X, y ∈ Y) can be represented by a *function*  `X -> PowerSet{Y}`. As usual in computer science, we interpret the set `PowerSet{Y}` as a multi-set (realized as a regular scheme list). Compare with SQL, which likewise uses multisets and sequences were sets are properly called for. Also compare with [Wadler's "representing failure as a list of successes."](http://citeseer.uark.edu:8080/citeseerx/showciting;jsessionid=FF5F5EAA9D94B1A8618C49C37451D762?cid=377301).

Thus, we represent a 'relation' (aka `non-deterministic function') as a regular CoffeeScript function that returns an array of possible results.

First, we define two primitive non-deterministic functions; one of them yields no result whatsoever for any argument; the other merely returns its argument as the sole result.

    F.succeed = (result) -> [result]
    F.fail = _.always []

We build more complex non-deterministic functions by combining the existing ones with the help of the following two combinators.

`(disjunction l r)` returns all the results of `l` and all the results of `r`, or returns no results only if neither `l` nor `r` returned any.  In that sense, it is analogous to the logical disjunctionunction.

    disjunction = (l, r) ->
      (x) -> _.cat(l(x), r(x))

`(conjunction l r)` looks like a functional composition of `r` and `l`.  Only `(l x)` may return several results, so we have to apply `r` to each of them.  Obviously `(conjunction fail f)` and `(conjunction f fail)` are both equivalent to `fail`: they return no results, ever. It that sense, `conjunction` is analogous to the logical conjunction.

    conjunction = (l, r) ->
      (x) -> _.mapcat(l(x), r)

JavaScript allows you to pass any number of arguments to a function.  Therefore, we can make a function `disj` that takes any number of arguments and performs a logical disjunction over each.  This makes this version of Sokuza Kanren a bit more flexible in that it allows you to nest any number of relations therein.

    F.disj = () ->
      return F.fail if _.isEmpty(arguments)
      disjunction(_.first(arguments),
	              F.disj.apply(this, _.rest(arguments)))

Likewise, the `conj` function accepts any number of clauses, nit just two as in the original Sokuza.

    F.conj = () ->
      clauses = _.toArray(arguments)
      return F.succeed if _.isEmpty(clauses)
      return _.first(clauses) if _.size(clauses) is 1
      conjunction(_.first(clauses),
                  (s) -> F.conj.apply(null, _.rest(clauses))(s))

And that's all that there is for the built-in non-deterministic functions.

# Knowledge representation
# ------------------------

One may think of regular variables as "certain knowledge": they give  names to definite values.  A logic variable then stands for "improvable ignorance".  An unbound logic variable represents no  knowledge at all; in other words, it represents the result of a measurement *before* we have done the measurement. A logic variable may be associated with a definite value, like 10. That means definite knowledge.  A logic variable may be associated with a semi-definite value, like `[$X]` where `$X` is an unbound variable. We know something about the original variable: it is associated with the array of one element.  We can't say though what that element is. A logic variable can be associated with another, unbound logic variable. In that case, we still don't know what precisely the original variable stands for. However, we can say that it represents the same thing as the other variable. So, our uncertainty is reduced.

I've chosen to represent logic variables with their own simple type.

    class LVar
      constructor: (@name) ->

I've also created a couple of helper functions for creating new variables and checking "variableness" to decouple the representation a bit.

    F.lvar = (name) -> new LVar(name)
    F.isLVar = (v) -> (v instanceof LVar)

    find = (v, bindings) ->
      lvar = bindings.lookup(v)
      return lvar if F.isLVar(v)
      if _.isArray(lvar)
        if _.isEmpty(lvar)
          return lvar
        else
          return _.cons(find(_.first(lvar), bindings),
  		              find(_.rest(lvar), bindings))
      lvar

  class Bindings
    constructor: (seed = {}) ->
      @binds = _.merge({}, seed)
    extend: (lvar, value) ->
      o = {}
      o[lvar.name] = value
      new Bindings(_.merge(@binds, o))
    has: (lvar) ->
      @binds.hasOwnProperty(lvar.name)
    lookup: (lvar) ->
      return lvar if !F.isLVar(lvar)
      return this.lookup(@binds[lvar.name]) if this.has(lvar)
      lvar

  F.ignorance = new Bindings()

  # Unification
  # -----------

  F.unify = (l, r, bindings) ->
    t1 = bindings.lookup(l)
    t2 = bindings.lookup(r)

    if _.isEqual(t1, t2)
      return s
    if F.isLVar(t1)
      return bindings.extend(t1, t2)
    if F.isLVar(t2)
      return bindings.extend(t2, t1)
    if _.isArray(t1) && _.isArray(t2)
      s = F.unify(_.first(t1), _.first(t2), bindings)
      s = if (s isnt null) then F.unify(_.rest(t1), _.rest(t2), bindings) else s
      return s
    return null

  # Operational logic
  # -----------------

  F.goal = (l, r) ->
    (bindings) ->
      result = F.unify(l, r, bindings)
      return F.succeed(result) if result isnt null
      return F.fail(bindings)

  F.run = (goal) ->
    goal(F.ignorance)

  # Logico
  # ------

  F.choice = ($v, list) ->
    return F.fail if _.isEmpty(list)

    F.disj(F.goal($v, _.first(list)),
                  F.choice($v, _.rest(list)))

  # Exports and sundries
  # --------------------

  if module?
    module.exports = F
  else
    root.F = F

)(this)

We always start with the JavaScript-like magic scoping mojo!

    ((root) ->
      root = this
      _ = root._ || require 'underscore'
      F = {}

Non-determinism
---------------

Non-deterministic functions are functions that can have more (or less) than one result.  As known from logic, a binary relation xRy (where x ∈ X, y ∈ Y) can be represented by a *function*  `X -> PowerSet{Y}`. As usual in computer science, we interpret the set `PowerSet{Y}` as a multi-set (realized as a regular scheme list). Compare with SQL, which likewise uses multisets and sequences were sets are properly called for. Also compare with [Wadler's "representing failure as a list of successes."](http://citeseer.uark.edu:8080/citeseerx/showciting;jsessionid=FF5F5EAA9D94B1A8618C49C37451D762?cid=377301).

Thus, we represent a 'relation' (aka `non-deterministic function') as a regular CoffeeScript function that returns an array of possible results.

First, we define two primitive non-deterministic functions; one of them yields no result whatsoever for any argument; the other merely returns its argument as the sole result.

    F.succeed = (result) -> [result]
    F.fail = _.always []

We build more complex non-deterministic functions by combining the existing ones with the help of the following two combinators.

`(disjunction l r)` returns all the results of `l` and all the results of `r`, or returns no results only if neither `l` nor `r` returned any.  In that sense, it is analogous to the logical disjunctionunction.

    disjunction = (l, r) ->
      (x) -> _.cat(l(x), r(x))

`(conjunction l r)` looks like a functional composition of `r` and `l`.  Only `(l x)` may return several results, so we have to apply `r` to each of them.  Obviously `(conjunction fail f)` and `(conjunction f fail)` are both equivalent to `fail`: they return no results, ever. It that sense, `conjunction` is analogous to the logical conjunction.

    conjunction = (l, r) ->
      (x) -> _.mapcat(l(x), r)

JavaScript allows you to pass any number of arguments to a function.  Therefore, we can make a function `disj` that takes any number of arguments and performs a logical disjunction over each.  This makes this version of Sokuza Kanren a bit more flexible in that it allows you to nest any number of relations therein.

    F.disj = () ->
      return F.fail if _.isEmpty(arguments)
      disjunction(_.first(arguments),
	              F.disj.apply(this, _.rest(arguments)))

Likewise, the `conj` function accepts any number of clauses, nit just two as in the original Sokuza.

    F.conj = () ->
      clauses = _.toArray(arguments)
      return F.succeed if _.isEmpty(clauses)
      return _.first(clauses) if _.size(clauses) is 1
      conjunction(_.first(clauses),
                  (s) -> F.conj.apply(null, _.rest(clauses))(s))

And that's all that there is for the built-in non-deterministic functions.

# Knowledge representation
# ------------------------

  class LVar
    constructor: (@name) ->

  F.lvar = (name) -> new LVar(name)
  F.isLVar = (v) -> (v instanceof LVar)

  find = (v, bindings) ->
    lvar = bindings.lookup(v)
    return lvar if F.isLVar(v)
    if _.isArray(lvar)
      if _.isEmpty(lvar)
        return lvar
      else
        return _.cons(find(_.first(lvar), bindings), find(_.rest(lvar), bindings))
    lvar

  class Bindings
    constructor: (seed = {}) ->
      @binds = _.merge({}, seed)
    extend: (lvar, value) ->
      o = {}
      o[lvar.name] = value
      new Bindings(_.merge(@binds, o))
    has: (lvar) ->
      @binds.hasOwnProperty(lvar.name)
    lookup: (lvar) ->
      return lvar if !F.isLVar(lvar)
      return this.lookup(@binds[lvar.name]) if this.has(lvar)
      lvar

  F.ignorance = new Bindings()

  # Unification
  # -----------

  F.unify = (l, r, bindings) ->
    t1 = bindings.lookup(l)
    t2 = bindings.lookup(r)

    if _.isEqual(t1, t2)
      return s
    if F.isLVar(t1)
      return bindings.extend(t1, t2)
    if F.isLVar(t2)
      return bindings.extend(t2, t1)
    if _.isArray(t1) && _.isArray(t2)
      s = F.unify(_.first(t1), _.first(t2), bindings)
      s = if (s isnt null) then F.unify(_.rest(t1), _.rest(t2), bindings) else s
      return s
    return null

  # Operational logic
  # -----------------

  F.goal = (l, r) ->
    (bindings) ->
      result = F.unify(l, r, bindings)
      return F.succeed(result) if result isnt null
      return F.fail(bindings)

  F.run = (goal) ->
    goal(F.ignorance)

  # Logico
  # ------

  F.choice = ($v, list) ->
    return F.fail if _.isEmpty(list)

    F.disj(F.goal($v, _.first(list)),
                  F.choice($v, _.rest(list)))

  # Exports and sundries
  # --------------------

  if module?
    module.exports = F
  else
    root.F = F

)(this)


webpack

webpack

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc).
It also manages loading via JavaScript `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    path    = require('path')
    webpack = require('webpack')
    _       = require('lodash')

Define an empty configuration:

    module.exports = {}

Entry bundles, i.e. package source paths. See [docs](http://webpack.github.io/docs/configuration.html#entry).

    module.exports.entry =
      "main"            : "./src/scripts/main.litcoffee"
      "styles"          : "./src/styles/styles.scss"
      "vendor/es5-shim" : "./bower_components/es5-shim/es5-shim.js"
      "vendor/es5-sham" : "./bower_components/es5-shim/es5-sham.js"

## Loaders

Define how files should be loaded (required) based on the extension.

### Scripts

Process CoffeeScript and JSX.

    jsLoaders = ["jsx"]
    scriptModLoaders = [
      { test: /\.coffee$/   , loaders: jsLoaders.concat(["coffee"]) }
      { test: /\.litcoffee$/, loaders: jsLoaders.concat(["coffee?literate"]) }
      { test: /\.js$/       , loaders: jsLoaders }
    ]

### Styles

Process Sass and use Autoprefixer.

    cssLoaders = ['style', 'css', 'autoprefixer-loader?last 2 versions']
    styleModLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat([
          "sass?precision=10&outputStyle=expanded&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/ , loaders: cssLoaders }
    ]

### Static assets

Embed data-URLs into CSS and JS for small images and `.woff` fonts:

    staticModLoaders = [
      { test: /\.gif$/ , loader: "url?limit=10000&mimetype=image/gif" }
      { test: /\.jpg$/ , loader: "url?limit=10000&mimetype=image/jpg" }
      { test: /\.png$/ , loader: "url?limit=10000&mimetype=image/png" }
      { test: /\.woff$/, loader: "url?limit=10000&mimetype=application/font-woff" }
      { test: /\.ttf$/ , loader: "file?mimetype=application/vnd.ms-fontobject" }
      { test: /\.eot$/ , loader: "file?mimetype=application/x-font-ttf" }
      { test: /\.svg$/ , loader: "file?mimetype=image/svg+xml" }
    ]

### Output CSS to `.css` files

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not as `.js` files with embedded CSS strings.

Require the plugin:

    ExtractTextPlugin = require("extract-text-webpack-plugin")

Set `styleModLoaders` to use the plugin:

    styleModLoaders = styleModLoaders.map (e) ->
      { test: e.test, loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!')) }

Create an instance of the extractTextPlugin:

    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

### Define macro variables

`DefinePlugin` defines variables to be substituted in the assets (a la macro).

Define `__PRODUCTION__: false` variable (set to true on `useProductionSettings()`):

    definePlugin = new webpack.DefinePlugin(
      __PRODUCTION__: JSON.stringify(false)
    )

### Other options

    _.merge module.exports,

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300

Output options:

      output:
        path         : path.join(__dirname, "dist", "assets")
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: ['bower_components', 'node_modules']

Define how modules should be loaded based on path extension:

      module:
        loaders: styleModLoaders.concat(scriptModLoaders).concat(staticModLoaders)
        noParse: /\.min\.js$/

Define the plugins:

      plugins: [

`definePlugin` defines variables to be substituted in the assets (a la macro):

        definePlugin

`extractTextPlugin` (defined above) will compile CSS to a .css file, as opposed to inlining it as a string in a .js file.

        extractTextPlugin
      ]

## Production overrides

Export a method that applies production settings (used in gulpfile):

      useProductionSettings: ->

Production plugins:

Set `__PRODUCTION__` to true in the `DefinePlugin` instance:

        definePlugin.definitions.__PRODUCTION__ = JSON.stringify(true)

Tell `ExtractTextPlugin` to append hashes (BROKEN, see [plugin issue #9](https://github.com/webpack/extract-text-webpack-plugin/issues/9)):

        extractTextPlugin.filename = '[name]-[hash].css'

Merge in production config (deep merge):

        _.merge @,

Disable development settings:

          debug: false
          watch: false
          devtool: null

Add content hashes to the output filenames:

          output:
            filename: "[name]-[hash].js"

          plugins: @plugins.concat [

Minify JavaScript with UglifyJS:

            new webpack.optimize.UglifyJsPlugin()
          ]

# Webpack Configuration

[Webpack](https://github.com/webpack/webpack) handles asset compilation (Sass, CoffeeScript, etc).
It also manages loading via JavaScript `require`, Sass `@import`, and CSS `url()`.

First, require the dependencies:

    path    = require('path')
    webpack = require('webpack')
    _       = require('lodash')

Define an empty configuration:

    module.exports = {}

Entry bundles, i.e. package source paths. See [docs](http://webpack.github.io/docs/configuration.html#entry).

    module.exports.entry =
      "main"            : "./src/scripts/main.litcoffee"
      "styles"          : "./src/styles/styles.scss"
      "vendor/es5-shim" : "./bower_components/es5-shim/es5-shim.js"
      "vendor/es5-sham" : "./bower_components/es5-shim/es5-sham.js"

## Loaders

Define how files should be loaded (required) based on the extension.

### Scripts

Process CoffeeScript and JSX.

    jsLoaders = ["jsx"]
    scriptModLoaders = [
      { test: /\.coffee$/   , loaders: jsLoaders.concat(["coffee"]) }
      { test: /\.litcoffee$/, loaders: jsLoaders.concat(["coffee?literate"]) }
      { test: /\.js$/       , loaders: jsLoaders }
    ]

### Styles

Process Sass and use Autoprefixer.

    cssLoaders = ['style', 'css', 'autoprefixer-loader?last 2 versions']
    styleModLoaders = [
      { test: /\.scss$/, loaders: cssLoaders.concat([
          "sass?precision=10&outputStyle=expanded&includePaths[]=" + path.resolve(__dirname, './bower_components')]) }
      { test: /\.css$/ , loaders: cssLoaders }
    ]

### Static assets

Embed data-URLs into CSS and JS for small images and `.woff` fonts:

    staticModLoaders = [
      { test: /\.gif$/ , loader: "url?limit=10000&mimetype=image/gif" }
      { test: /\.jpg$/ , loader: "url?limit=10000&mimetype=image/jpg" }
      { test: /\.png$/ , loader: "url?limit=10000&mimetype=image/png" }
      { test: /\.woff$/, loader: "url?limit=10000&mimetype=application/font-woff" }
      { test: /\.ttf$/ , loader: "file?mimetype=application/vnd.ms-fontobject" }
      { test: /\.eot$/ , loader: "file?mimetype=application/x-font-ttf" }
      { test: /\.svg$/ , loader: "file?mimetype=image/svg+xml" }
    ]

### Output CSS to `.css` files

`ExtractTextPlugin` is an experimental plugin to output CSS in `.css` and not as `.js` files with embedded CSS strings.

Require the plugin:

    ExtractTextPlugin = require("extract-text-webpack-plugin")

Set `styleModLoaders` to use the plugin:

    styleModLoaders = styleModLoaders.map (e) ->
      { test: e.test, loader: ExtractTextPlugin.extract(e.loaders.slice(1).join('!')) }

Create an instance of the extractTextPlugin:

    extractTextPlugin = new ExtractTextPlugin("[name].css", allChunks: true)

### Define macro variables

`DefinePlugin` defines variables to be substituted in the assets (a la macro).

Define `__PRODUCTION__: false` variable (set to true on `useProductionSettings()`):

    definePlugin = new webpack.DefinePlugin(
      __PRODUCTION__: JSON.stringify(false)
    )

### Other options

    _.merge module.exports,

Set compilation target to "web". See [docs](http://webpack.github.io/docs/configuration.html#target).

      target: "web"

Set development options by default:

      debug: true
      # We are watching in Gulp, so tell webpack not to watch
      watch: false
      # watchDelay: 300

Output options:

      output:
        path         : path.join(__dirname, "dist", "assets")
        publicPath   : "/assets/"
        filename     : "[name].js"
        chunkFilename: "[name].[id].[chunkhash].js"

Look for required files in bower and node

      resolve:
        modulesDirectories: ['bower_components', 'node_modules']

Define how modules should be loaded based on path extension:

      module:
        loaders: styleModLoaders.concat(scriptModLoaders).concat(staticModLoaders)
        noParse: /\.min\.js$/

Define the plugins:

      plugins: [

`definePlugin` defines variables to be substituted in the assets (a la macro):

        definePlugin

`extractTextPlugin` (defined above) will compile CSS to a .css file, as opposed to inlining it as a string in a .js file.

        extractTextPlugin
      ]

## Production overrides

Export a method that applies production settings (used in gulpfile):

      useProductionSettings: ->

Production plugins:

        plugins = @plugins.concat [

Minify JavaScript with UglifyJS:

          new webpack.optimize.UglifyJsPlugin()
        ]

Set `__PRODUCTION__` to true in the `DefinePlugin` instance:

        definePlugin.definitions.__PRODUCTION__ = JSON.stringify(true)

Tell `ExtractTextPlugin` to append hashes (BROKEN, see [plugin issue #9](https://github.com/webpack/extract-text-webpack-plugin/issues/9)):

        extractTextPlugin.filename = '[name]-[hash].css'

Merge in production config (deep merge):

        _.merge @,

Disable development settings:

          debug: false
          watch: false
          devtool: null

Add content hashes to the output filenames:

          output:
            filename: "[name]-[hash].js"

Production-only plugins:

          plugins: plugins