code: function depFinder() {
    if (arguments.length === 0) {
      throw new Error('No patterns provided.');
    }
  
    let seed = 0;
  
    let patterns = Array.prototype.map.call(arguments, function (p) {
      // replace __dep and __deps into
      // __str_1, __str_2, __arr_3
  
      // wantArr is the result of (s?)
      return compilePattern(p.replace(/__dep(s?)/g, function (m, wantArr) {
        return (wantArr ? '__arr_' : '__str_') + (++seed);
      }))
    });
  
    let len = patterns.length;
  
    return function(jsStr) {
      let node = ensureParsed(jsStr);
  
      let deps = [];
  
      // directly use extract() instead of astMatcher()
      // for efficiency
      traverse(node, function (n) {
        for (let i = 0; i < len; i += 1) {
          let result = extract(patterns[i], n);
          if (result) {
            // result is like {"1": "dep1", "2": ["dep2", "dep3"]}
            // we only want values
            Object.keys(result).forEach(function (k) {
              let d = result[k];
              if (typeof d === 'string') deps.push(d);
              else deps.push.apply(deps, d);
            });
  
            // found a match, don't try other pattern
            break;
          }
        }
      });
  
      return deps;
    };
  }
docs: Dependency analysis for dummies, this is a high level api to simplify the usage of astMatcher
  @param arguments Multiple patterns to match, instead of using __str_/__arr_,
  use __dep and __deps to match string and partial string array.
  @return Returns a function that takes source code string (or estree syntax tree) as input, produces an array of string matched, or empty array.
  
  Usage:
  let f = depFinder('a(__dep)', '__any.globalResources([__deps])');
  f('a("a"); a("b"); config.globalResources(["./c", "./d"])');
  
  => ['a', 'b', './c', './d']