├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json └── test ├── angularFilesort_test.js └── fixtures ├── another-factory.js ├── another.js ├── circular.js ├── circular2.js ├── circular3.js ├── dep-on-non-declared.js ├── empty.js ├── module-controller.js ├── module.js ├── no-deps.js └── yet-another.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.11' 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Joakim Bengtson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gulp-angular-filesort [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][depstat-image]][depstat-url] 2 | 3 | --- 4 | 5 | ## WARNING: Considering this for new apps? Don't! 6 | 7 | **Use something like [Browserify](http://browserify.org/) or [Webpack](https://webpack.github.io/) instead!** 8 | 9 | --- 10 | 11 | > Automatically sort AngularJS app files depending on module definitions and usage 12 | 13 | Used in conjunction with [`gulp-inject`](https://www.npmjs.org/package/gulp-inject) to inject your AngularJS application files (scripts) in a correct order, to get rid of all `Uncaught Error: [$injector:modulerr]`. To work correctly, each angular file needs to have a uniquely named module and setter syntax (with the brackets), i.e. `angular.module('myModule', [])`. 14 | 15 | ## Installation 16 | 17 | Install `gulp-angular-filesort` as a development dependency: 18 | 19 | ```shell 20 | npm install --save-dev gulp-angular-filesort 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### In your `gulpfile.js`: 26 | 27 | ```javascript 28 | var angularFilesort = require('gulp-angular-filesort'), 29 | inject = require('gulp-inject'); 30 | 31 | gulp.src('./src/app/index.html') 32 | .pipe(inject( 33 | gulp.src(['./src/app/**/*.js']).pipe(angularFilesort()) 34 | )) 35 | .pipe(gulp.dest('./build')); 36 | ``` 37 | 38 | **NOTE** Do not use the `read` option for `gulp.src`! This plugin analyzes the contents of each file to determine sort order. 39 | 40 | ## License 41 | 42 | [MIT License](http://en.wikipedia.org/wiki/MIT_License) 43 | 44 | [npm-url]: https://npmjs.org/package/gulp-angular-filesort 45 | [npm-image]: https://badge.fury.io/js/gulp-angular-filesort.png 46 | 47 | [travis-url]: http://travis-ci.org/klei/gulp-angular-filesort 48 | [travis-image]: https://secure.travis-ci.org/klei/gulp-angular-filesort.png?branch=master 49 | 50 | [depstat-url]: https://david-dm.org/klei/gulp-angular-filesort 51 | [depstat-image]: https://david-dm.org/klei/gulp-angular-filesort.png 52 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var through = require('through2'); 4 | var ngDep = require('ng-dependencies'); 5 | var toposort = require('toposort'); 6 | var PluginError = require('plugin-error'); 7 | 8 | var PLUGIN_NAME = 'gulp-angular-filesort'; 9 | var ANGULAR_MODULE = 'ng'; 10 | 11 | module.exports = function angularFilesort() { 12 | var files = []; 13 | var ngModules = {}; 14 | var toSort = []; 15 | 16 | function transformFunction(file, encoding, next) { 17 | 18 | // Fail on empty files 19 | if (file.isNull()) { 20 | this.emit('error', new PluginError(PLUGIN_NAME, 'File: "' + file.relative + '" without content. You have to read it with gulp.src(..)')); 21 | return; 22 | } 23 | 24 | // Streams not supported 25 | if (file.isStream()) { 26 | /* jshint validthis:true */ 27 | this.emit('error', new PluginError(PLUGIN_NAME, 'Streaming not supported')); 28 | next(); 29 | return; 30 | } 31 | 32 | var deps; 33 | try { 34 | deps = ngDep(file.contents); 35 | } catch (err) { 36 | this.emit('error', new PluginError(PLUGIN_NAME, 'Error in parsing: "' + file.relative + '", ' + err.message)); 37 | return; 38 | } 39 | 40 | if (deps.modules) { 41 | // Store references to each file with a declaration: 42 | Object.keys(deps.modules).forEach(function(name) { 43 | ngModules[name] = file; 44 | }); 45 | } 46 | 47 | if (deps.dependencies) { 48 | // Add each file with dependencies to the array to sort: 49 | deps.dependencies.forEach(function(dep) { 50 | if (isDependecyUsedInAnyDeclaration(dep, deps)) { 51 | return; 52 | } 53 | if (dep === ANGULAR_MODULE) { 54 | return; 55 | } 56 | toSort.push([file, dep]); 57 | }); 58 | } 59 | 60 | files.push(file); 61 | next(); 62 | 63 | } 64 | 65 | function flushFunction(next) { 66 | 67 | // Convert all module names to actual files with declarations: 68 | for (var i = 0; i < toSort.length; i++) { 69 | var moduleName = toSort[i][1]; 70 | var declarationFile = ngModules[moduleName]; 71 | if (declarationFile) { 72 | toSort[i][1] = declarationFile; 73 | } else { 74 | // Depending on module outside stream (possibly a 3rd party one), 75 | // don't care when sorting: 76 | toSort.splice(i--, 1); 77 | } 78 | } 79 | 80 | // Sort `files` with `toSort` as dependency tree: 81 | toposort.array(files, toSort) 82 | .reverse() 83 | .forEach(function(file) { 84 | this.push(file); 85 | }.bind(this)); 86 | 87 | next(); 88 | } 89 | 90 | return through.obj(transformFunction, flushFunction); 91 | 92 | }; 93 | 94 | function isDependecyUsedInAnyDeclaration(dependency, ngDeps) { 95 | if (!ngDeps.modules) { 96 | return false; 97 | } 98 | if (dependency in ngDeps.modules) { 99 | return true; 100 | } 101 | return Object.keys(ngDeps.modules).some(function(module) { 102 | return ngDeps.modules[module].indexOf(dependency) > -1; 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-angular-filesort", 3 | "version": "1.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-colors": { 8 | "version": "1.1.0", 9 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", 10 | "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", 11 | "requires": { 12 | "ansi-wrap": "0.1.0" 13 | } 14 | }, 15 | "ansi-wrap": { 16 | "version": "0.1.0", 17 | "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", 18 | "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" 19 | }, 20 | "arr-diff": { 21 | "version": "4.0.0", 22 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 23 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" 24 | }, 25 | "arr-union": { 26 | "version": "3.1.0", 27 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 28 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" 29 | }, 30 | "assertion-error": { 31 | "version": "1.1.0", 32 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 33 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 34 | "dev": true 35 | }, 36 | "assign-symbols": { 37 | "version": "1.0.0", 38 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 39 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" 40 | }, 41 | "chai": { 42 | "version": "3.5.0", 43 | "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", 44 | "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", 45 | "dev": true, 46 | "requires": { 47 | "assertion-error": "1.1.0", 48 | "deep-eql": "0.1.3", 49 | "type-detect": "1.0.0" 50 | } 51 | }, 52 | "clone": { 53 | "version": "2.1.1", 54 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", 55 | "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", 56 | "dev": true 57 | }, 58 | "clone-buffer": { 59 | "version": "1.0.0", 60 | "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", 61 | "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", 62 | "dev": true 63 | }, 64 | "clone-stats": { 65 | "version": "1.0.0", 66 | "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", 67 | "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", 68 | "dev": true 69 | }, 70 | "cloneable-readable": { 71 | "version": "1.1.1", 72 | "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.1.tgz", 73 | "integrity": "sha512-DNNEq6JdqBFPzS29TaoqZFPNLn5Xn3XyPFqLIhyBT8Xou4lHQEWzD6FinXoJUfhIfWX3aE1JkRa3cbWCHFbt1g==", 74 | "dev": true, 75 | "requires": { 76 | "inherits": "2.0.3", 77 | "process-nextick-args": "2.0.0", 78 | "readable-stream": "2.3.5" 79 | } 80 | }, 81 | "commander": { 82 | "version": "2.3.0", 83 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", 84 | "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", 85 | "dev": true 86 | }, 87 | "core-util-is": { 88 | "version": "1.0.2", 89 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 90 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 91 | }, 92 | "debug": { 93 | "version": "2.2.0", 94 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 95 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 96 | "dev": true, 97 | "requires": { 98 | "ms": "0.7.1" 99 | } 100 | }, 101 | "deep-eql": { 102 | "version": "0.1.3", 103 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", 104 | "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", 105 | "dev": true, 106 | "requires": { 107 | "type-detect": "0.1.1" 108 | }, 109 | "dependencies": { 110 | "type-detect": { 111 | "version": "0.1.1", 112 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", 113 | "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", 114 | "dev": true 115 | } 116 | } 117 | }, 118 | "diff": { 119 | "version": "1.4.0", 120 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", 121 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", 122 | "dev": true 123 | }, 124 | "escape-string-regexp": { 125 | "version": "1.0.2", 126 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", 127 | "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", 128 | "dev": true 129 | }, 130 | "esprima": { 131 | "version": "2.7.3", 132 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 133 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" 134 | }, 135 | "estraverse": { 136 | "version": "4.2.0", 137 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 138 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" 139 | }, 140 | "extend-shallow": { 141 | "version": "3.0.2", 142 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 143 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 144 | "requires": { 145 | "assign-symbols": "1.0.0", 146 | "is-extendable": "1.0.1" 147 | } 148 | }, 149 | "glob": { 150 | "version": "3.2.11", 151 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 152 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 153 | "dev": true, 154 | "requires": { 155 | "inherits": "2.0.3", 156 | "minimatch": "0.3.0" 157 | } 158 | }, 159 | "growl": { 160 | "version": "1.9.2", 161 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 162 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 163 | "dev": true 164 | }, 165 | "inherits": { 166 | "version": "2.0.3", 167 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 168 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 169 | }, 170 | "is-extendable": { 171 | "version": "1.0.1", 172 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 173 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 174 | "requires": { 175 | "is-plain-object": "2.0.4" 176 | } 177 | }, 178 | "is-plain-object": { 179 | "version": "2.0.4", 180 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 181 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 182 | "requires": { 183 | "isobject": "3.0.1" 184 | } 185 | }, 186 | "isarray": { 187 | "version": "1.0.0", 188 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 189 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 190 | }, 191 | "isobject": { 192 | "version": "3.0.1", 193 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 194 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" 195 | }, 196 | "jade": { 197 | "version": "0.26.3", 198 | "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", 199 | "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", 200 | "dev": true, 201 | "requires": { 202 | "commander": "0.6.1", 203 | "mkdirp": "0.3.0" 204 | }, 205 | "dependencies": { 206 | "commander": { 207 | "version": "0.6.1", 208 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 209 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 210 | "dev": true 211 | }, 212 | "mkdirp": { 213 | "version": "0.3.0", 214 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", 215 | "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", 216 | "dev": true 217 | } 218 | } 219 | }, 220 | "lodash": { 221 | "version": "4.17.5", 222 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", 223 | "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" 224 | }, 225 | "lru-cache": { 226 | "version": "2.7.3", 227 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 228 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 229 | "dev": true 230 | }, 231 | "minimatch": { 232 | "version": "0.3.0", 233 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 234 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 235 | "dev": true, 236 | "requires": { 237 | "lru-cache": "2.7.3", 238 | "sigmund": "1.0.1" 239 | } 240 | }, 241 | "minimist": { 242 | "version": "0.0.8", 243 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 244 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 245 | "dev": true 246 | }, 247 | "mkdirp": { 248 | "version": "0.5.1", 249 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 250 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 251 | "dev": true, 252 | "requires": { 253 | "minimist": "0.0.8" 254 | } 255 | }, 256 | "mocha": { 257 | "version": "2.5.3", 258 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", 259 | "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", 260 | "dev": true, 261 | "requires": { 262 | "commander": "2.3.0", 263 | "debug": "2.2.0", 264 | "diff": "1.4.0", 265 | "escape-string-regexp": "1.0.2", 266 | "glob": "3.2.11", 267 | "growl": "1.9.2", 268 | "jade": "0.26.3", 269 | "mkdirp": "0.5.1", 270 | "supports-color": "1.2.0", 271 | "to-iso-string": "0.0.2" 272 | } 273 | }, 274 | "ms": { 275 | "version": "0.7.1", 276 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 277 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 278 | "dev": true 279 | }, 280 | "ng-dependencies": { 281 | "version": "0.8.1", 282 | "resolved": "https://registry.npmjs.org/ng-dependencies/-/ng-dependencies-0.8.1.tgz", 283 | "integrity": "sha1-GP1jMscC4PPjdKNv4e1FXGdSu2g=", 284 | "requires": { 285 | "esprima": "2.7.3", 286 | "estraverse": "4.2.0", 287 | "lodash": "4.17.5" 288 | } 289 | }, 290 | "plugin-error": { 291 | "version": "1.0.1", 292 | "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", 293 | "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", 294 | "requires": { 295 | "ansi-colors": "1.1.0", 296 | "arr-diff": "4.0.0", 297 | "arr-union": "3.1.0", 298 | "extend-shallow": "3.0.2" 299 | } 300 | }, 301 | "process-nextick-args": { 302 | "version": "2.0.0", 303 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 304 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 305 | }, 306 | "readable-stream": { 307 | "version": "2.3.5", 308 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", 309 | "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", 310 | "requires": { 311 | "core-util-is": "1.0.2", 312 | "inherits": "2.0.3", 313 | "isarray": "1.0.0", 314 | "process-nextick-args": "2.0.0", 315 | "safe-buffer": "5.1.1", 316 | "string_decoder": "1.0.3", 317 | "util-deprecate": "1.0.2" 318 | } 319 | }, 320 | "remove-trailing-separator": { 321 | "version": "1.1.0", 322 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 323 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", 324 | "dev": true 325 | }, 326 | "replace-ext": { 327 | "version": "1.0.0", 328 | "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", 329 | "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", 330 | "dev": true 331 | }, 332 | "safe-buffer": { 333 | "version": "5.1.1", 334 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 335 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 336 | }, 337 | "sigmund": { 338 | "version": "1.0.1", 339 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 340 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 341 | "dev": true 342 | }, 343 | "string_decoder": { 344 | "version": "1.0.3", 345 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 346 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 347 | "requires": { 348 | "safe-buffer": "5.1.1" 349 | } 350 | }, 351 | "supports-color": { 352 | "version": "1.2.0", 353 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", 354 | "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", 355 | "dev": true 356 | }, 357 | "through2": { 358 | "version": "2.0.3", 359 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", 360 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", 361 | "requires": { 362 | "readable-stream": "2.3.5", 363 | "xtend": "4.0.1" 364 | } 365 | }, 366 | "to-iso-string": { 367 | "version": "0.0.2", 368 | "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", 369 | "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", 370 | "dev": true 371 | }, 372 | "toposort": { 373 | "version": "1.0.6", 374 | "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", 375 | "integrity": "sha1-wxdI5V0hDv/AD9zcfW5o19e7nOw=" 376 | }, 377 | "type-detect": { 378 | "version": "1.0.0", 379 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", 380 | "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", 381 | "dev": true 382 | }, 383 | "util-deprecate": { 384 | "version": "1.0.2", 385 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 386 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 387 | }, 388 | "vinyl": { 389 | "version": "2.1.0", 390 | "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", 391 | "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", 392 | "dev": true, 393 | "requires": { 394 | "clone": "2.1.1", 395 | "clone-buffer": "1.0.0", 396 | "clone-stats": "1.0.0", 397 | "cloneable-readable": "1.1.1", 398 | "remove-trailing-separator": "1.1.0", 399 | "replace-ext": "1.0.0" 400 | } 401 | }, 402 | "xtend": { 403 | "version": "4.0.1", 404 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 405 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 406 | } 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-angular-filesort", 3 | "version": "1.2.1", 4 | "description": "Automatically sort AngularJS app files depending on module definitions and usage", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -R spec test/*_test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/klei/gulp-angular-filesort" 12 | }, 13 | "keywords": [ 14 | "gulpplugin", 15 | "angularjs", 16 | "fileorder", 17 | "modules" 18 | ], 19 | "author": "Joakim Bengtson ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/klei/gulp-angular-filesort/issues" 23 | }, 24 | "homepage": "https://github.com/klei/gulp-angular-filesort", 25 | "devDependencies": { 26 | "chai": "^3.5.0", 27 | "mocha": "^2.4.5", 28 | "vinyl": "^2.1.0" 29 | }, 30 | "dependencies": { 31 | "ng-dependencies": "^0.8.1", 32 | "plugin-error": "^1.0.1", 33 | "through2": "^2.0.0", 34 | "toposort": "^1.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/angularFilesort_test.js: -------------------------------------------------------------------------------- 1 | /* jshint camelcase: false, strict: false */ 2 | /* global describe, it */ 3 | var chai = require('chai'), 4 | should = chai.should(), 5 | Vinyl = require('vinyl'), 6 | fs = require('fs'), 7 | path = require('path'), 8 | angularFilesort = require('../.'); 9 | 10 | function fixture(file, config) { 11 | var filepath = path.join(__dirname, file); 12 | return new Vinyl({ 13 | path: filepath, 14 | cwd: __dirname, 15 | base: __dirname, 16 | contents: config && config.withoutContents ? undefined : fs.readFileSync(filepath) 17 | }); 18 | } 19 | 20 | function sort(files, checkResults, handleError) { 21 | var resultFiles = []; 22 | 23 | var stream = angularFilesort(); 24 | 25 | stream.on('error', function (err) { 26 | if (handleError) { 27 | handleError(err); 28 | } else { 29 | should.exist(err); 30 | done(err); 31 | } 32 | }); 33 | 34 | stream.on('data', function (file) { 35 | resultFiles.push(file.relative); 36 | }); 37 | 38 | stream.on('end', function () { 39 | checkResults(resultFiles); 40 | }); 41 | 42 | files.forEach(function (file) { 43 | stream.write(file); 44 | }); 45 | 46 | stream.end(); 47 | } 48 | 49 | describe('gulp-angular-filesort', function () { 50 | it('should sort file with a module definition before files that uses it', function (done) { 51 | var files = [ 52 | fixture('fixtures/another-factory.js'), 53 | fixture('fixtures/another.js'), 54 | fixture('fixtures/module-controller.js'), 55 | fixture('fixtures/no-deps.js'), 56 | fixture('fixtures/module.js'), 57 | fixture('fixtures/dep-on-non-declared.js'), 58 | fixture('fixtures/yet-another.js') 59 | ]; 60 | 61 | sort(files, function (resultFiles) { 62 | resultFiles.length.should.equal(7); 63 | resultFiles.indexOf(path.join('fixtures','module-controller.js')).should.be.above(resultFiles.indexOf(path.join('fixtures','module.js'))); 64 | resultFiles.indexOf(path.join('fixtures','yet-another.js')).should.be.above(resultFiles.indexOf(path.join('fixtures','another.js'))); 65 | resultFiles.indexOf(path.join('fixtures','another-factory.js')).should.be.above(resultFiles.indexOf(path.join('fixtures','another.js'))); 66 | done(); 67 | }) 68 | 69 | }); 70 | 71 | it('should not crash when a module is both declared and used in the same file (Issue #5)', function (done) { 72 | var files = [ 73 | fixture('fixtures/circular.js') 74 | ]; 75 | 76 | sort(files, function (resultFiles) { 77 | resultFiles.length.should.equal(1); 78 | resultFiles[0].should.equal(path.join('fixtures','circular.js')); 79 | done(); 80 | }) 81 | }); 82 | 83 | it('should not crash when a module is used inside a declaration even though it\'s before that module\'s declaration (Issue #7)', function (done) { 84 | var files = [ 85 | fixture('fixtures/circular2.js'), 86 | fixture('fixtures/circular3.js') 87 | ]; 88 | 89 | sort(files, function (resultFiles) { 90 | resultFiles.length.should.equal(2); 91 | resultFiles.should.contain(path.join('fixtures','circular2.js')); 92 | resultFiles.should.contain(path.join('fixtures','circular3.js')); 93 | done(); 94 | }) 95 | }); 96 | 97 | it('fails for not read file', function (done) { 98 | var files = [ 99 | fixture('fake.js', {withoutContents: true}) 100 | ]; 101 | 102 | sort(files, function () { 103 | }, function (err) { 104 | should.exist(err); 105 | done() 106 | }) 107 | }); 108 | 109 | it('does not fail for empty file', function (done) { 110 | var files = [ 111 | fixture('fixtures/empty.js') 112 | ]; 113 | 114 | sort(files, function (resultFiles) { 115 | resultFiles.should.eql([path.join('fixtures','empty.js')]) 116 | done(); 117 | }) 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /test/fixtures/another-factory.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('another') 3 | .factory('AnotherFactory', [function () { 4 | return { 5 | 6 | }; 7 | }]); 8 | -------------------------------------------------------------------------------- /test/fixtures/another.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('another', ['module', 'yet-another']); 3 | -------------------------------------------------------------------------------- /test/fixtures/circular.js: -------------------------------------------------------------------------------- 1 | angular.module('app', ['templates']); 2 | 3 | angular.module('templates', []); 4 | -------------------------------------------------------------------------------- /test/fixtures/circular2.js: -------------------------------------------------------------------------------- 1 | angular.module('app', ['module']); 2 | angular.module('foo', []); 3 | -------------------------------------------------------------------------------- /test/fixtures/circular3.js: -------------------------------------------------------------------------------- 1 | angular.module('module', ['foo']); 2 | -------------------------------------------------------------------------------- /test/fixtures/dep-on-non-declared.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('dep-on-non-declared', ['non-declared']); 3 | -------------------------------------------------------------------------------- /test/fixtures/empty.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klei/gulp-angular-filesort/bef27f6339270682f77a5d25736626ad4a21f826/test/fixtures/empty.js -------------------------------------------------------------------------------- /test/fixtures/module-controller.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('module') 3 | .controller('ModuleCtrl', ['$scope', function ($scope) { 4 | $scope.greeting = 'Hello world'; 5 | }]); 6 | -------------------------------------------------------------------------------- /test/fixtures/module.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('module', []); 3 | -------------------------------------------------------------------------------- /test/fixtures/no-deps.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('no-deps', []); 3 | -------------------------------------------------------------------------------- /test/fixtures/yet-another.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('yet-another', ['module']); 3 | 4 | angular.module('another').service('AnotherService', [function () { 5 | 6 | }]); 7 | --------------------------------------------------------------------------------