Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
mrjoelkemp committed Aug 2, 2015
0 parents commit eff9c54
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
3 changes: 3 additions & 0 deletions .jscsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"preset": "google"
}
3 changes: 3 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"unused": true
}
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: node_js
node_js:
- "0.10"

notifications:
email: false

sudo: false
28 changes: 28 additions & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env node

'use strict';

var program = require('commander');
var cabinet = require('../');

program
.version(require('../package.json').version)
.usage('[options] <path>')
.option('-d, --directory <path>', 'root of all files')
.option('-c, --config [path]', 'location of a RequireJS config file for AMD')
.option('-f, --filename [path]', 'file containing the dependency')
.parse(process.argv);

var filename = program.filename;
var directory = program.directory;
var config = program.config;
var dep = program.args[0];

var result = cabinet({
partial: dep,
filename: filename,
directory: directory,
config: config
});

console.log(result);
83 changes: 83 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
var path = require('path');
var debug = require('debug')('cabinet');

var getModuleType = require('module-definition');

var amdLookup = require('module-lookup-amd');
var stylusLookup = require('stylus-lookup');
var sassLookup = require('sass-lookup');
var resolveDependencyPath = require('resolve-dependency-path');
var assign = require('lodash.assign');

var defaultLookups = {};

module.exports = function(options) {
// Lazy binding for test stubbing purposes
defaultLookups = assign(defaultLookups, {
'.js': jsLookup,
'.scss': sassLookup,
'.sass': sassLookup,
'.styl': stylusLookup
});

var partial = options.partial;
var filename = options.filename;
var directory = options.directory;
var config = options.config;

var ext = path.extname(filename);

var resolver = defaultLookups[ext];

if (!resolver) {
debug('using generic resolver');
resolver = resolveDependencyPath;
}

debug('found a resolver for ' + ext);
return resolver(partial, filename, directory, config);
};

/**
* Register a custom lookup resolver for a file extension
*
* @param {String} extension - The file extension that should use the resolver
* @param {Function} lookupStrategy - A resolver of partial paths
*/
module.exports.register = function(extension, lookupStrategy) {
defaultLookups[extension] = lookupStrategy;
};

/**
* @private
* @param {String} partial
* @param {String} filename
* @param {String} directory
* @param {String} config
* @return {String}
*/
function jsLookup(partial, filename, directory, config) {
var type = getModuleType.sync(filename);

switch (type) {
case 'amd':
debug('using amd resolver');
return amdLookup(config, partial, filename, directory)
case 'commonjs':
debug('using commonjs resolver');
return commonJSLookup(partial);
case 'es6':
default:
debug('using generic resolver for es6');
return resolveDependencyPath(partial, filename, directory);
}
}

/**
* @private
* @param {String} partial
* @return {String}
*/
function commonJSLookup(partial) {
return require.resolve(partial);
}
53 changes: 53 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "filing-cabinet",
"version": "1.0.0",
"description": "Find files based on partial paths",
"main": "index.js",
"bin": {
"filing-cabinet": "cli.js"
},
"directories": {
"test": "test"
},
"scripts": {
"test": "jscs index.js test/test.js && mocha"
},
"repository": {
"type": "git",
"url": "https://github.com/mrjoelkemp/node-filing-cabinet.git"
},
"keywords": [
"lookup",
"es6",
"amd",
"commonjs",
"sass",
"stylus",
"partial",
"resolution",
"paths"
],
"author": "Joel Kemp <[email protected]> (http://www.mrjoelkemp.com/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/mrjoelkemp/node-filing-cabinet/issues"
},
"homepage": "https://github.com/mrjoelkemp/node-filing-cabinet",
"devDependencies": {
"jscs": "~1.13.1",
"mocha": "~2.2.5",
"mock-fs": "~3.0.0",
"rewire": "~2.3.4",
"sinon": "~1.15.4"
},
"dependencies": {
"commander": "~2.8.1",
"debug": "~2.2.0",
"lodash.assign": "~3.2.0",
"module-definition": "~2.2.2",
"module-lookup-amd": "~2.0.4",
"resolve-dependency-path": "~1.0.2",
"sass-lookup": "~1.0.2",
"stylus-lookup": "~1.0.0"
}
}
59 changes: 59 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
### filing-cabinet [![npm](http://img.shields.io/npm/v/filing-cabinet.svg)](https://npmjs.org/package/filing-cabinet) [![npm](http://img.shields.io/npm/dm/filing-cabinet.svg)](https://npmjs.org/package/filing-cabinet)

> Look up a filename based on a partial path
`npm install filing-cabinet`

### Usage

```js

var cabinet = require('filing-cabinet');

var result = cabinet({
partial: 'somePartialPath',
directory: 'path/to/all/files',
filename: 'path/to/parent/file',
config: 'path/to/requirejs/config'
});

console.log(result);
```

* `partial`: the dependency path
* This could be in any of the registered languages


### Registered languages

By default, filing-cabinet provides support for the following languages:

* JavaScript (all files with the `.js` extension)
* Sass (`.scss` and `.sass`)
* Stylus (`.styl`)

You can register resolvers for new languages via `cabinet.register(extension, resolver)`.

* `extension`: the extension of the file that should use the custom resolver (ex: '.py', '.php')
* `resolver`: a function that accepts the following (ordered) arguments that were given to cabinet:
* `partial`
* `filename`
* `directory`
* `config`

For examples of resolver implementations, take a look at the default language resolvers:

* [sass-lookup](https://github.com/mrjoelkemp/node-sass-lookup)
* [stylus-lookup](https://github.com/mrjoelkemp/node-stylus-lookup)
* [amdLookup](https://github.com/mrjoelkemp/node-module-lookup-amd)

If a given extension does not have a registered resolver, cabinet will use
a generic file resolver which is basically `require('path').join` with a bit of extension defaulting logic.

### Shell script

* Requires a global install `npm install -g filing-cabinet`

`filing-cabinet [options] <dependencyPath>`

* See `filing-cabinet --help` for details on the options
147 changes: 147 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
var assert = require('assert');
var sinon = require('sinon');
var rewire = require('rewire');
var mock = require('mock-fs');

var cabinet = rewire('../');

describe('filing-cabinet', function() {
describe('JavaScript', function() {
beforeEach(function() {
mock({
'js': {
'es6': {
'foo.js': 'import bar from "./bar";',
'bar.js': 'export default function() {};'
},
'amd': {
'foo.js': 'define(["./bar"], function(bar){ return bar; });',
'bar.js': 'define({});'
},
'commonjs': {
'foo.js': 'var bar = require("./bar");',
'bar.js': 'module.exports = function() {};'
}
}
});
});

describe('es6', function() {
it('uses a generic resolver', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('resolveDependencyPath', stub);

var path = cabinet({
partial: './bar',
filename: 'js/es6/foo.js',
directory: 'js/es6/'
});

assert.ok(stub.called);

revert();
});
});

describe('amd', function() {
it('uses the amd resolver', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('amdLookup', stub);

var path = cabinet({
partial: './bar',
filename: 'js/amd/foo.js',
directory: 'js/amd/'
});

assert.ok(stub.called);

revert();
});
});

describe('commonjs', function() {
it('uses require\'s resolver', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('commonJSLookup', stub);

var path = cabinet({
partial: './bar',
filename: 'js/commonjs/foo.js',
directory: 'js/commonjs/'
});

assert.ok(stub.called);

revert();
});
});
});

describe('CSS', function() {
describe('Sass', function() {
it('uses the sass resolver for .scss files', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('sassLookup', stub);

var path = cabinet({
partial: './bar',
filename: 'js/sass/foo.scss',
directory: 'js/sass/'
});

assert.ok(stub.called);

revert();
});

it('uses the sass resolver for .sass files', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('sassLookup', stub);

var path = cabinet({
partial: './bar',
filename: 'sass/foo.sass',
directory: 'sass/'
});

assert.ok(stub.called);

revert();
});
});

describe('stylus', function() {
it('uses the stylus resolver', function() {
var stub = sinon.stub();
var revert = cabinet.__set__('stylusLookup', stub);

var path = cabinet({
partial: './bar',
filename: 'stylus/foo.styl',
directory: 'stylus/'
});

assert.ok(stub.called);

revert();
});
});
});

describe('.register', function() {
it('registers a custom resolver for a given extension', function() {
var stub = sinon.stub().returns('foo');
cabinet.register('.foobar', stub);

var path = cabinet({
partial: './bar',
filename: 'js/amd/foo.foobar',
directory: 'js/amd/'
});

assert.ok(stub.called);
assert.equal(path, 'foo');
});
});
});

0 comments on commit eff9c54

Please sign in to comment.