├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── bin └── bower-requirejs.js ├── bower.json ├── contributing.md ├── lib ├── build-config.js ├── index.js ├── parse.js └── primary.js ├── package.json ├── readme.md ├── templates └── config.js └── test ├── acceptance ├── fixtures │ ├── baseurl-expected.js │ ├── baseurl.js │ ├── config-expected.js │ ├── config.js │ ├── generated-config-expected.js │ ├── global-config-expected.js │ ├── global-config.js │ ├── no-devdependencies-config-expected.js │ ├── pathless-config-expected.js │ ├── pathless-config.js │ ├── shim-config-expected.js │ ├── shim-config.js │ ├── transitive-config-expected.js │ └── transitive-shim-config-expected.js └── index.js ├── binary └── bower-requirejs.js ├── mocha.opts └── unit ├── build-config.js ├── fixtures ├── bower_components │ ├── backbone-amd │ │ ├── backbone.js │ │ ├── backbone.min.js │ │ ├── bogus.js │ │ └── package.json │ ├── backbone │ │ ├── backbone-min.js │ │ └── backbone.js │ ├── jquery-ui-touch-punch-amd │ │ ├── grunt.js │ │ ├── jquery.ui.touch-punch.js │ │ └── jquery.ui.touch-punch.min.js │ ├── mout │ │ └── src │ │ │ ├── bogus.js │ │ │ └── index.js │ ├── no-primary │ │ ├── bar.js │ │ └── foo.js │ ├── non-js │ │ └── non-js.js │ ├── non-jss │ │ └── non-jss.js │ ├── requirejs │ │ ├── bogus.js │ │ └── require.js │ ├── some-js │ │ └── some-js.js │ ├── uses-custom-dir │ │ └── custom │ │ │ └── uses-custom-dir.js │ └── uses-dist │ │ └── dist │ │ └── uses-dist.js └── deps.js ├── index.js ├── parse.js └── primary.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | components 3 | bower_components 4 | tmp 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 'iojs' 5 | - '0.12' 6 | - '0.10' 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function (grunt) { 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | jshint: { 7 | options: { 8 | jshintrc: '.jshintrc' 9 | }, 10 | all: [ 11 | 'Gruntfile.js', 12 | 'lib/*.js', 13 | 'bin/*.js', 14 | 'test/**/*.js' 15 | ] 16 | }, 17 | clean: { 18 | bower: 'bower_components', 19 | tmp: 'tmp' 20 | }, 21 | copy: { 22 | unit: { 23 | expand: true, 24 | cwd: 'test/unit/fixtures/bower_components', 25 | src: ['**/*'], 26 | dest: 'tmp/bower_components' 27 | }, 28 | acceptance: { 29 | expand: true, 30 | cwd: 'test/acceptance/fixtures', 31 | src: ['*.js', '!*-expected.js'], 32 | dest: 'tmp/' 33 | } 34 | }, 35 | simplemocha: { 36 | options: { 37 | reporter: 'dot', 38 | timeout: '5000' 39 | }, 40 | bin: { 41 | src: ['test/binary/*.js'] 42 | }, 43 | unit: { 44 | src: ['test/unit/*.js'] 45 | }, 46 | acceptance: { 47 | src: ['test/acceptance/*.js'] 48 | } 49 | }, 50 | bower: { 51 | options: { 52 | exclude: ['underscore'] 53 | }, 54 | standard: { 55 | rjsConfig: 'tmp/config.js' 56 | }, 57 | pathless: { 58 | rjsConfig: 'tmp/pathless-config.js' 59 | }, 60 | global: { 61 | rjsConfig: 'tmp/global-config.js' 62 | }, 63 | baseurl: { 64 | options: { 65 | baseUrl: './' 66 | }, 67 | rjsConfig: 'tmp/baseurl.js' 68 | } 69 | } 70 | }); 71 | 72 | grunt.registerTask('mkdir', function (dir) { 73 | require('fs').mkdirSync(dir); 74 | }); 75 | 76 | grunt.registerTask('bower-install', function () { 77 | var done = this.async(); 78 | grunt.util.spawn({ 79 | cmd: 'bower', 80 | args: ['install'], 81 | opts: { 82 | stdio: 'inherit' 83 | } 84 | }, function (error, result) { 85 | if (error) { 86 | grunt.fail.fatal(result.stdout); 87 | } 88 | grunt.log.writeln(result.stdout); 89 | done(); 90 | }); 91 | }); 92 | 93 | grunt.registerTask('reset-tmp', ['clean:tmp', 'mkdir:tmp']); 94 | 95 | grunt.registerTask('test', [ 96 | 'clean', 97 | 'mkdir:tmp', 98 | 'bower-install', 99 | 'simplemocha:bin', 100 | 'reset-tmp', 101 | 'copy:unit', 102 | 'simplemocha:unit', 103 | 'reset-tmp', 104 | 'copy:acceptance', 105 | 'simplemocha:acceptance', 106 | 'clean' 107 | ]); 108 | 109 | grunt.registerTask('default', ['test']); 110 | }; 111 | -------------------------------------------------------------------------------- /bin/bower-requirejs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | var nopt = require('nopt'); 4 | var path = require('path'); 5 | var sudoBlock = require('sudo-block'); 6 | var updateNotifier = require('update-notifier'); 7 | var pkg = require('../package.json'); 8 | var project = require('../lib'); 9 | 10 | var opts = nopt({ 11 | help: Boolean, 12 | version: Boolean, 13 | config: path, 14 | exclude: Array, 15 | 'base-url': path, 16 | baseUrl: path, // alias for --base-url 17 | transitive: Boolean, 18 | shim: Boolean, 19 | 'exclude-dev': Boolean 20 | }, { 21 | h: '--help', 22 | v: '--version', 23 | c: '--config', 24 | e: '--exclude', 25 | b: '--base-url', 26 | t: '--transitive', 27 | s: '--shim', 28 | d: '--exclude-dev' 29 | }); 30 | 31 | if (opts['base-url']) { 32 | opts.baseUrl = opts['base-url']; 33 | } 34 | 35 | function init() { 36 | project(opts); 37 | } 38 | 39 | function help() { 40 | var out = [ 41 | 'Usage: bower-requirejs [options]', 42 | '', 43 | 'General options:', 44 | ' -h, --help # Print options and usage', 45 | ' -v, --version # Print the version number', 46 | ' -c, --config # Path to your RequireJS config file', 47 | ' -e, --exclude # Name of a dependency to be excluded from the process', 48 | ' -b, --base-url # Path which all dependencies will be relative to', 49 | ' -t, --transitive # Process transitive dependencies', 50 | ' -s, --shim # Shim dependencies', 51 | ' -d, --exclude-dev # Exclude devDependencies', 52 | '' 53 | ]; 54 | 55 | return out.join('\n'); 56 | } 57 | 58 | function pre() { 59 | if (opts.version) { 60 | return console.log(pkg.version); 61 | } 62 | 63 | if (opts.help) { 64 | return console.log(help()); 65 | } 66 | 67 | init(); 68 | } 69 | 70 | if (opts['update-notifier'] !== false) { 71 | updateNotifier({pkg: pkg}).notify(); 72 | } 73 | 74 | sudoBlock(); 75 | pre(); 76 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bower-requirejs", 3 | "private": true, 4 | "dependencies": { 5 | "jquery": "~1.10.0", 6 | "underscore": "~1.5.1", 7 | "requirejs": "~2.1.8", 8 | "respond": "~1.2.0", 9 | "anima": "~0.3.2", 10 | "typeahead.js": "~0.9.3", 11 | "jquery-ui-touch-punch-amd": "0.1.0", 12 | "handlebars": "~1.0.0", 13 | "backbone": "~1.0.0", 14 | "backbone-amd": "~1.0.0", 15 | "konamicode.js": "*", 16 | "mout": "~0.7.1", 17 | "backbone.marionette": "~1.6.2", 18 | "node-module-type-stub": "*" 19 | }, 20 | "resolutions": { 21 | "underscore": "~1.5.1", 22 | "jquery": "~1.10.0" 23 | }, 24 | "overrides": { 25 | "jquery": { 26 | "main": "jquery.min.js" 27 | }, 28 | "anima": { 29 | "main": "anima.min.js" 30 | }, 31 | "backbone": { 32 | "main": " " 33 | } 34 | }, 35 | "devDependencies": { 36 | "json2": "*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 2 | -------------------------------------------------------------------------------- /lib/build-config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var _ = require('lodash'); 3 | var assign = require('object-assign'); 4 | var parse = require('./parse'); 5 | 6 | 7 | /** 8 | * Build requirejs config object from bower dependencies object. 9 | */ 10 | module.exports = function (dependencyGraph, opts) { 11 | opts = opts || {}; 12 | var exclude = opts.exclude || []; 13 | var baseUrl = opts.baseUrl || ''; 14 | var overrides = dependencyGraph.pkgMeta.overrides; 15 | 16 | // Override the main property of each direct dependency. 17 | if (overrides) { 18 | _.forOwn(overrides, function (dep, name) { 19 | if (dep.main) { 20 | var main = (typeof dep.main === 'string') ? dep.main.trim() : dep.main; 21 | var dependency = dependencyGraph.dependencies[name]; 22 | if (dependency && main) { 23 | dependency.pkgMeta.main = main; 24 | } 25 | } 26 | }); 27 | } 28 | 29 | // #84 exclude devDependencies 30 | if (opts['exclude-dev']) { 31 | exclude = _.chain(dependencyGraph.pkgMeta.devDependencies || {}) 32 | .reduce(function(exclude,val,key){ 33 | exclude.push(key); 34 | return exclude; 35 | },exclude).uniq().value(); 36 | } 37 | 38 | var dependencies = {}; 39 | // Recursively register dependencies if transitive option is specified. 40 | if (opts.transitive) { 41 | var registerTransitiveDependencies = function (node) { 42 | if (node.dependencies) { 43 | _.forOwn(node.dependencies, function (dep, name) { 44 | if (!_.has(dependencies, name)) { 45 | dependencies[name] = dep; 46 | registerTransitiveDependencies(dep); 47 | } 48 | }); 49 | } 50 | }; 51 | registerTransitiveDependencies(dependencyGraph); 52 | } else { 53 | // Otherwise just use top-level dependencies. 54 | dependencies = dependencyGraph.dependencies; 55 | } 56 | 57 | var config = { 58 | shim: {}, 59 | paths: {}, 60 | packages: [] 61 | }; 62 | 63 | _.forOwn(dependencies, function (dep, name) { 64 | if (exclude.indexOf(name) !== -1) { 65 | return; 66 | } 67 | 68 | var configElement = parse(dep, name, baseUrl); 69 | if (configElement) { 70 | if (configElement.paths) { 71 | assign(config.paths, configElement.paths); 72 | if (opts.shim) { 73 | var deps = _.difference(Object.keys(dep.dependencies), exclude); 74 | if (!opts.transitive) { 75 | deps = _.intersection(Object.keys(dependencies), deps); 76 | } 77 | if (deps.length) { 78 | config.shim[name] = { deps: deps }; 79 | } 80 | } 81 | } 82 | if (configElement.package) { 83 | config.packages.push(configElement.package); 84 | } 85 | } 86 | }); 87 | 88 | return config; 89 | }; 90 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var bower = require('bower'); 5 | var file = require('file-utils'); 6 | var requirejs = require('requirejs/bin/r.js'); 7 | var _ = require('lodash'); 8 | var assign = require('object-assign'); 9 | var chalk = require('chalk'); 10 | var success = chalk.green; 11 | var danger = chalk.black.bgRed; 12 | var buildConfig = require('./build-config'); 13 | 14 | /** 15 | * Convert bower dependencies into paths for 16 | * RequireJS config file 17 | */ 18 | module.exports = function (opts, done) { 19 | opts = opts || {}; 20 | 21 | var bowerOpts = _.extend({offline: true}, opts.bowerOpts); 22 | 23 | var configDir; 24 | var config; 25 | var baseUrl = opts.baseUrl; 26 | var configPath = opts.config; 27 | 28 | if (configPath) { 29 | configDir = path.dirname(configPath); 30 | baseUrl = baseUrl || configDir; 31 | 32 | // Grab the config file, or create one if it doesn't exist 33 | if (file.exists(configPath)) { 34 | config = fs.readFileSync(String(configPath), 'utf8'); 35 | } else { 36 | config = fs.readFileSync(path.join(__dirname, '../templates/config.js'), 'utf8'); 37 | } 38 | } else { 39 | baseUrl = baseUrl || './'; 40 | } 41 | 42 | if (!done) { 43 | done = function () {}; 44 | } 45 | 46 | function run() { 47 | bower.commands.list({}, bowerOpts) 48 | .on('end', function (dependencyGraph) { 49 | if (dependencyGraph) { 50 | var generatedConfig; 51 | 52 | try { 53 | generatedConfig = buildConfig(dependencyGraph, _.extend(opts, { 54 | baseUrl: baseUrl 55 | })); 56 | } catch (err) { 57 | return done(false); 58 | } 59 | 60 | if (configPath) { 61 | writeConfig(generatedConfig); 62 | } else { 63 | done(generatedConfig); 64 | } 65 | } 66 | }) 67 | .on('error', function (err) { 68 | console.error(danger('ERR'), process.argv.slice(2).join(' '), '\n'); 69 | console.error(opts.debug ? err.stack : err.message); 70 | process.exit(err.code || 1); 71 | }); 72 | } 73 | 74 | /** 75 | * Write all dependencies to rjs config file 76 | */ 77 | // @TODO: should maybe make this 'mergeConfig'? 78 | function writeConfig(generatedConfig) { 79 | var rjsConfig; 80 | requirejs.tools.useLib(function (require) { 81 | rjsConfig = require('transform').modifyConfig(config, function (config) { 82 | 83 | // If the original config defines paths, add the 84 | // bower component paths to it; otherwise, add a 85 | // paths map with the bower components. 86 | // @TODO: CHECK FOR CONFLICTS WITH EXISTING PATHS 87 | if (generatedConfig.paths) { 88 | if (config.paths) { 89 | assign(config.paths, generatedConfig.paths); 90 | } else { 91 | config.paths = generatedConfig.paths; 92 | } 93 | } 94 | 95 | // Add packages to merged config. 96 | if (generatedConfig.packages) { 97 | if (!config.packages) { 98 | config.packages = []; 99 | } 100 | 101 | // strip packages that are already added 102 | var generatedPackages = _.filter(generatedConfig.packages, function(pkg) { 103 | return typeof _.find(config.packages, function(installedPkg) { 104 | return installedPkg.name === pkg.name; 105 | }) === 'undefined'; 106 | }); 107 | 108 | config.packages = config.packages.concat(generatedPackages); 109 | } 110 | 111 | if (generatedConfig.shim) { 112 | if (config.shim) { 113 | _.forOwn(generatedConfig.shim, function (value, key) { 114 | if (config.shim[key]) { 115 | config.shim[key].deps = _.union(value.deps, config.shim[key].deps); 116 | } else { 117 | config.shim[key] = value; 118 | } 119 | }); 120 | } else { 121 | config.shim = generatedConfig.shim; 122 | } 123 | } 124 | 125 | return config; 126 | }); 127 | 128 | fs.writeFileSync(configPath, rjsConfig, 'utf-8'); 129 | console.log(success('Updated RequireJS config with installed Bower components')); 130 | 131 | done(generatedConfig); 132 | }); 133 | } 134 | 135 | run(); 136 | }; 137 | -------------------------------------------------------------------------------- /lib/parse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var _ = require('lodash'); 4 | var slash = require('slash'); 5 | var assign = require('object-assign'); 6 | var slice = Array.prototype.slice; 7 | var chalk = require('chalk'); 8 | var warn = chalk.black.bgYellow; 9 | var danger = chalk.black.bgRed; 10 | var primary = require('./primary'); 11 | 12 | /** 13 | * Parse bower dependency down to one or more primary 14 | * js files. 15 | */ 16 | module.exports = function (dep, name, baseUrl) { 17 | 18 | /** 19 | * Fixup slashes in file paths for windows 20 | */ 21 | function normalizePath(str) { 22 | return process.platform === 'win32' ? slash(str) : str; 23 | } 24 | 25 | function parsePackage(dep, name) { 26 | var main = dep.pkgMeta.main || 'main.js'; 27 | 28 | if (dep.missing) { 29 | console.error(danger('ERR'), dep.endpoint.name, 'is not installed in your bower components directory'); 30 | throw new Error('Missing dependency'); 31 | } 32 | 33 | var configElement = { 34 | type: 'package', 35 | package: { 36 | name: name, 37 | main: main 38 | } 39 | }; 40 | return configElement; 41 | } 42 | 43 | function parsePaths(dep, name, baseUrl) { 44 | var canonicalDir = dep.canonicalDir; 45 | var main; 46 | 47 | if (dep.pkgMeta.main) { 48 | var pkgMain = dep.pkgMeta.main; 49 | if (!Array.isArray(pkgMain)) { 50 | pkgMain = [pkgMain]; 51 | } 52 | main = _.filter(pkgMain, function (dep) { 53 | var extname = path.extname(dep); 54 | return !extname || extname === '.js'; 55 | }); 56 | } 57 | 58 | /** 59 | * Get resolved paths for dependency. 60 | */ 61 | function getResolvedPaths() { 62 | // If no `main` is listed in the bower.json 63 | if (!main) { 64 | // Look for top level js, otherwise 65 | // bail out. 66 | main = primary(name, dep); 67 | if (!main) { 68 | return false; 69 | } 70 | } 71 | 72 | // If main should be turned into an Array 73 | if (Array.isArray(main)) { 74 | dep = main; 75 | } else { 76 | dep = [main]; 77 | } 78 | 79 | // If there are multiple files filter to 80 | // only the js ones 81 | if (dep.length > 1) { 82 | dep = filter(dep); 83 | } 84 | 85 | var resolvedPaths = {}; 86 | var resolve = resolver(resolvedPaths); 87 | _.each(dep, resolve); 88 | return resolvedPaths; 89 | } 90 | 91 | /** 92 | * Filter an Array down to only js files 93 | */ 94 | function filter(arr) { 95 | var jsfiles = _.filter(arr, function (val) { 96 | return path.extname(val) === '.js'; 97 | }); 98 | 99 | return jsfiles; 100 | } 101 | 102 | /** 103 | * Disambiguate a dependency path if a dependency was 104 | * not explicitly listed in bower.json's main array 105 | * Some dependencies have multiple paths because there is more 106 | * than one .js file in bower.json's main attribute. 107 | */ 108 | function resolver(dependencies) { 109 | return function (val, index, arr) { 110 | if (arr.length > 1) { 111 | assign(dependencies, dependencyByFilename(val)); 112 | } else { 113 | assign(dependencies, dependencyByComponentName(name, val)); 114 | } 115 | }; 116 | } 117 | 118 | /** 119 | * Create dependency based off of filename 120 | */ 121 | function dependencyByFilename(val) { 122 | var dep = {}; 123 | var name = getName(path.basename(val)); 124 | var filepath = getPath(val); 125 | dep[name] = filepath; 126 | return dep; 127 | } 128 | 129 | /** 130 | * Create dependency based off of component name 131 | */ 132 | function dependencyByComponentName(componentName, val) { 133 | var dep = {}; 134 | var name = getName(componentName); 135 | var filepath = getPath(val); 136 | dep[name] = filepath; 137 | return dep; 138 | } 139 | 140 | /** 141 | * Return a dependency name that strips out extensions 142 | * like .js or .min 143 | */ 144 | function getName(name) { 145 | return filterName(name, 'js', 'min'); 146 | } 147 | 148 | /** 149 | * Return a dependency path that is relative to the baseUrl 150 | * and has normalized slashes for Windows users 151 | */ 152 | function getPath(val) { 153 | var filepath = relative(canonical(removeExtension(val, 'js'))); 154 | filepath = normalizePath(filepath); 155 | return filepath; 156 | } 157 | 158 | /** 159 | * Remove extensions from file paths but ignore folders 160 | */ 161 | function removeExtension(filepath, extension) { 162 | var newPath; 163 | if (extension[0] !== '.') { 164 | extension = '.'.concat(extension); 165 | } 166 | newPath = path.join(path.dirname(filepath), path.basename(filepath, extension)); 167 | return newPath; 168 | } 169 | 170 | /** 171 | * Remove '.' separated extensions from library/file names 172 | * ex: filterName('typeahead.js', 'js') returns 'typeahead' 173 | * ex: filterName('foo.min.js', 'js, 'min') returns 'foo' 174 | */ 175 | function filterName() { 176 | var oldName = arguments[0]; 177 | var newName = _.difference(oldName.split('.'), slice.call(arguments, 1)); 178 | 179 | // Re-attach any leftover pieces 180 | // ex: handlebars.runtime.js becomes handlebars.runtime 181 | if (newName.length > 1) { 182 | newName = newName.join('.'); 183 | } else { 184 | newName = newName[0]; 185 | } 186 | 187 | if (newName !== oldName) { 188 | console.log(warn('WARN'), 'Renaming ' + oldName + ' to ' + newName + '\n'); 189 | } 190 | 191 | return newName; 192 | } 193 | 194 | /** 195 | * Combine the main.js file with its canonicalDir to 196 | * produce a full file path 197 | */ 198 | function canonical(filepath) { 199 | return path.join(canonicalDir, filepath); 200 | } 201 | 202 | /** 203 | * Generate a relative path name using the baseUrl. If 204 | * baseUrl was not defined then it will just use the dir 205 | * that contains the rjs config file. 206 | */ 207 | function relative(filepath) { 208 | return path.relative(baseUrl, filepath); 209 | } 210 | 211 | var resolvedPaths = getResolvedPaths(); 212 | var configElement = { 213 | type: 'paths', 214 | paths: resolvedPaths 215 | }; 216 | 217 | return configElement; 218 | } 219 | 220 | // Check for module type. 221 | var moduleTypes = dep.pkgMeta.moduleType || []; 222 | var canSupportNode = moduleTypes.indexOf('node') !== -1; 223 | var canSupportAmd = moduleTypes.indexOf('amd') !== -1; 224 | if (canSupportNode && !canSupportAmd) { 225 | return parsePackage(dep, name); 226 | } 227 | 228 | // Parse as paths if not package. 229 | return parsePaths(dep, name, baseUrl); 230 | 231 | }; 232 | -------------------------------------------------------------------------------- /lib/primary.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var slash = require('slash'); 4 | var _ = require('lodash'); 5 | var chalk = require('chalk'); 6 | var warn = chalk.black.bgYellow; 7 | var file = require('file-utils'); 8 | var path = require('path'); 9 | 10 | /** 11 | * Find primary js file in directory if no bower.json 12 | * exists. 13 | */ 14 | module.exports = function (name, dep, opts) { 15 | 16 | opts = opts || {}; 17 | 18 | // Define extra search dirs, relatie to canonicalDir. 19 | // Default is to add 'dist' folder (e.g. for jquery). 20 | // canonialDir is included as first searchDir. 21 | var extraSearchDirs = opts.extraSearchDirs || ['dist']; 22 | var searchDirs = [''].concat(extraSearchDirs); 23 | 24 | /** 25 | * Fixup slashes in file paths for windows 26 | */ 27 | function normalizePath(str) { 28 | return process.platform === 'win32' ? slash(str) : str; 29 | } 30 | 31 | /** 32 | * If we find any Gruntfiles, remove them and log a warning. 33 | */ 34 | function excludeGrunt() { 35 | if (_.contains(main, 'grunt.js') || _.contains(main, 'Gruntfile.js')) { 36 | console.log(warn('WARN'), 'Ignoring Gruntfile in ' + name); 37 | console.log('You should inform the author to ignore this file in their bower.json\n'); 38 | main = _.without(main, 'grunt.js', 'Gruntfile.js'); 39 | } 40 | return main; 41 | } 42 | 43 | /** 44 | * Test for candidate files in search dirs. 45 | */ 46 | function findCandidateFile(candidateFile) { 47 | var searches = _.map(searchDirs, function (searchDir) { 48 | return function () { 49 | var candidatePath = path.join(searchDir, candidateFile); 50 | if (_.contains(main, candidatePath)) { 51 | main = [candidatePath]; 52 | } 53 | }; 54 | }); 55 | until(primaryFound, searches, function () {}); 56 | } 57 | 58 | /** 59 | * Look for a primary .js file based on the project name 60 | * ex: backbone.js inside backbone dir 61 | */ 62 | function findByDirname() { 63 | var candidateFile = path.basename(dep.canonicalDir) + '.js'; 64 | findCandidateFile(candidateFile); 65 | } 66 | 67 | /** 68 | * Look for a primary .js file based on the project name minus 'js' 69 | * ex: require.js inside requirejs dir 70 | */ 71 | function findByDirnameSuffix() { 72 | var candidateFile = path.basename(dep.canonicalDir).replace(/js$/, '') + '.js'; 73 | findCandidateFile(candidateFile); 74 | } 75 | 76 | /** 77 | * Look for primary .js file in package.json 78 | */ 79 | function findByPackage() { 80 | var pkgPath = path.join(dep.canonicalDir, 'package.json'); 81 | if (file.exists(pkgPath)) { 82 | var pkg = file.readJSON(pkgPath); 83 | 84 | if (pkg.main) { 85 | main = [pkg.main]; 86 | } 87 | } 88 | } 89 | 90 | /** 91 | * Execute callbacks in order until test passes or 92 | * we run out of callbacks 93 | */ 94 | function until(test, callbacks, done) { 95 | for (var i = 0; i < callbacks.length; i++) { 96 | if (test()) { 97 | break; 98 | } else { 99 | callbacks[i].call(); 100 | } 101 | } 102 | 103 | done(); 104 | } 105 | 106 | /** 107 | * Test if only one js file remains 108 | */ 109 | function primaryFound() { 110 | return main.length === 1; 111 | } 112 | 113 | /** 114 | * If a top level js file is found set that to the return 115 | * value. Otherwise return false to indicate a failure 116 | */ 117 | function end() { 118 | if (primaryFound()) { 119 | dep = main[0]; 120 | } else { 121 | dep = false; 122 | } 123 | } 124 | 125 | // Put all js files in search dirs into an array 126 | var main = []; 127 | _.each(searchDirs, function (searchDir) { 128 | var searchPath = path.join(dep.canonicalDir, searchDir); 129 | var candidateFiles = file.expand({ cwd: normalizePath(searchPath)}, '*.js', '!*.min.js'); 130 | _.each(candidateFiles, function (candidateFile) { 131 | main.push(normalizePath(path.join(searchDir, candidateFile))); 132 | }); 133 | }); 134 | 135 | // Remove any Gruntfiles 136 | excludeGrunt(); 137 | 138 | // Call find functions until test passes or 139 | // we run out of functions 140 | until(primaryFound, [ 141 | findByDirname, 142 | findByDirnameSuffix, 143 | findByPackage 144 | ], end); 145 | 146 | return dep; 147 | }; 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bower-requirejs", 3 | "version": "1.2.0", 4 | "description": "Automagically wire-up installed Bower components into your RequireJS config", 5 | "keywords": [ 6 | "bower", 7 | "requirejs", 8 | "rjs", 9 | "config", 10 | "wire", 11 | "inject", 12 | "install", 13 | "component", 14 | "package", 15 | "module" 16 | ], 17 | "license": "BSD-2-Clause", 18 | "author": { 19 | "name": "Sindre Sorhus", 20 | "email": "sindresorhus@gmail.com", 21 | "url": "sindresorhus.com" 22 | }, 23 | "maintainers": [ 24 | { 25 | "name": "Rob Dodson", 26 | "email": "lets.email.rob@gmail.com", 27 | "url": "robdodson.me" 28 | } 29 | ], 30 | "contributors": [ 31 | { 32 | "name": "Merrick Christensen", 33 | "email": "merrick.christensen@gmail.com", 34 | "url": "merrickchristensen.com" 35 | } 36 | ], 37 | "main": "lib", 38 | "bin": "bin/bower-requirejs.js", 39 | "repository": "yeoman/bower-requirejs", 40 | "scripts": { 41 | "test": "grunt test" 42 | }, 43 | "dependencies": { 44 | "chalk": "^1.0.0", 45 | "file-utils": "^0.2.1", 46 | "lodash": "^3.3.0", 47 | "nopt": "^3.0.0", 48 | "object-assign": "^2.0.0", 49 | "requirejs": "^2.1.5", 50 | "slash": "^1.0.0", 51 | "sudo-block": "^1.0.0", 52 | "update-notifier": "^0.3.0" 53 | }, 54 | "devDependencies": { 55 | "bower": "^1.x", 56 | "durable-json-lint": "^0.0.1", 57 | "grunt": "^0.4.5", 58 | "grunt-cli": "^0.1.13", 59 | "grunt-contrib-clean": "^0.6.0", 60 | "grunt-contrib-copy": "^0.8.0", 61 | "grunt-contrib-jshint": "^0.11.0", 62 | "grunt-contrib-nodeunit": "^0.4.1", 63 | "grunt-simple-mocha": "^0.4.0", 64 | "load-grunt-tasks": "^3.1.0", 65 | "mocha": "*", 66 | "mockery": "^1.4.0", 67 | "should": "^5.0.1" 68 | }, 69 | "peerDependencies": { 70 | "bower": "^1.x" 71 | }, 72 | "engines": { 73 | "node": ">=0.10.0" 74 | }, 75 | "files": [ 76 | "bin", 77 | "lib", 78 | "templates" 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # bower-requirejs [![Build Status](https://secure.travis-ci.org/yeoman/bower-requirejs.svg?branch=master)](http://travis-ci.org/yeoman/bower-requirejs) 2 | 3 | > Automagically wire-up installed Bower components into your RequireJS config 4 | 5 | 6 | ## Install 7 | 8 | ```sh 9 | $ npm install --save bower-requirejs 10 | ``` 11 | 12 | 13 | ## Usage 14 | 15 | ``` 16 | ./node_modules/.bin/bower-requirejs -c path/to/config.js -e underscore -e jquery 17 | ``` 18 | 19 | 20 | ## Options 21 | 22 | ``` 23 | -h, --help # Print options and usage 24 | -v, --version # Print the version number 25 | -c, --config # Path to your RequireJS config file 26 | -e, --exclude # Name of a dependency to be excluded from the process 27 | -b, --base-url # Path which all dependencies will be relative to 28 | -t, --transitive # Process transitive dependencies 29 | -s, --shim # Shim dependencies 30 | -d, --exclude-dev # Exclude devDependencies 31 | ``` 32 | 33 | 34 | ## Using Bower Hooks 35 | 36 | Bower >=v1.3.1 includes [hooks](https://github.com/bower/bower/blob/master/HOOKS.md) for `preinstall`, `postinstall` and `preuninstall` actions. To run grunt-bower-requirejs after every bower install, add a `scripts` block to your `.bowerrc`. 37 | 38 | ``` 39 | { 40 | "scripts": { 41 | "postinstall": "bower-requirejs -c path/to/config.js" 42 | } 43 | } 44 | ``` 45 | 46 | 47 | ## Things to remember 48 | 49 | ### Config file 50 | 51 | If you do not already have a `config.js` file at the location specified by the `--config` option then one will be generated for you. A basic `config.js` file looks like this: 52 | 53 | ``` js 54 | require.config({ 55 | shim: {}, 56 | paths: {} 57 | }); 58 | ``` 59 | 60 | You still need to create a path for *your* js files. This tool will only create paths for third party libraries specified in `bower.json`. 61 | 62 | ``` js 63 | require.config({ 64 | shim: {}, 65 | paths: { 66 | myComponent: 'js/myComponent.js' // make sure to add your components! 67 | } 68 | }); 69 | ``` 70 | 71 | The tool does not overwrite the config file, it just adds additional paths to it. So paths you add will be preserved. Keep in mind that if you change or remove one of your Bower dependencies after you've run the task, that path will still exist in the config file and you'll need to manually remove it. 72 | 73 | 74 | ### Transitive option 75 | 76 | If the transitive option is set to ```true```, then transitive dependencies will be also added to the require config. 77 | 78 | For example, say we explicitly have an entry in our bower config for module ```myTotallyCoolModule```, which depends on ```jQuery``` and ```underscore```. If the transitive option is set to ```true```, there will be config entries for ```myTotallyCoolModule```, ```jQuery```, and ```underscore```. Otherwise, if the transitive option is set to ```false```, there will only be a config entry for ```myTotallyCoolModule```. 79 | 80 | Each transitive dependency is only included once, even if the dependency is used multiple times. 81 | 82 | ### exclude-dev option 83 | 84 | If the `exclude-dev` option is set to ```true```, then dev-dependencies will not be added to the require config. 85 | 86 | 87 | ### RequireJS component 88 | 89 | ## Package Support 90 | 91 | If a dependency's `moduleType` is set to `node` in `bower.json` it will be treated as a [CommonJS Package](http://requirejs.org/docs/api.html#packages). 92 | 93 | The following `bower.json` file: 94 | 95 | ``` js 96 | { 97 | "name": "node-module-type-stub", 98 | "version": "0.0.1", 99 | "moduleType": ["node"], 100 | "main": "myMain.js" 101 | } 102 | ``` 103 | 104 | Will generate this entry in your `config.js` file: 105 | 106 | ``` 107 | require.config({ 108 | shim: {}, 109 | packages: [ 110 | { 111 | name: 'node-module-type-stub', 112 | main: 'myMain.js' 113 | } 114 | ], 115 | paths: {} 116 | }); 117 | ``` 118 | 119 | ### Overriding the main file of a dependency 120 | 121 | You can override the main file of a given dependency by specifying the `overrides.{dependency}.main` property 122 | in your `bower.json` file: 123 | 124 | ```js 125 | { 126 | "overrides": { 127 | "jquery": { 128 | "main": "jquery.min.js" 129 | }, 130 | "anima": { 131 | "main": "anima.min.js" 132 | } 133 | } 134 | } 135 | ``` 136 | 137 | > The file path is relative to the dependency folder 138 | 139 | ## Programmatic API 140 | 141 | ### bowerRequireJS(options, callback) 142 | 143 | - `options` — An [options object](https://github.com/yeoman/bower-requirejs#options) containing optional config, baseUrl, and exclude options. The `config` option specifies an output file to which the generated require.js config will be written. If a require.js config file already exists at this location, the generated config will be merged into this file. 144 | - `callback` — A callback to execute when the task is finished. This callback will receive an object that contains the require.js configuration generated from bower components. Note that this includes *only* config elements representing bower components. 145 | 146 | You can use `bower-requirejs` directly in your app if you prefer to not rely on the binary. 147 | 148 | ```js 149 | var bowerRequireJS = require('bower-requirejs'); 150 | 151 | var options = { 152 | config: 'scripts/config.js', 153 | exclude: ['underscore', 'jquery'], 154 | transitive: true 155 | }; 156 | 157 | bowerRequireJS(options, function (rjsConfigFromBower) { 158 | // all done! 159 | }); 160 | ``` 161 | 162 | 163 | ### parse(pkg, name, baseUrl) 164 | 165 | - `pkg` — A package object returned from `bower list` 166 | - `name` — The name of the package 167 | - `baseUrl` — A baseUrl to use when generating the path 168 | 169 | If you would like to just receive a paths object you can do so with the `parse` module. If your package does not contain a `bower.json` file, or if the `bower.json` does not contain a `main` attribute then the parse module will try to use the `primary` module to find a primary, top-level js file. 170 | 171 | ```js 172 | var bower = require('bower'); 173 | var _ = require('lodash'); 174 | var parse = require('bower-requirejs/lib/parse'); 175 | 176 | var baseUrl = './'; 177 | 178 | bower.commands.list() 179 | .on('end', function (data) { 180 | _.forOwn(data.dependencies, function (pkg, name) { 181 | if (name == 'jquery') { 182 | var pathObj = parse(pkg, name, baseUrl); 183 | } 184 | }); 185 | }); 186 | ``` 187 | 188 | ### primary(name, canonicalDir, opts) 189 | 190 | - `name` — The package name 191 | - `canonicalDir` — The canonicalDir for the package, either returned by `bower list` or passed in manually 192 | - `opts` — Use the ```opts.extraSearchDirs``` to specify other dirs to search, relative to the canonicalDir. By default this is ```['dist']```. 193 | 194 | If you just want to look for the js file in a bower component's top-level directory or 'dist' directory you can use the `primary` module. The `primary` module will exclude gruntfiles and `min.js` files. It will also check if `package.json` specifies a `main` js file. 195 | 196 | ```js 197 | var primary = require('bower-requirejs/lib/primary'); 198 | 199 | var name = 'backbone'; 200 | var dep = { canonicalDir: './bower_components/backbone' }; 201 | 202 | var primaryJS = primary(name, dep); 203 | // returns backbone.js 204 | ``` 205 | 206 | ### buildConfig(bowerDependencyGraph, options) 207 | 208 | - `bowerDependencyGraph` — A bower dependency graph, as returned by a call to `bower.commands.list` 209 | - `options` — An object containing `baseUrl`, `exclude`, and `transitive` options, as described above. 210 | 211 | This module can be used to generate a requireJs config elements from bower components. 212 | 213 | ```js 214 | var buildConfig = require('bower-requirejs/lib/build-config'); 215 | 216 | bower.commands.list({}) 217 | .on('end', function (dependencyGraph) { 218 | var configElementsFromBower = buildConfig(dependencyGraph, { 219 | baseUrl : '/some/base/url', 220 | exclude: ['underscore', 'jquery'], 221 | transitive: true 222 | }); 223 | }); 224 | ``` 225 | 226 | ## Credit 227 | 228 | [![Sindre Sorhus](http://gravatar.com/avatar/d36a92237c75c5337c17b60d90686bf9?s=144)](http://sindresorhus.com) | [![Rob Dodson](http://gravatar.com/avatar/95c3a3b33ea51545229c625bef42e343?s=144)](http://robdodson.me) 229 | :---:|:---: 230 | [Sindre Sorhus](http://sindresorhus.com) (creator) | [Rob Dodson](http://robdodson.me) (maintainer) 231 | 232 | 233 | ## License 234 | 235 | [BSD license](http://opensource.org/licenses/bsd-license.php) and copyright Google 236 | -------------------------------------------------------------------------------- /templates/config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: {}, 3 | paths: {} 4 | }); 5 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/baseurl-expected.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: {}, 3 | packages: [ 4 | { 5 | name: 'node-module-type-stub', 6 | main: 'myMain.js' 7 | } 8 | ], 9 | paths: { 10 | hm: 'scripts/vendor/hm', 11 | esprima: 'scripts/vendor/esprima', 12 | anima: 'bower_components/anima/anima.min', 13 | 'backbone-amd': 'bower_components/backbone-amd/backbone', 14 | backbone: 'bower_components/backbone/backbone', 15 | 'jquery-ui-touch-punch-amd': 'bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 16 | jquery: 'bower_components/jquery/jquery.min', 17 | json2: 'bower_components/json2/json2', 18 | requirejs: 'bower_components/requirejs/require', 19 | respond: 'bower_components/respond/respond.src', 20 | konamicode: 'bower_components/konamicode.js/build/konamicode.min', 21 | typeahead: 'bower_components/typeahead.js/dist/typeahead', 22 | handlebars: 'bower_components/handlebars/handlebars', 23 | mout: 'bower_components/mout/src', 24 | 'handlebars.runtime': 'bower_components/handlebars/handlebars.runtime', 25 | 'backbone.marionette': 'bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/baseurl.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: {}, 3 | paths: { 4 | hm: 'scripts/vendor/hm', 5 | esprima: 'scripts/vendor/esprima' 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/config-expected.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | hm: 'vendor/hm', 13 | esprima: 'vendor/esprima', 14 | anima: '../bower_components/anima/anima.min', 15 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 16 | backbone: '../bower_components/backbone/backbone', 17 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 18 | jquery: '../bower_components/jquery/jquery.min', 19 | json2: '../bower_components/json2/json2', 20 | requirejs: '../bower_components/requirejs/require', 21 | respond: '../bower_components/respond/respond.src', 22 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 23 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 24 | handlebars: '../bower_components/handlebars/handlebars', 25 | mout: '../bower_components/mout/src', 26 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 27 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: { 3 | 4 | }, 5 | paths: { 6 | hm: 'vendor/hm', 7 | esprima: 'vendor/esprima' 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/generated-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | anima: '../bower_components/anima/anima.min', 13 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 14 | backbone: '../bower_components/backbone/backbone', 15 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 16 | jquery: '../bower_components/jquery/jquery.min', 17 | json2: '../bower_components/json2/json2', 18 | requirejs: '../bower_components/requirejs/require', 19 | respond: '../bower_components/respond/respond.src', 20 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 21 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 22 | mout: '../bower_components/mout/src', 23 | handlebars: '../bower_components/handlebars/handlebars', 24 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 25 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/global-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | hm: 'vendor/hm', 13 | esprima: 'vendor/esprima', 14 | anima: '../bower_components/anima/anima.min', 15 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 16 | backbone: '../bower_components/backbone/backbone', 17 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 18 | jquery: '../bower_components/jquery/jquery.min', 19 | json2: '../bower_components/json2/json2', 20 | requirejs: '../bower_components/requirejs/require', 21 | respond: '../bower_components/respond/respond.src', 22 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 23 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 24 | handlebars: '../bower_components/handlebars/handlebars', 25 | mout: '../bower_components/mout/src', 26 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 27 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/global-config.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: {}, 3 | paths: { 4 | hm: 'vendor/hm', 5 | esprima: 'vendor/esprima' 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/no-devdependencies-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | anima: '../bower_components/anima/anima.min', 13 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 14 | backbone: '../bower_components/backbone/backbone', 15 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 16 | jquery: '../bower_components/jquery/jquery.min', 17 | requirejs: '../bower_components/requirejs/require', 18 | respond: '../bower_components/respond/respond.src', 19 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 20 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 21 | mout: '../bower_components/mout/src', 22 | handlebars: '../bower_components/handlebars/handlebars', 23 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 24 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/pathless-config-expected.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | anima: '../bower_components/anima/anima.min', 13 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 14 | backbone: '../bower_components/backbone/backbone', 15 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 16 | jquery: '../bower_components/jquery/jquery.min', 17 | json2: '../bower_components/json2/json2', 18 | requirejs: '../bower_components/requirejs/require', 19 | respond: '../bower_components/respond/respond.src', 20 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 21 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 22 | handlebars: '../bower_components/handlebars/handlebars', 23 | mout: '../bower_components/mout/src', 24 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 25 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/pathless-config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: {} 3 | }); 4 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/shim-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 'backbone.babysitter': { 4 | deps: ['backbone', '../vendor/backbone.wreqr/reports/coverage/prettify.css'] 5 | }, 6 | 'backbone.marionette': { 7 | deps: [ 8 | 'backbone', 9 | 'jquery' 10 | ] 11 | }, 12 | 'typeahead.js': { 13 | exports: 'jQuery', 14 | deps: ['jquery'] 15 | }, 16 | }, 17 | packages: [ 18 | { 19 | name: 'node-module-type-stub', 20 | main: 'myMain.js' 21 | } 22 | ], 23 | paths: { 24 | anima: '../bower_components/anima/anima.min', 25 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 26 | backbone: '../bower_components/backbone/backbone', 27 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 28 | jquery: '../bower_components/jquery/jquery.min', 29 | json2: '../bower_components/json2/json2', 30 | requirejs: '../bower_components/requirejs/require', 31 | respond: '../bower_components/respond/respond.src', 32 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 33 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 34 | handlebars: '../bower_components/handlebars/handlebars', 35 | mout: '../bower_components/mout/src', 36 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 37 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette' 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/shim-config.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 'typeahead.js': { 4 | exports: 'jQuery' 5 | }, 6 | 'backbone.babysitter': { 7 | deps: ['backbone', '../vendor/backbone.wreqr/reports/coverage/prettify.css'] 8 | } 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/transitive-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 4 | }, 5 | packages: [ 6 | { 7 | name: 'node-module-type-stub', 8 | main: 'myMain.js' 9 | } 10 | ], 11 | paths: { 12 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 13 | respond: '../bower_components/respond/respond.src', 14 | requirejs: '../bower_components/requirejs/require', 15 | mout: '../bower_components/mout/src', 16 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 17 | json2: '../bower_components/json2/json2', 18 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 19 | handlebars: '../bower_components/handlebars/handlebars', 20 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 21 | underscore: '../bower_components/underscore/underscore', 22 | jquery: '../bower_components/jquery/jquery.min', 23 | 'backbone.wreqr': '../bower_components/backbone.wreqr/lib/amd/backbone.wreqr', 24 | 'backbone.babysitter': '../bower_components/backbone.babysitter/lib/backbone.babysitter', 25 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette', 26 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 27 | backbone: '../bower_components/backbone/backbone', 28 | anima: '../bower_components/anima/anima.min' 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /test/acceptance/fixtures/transitive-shim-config-expected.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | shim: { 3 | 'backbone.babysitter': { 4 | deps: ['backbone', 'underscore', '../vendor/backbone.wreqr/reports/coverage/prettify.css'] 5 | }, 6 | 'backbone.marionette': { 7 | deps: [ 8 | 'backbone', 9 | 'backbone.babysitter', 10 | 'backbone.wreqr', 11 | 'jquery', 12 | 'underscore' 13 | ] 14 | }, 15 | 'typeahead.js': { 16 | exports: 'jQuery', 17 | deps: ['jquery'] 18 | }, 19 | }, 20 | packages: [ 21 | { 22 | name: 'node-module-type-stub', 23 | main: 'myMain.js' 24 | } 25 | ], 26 | paths: { 27 | typeahead: '../bower_components/typeahead.js/dist/typeahead', 28 | respond: '../bower_components/respond/respond.src', 29 | requirejs: '../bower_components/requirejs/require', 30 | mout: '../bower_components/mout/src', 31 | konamicode: '../bower_components/konamicode.js/build/konamicode.min', 32 | json2: '../bower_components/json2/json2', 33 | 'jquery-ui-touch-punch-amd': '../bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch', 34 | handlebars: '../bower_components/handlebars/handlebars', 35 | 'handlebars.runtime': '../bower_components/handlebars/handlebars.runtime', 36 | underscore: '../bower_components/underscore/underscore', 37 | jquery: '../bower_components/jquery/jquery.min', 38 | 'backbone.wreqr': '../bower_components/backbone.wreqr/lib/amd/backbone.wreqr', 39 | 'backbone.babysitter': '../bower_components/backbone.babysitter/lib/backbone.babysitter', 40 | 'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette', 41 | 'backbone-amd': '../bower_components/backbone-amd/backbone', 42 | backbone: '../bower_components/backbone/backbone', 43 | anima: '../bower_components/anima/anima.min' 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /test/acceptance/index.js: -------------------------------------------------------------------------------- 1 | /* global describe:true, it:true */ 2 | 3 | 'use strict'; 4 | var fs = require('fs'); 5 | var should = require('should'); 6 | var durableJsonLint = require('durable-json-lint'); 7 | 8 | 9 | // extract the config object as a string from the actual and expected files. 10 | // then turn the string into json so we can deeply compare the objects. 11 | // we do this because bower does not always create the paths object's keys 12 | // in the same order. so a pure string to string comparison will break. 13 | var jsonify = function (str) { 14 | var dirtyJson = str.slice(str.indexOf('{'), str.lastIndexOf('}') + 1); 15 | var cleanJson = durableJsonLint(dirtyJson).json; 16 | 17 | return JSON.parse(cleanJson); 18 | }; 19 | 20 | describe('index', function () { 21 | 22 | describe('config', function () { 23 | it('should return the expected result', function (done) { 24 | var opts = { config: 'tmp/config.js', exclude: ['underscore'] }; 25 | require('../../lib')(opts, function () { 26 | var actual = jsonify(fs.readFileSync('tmp/config.js', 'utf8')); 27 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/config-expected.js', 'utf8')); 28 | actual.should.eql(expected); 29 | done(); 30 | }); 31 | }); 32 | }); 33 | 34 | describe('global-config', function () { 35 | it('should return the expected result', function (done) { 36 | var opts = { config: 'tmp/global-config.js', exclude: ['underscore'] }; 37 | require('../../lib')(opts, function () { 38 | var actual = jsonify(fs.readFileSync('tmp/global-config.js', 'utf8')); 39 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/global-config-expected.js', 'utf8')); 40 | actual.should.eql(expected); 41 | done(); 42 | }); 43 | }); 44 | }); 45 | 46 | describe('baseurl', function () { 47 | it('should return the expected result', function (done) { 48 | var opts = { config: 'tmp/baseurl.js', exclude: ['underscore'], baseUrl: './' }; 49 | require('../../lib')(opts, function () { 50 | var actual = jsonify(fs.readFileSync('tmp/baseurl.js', 'utf8')); 51 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/baseurl-expected.js', 'utf8')); 52 | actual.should.eql(expected); 53 | done(); 54 | }); 55 | }); 56 | }); 57 | 58 | describe('pathless-config', function () { 59 | it('should return the expected result', function (done) { 60 | var opts = { config: 'tmp/pathless-config.js', exclude: ['underscore'] }; 61 | require('../../lib')(opts, function () { 62 | var actual = jsonify(fs.readFileSync('tmp/pathless-config.js', 'utf8')); 63 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/pathless-config-expected.js', 'utf8')); 64 | actual.should.eql(expected); 65 | done(); 66 | }); 67 | }); 68 | }); 69 | 70 | describe('generated-config', function () { 71 | it('should return the expected result', function (done) { 72 | var opts = { config: 'tmp/generated-config.js', exclude: ['underscore'] }; 73 | require('../../lib')(opts, function () { 74 | var actual = jsonify(fs.readFileSync('tmp/generated-config.js', 'utf8')); 75 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/generated-config-expected.js', 'utf8')); 76 | actual.should.eql(expected); 77 | done(); 78 | }); 79 | }); 80 | }); 81 | 82 | describe('shims', function() { 83 | it('should return the expected result', function (done) { 84 | var opts = { shim: true, config: 'tmp/shim-config.js', exclude: ['underscore'] }; 85 | require('../../lib')(opts, function () { 86 | var actual = jsonify(fs.readFileSync('tmp/shim-config.js', 'utf8')); 87 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/shim-config-expected.js', 'utf8')); 88 | actual.should.eql(expected); 89 | done(); 90 | }); 91 | }); 92 | }); 93 | 94 | describe('with transitive dependencies', function () { 95 | it('should return the expected result', function (done) { 96 | var opts = { transitive: true, config: 'tmp/transitive-config.js' }; 97 | require('../../lib')(opts, function () { 98 | var actual = jsonify(fs.readFileSync('tmp/transitive-config.js', 'utf8')); 99 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/transitive-config-expected.js', 'utf8')); 100 | actual.should.eql(expected); 101 | done(); 102 | }); 103 | }); 104 | 105 | it('should shim transitive dependencies', function (done) { 106 | var opts = { transitive: true, shim: true, config: 'tmp/shim-config.js' }; 107 | require('../../lib')(opts, function () { 108 | var actual = jsonify(fs.readFileSync('tmp/shim-config.js', 'utf8')); 109 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/transitive-shim-config-expected.js', 'utf8')); 110 | actual.should.eql(expected); 111 | done(); 112 | }); 113 | }); 114 | }); 115 | 116 | describe('when dependency is missing', function () { 117 | it('should callback with false', function (done) { 118 | var opts = { config: 'tmp/config.js' }; 119 | fs.renameSync('bower_components/jquery', 'bower_components/foo'); 120 | require('../../lib')(opts, function (completed) { 121 | console.log('Testing for missing jquery...'); 122 | var actual = completed; 123 | var expected = false; 124 | actual.should.eql(expected); 125 | fs.renameSync('bower_components/foo', 'bower_components/jquery'); 126 | done(); 127 | }); 128 | }); 129 | }); 130 | 131 | describe('without dev-dependencies', function () { 132 | it('should return the expected result', function (done) { 133 | var opts = { config: 'tmp/no-devdependencies-config.js', exclude: ['underscore'], 'exclude-dev': true }; 134 | require('../../lib')(opts, function () { 135 | var actual = jsonify(fs.readFileSync('tmp/no-devdependencies-config.js', 'utf8')); 136 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/no-devdependencies-config-expected.js', 'utf8')); 137 | actual.should.eql(expected); 138 | done(); 139 | }); 140 | }); 141 | }); 142 | 143 | describe('running multiple times', function () { 144 | it('should return the expected result', function (done) { 145 | var opts = { config: 'tmp/multiple-generated-config.js', exclude: ['underscore'] }; 146 | require('../../lib')(opts, function () { 147 | require('../../lib')(opts, function () { 148 | var actual = jsonify(fs.readFileSync('tmp/multiple-generated-config.js', 'utf8')); 149 | var expected = jsonify(fs.readFileSync('test/acceptance/fixtures/generated-config-expected.js', 'utf8')); 150 | actual.should.eql(expected); 151 | done(); 152 | }); 153 | }); 154 | }); 155 | }); 156 | }); 157 | -------------------------------------------------------------------------------- /test/binary/bower-requirejs.js: -------------------------------------------------------------------------------- 1 | /* jshint expr:true, unused:false */ 2 | /* global describe:true, it:true, beforeEach:true, afterEach:true */ 3 | 4 | 'use strict'; 5 | var path = require('path'); 6 | var execFile = require('child_process').execFile; 7 | var should = require('should'); 8 | var mockery = require('mockery'); 9 | var pkg = require('../../package.json'); 10 | 11 | describe('bin', function () { 12 | describe('mocked', function () { 13 | beforeEach(function () { 14 | this.origArgv = process.argv; 15 | this.origExit = process.exit; 16 | 17 | mockery.enable({ 18 | warnOnUnregistered: false, 19 | useCleanCache: true 20 | }); 21 | 22 | // Mock lib/index.js to verify the binary passes along the 23 | // correct arguments 24 | mockery.registerMock('../lib', function (opts, cb) { 25 | this.mockOpts = opts; 26 | }.bind(this)); 27 | }); 28 | 29 | afterEach(function () { 30 | mockery.disable(); 31 | process.argv = this.origArgv; 32 | process.exit = this.origExit; 33 | }); 34 | 35 | it('should pass the correct opts', function () { 36 | process.argv = [ 37 | 'node', 38 | path.join(__dirname, '../../', pkg.bin), 39 | '-c', 'foo', 40 | '-b', 'bar', 41 | '-e', 'baz', 42 | '-t', 43 | '-d' 44 | ]; 45 | require('../../bin/bower-requirejs'); 46 | this.mockOpts.config.should.eql(path.join(process.cwd(), 'foo')); 47 | this.mockOpts.baseUrl.should.eql(path.join(process.cwd(), 'bar')); 48 | this.mockOpts.exclude.should.eql(['baz']); 49 | this.mockOpts.transitive.should.eql(true); 50 | this.mockOpts['exclude-dev'].should.eql(true); 51 | }); 52 | 53 | it('should alias base-url', function () { 54 | process.argv = [ 55 | 'node', 56 | path.join(__dirname, '../../', pkg.bin), 57 | '-c', 'foo', 58 | '--baseUrl', 'bar', 59 | '-e', 'baz' 60 | ]; 61 | require('../../bin/bower-requirejs'); 62 | this.mockOpts.config.should.eql(path.join(process.cwd(), 'foo')); 63 | this.mockOpts.baseUrl.should.eql(path.join(process.cwd(), 'bar')); 64 | this.mockOpts.exclude.should.eql(['baz']); 65 | }); 66 | 67 | it('should pass base-url', function () { 68 | process.argv = [ 69 | 'node', 70 | path.join(__dirname, '../../', pkg.bin), 71 | '-c', 'foo', 72 | '--base-url', 'bar', 73 | '-e', 'baz' 74 | ]; 75 | require('../../bin/bower-requirejs'); 76 | this.mockOpts.config.should.eql(path.join(process.cwd(), 'foo')); 77 | this.mockOpts.baseUrl.should.eql(path.join(process.cwd(), 'bar')); 78 | this.mockOpts.exclude.should.eql(['baz']); 79 | }); 80 | 81 | it('should pass dev-dependencies', function () { 82 | process.argv = [ 83 | 'node', 84 | path.join(__dirname, '../../', pkg.bin), 85 | '-c', 'foo', 86 | '--exclude-dev', 87 | '-e', 'baz' 88 | ]; 89 | require('../../bin/bower-requirejs'); 90 | this.mockOpts.config.should.eql(path.join(process.cwd(), 'foo')); 91 | this.mockOpts['exclude-dev'].should.eql(true); 92 | this.mockOpts.exclude.should.eql(['baz']); 93 | }); 94 | 95 | 96 | 97 | }); 98 | 99 | it('should return the version', function (done) { 100 | var cp = execFile('node', [path.join(__dirname, '../../', pkg.bin), '--version', '--no-update-notifier']); 101 | var expected = pkg.version; 102 | 103 | cp.stdout.on('data', function (data) { 104 | data.replace(/\r\n|\n/g, '').should.eql(expected); 105 | done(); 106 | }); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec 2 | --timeout 5000 3 | -------------------------------------------------------------------------------- /test/unit/build-config.js: -------------------------------------------------------------------------------- 1 | /* jshint expr: true, unused: false */ 2 | /* global describe:true, it:true */ 3 | 4 | 'use strict'; 5 | var should = require('should'); 6 | var path = require('path'); 7 | var _ = require('lodash'); 8 | var buildConfig = require('../../lib/build-config'); 9 | 10 | 11 | describe('buildConfig', function () { 12 | 13 | /* 14 | * Helper functions to create mock dependency graphs. 15 | */ 16 | var generateDependencyGraph = function (opts) { 17 | var overrides = opts.overrides; 18 | var dependencyGraph = { 19 | canonicalDir: '/test/canonical/dir', 20 | pkgMeta: { 21 | name: 'testName' 22 | } 23 | }; 24 | 25 | if (overrides) { 26 | dependencyGraph.pkgMeta.overrides = overrides; 27 | } 28 | 29 | var generatedDependencies = {}; 30 | 31 | for (var i = 0; i < opts.dependencies.length; i++) { 32 | var dep = opts.dependencies[i]; 33 | generatedDependencies[dep.name] = generateDependency(_.extend({ 34 | baseUrl: opts.baseUrl 35 | }, dep)); 36 | } 37 | 38 | dependencyGraph.dependencies = generatedDependencies; 39 | 40 | return dependencyGraph; 41 | }; 42 | 43 | var generateDependency = function (opts) { 44 | opts = opts || {}; 45 | var baseUrl = opts.baseUrl || '/'; 46 | var dependencies = opts.dependencies || []; 47 | var moduleType = opts.moduleType; 48 | 49 | 50 | var dep = { 51 | canonicalDir: path.join(baseUrl, opts.name), 52 | pkgMeta: { 53 | name: opts.name, 54 | main: opts.main || 'main.js' 55 | }, 56 | dependencies: {} 57 | }; 58 | 59 | if (moduleType) { 60 | dep.pkgMeta.moduleType = moduleType; 61 | } 62 | 63 | for (var i = 0; i < dependencies.length; i++) { 64 | var subdep = dependencies[i]; 65 | dep.dependencies[subdep.name] = generateDependency(_.extend({ 66 | baseUrl: baseUrl 67 | }, subdep)); 68 | } 69 | 70 | return dep; 71 | }; 72 | 73 | it('should create config w/ only top-level dependencies', function () { 74 | var baseUrl = '/'; 75 | var dependencyGraph = generateDependencyGraph({ 76 | baseUrl: baseUrl, 77 | dependencies: [ 78 | {name: 'a'}, 79 | {name: 'b', dependencies: [ 80 | {name: 'child-of-b'} 81 | ]} 82 | ] 83 | }); 84 | 85 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl}); 86 | 87 | var expected = { 88 | paths: { 89 | a: 'a/main', 90 | b: 'b/main' 91 | }, 92 | packages: [], 93 | shim: {} 94 | }; 95 | 96 | actual.should.eql(expected); 97 | }); 98 | 99 | it('should create config with transitive dependencies', function () { 100 | var baseUrl = '/'; 101 | var dependencyGraph = generateDependencyGraph({ 102 | baseUrl: baseUrl, 103 | dependencies: [ 104 | {name: 'a'}, 105 | {name: 'b', dependencies: [ 106 | {name: 'child-of-b'} 107 | ]} 108 | ] 109 | }); 110 | 111 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl, transitive: true}); 112 | 113 | var expected = { 114 | paths: { 115 | a: 'a/main', 116 | b: 'b/main', 117 | 'child-of-b': 'child-of-b/main' 118 | }, 119 | packages: [], 120 | shim: {} 121 | }; 122 | actual.should.eql(expected); 123 | }); 124 | 125 | it('should create config w/ only top-level dependencies and shims', function () { 126 | var baseUrl = '/'; 127 | var dependencyGraph = generateDependencyGraph({ 128 | baseUrl: baseUrl, 129 | dependencies: [ 130 | {name: 'a'}, 131 | {name: 'b', dependencies: [ 132 | {name: 'child-of-b'} 133 | ]} 134 | ] 135 | }); 136 | 137 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl, shim: true}); 138 | 139 | var expected = { 140 | paths: { 141 | a: 'a/main', 142 | b: 'b/main' 143 | }, 144 | packages: [], 145 | shim: {} 146 | }; 147 | 148 | actual.should.eql(expected); 149 | }); 150 | 151 | it('should create config with transitive dependencies and shims', function () { 152 | var baseUrl = '/'; 153 | var dependencyGraph = generateDependencyGraph({ 154 | baseUrl: baseUrl, 155 | dependencies: [ 156 | {name: 'a'}, 157 | {name: 'b', dependencies: [ 158 | {name: 'child-of-b', dependencies: [ 159 | {name: 'grandchild-of-b'} 160 | ]} 161 | ]} 162 | ] 163 | }); 164 | 165 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl, transitive: true, shim: true}); 166 | 167 | var expected = { 168 | paths: { 169 | a: 'a/main', 170 | b: 'b/main', 171 | 'child-of-b': 'child-of-b/main', 172 | 'grandchild-of-b': 'grandchild-of-b/main', 173 | }, 174 | packages: [], 175 | shim: { 176 | b: { 177 | deps: ['child-of-b'] 178 | }, 179 | 'child-of-b': { 180 | deps: ['grandchild-of-b'] 181 | } 182 | } 183 | }; 184 | actual.should.eql(expected); 185 | }); 186 | 187 | it('should create without dev-dependencies', function () { 188 | var baseUrl = '/'; 189 | var dependencyGraph = generateDependencyGraph({ 190 | baseUrl: baseUrl, 191 | dependencies: [ 192 | {name: 'a'}, 193 | {name: 'b', dependencies: [ 194 | {name: 'child-of-b'} 195 | ]}, 196 | {name: 'c'} 197 | ] 198 | }); 199 | 200 | dependencyGraph.pkgMeta.devDependencies = {c: '*'}; 201 | 202 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl, transitive: true, 'exclude-dev': true}); 203 | 204 | var expected = { 205 | paths: { 206 | a: 'a/main', 207 | b: 'b/main', 208 | 'child-of-b': 'child-of-b/main' 209 | }, 210 | packages: [], 211 | shim: {} 212 | }; 213 | actual.should.eql(expected); 214 | }); 215 | 216 | it('should create with array as main and configured overrides', function () { 217 | var baseUrl = '/'; 218 | var dependencyGraph = generateDependencyGraph({ 219 | baseUrl: baseUrl, 220 | dependencies: [ 221 | { 222 | name: 'a', 223 | main: ['b.js', 'c.js'] 224 | } 225 | ], 226 | overrides: { 227 | a: { 228 | main: ['b.js', 'c.js', 'd.js'] 229 | } 230 | } 231 | }); 232 | 233 | var actual = buildConfig(dependencyGraph, {baseUrl: baseUrl}); 234 | var expected = { 235 | paths: { 236 | b: 'a/b', 237 | c: 'a/c', 238 | d: 'a/d' 239 | }, 240 | packages: [], 241 | shim: {} 242 | }; 243 | 244 | actual.should.eql(expected); 245 | }); 246 | }); 247 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone-amd/backbone.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone-amd/backbone.min.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone-amd/bogus.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeoman/bower-requirejs/5920f5c2f4feffc8f3f13eef6199f90a8045f5f2/test/unit/fixtures/bower_components/backbone-amd/bogus.js -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone-amd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "backbone", 3 | "main" : "backbone.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone/backbone-min.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/backbone/backbone.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/jquery-ui-touch-punch-amd/grunt.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/jquery-ui-touch-punch-amd/jquery.ui.touch-punch.min.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/mout/src/bogus.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeoman/bower-requirejs/5920f5c2f4feffc8f3f13eef6199f90a8045f5f2/test/unit/fixtures/bower_components/mout/src/bogus.js -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/mout/src/index.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/no-primary/bar.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/no-primary/foo.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/non-js/non-js.js: -------------------------------------------------------------------------------- 1 | // test fixture -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/non-jss/non-jss.js: -------------------------------------------------------------------------------- 1 | // test fixture -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/requirejs/bogus.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeoman/bower-requirejs/5920f5c2f4feffc8f3f13eef6199f90a8045f5f2/test/unit/fixtures/bower_components/requirejs/bogus.js -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/requirejs/require.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/some-js/some-js.js: -------------------------------------------------------------------------------- 1 | // test fixture -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/uses-custom-dir/custom/uses-custom-dir.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/bower_components/uses-dist/dist/uses-dist.js: -------------------------------------------------------------------------------- 1 | // test fixture 2 | -------------------------------------------------------------------------------- /test/unit/fixtures/deps.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // dependencies without a main field for testing primary.js 3 | // these items are paired with dummy files in the fixtures/bower_components dir 4 | 'backbone': { 5 | canonicalDir: './tmp/bower_components/backbone' 6 | }, 7 | 'requirejs': { 8 | canonicalDir: './tmp/bower_components/requirejs' 9 | }, 10 | 'backbone-amd': { 11 | canonicalDir: './tmp/bower_components/backbone-amd' 12 | }, 13 | 'jquery-ui-touch-punch-amd': { 14 | canonicalDir: './tmp/bower_components/jquery-ui-touch-punch-amd' 15 | }, 16 | 'noPrimary': { 17 | canonicalDir: './tmp/bower_components/no-primary' 18 | }, 19 | 20 | // dependencies with a main field for testing parse.js 21 | 'jquery': { 22 | canonicalDir: './tmp/bower_components/jquery', 23 | pkgMeta: { 24 | main: 'jquery.js' 25 | } 26 | }, 27 | 'handlebars': { 28 | canonicalDir: './tmp/bower_components/handlebars', 29 | pkgMeta: { 30 | main: ['handlebars.js', 'handlebars.runtime.js'] 31 | } 32 | }, 33 | 'withCSS': { 34 | canonicalDir: './tmp/bower_components/withCSS', 35 | pkgMeta: { 36 | main: ['withCSS.js', 'withCSS.css'] 37 | } 38 | }, 39 | 'mout': { 40 | canonicalDir: './tmp/bower_components/mout', 41 | pkgMeta: { 42 | main: 'src/' 43 | } 44 | }, 45 | 'non-js': { 46 | canonicalDir: './tmp/bower_components/non-js', 47 | pkgMeta: { 48 | main: 'not/js/foo.css' 49 | } 50 | }, 51 | 'non-jss': { 52 | canonicalDir: './tmp/bower_components/non-jss', 53 | pkgMeta: { 54 | main: [ 55 | 'not/js/foo.css', 56 | 'not/js/also/bar.css' 57 | ] 58 | } 59 | }, 60 | 'some-js': { 61 | canonicalDir: './tmp/bower_components/some-js', 62 | pkgMeta: { 63 | main: [ 64 | 'not/js/foo.css', 65 | 'not/js/also/bar.css', 66 | 'is/js/baz.js' 67 | ] 68 | } 69 | }, 70 | 'some-package': { 71 | canonicalDir: './tmp/bower_components/some-package', 72 | pkgMeta: { 73 | moduleType: ['node'] 74 | } 75 | }, 76 | 'some-package-with-a-main': { 77 | canonicalDir: './tmp/bower_components/some-package-with-a-main', 78 | pkgMeta: { 79 | moduleType: ['node'], 80 | main: 'some-main.js' 81 | } 82 | }, 83 | 'supports-amd-and-node': { 84 | canonicalDir: './tmp/bower_components/supports-amd-and-node', 85 | pkgMeta: { 86 | moduleType: ['node', 'amd'] 87 | } 88 | }, 89 | 90 | // Dependencies that use extra search directories. 91 | 'uses-dist': { 92 | canonicalDir: './tmp/bower_components/uses-dist', 93 | pkgMeta: {} 94 | }, 95 | 'uses-custom-dir': { 96 | canonicalDir: './tmp/bower_components/uses-custom-dir', 97 | pkgMeta: {} 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | /* jshint expr: true, unused: false */ 2 | /* global describe:true, it:true */ 3 | 4 | 'use strict'; 5 | var should = require('should'); 6 | var path = require('path'); 7 | var file = require('file-utils'); 8 | 9 | describe('index', function () { 10 | describe('when config option provided', function () { 11 | it('should create a config file if one does not exist', function (done) { 12 | require('../../lib')({ config: 'tmp/generated-config.js' }, function (generatedConfig) { 13 | file.exists(path.join(__dirname, '../../tmp/generated-config.js')).should.be.ok; 14 | generatedConfig.should.be.ok; 15 | done(); 16 | }); 17 | }); 18 | }); 19 | 20 | describe('when no config option is provided', function () { 21 | it('should just fire callback with generatedConfig object', function (done) { 22 | require('../../lib')({}, function (generatedConfig) { 23 | generatedConfig.should.be.ok; 24 | done(); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/unit/parse.js: -------------------------------------------------------------------------------- 1 | /* jshint expr: true */ 2 | /* global describe:true, it:true */ 3 | 4 | 'use strict'; 5 | var should = require('should'); 6 | var parse = require('../../lib/parse'); 7 | var path = require('path'); 8 | var deps = require('./fixtures/deps'); 9 | 10 | describe('parse', function () { 11 | it('should return a paths object with a single path', function () { 12 | var actual = parse(deps.jquery, 'jquery', './'); 13 | var expected = { type: 'paths', paths: { jquery: 'tmp/bower_components/jquery/jquery' }}; 14 | actual.should.eql(expected); 15 | }); 16 | 17 | it('should return paths by filename if there are multiple js files', function () { 18 | var actual = parse(deps.handlebars, 'handlebars', './'); 19 | var expected = { 20 | type: 'paths', 21 | paths: { 22 | 'handlebars': 'tmp/bower_components/handlebars/handlebars', 23 | 'handlebars.runtime': 'tmp/bower_components/handlebars/handlebars.runtime' 24 | } 25 | }; 26 | actual.should.eql(expected); 27 | }); 28 | 29 | it('should ignore non-JavaScript files', function () { 30 | var actual = parse(deps.withCSS, 'withCSS', './'); 31 | var expected = { 32 | type: 'paths', 33 | paths: { withCSS: 'tmp/bower_components/withCSS/withCSS' } 34 | }; 35 | actual.should.eql(expected); 36 | }); 37 | 38 | it('should ignore single non-JavaScript file in main', function () { 39 | var actual = parse(deps['non-js'], 'non-js', './'); 40 | var expected = { 41 | type: 'paths', 42 | paths: {} 43 | }; 44 | actual.should.eql(expected); 45 | }); 46 | 47 | it('should ignore multiple non-JavaScript files in main', function () { 48 | var actual = parse(deps['non-jss'], 'non-jss', './'); 49 | var expected = { 50 | type: 'paths', 51 | paths: {} 52 | }; 53 | actual.should.eql(expected); 54 | }); 55 | 56 | it('should ignore some non-JavaScript files in main', function () { 57 | var actual = parse(deps['some-js'], 'some-js', './'); 58 | var expected = { 59 | type: 'paths', 60 | paths: { 'some-js': 'tmp/bower_components/some-js/is/js/baz' } 61 | }; 62 | actual.should.eql(expected); 63 | }); 64 | 65 | it('should return a directory path if one is listed in main', function () { 66 | var actual = parse(deps.mout, 'mout', './'); 67 | var expected = { 68 | type: 'paths', 69 | paths: { 70 | mout: 'tmp/bower_components/mout/src' 71 | } 72 | }; 73 | actual.should.eql(expected); 74 | }); 75 | 76 | it('should return a package if moduleType is node', function () { 77 | var name = 'some-package'; 78 | var actual = parse(deps[name], name, './'); 79 | var expected = { 80 | type: 'package', 81 | package: { 82 | name: 'some-package', 83 | main: 'main.js' 84 | } 85 | }; 86 | actual.should.eql(expected); 87 | }); 88 | 89 | it('should parse package main if given', function () { 90 | var name = 'some-package-with-a-main'; 91 | var actual = parse(deps[name], name, './'); 92 | var expected = { 93 | type: 'package', 94 | package: { 95 | name: 'some-package-with-a-main', 96 | main: 'some-main.js' 97 | } 98 | }; 99 | actual.should.eql(expected); 100 | }); 101 | 102 | it('should parse as AMD when both AMD and node are supported', function () { 103 | var name = 'supports-amd-and-node'; 104 | var actual = parse(deps[name], name, './'); 105 | var expected = { 106 | type: 'paths', 107 | paths: false 108 | }; 109 | actual.should.eql(expected); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/unit/primary.js: -------------------------------------------------------------------------------- 1 | /* jshint expr: true */ 2 | /* global describe:true, it:true */ 3 | 4 | 'use strict'; 5 | var should = require('should'); 6 | var primary = require('../../lib/primary'); 7 | var deps = require('./fixtures/deps'); 8 | 9 | describe('primary', function () { 10 | it('should return a js file that matches the project dir', function () { 11 | var actual = primary('backbone', deps.backbone); 12 | var expected = 'backbone.js'; 13 | actual.should.eql(expected); 14 | }); 15 | 16 | it('should return a js file that matches the project dir with suffix', function () { 17 | var actual = primary('requirejs', deps.requirejs); 18 | var expected = 'require.js'; 19 | actual.should.eql(expected); 20 | }); 21 | 22 | it('should return false if no primary js is found', function () { 23 | var actual = primary('noPrimary', deps.noPrimary); 24 | var expected = false; 25 | actual.should.eql(expected); 26 | }); 27 | 28 | it('should return a js file that matches the primary js found in package.json', function () { 29 | var actual = primary('backbone-amd', deps['backbone-amd']); 30 | var expected = 'backbone.js'; 31 | actual.should.eql(expected); 32 | }); 33 | 34 | it('should exclude Gruntfiles', function () { 35 | var actual = primary('jquery-ui-touch-punch-amd', deps['jquery-ui-touch-punch-amd']); 36 | var expected = 'jquery.ui.touch-punch.js'; 37 | actual.should.eql(expected); 38 | }); 39 | 40 | it('should return a js file in dist dir that matches the project dir', function () { 41 | var actual = primary('uses-dist', deps['uses-dist']); 42 | var expected = 'dist/uses-dist.js'; 43 | actual.should.eql(expected); 44 | }); 45 | 46 | it('should return a js file in a custom seach dir that matches the project dir', function () { 47 | var actual = primary('uses-custom-dir', deps['uses-custom-dir'], {extraSearchDirs: ['custom']}); 48 | var expected = 'custom/uses-custom-dir.js'; 49 | actual.should.eql(expected); 50 | }); 51 | }); 52 | --------------------------------------------------------------------------------