Recursively finds dependencies of style and template source files

Usage no npm install needed!

<script type="module">
  import progeny from '';



Recursively finds dependencies of style and template source files.

Or configure it to do the same kind of thing with any other type of code file that has an import-type syntax.


progeny ([config]) (path, [sourceContents], callback)

progeny.Sync ([config]) (path, [sourceContents])

Call progeny with an optional configuration object, it returns a reusable function. Call that function with a path to a source file (and its source code if you already have it handy), and it will figure out all of that file's dependencies and sub-dependencies, passing an array of them to your callback. Or use the Sync API to get the results as a return value.

Result array has non-enumerable patterns property with an array of glob patterns found in source files' import statements.

Examples using path assume you already have var path = require('path');. You could just use strings like '/path/to/project', but you may run into cross-compatibility issues.

Quick and Simple

You can skip the config object and the source code, letting Progeny read the source from the file itself and apply a built-in configuration based on the file extension.

var progeny = require('progeny');
var filePath = path.join('path', 'to', 'project', 'style-or-template.pug');

// Async
progeny()(filePath, function (err, dependencies) {
    // use the dependencies array in here

// Sync
var dependencies = progeny()(filePath);

There are built-in configurations already for css, sass/scss, less, stylus, pug/jade, slm, and proto. Configuration must be specified for any other formats. Feel free to submit Pull Requests to add default types, or improve the settings for the existing ones.

var progenyConfig = {
    // The file extension for the source code you want parsed
    // Will be derived from the source file path if not specified
    extension: 'styl',

    // Array of multiple file extensions to try when looking for dependencies
    extensionsList: ['scss', 'sass'],

    // Regexp to run on each line of source code to match dependency references
    // Make sure you wrap the file name part in (parentheses)
    regexp: /^\s*@import\s+['"]?([^'"]+)['"]?/,

    // File prefix to try (in addition to the raw value matched in the regexp)
    prefix: '_',

    // Matched stuff to exclude: string, regex, or array of either/both
    exclusion: /^compass/,

    // In case a match starts with a slash, the absolute path to apply
    rootPath: path.join('path', 'to', 'project'),

    // Other paths to check for possible dependency resolution
    altPaths: [
      path.join('path', 'to', 'shared'),
      path.join('path', 'to', 'common')

    // An array of regexps to run in series for more complex dependency parsing
    // Useful for matching multiple dependencies from one, possibly mult-line,
    // statement. All regexps except the last one must use the global flag.
    multipass: [

    // By default the list of paths progeny provides will be limited to files
    // actually found in the file system. Use this option to get every possible
    // path progeny thinks a depencency could be located at.
    potentialDeps: true,

    // By default progeny will strip all line comments like "// ..." and
    // multiline comments like "/* ... */". You could disable this behavior.
    skipComments: true;

    // Custom resolver allows to preprocess dependency name. For example, webpack
    // has well known way to reference node_modules-related path with ~ in the
    // beginning of import name.
    // Return true, undefined or null to accept dependency without changes.
    // Return false to reject dependency.
    // Return new filename to override dependency.
    resolver: function (depFilename, parentDir, parentFilename) {
      if (depFilename.startsWith('~')) {
        var absPath = path.resolve(path.join('.', 'node_modules', depFilename.substr(1)));
        return path.relative(parentDir, absPath);

    // Print dependency resolution information to console.log
    debug: true
More Examples

Process a list of files:

var progeny = require('progeny');
var getDependencies = progeny(progenyConfig);
myFiles.forEach(function (file) {
    getDependencies(file.path, file.source, function (err, deps) {
        if (err) throw new Error(err);
        file.dependencies = deps;

Multiple configs:

var getDefaultDependencies = progeny();
var getCustomDependencies = progeny({
    extension: 'foo',
    regexp: /([^\s,]+)/

Process source code from a string without its file path:

var mySourceString; // assume this contains valid source code
    // extension and rootPath must be specified for this to work
    // also need regexp if extension not one of the predefined ones
    extension: 'less',
    rootPath: path.join('path', 'to', 'project')
})(null, mySourceString, function (err, deps) {});

Change Log

See release notes page on GitHub