Repository: jamesramsay/hercule
Pull request #36 (2015-07-11 06:52:17)

Verbose logging and optional function arguments
- Added test for reference name collision handling
- Added test for parent leakage
- Improved internal consistency of pegjs grammar
- Support for optional arguments for `transcludeString` and `transcludeFile`
- Fixed verbose logging (closes #36)


Patch:
diff --git a/.gitignore b/.gitignore
index a87ee0f..72d05e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,5 @@ node_modules
 lib
 .coveralls.yml
 coverage.html
-npm-debug.log
+*.log
 test/modules*
diff --git a/README.md b/README.md
index c0b969d..674616f 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ Or use as a library:
 ```javascript
 var hercule = require('hercule');
 
-hercule.transcludeString("# Title\n\n:[abstract](abstract.md)", null, null, null, function(output) {
+hercule.transcludeString("# Title\n\n:[abstract](abstract.md)", function(output) {
   return console.log(output);
 });
 ```
diff --git a/src/grammar.coffee b/src/grammar.coffee
index e008d30..a871873 100644
--- a/src/grammar.coffee
+++ b/src/grammar.coffee
@@ -13,10 +13,10 @@
 # }
 
 transcludeGrammar = """
-start = f:link? ' '? o:reference* {
+start = l:link? ' '? o:reference* {
   return {
-    "link": f.value,
-    "type": f.type,
+    "href": l.href,
+    "hrefType": l.hrefType,
     "references": o
   };
 }
@@ -24,8 +24,8 @@ start = f:link? ' '? o:reference* {
 reference = p:placeholder ':' l:link ' '? {
   return {
     "placeholder": p,
-    "type": l.type,
-    "value": l.value
+    "href": l.href,
+    "hrefType": l.hrefType
   };
 }
 
@@ -37,29 +37,29 @@ link = httpLink / fileLink / string / reset
 
 fileLink = f:[^ ()\"]+ {
   return {
-    "type": "file",
-    "value": f.join("")
+    "hrefType": "file",
+    "href": f.join("")
   };
 }
 
 httpLink = left:("http://" / "https://") right:[^ ()]+ {
   return {
-    "type": "http",
-    "value": left + right.join("")
+    "hrefType": "http",
+    "href": left + right.join("")
   };
 }
 
 string = '\"' s:([^\"]+) '\"' {
   return {
-    "type": "string",
-    "value": s.join("")
+    "hrefType": "string",
+    "href": s.join("")
   };
 }
 
 reset = {
   return {
-    "type": "string",
-    "value": ""
+    "hrefType": "string",
+    "href": ""
   };
 }
 """
diff --git a/src/hercule.coffee b/src/hercule.coffee
index e29453b..8a8a11f 100644
--- a/src/hercule.coffee
+++ b/src/hercule.coffee
@@ -5,81 +5,117 @@ _ = require 'lodash'
 utils = require './utils'
 async = require 'async'
 
-#log = (message) -> console.error "#{message}"
-
-processInput = (input, parents, dir) ->
-  rawLinks = utils.scan input
-  #log "Scan: #{rawLinks.length} links found"
 
+transclude = (input, relativePath, parents, parentRefs, logger, cb) ->
+  rawLinks = utils.scan input, relativePath, parents
   links = _.forEach rawLinks, (rawLink) ->
-    rawLink.relativePath = dir
-    rawLink.parents = parents[..]
-
-    parsedLink = utils.parse rawLink
-    #log "Parse: #{parsedLink.references.length} references found"
-
-    return parsedLink
+    utils.parse rawLink
 
-  return links
-
-
-transclude = (input, relativePath, parents, parentRefs, cb) ->
-  # TODO: rename processInput...
-  # log "Scanning: #{input}"
-  links = processInput input, parents, relativePath
+  logger "Links found: #{links.length}"
   if links.length < 1 then return cb input
 
-  async.eachSeries links, ({link, type, file, references, parents, whitespace, placeholder}, done) ->
-    linkType = type
+  async.eachSeries links, (link, done) ->
+    {href, hrefType, references, parents, whitespace, placeholder} = link
 
-    references = _.merge parentRefs, references
-    match = utils.find link, references
+    matchingReferences = parentRefs.filter (ref) -> "#{ref.placeholder}" is "#{href}"
+    if matchingReferences[0]?
+      overridingReference = matchingReferences[0]
+      logger "Overriding reference: #{JSON.stringify overridingReference}"
 
-    if match?
-      #log "Expanding: #{link} -> #{match.value}"
-      link = match.value
-      linkType = match.type
-    else if linkType is "file"
-      link = path.join relativePath, link
+    if not matchingReferences[0]? and hrefType is "file"
+      href = path.join relativePath, href
 
-    if _.contains parents, link
-      # #{link} is in parents:\n#{JSON.stringify parents}
-      throw new Error("Circular reference detected")
+    href = overridingReference?.href || href
+    hrefType = overridingReference?.hrefType || hrefType
 
-    #log "Transclude: #{link} into #{parents[-1..][0]}"
-    parents.push link
-    dir = path.dirname link
+    if _.contains parents, href
+      logger "#{href} is in parents:\n#{JSON.stringify parents}"
+      throw new Error("Circular reference detected")
 
-    utils.inflate link, linkType, (content) ->
+    parents.push href
+    dir = path.dirname href
+    references = _.merge parentRefs, references
 
-      transclude content, dir, parents, references, (output) ->
+    utils.inflate href, hrefType, (content) ->
+      logger "Transcluding: #{href} (#{hrefType}) into #{parents[-1..][0]}"
+      transclude content, dir, parents, references, logger, (output) ->
         if output?
-          # Preserve indentation if transclude is not preceded by content
-          # Remove new lines at EOF which cause unexpected paragraphs and breaks
+          # Preserve leading whitespace and trim excess new lines at EOF
           output = output
             .replace /\n/g, "\n#{whitespace}"
             .replace /\n$/, ""
 
           input = input.replace "#{placeholder}", output
-          #log "Replaced: \"#{placeholder}\"\n    with: #{JSON.stringify output}"
           return done()
   , ->
     return cb input
 
 
-transcludeString = (input, relativePath = "", parents = [], parentRefs = [], cb) ->
-    transclude input, relativePath, parents, parentRefs, (output) ->
-      return cb output
+validateOptionalArgs = (args) ->
+  OPTION_LOGGER = 0
+  OPTION_OPTIONS = 1
+
+  defaultOptions =
+    relativePath: ""
+    parents: []
+    parentRefs: []
+
+  logger = (message) -> return true
+
+  [input, optionalArgs..., cb] = args
+
+  if not (typeof cb is 'function')
+    throw new Error("Argument error: 'callback' should be a function")
+
+  if not (typeof input is 'string')
+    throw new Error("Argument error: 'input' should be a string")
+
+  if typeof optionalArgs[OPTION_LOGGER] is 'function'
+    logger = optionalArgs[OPTION_LOGGER]
+
+  {relativePath, parents, parentRefs} = _.merge defaultOptions, optionalArgs[OPTION_OPTIONS]
+
+  return {input, relativePath, parents, parentRefs, logger, cb}
+
+
+# transcludeString(input, [logger], [options], callback)
+#
+# Arguments:
+#  1. input (string): The input string which will be processed for transclusion links
+#  2. [log (function)]: Logging function accepting a string as the input
+#  3. [options (Object)]: todo
+#  4. callback (function): Function returns through the callback
+#
+# Returns: (string): Transcluded string
+transcludeString = (args...) ->
+  {input, relativePath, parents, parentRefs, logger, cb} = validateOptionalArgs args
+
+  logger "Transcluding string..."
+  transclude input, relativePath, parents, parentRefs, logger, (output) ->
+    return cb output
+
+
+# transcludeFile(input, [logger], [options], callback)
+#
+# Arguments:
+#  1. filepath (string): The location of the local file which will be processed for transclusion links
+#  2. [log (function)]: Logging function accepting a string as the input
+#  3. [options (Object)]: todo
+#  4. callback (function): Function returns through the callback
+#
+# Returns: (string): Transcluded string
+transcludeFile = (args...) ->
+  {input, relativePath, parents, parentRefs, logger, cb} = validateOptionalArgs args
 
-transcludeFile = (file, relativePath = "", parents = [], parentRefs = [], cb) ->
-    fullFilePath = path.join relativePath, file
-    fullRelativePath = path.dirname fullFilePath
+  logger "Transcluding file... #{input}"
+  fullFilePath = path.join relativePath, input
+  fullRelativePath = path.dirname fullFilePath
 
-    parents.push fullFilePath
-    content = utils.readFile fullFilePath
+  parents.push fullFilePath
+  content = utils.readFile fullFilePath
 
-    transclude content, fullRelativePath, parents, parentRefs, (output) ->
-      return cb output
+  transclude content, fullRelativePath, parents, parentRefs, logger, (output) ->
+    return cb output
 
 
 module.exports = {transcludeString, transcludeFile}
diff --git a/src/main.coffee b/src/main.coffee
index f571d01..9b437ea 100644
--- a/src/main.coffee
+++ b/src/main.coffee
@@ -8,6 +8,9 @@ fs = require 'fs'
 path = require 'path'
 async = require 'async'
 
+_VERBOSE = false
+_DEBUG = false
+
 parser = dashdash.createParser options: [
   names: ['help', 'h']
   type: 'bool'
@@ -35,16 +38,20 @@ if opts.help
   console.log "usage: hercule [OPTIONS]\noptions:\n#{help}"
   process.exit()
 
+logger = (message) ->
+  if _VERBOSE then console.error "#{message}"
 
 main = ->
   transcludedOutput = ""
 
+  if opts.verbose then _VERBOSE = true
+
   async.eachSeries opts._args, (input, done) ->
-    hercule.transcludeFile input, null, null, null, (output) ->
+    hercule.transcludeFile input, logger, (output) ->
       transcludedOutput += output
       return done()
 
-  , ->  
+  , ->
     if opts.output
       fs.writeFile opts.output, transcludedOutput, (err) ->
         throw err if err
diff --git a/src/utils.coffee b/src/utils.coffee
index f45c267..b642e94 100644
--- a/src/utils.coffee
+++ b/src/utils.coffee
@@ -18,28 +18,25 @@ linkParser = peg.buildParser grammar.transcludeGrammar
 
 
 # Scan a document string for links
-scan = (input) ->
+scan = (input, relativePath = "", parents = []) ->
   links = []
-
   while (match = linkRegExp.exec input)
     links.push
       placeholder: match[PLACEHOLDER_GROUP]
-      link: match[LINK_GROUP]
+      href: match[LINK_GROUP]
       whitespace: if match[WHITESPACE_GROUP] then match[WHITESPACE_GROUP] else ""
-
+      relativePath: relativePath
+      parents: parents[..]
   return links
 
 
 # Parse a transclude link
-parse = (rawLink) ->
-  parsedLink = linkParser.parse rawLink.link
-
-  # References are relative to the document where declared
+parse = (link) ->
+  parsedLink = linkParser.parse link.href
   parsedLink.references.forEach (ref) ->
-    if ref.type is "file"
-      ref.value = path.join rawLink.relativePath, ref.value
-
-  return _.merge rawLink, parsedLink
+    if ref.hrefType is "file"
+      ref.href = path.join link.relativePath, ref.href
+  return _.merge link, parsedLink
 
 
 # Read file to string
@@ -47,43 +44,31 @@ readFile = (filename) ->
   try
     content = (fs.readFileSync filename).toString()
     return content
-
   catch err
     if err.code = 'ENOENT'
-      console.error "File (#{filename}) not found."
-
+      console.error "Error: File (#{filename}) not found."
   return null
 
 
 # Read URI contents to string
-readUri = (link, cb) ->
-  request link, (err, res, body) ->
+readUri = (uri, cb) ->
+  request uri, (err, res, body) ->
     if (err) or not (res.statusCode is 200)
-      console.error "Remote file (#{link}) could not be retrieved."
+      console.error "Error: Remote file (#{uri}) could not be retrieved."
       return cb null
-
     return cb body
 
 
-find = (link, references) ->
-  matches = _.filter references, (ref) ->
-    return ref?.placeholder is link
-
-  if matches.length > 1
-    console.error "Multiple matching references found for #{link}."
-    #log.error "Multiple matching references found for #{link}.", {matches}
-
-  return matches[0]
-
-
-inflate = (link, linkType, cb) ->
-  switch linkType
+inflate = (href, hrefType, cb) ->
+  switch hrefType
     when "string"
-      return cb link
+      return cb href
     when "file"
-      return cb (readFile link)
+      content = readFile href
+      return cb content
     when "http"
-      readUri link, (content) -> return cb content
+      readUri href, (content) ->
+        return cb content
     else
       return cb ""
 
@@ -93,6 +78,5 @@ module.exports = {
   parse
   readFile
   readUri
-  find
   inflate
 }


Test patch:
diff --git a/test/fixtures/test-parent-leakage/fox.md b/test/fixtures/test-parent-leakage/fox.md
new file mode 100644
index 0000000..2fe6575
--- /dev/null
+++ b/test/fixtures/test-parent-leakage/fox.md
@@ -0,0 +1,1 @@
+The quick brown fox jumps over the lazy dog.
diff --git a/test/fixtures/test-parent-leakage/index.md b/test/fixtures/test-parent-leakage/index.md
new file mode 100644
index 0000000..f013e93
--- /dev/null
+++ b/test/fixtures/test-parent-leakage/index.md
@@ -0,0 +1,3 @@
+:[fox 1](fox.md)
+
+:[fox 2](fox.md)
diff --git a/test/fixtures/test-reference-collision/activity.md b/test/fixtures/test-reference-collision/activity.md
new file mode 100644
index 0000000..fc90e28
--- /dev/null
+++ b/test/fixtures/test-reference-collision/activity.md
@@ -0,0 +1,1 @@
+:[jumpy thing](activity) over the :[state](state) :[animal](animal)
diff --git a/test/fixtures/test-reference-collision/canine.md b/test/fixtures/test-reference-collision/canine.md
new file mode 100644
index 0000000..18a619c
--- /dev/null
+++ b/test/fixtures/test-reference-collision/canine.md
@@ -0,0 +1,1 @@
+dog
diff --git a/test/fixtures/test-reference-collision/color.md b/test/fixtures/test-reference-collision/color.md
new file mode 100644
index 0000000..58fb04b
--- /dev/null
+++ b/test/fixtures/test-reference-collision/color.md
@@ -0,0 +1,1 @@
+brown
diff --git a/test/fixtures/test-reference-collision/disinterest.md b/test/fixtures/test-reference-collision/disinterest.md
new file mode 100644
index 0000000..36f068a
--- /dev/null
+++ b/test/fixtures/test-reference-collision/disinterest.md
@@ -0,0 +1,1 @@
+lazy
diff --git a/test/fixtures/test-reference-collision/fox.md b/test/fixtures/test-reference-collision/fox.md
new file mode 100644
index 0000000..cb70e15
--- /dev/null
+++ b/test/fixtures/test-reference-collision/fox.md
@@ -0,0 +1,1 @@
+The :[vulpis](fox fox:color.md) :[jumping activity](activity activity:jump.md animal:canine.md state:disinterest.md).
diff --git a/test/fixtures/test-reference-collision/index.md b/test/fixtures/test-reference-collision/index.md
new file mode 100644
index 0000000..5c5d0d6
--- /dev/null
+++ b/test/fixtures/test-reference-collision/index.md
@@ -0,0 +1,1 @@
+:[starts here...](fox.md fox:vulpis.md activity:activity.md)
diff --git a/test/fixtures/test-reference-collision/jump.md b/test/fixtures/test-reference-collision/jump.md
new file mode 100644
index 0000000..13e9cd4
--- /dev/null
+++ b/test/fixtures/test-reference-collision/jump.md
@@ -0,0 +1,1 @@
+jumps
diff --git a/test/fixtures/test-reference-collision/vulpis.md b/test/fixtures/test-reference-collision/vulpis.md
new file mode 100644
index 0000000..33c9ddc
--- /dev/null
+++ b/test/fixtures/test-reference-collision/vulpis.md
@@ -0,0 +1,1 @@
+quick :[colouration](fox) fox
diff --git a/test/hercule.coffee b/test/hercule.coffee
index 87384a9..8226af2 100644
--- a/test/hercule.coffee
+++ b/test/hercule.coffee
@@ -9,12 +9,38 @@ describe 'hercule', ->
 
   describe 'transcludeString', ->
 
+    it 'should require a callback function', (done) ->
+      input = "Jackdaws love my big sphinx of quartz."
+      assert.throws () ->
+        hercule.transcludeString input, input
+      , Error, "Argument error: 'callback' should be a function"
+      done()
+
+    it 'should require a string', (done) ->
+      assert.throws () ->
+        hercule.transcludeString 42, () -> null
+      , Error, "Argument error: 'input' should be a string"
+      done()
+
+    it 'should allow a custom logger to be provided', (done) ->
+      file = __dirname + "/fixtures/test-basic/jackdaw.md"
+      input = (fs.readFileSync file).toString()
+      dir = path.dirname file
+      logOutput = []
+
+      logger = (message) ->
+        logOutput.push message
+
+      hercule.transcludeString input, logger, {relativePath: dir}, (output) ->
+        assert.equal output, 'Jackdaws love my big sphinx of quartz.\n'
+        assert.equal logOutput.length, 4
+        done()
+
     it 'should transclude strings', (done) ->
       input = "Jackdaws love my big sphinx of quartz."
 
-      hercule.transcludeString input, null, null, null, (output) ->
+      hercule.transcludeString input, (output) ->
         assert.equal output, 'Jackdaws love my big sphinx of quartz.'
-
         done()
 
     it 'should transclude strings with valid links', (done) ->
@@ -22,9 +48,8 @@ describe 'hercule', ->
       input = (fs.readFileSync file).toString()
       dir = path.dirname file
 
-      hercule.transcludeString input, dir, null, null, (output) ->
+      hercule.transcludeString input, null, {relativePath: dir}, (output) ->
         assert.equal output, 'Jackdaws love my big sphinx of quartz.\n'
-
         done()
 
     it 'should transclude strings with valid remote http links', (done) ->
@@ -40,65 +65,75 @@ describe 'hercule', ->
       input = (fs.readFileSync file).toString()
       dir = path.dirname file
 
-      hercule.transcludeString input, dir, null, null, (output) ->
+      hercule.transcludeString input, null, {relativePath: dir}, (output) ->
         assert.equal output, 'Jackdaws love my big sphinx of quartz.\n'
         done()
 
   describe 'transcludeFile', ->
 
+    beforeEach ->
+      hercule._VERBOSE = false
+
     it 'should exit if a circular link exists', (done) ->
       inputFile = __dirname + "/fixtures/test-circular/fox.md"
 
       assert.throws () ->
-        hercule.transcludeFile inputFile, null, null, null, (output) -> return null
+        hercule.transcludeFile inputFile, (output) -> return null
       , Error, "Circular reference detected"
-
       done()
 
     it 'should not change a file without links', (done) ->
       inputFile = __dirname + "/fixtures/test-base/fox.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, 'The quick brown fox jumps over the lazy dog.\n'
-
         done()
 
     it 'should not change a file without valid links', (done) ->
       inputFile = __dirname + "/fixtures/test-invalid/fox.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, 'The quick brown fox {{jumps}} over the lazy dog.\n'
-
         done()
 
     it 'should transclude files with valid links', (done) ->
       inputFile = __dirname + "/fixtures/test-basic/jackdaw.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, 'Jackdaws love my big sphinx of quartz.\n'
-
         done()
 
     it 'should transclude files with valid links and respect leading whitespace', (done) ->
       inputFile = __dirname + "/fixtures/test-whitespace/jackdaw.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, 'Jackdaws love my\n  big\n  \n    sphinx of quartz.\n'
-
         done()
 
     it 'should transclude files with valid links and references', (done) ->
       inputFile = __dirname + "/fixtures/test-extend/fox.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, "The quick brown fox jumps over the lazy dog.\n"
+        done()
+
+    it 'should transclude files with reference naming collisions', (done) ->
+      inputFile = __dirname + "/fixtures/test-reference-collision/index.md"
 
+      hercule.transcludeFile inputFile, (output) ->
+        assert.equal output, "The quick brown fox jumps over the lazy dog.\n"
+        done()
+
+    it 'should transclude files with parent leakage', (done) ->
+      inputFile = __dirname + "/fixtures/test-parent-leakage/index.md"
+
+      hercule.transcludeFile inputFile, (output) ->
+        assert.equal output, "The quick brown fox jumps over the lazy dog.\n\nThe quick brown fox jumps over the lazy dog.\n"
         done()
 
     it 'should transclude files with valid links, references and string substitutions', (done) ->
       inputFile = __dirname + "/fixtures/test-string-extend/fox.md"
 
-      hercule.transcludeFile inputFile, null, null, null, (output) ->
+      hercule.transcludeFile inputFile, (output) ->
         assert.equal output, "The quick brown fox jumps over the lazy dog.\n"
-
         done()
diff --git a/test/utils.coffee b/test/utils.coffee
index f29a094..8820495 100644
--- a/test/utils.coffee
+++ b/test/utils.coffee
@@ -53,15 +53,15 @@ describe 'utils', ->
     it 'should parse simple local links', (done) ->
       file = "file.md"
       link =
-        link: file
+        href: file
         placeholder: ":[simple](#{file})"
         relativePath: ""
 
       parsedLink = utils.parse link
 
       assert.deepEqual parsedLink, {
-        link: "file.md"
-        type: "file"
+        href: "file.md"
+        hrefType: "file"
         placeholder: link.placeholder
         references: []
         relativePath: ""
@@ -72,15 +72,15 @@ describe 'utils', ->
     it 'should parse remote http links', (done) ->
       url = "http://github.com/example.md"
       link =
-        link: url
+        href: url
         placeholder: ":[remote http link](#{url})"
         relativePath: ""
 
       parsedLink = utils.parse link
 
       assert.deepEqual parsedLink, {
-        link: "http://github.com/example.md"
-        type: "http"
+        href: "http://github.com/example.md"
+        hrefType: "http"
         placeholder: link.placeholder
         references: []
         relativePath: ""
@@ -91,32 +91,32 @@ describe 'utils', ->
     it 'should parse complex links', (done) ->
       mixedLink = "file.md fruit:apple.md header: footer:../common/footer.md copyright:\"Copyright 2014 (c)\""
       link =
-        link: mixedLink
+        href: mixedLink
         placeholder: ":[](#{mixedLink})"
         relativePath: "customer/farmers-market"
 
       parsedLink = utils.parse link
 
       assert.deepEqual parsedLink, {
-        link: "file.md"
-        type: "file"
+        href: "file.md"
+        hrefType: "file"
         placeholder: link.placeholder
         references: [
           placeholder: "fruit"
-          type: "file"
-          value: "customer/farmers-market/apple.md"
+          hrefType: "file"
+          href: "customer/farmers-market/apple.md"
         ,
           placeholder: "header"
-          type: "string"
-          value: ""
+          hrefType: "string"
+          href: ""
         ,
           placeholder: "footer"
-          type: "file"
-          value: "customer/common/footer.md"
+          hrefType: "file"
+          href: "customer/common/footer.md"
         ,
           placeholder:"copyright"
-          type:"string"
-          value:"Copyright 2014 (c)"
+          hrefType:"string"
+          href:"Copyright 2014 (c)"
         ]
         relativePath: "customer/farmers-market"
       }
@@ -124,48 +124,6 @@ describe 'utils', ->
       done()
 
 
-  describe 'find', ->
-    it 'should not find a match when no references provided', (done) ->
-      link = "file.md"
-      references = []
-
-      match = utils.find link, references
-      assert.deepEqual match, undefined
-
-      done()
-
-    it 'should not find a match when there are no matching references', (done) ->
-      link = "file.md"
-      references = [
-        placeholder: "footer"
-        type: "file"
-        value: "footer.md"
-      ]
-
-      match = utils.find link, references
-      assert.deepEqual match, undefined
-
-      done()
-
-    it 'should find matching references', (done) ->
-      link = "footer"
-      type = "file"
-      references = [
-        placeholder: "footer"
-        type: "file"
-        value: "common/footer.md"
-      ,
-        placeholder: "footer"
-        type: "file"
-        value: "other/footer.md"
-      ]
-
-      match = utils.find link, references
-      assert.deepEqual match, references[0]
-
-      done()
-
-
   describe 'readFile', ->
     it 'should return null for missing files', (done) ->
       inputFile = __dirname + "/fixtures/missing.md"